forked from mirrors/cobblemon
Compare commits
750
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
891f984d08 | ||
|
|
bb379764f7 | ||
|
|
3ec78d9d7e | ||
|
|
12973dd66a | ||
|
|
ed30e4cd6f | ||
|
|
32c260446e | ||
|
|
41f1eb699f | ||
|
|
e68a593e9e | ||
|
|
903ffe2143 | ||
|
|
1d6845d595 | ||
|
|
f8eb72e437 | ||
|
|
078c961090 | ||
|
|
676342348a | ||
|
|
97442cb880 | ||
|
|
478804f652 | ||
|
|
55dc5c6760 | ||
|
|
0d3b89828a | ||
|
|
fab1bc6f80 | ||
|
|
6b4ff0ac84 | ||
|
|
34805ea496 | ||
|
|
b670d44e21 | ||
|
|
28a3b8edfe | ||
|
|
96ee23b7d1 | ||
|
|
159905eb3b | ||
|
|
c10213480b | ||
|
|
d3ce829e5b | ||
|
|
193daed8ff | ||
|
|
4010f138ae | ||
|
|
5100d6c028 | ||
|
|
baf3cd5f30 | ||
|
|
2327f1aa2c | ||
|
|
62036c0ac6 | ||
|
|
154ff75a9d | ||
|
|
678c98a5b6 | ||
|
|
d9143788bf | ||
|
|
7e1956f165 | ||
|
|
2db494ff5e | ||
|
|
994a41af78 | ||
|
|
7fe1415551 | ||
|
|
2d5f15a4db | ||
|
|
8442000708 | ||
|
|
695ac93f99 | ||
|
|
e5e5c29c12 | ||
|
|
ca4d4ed3be | ||
|
|
700227be41 | ||
|
|
985a4f65dc | ||
|
|
e117100e34 | ||
|
|
93ea13fa4d | ||
|
|
893277fdec | ||
|
|
60dc881e3d | ||
|
|
f98acf0bc4 | ||
|
|
6e104fdb01 | ||
|
|
05c559e203 | ||
|
|
1323caeeec | ||
|
|
cd14881d17 | ||
|
|
1393cc3ef3 | ||
|
|
23ebd0573a | ||
|
|
6447c2e2eb | ||
|
|
039a18a2bf | ||
|
|
71736341f0 | ||
|
|
bb6e5607f1 | ||
|
|
4603f5ac7a | ||
|
|
c683294227 | ||
|
|
f29c2343e6 | ||
|
|
3a2da5a87d | ||
|
|
27d1de8e4e | ||
|
|
628c8f6093 | ||
|
|
eac0f209ce | ||
|
|
9ac0fc1b36 | ||
|
|
1c13ab24e8 | ||
|
|
380cf0ea71 | ||
|
|
8ded7334bb | ||
|
|
8af62f800b | ||
|
|
a50da47a8e | ||
|
|
f690781b0d | ||
|
|
6dc5809622 | ||
|
|
6a7fc67ae1 | ||
|
|
0ac34bf1a4 | ||
|
|
60fc0c1959 | ||
|
|
9716ea0806 | ||
|
|
ffea94f3b2 | ||
|
|
3061ba69e2 | ||
|
|
1cd112ac74 | ||
|
|
741e38d606 | ||
|
|
02f2c072c9 | ||
|
|
4fe54d3dba | ||
|
|
cb11c2b964 | ||
|
|
d4416e50b2 | ||
|
|
520bcda956 | ||
|
|
d10c082e67 | ||
|
|
72d608b300 | ||
|
|
2b4dc467ff | ||
|
|
4722defec2 | ||
|
|
b9390838d0 | ||
|
|
c54849f415 | ||
|
|
d44e625e9d | ||
|
|
7b7acb97d1 | ||
|
|
53af92f254 | ||
|
|
91bce4b153 | ||
|
|
511130d353 | ||
|
|
476c3e54f1 | ||
|
|
6a74d5982a | ||
|
|
03905c77d2 | ||
|
|
4bfe8b808c | ||
|
|
8db943d2a9 | ||
|
|
fdff6ecfa5 | ||
|
|
2eb698969d | ||
|
|
bba60f0098 | ||
|
|
8ee2c95853 | ||
|
|
77db2ce17a | ||
|
|
da9558f5f9 | ||
|
|
e36bbd98f2 | ||
|
|
c4aa925f39 | ||
|
|
5c65dffac8 | ||
|
|
b67b37c99e | ||
|
|
fbb7ee31c5 | ||
|
|
ad5e85ad97 | ||
|
|
5279603432 | ||
|
|
d3ef26976b | ||
|
|
583fba4e77 | ||
|
|
dac01a3730 | ||
|
|
ddb05768e4 | ||
|
|
5374940d24 | ||
|
|
1fd6a660dd | ||
|
|
fd45934775 | ||
|
|
9ee983b2a2 | ||
|
|
16ffbbbd9e | ||
|
|
f23495fe99 | ||
|
|
f61448c333 | ||
|
|
406770eaf1 | ||
|
|
2513fab317 | ||
|
|
3a79e49edb | ||
|
|
5e0ffd8bd3 | ||
|
|
b4b315360d | ||
|
|
a44c70648b | ||
|
|
c41b0cdca2 | ||
|
|
88f743ee48 | ||
|
|
15b9afacf8 | ||
|
|
babcf7430b | ||
|
|
3439ca2011 | ||
|
|
ff5ea6fa21 | ||
|
|
6539f3dea1 | ||
|
|
4820d78416 | ||
|
|
2f417e953c | ||
|
|
8fde0ed4f6 | ||
|
|
87dad0143b | ||
|
|
6715874a8f | ||
|
|
31f88a1f68 | ||
|
|
1677598ec0 | ||
|
|
fcde1eb171 | ||
|
|
a30a5644df | ||
|
|
a5672a38b9 | ||
|
|
3b14ea319b | ||
|
|
bdc91fea71 | ||
|
|
57e2765f90 | ||
|
|
a090c90831 | ||
|
|
f80aa2769a | ||
|
|
20aa4d43b8 | ||
|
|
9bec3e088f | ||
|
|
5b4dbe1957 | ||
|
|
48f248d481 | ||
|
|
d726c4d0ed | ||
|
|
5dcc9ba46d | ||
|
|
f8e4ea70df | ||
|
|
eb64666229 | ||
|
|
5dc1c749f3 | ||
|
|
f7ed0c8799 | ||
|
|
9fde7adb7b | ||
|
|
8b8c07065b | ||
|
|
3accfa29b7 | ||
|
|
1af1569f63 | ||
|
|
c9c421ba2a | ||
|
|
2436a8ddcc | ||
|
|
3364944c26 | ||
|
|
9e6a6eabc7 | ||
|
|
78def7318e | ||
|
|
fdf062bd4c | ||
|
|
ef5a682adb | ||
|
|
dbd2f5d340 | ||
|
|
86bf413f00 | ||
|
|
f76d28d29e | ||
|
|
9c70aad64d | ||
|
|
25de1ad180 | ||
|
|
f967d1ec11 | ||
|
|
efd0497de1 | ||
|
|
f13e7d03a1 | ||
|
|
4a025ac65e | ||
|
|
8a0c98c9ab | ||
|
|
36c5fe2419 | ||
|
|
0c79d102cf | ||
|
|
b14b25ae19 | ||
|
|
b30c0a4a9a | ||
|
|
c99b26a44b | ||
|
|
bd8f644b9a | ||
|
|
7c84cdb05d | ||
|
|
b19bc1e4c7 | ||
|
|
bc5ffda1a5 | ||
|
|
491d6c9fd6 | ||
|
|
ccc6ad77a5 | ||
|
|
00fd9d1278 | ||
|
|
01464f8b71 | ||
|
|
d91fe0b876 | ||
|
|
0293c0e811 | ||
|
|
125975e25f | ||
|
|
c7223ae898 | ||
|
|
baf766298a | ||
|
|
83580e7e8b | ||
|
|
cd575e6b7d | ||
|
|
39dbf78ed2 | ||
|
|
38f5c12dce | ||
|
|
e6a9a27692 | ||
|
|
7ff413c401 | ||
|
|
90335ccb2d | ||
|
|
603f99e5f3 | ||
|
|
1b53a127af | ||
|
|
9679929694 | ||
|
|
fd6fb5db47 | ||
|
|
a80ada8590 | ||
|
|
3f6faf7796 | ||
|
|
c4a4b9cb86 | ||
|
|
5af96e75eb | ||
|
|
d5efdeee68 | ||
|
|
023a01befd | ||
|
|
4912a89e6e | ||
|
|
f2e10d1b01 | ||
|
|
25eb197491 | ||
|
|
8de233b572 | ||
|
|
83972ca9e6 | ||
|
|
35e2190cae | ||
|
|
b966cd2db0 | ||
|
|
57f446260c | ||
|
|
3e492541cc | ||
|
|
cc2022ed59 | ||
|
|
7806503ea7 | ||
|
|
298fdf45d5 | ||
|
|
4e9541d7f5 | ||
|
|
1dab5b8c7c | ||
|
|
2875e9efa9 | ||
|
|
2b42fff66b | ||
|
|
643a33a643 | ||
|
|
e348c48eff | ||
|
|
473f58cab9 | ||
|
|
d4cf44f8f0 | ||
|
|
a074ebbcce | ||
|
|
987b8619a3 | ||
|
|
87632941e8 | ||
|
|
6578ed55e3 | ||
|
|
041acab7ca | ||
|
|
b3de7d1c1a | ||
|
|
afcb2dd77c | ||
|
|
a7bd6d2bf4 | ||
|
|
b096cb60a3 | ||
|
|
f567ceadd8 | ||
|
|
5de92f78c6 | ||
|
|
a2402f78e7 | ||
|
|
1ad6d63137 | ||
|
|
39d417c651 | ||
|
|
ce1bf9f4f2 | ||
|
|
a6136906f8 | ||
|
|
37a99b528e | ||
|
|
048b237302 | ||
|
|
131773f9c8 | ||
|
|
22e55b7e77 | ||
|
|
6c288f9cc8 | ||
|
|
b5e86a9460 | ||
|
|
f199e7c1c0 | ||
|
|
4161d96707 | ||
|
|
59927dd701 | ||
|
|
220d8ddc0f | ||
|
|
0dd143e67e | ||
|
|
7f1c0c3d4c | ||
|
|
d83eb62821 | ||
|
|
a716fda023 | ||
|
|
d14aad787c | ||
|
|
2eb7b60dd1 | ||
|
|
a4f0bf9d2f | ||
|
|
f46c748e9f | ||
|
|
065479c58c | ||
|
|
eee3d46a2d | ||
|
|
d79ffc631b | ||
|
|
d7b43fcbfc | ||
|
|
c82e011f73 | ||
|
|
bf1b996962 | ||
|
|
fc46cdcda0 | ||
|
|
4e7b029afb | ||
|
|
5430f02770 | ||
|
|
6a51abe3ee | ||
|
|
008652b442 | ||
|
|
c1e088eb33 | ||
|
|
1669a2f428 | ||
|
|
2ba63f4641 | ||
|
|
41b9e9001d | ||
|
|
679920b786 | ||
|
|
f058d6e635 | ||
|
|
f9377b7489 | ||
|
|
e59b5094ad | ||
|
|
c8ec4e6f1f | ||
|
|
a2fef9f1be | ||
|
|
3d4df2c098 | ||
|
|
7557cab03d | ||
|
|
f1018b1da9 | ||
|
|
7cd1870f23 | ||
|
|
cbcc6abe40 | ||
|
|
5af4e3bddb | ||
|
|
64c9d47b0f | ||
|
|
1f519cae50 | ||
|
|
c0d2803f61 | ||
|
|
e249d5238f | ||
|
|
e32e505e95 | ||
|
|
7642a84108 | ||
|
|
b6e20d69cc | ||
|
|
9d04e20a30 | ||
|
|
d2624813f7 | ||
|
|
a2789e70ed | ||
|
|
f6f607904e | ||
|
|
22ea0296c0 | ||
|
|
24ae2f5324 | ||
|
|
9284497cec | ||
|
|
36cb12952a | ||
|
|
2700dc7f39 | ||
|
|
6d761fef4f | ||
|
|
737ce1314c | ||
|
|
7b89f82d45 | ||
|
|
2203d543a1 | ||
|
|
c129157687 | ||
|
|
276c49ac5c | ||
|
|
716d1b848e | ||
|
|
4878fc517d | ||
|
|
4d9d543110 | ||
|
|
c9d27d46b6 | ||
|
|
718a9b922b | ||
|
|
b68756378c | ||
|
|
1ff1880951 | ||
|
|
fea2d32de8 | ||
|
|
e3e6d4452c | ||
|
|
f687e8e658 | ||
|
|
e2a152aeb3 | ||
|
|
3e21226b27 | ||
|
|
c46c5b806c | ||
|
|
3c37d93046 | ||
|
|
7e4054ad8f | ||
|
|
9d38ad78bf | ||
|
|
2413981f6f | ||
|
|
4ac244003a | ||
|
|
9ac92a084f | ||
|
|
aacbcb1f28 | ||
|
|
39ff7e418c | ||
|
|
58498a091d | ||
|
|
b59483e52f | ||
|
|
a806f77aff | ||
|
|
60ae9e3a55 | ||
|
|
4bfe147730 | ||
|
|
2058184da2 | ||
|
|
9c861392f8 | ||
|
|
d3717fb222 | ||
|
|
963614f5fa | ||
|
|
7fdb70e3c3 | ||
|
|
37e8f0eab6 | ||
|
|
a6d17659f8 | ||
|
|
05edafa5c4 | ||
|
|
997a6de23b | ||
|
|
cea600617e | ||
|
|
c948b6d885 | ||
|
|
f517a63cc9 | ||
|
|
1e2f685ee5 | ||
|
|
5245614804 | ||
|
|
7b2790de50 | ||
|
|
7f2bb84c85 | ||
|
|
8b97c3cb85 | ||
|
|
d607463116 | ||
|
|
5508980384 | ||
|
|
e39dee01e5 | ||
|
|
a81412e176 | ||
|
|
09f9dd91aa | ||
|
|
2efc3c72ac | ||
|
|
a92fb03093 | ||
|
|
ad5847983f | ||
|
|
bb25300513 | ||
|
|
de33804eb4 | ||
|
|
de042f71dd | ||
|
|
5a1e85bbf4 | ||
|
|
3489e0df74 | ||
|
|
afe8eec343 | ||
|
|
331e1371d4 | ||
|
|
bdd57ba1a4 | ||
|
|
670e7e9ca1 | ||
|
|
54c7e05c8f | ||
|
|
7148f9d954 | ||
|
|
3b9a8c8492 | ||
|
|
3ae349aea5 | ||
|
|
91864b13d0 | ||
|
|
13650f98f9 | ||
|
|
d3379557fd | ||
|
|
143c2683fe | ||
|
|
72d64d36e5 | ||
|
|
b7446fa029 | ||
|
|
c0b52c38e3 | ||
|
|
adc8e9921a | ||
|
|
5e5473acae | ||
|
|
07cc92eb18 | ||
|
|
12a0ee309e | ||
|
|
824e37effd | ||
|
|
3509944f1a | ||
|
|
8a5489f805 | ||
|
|
922ee95fd2 | ||
|
|
9123cc3a2c | ||
|
|
f0dc9be471 | ||
|
|
819635f457 | ||
|
|
d3a2a5827e | ||
|
|
9665eba7b0 | ||
|
|
9f83c7c72c | ||
|
|
9bb74358f7 | ||
|
|
e2219730e6 | ||
|
|
4daaf50b1a | ||
|
|
b79792ebbf | ||
|
|
7a0b294d3d | ||
|
|
ad1312d077 | ||
|
|
3b7d56ff45 | ||
|
|
975cdf050f | ||
|
|
d65d7b779f | ||
|
|
7ce25d8158 | ||
|
|
178d7293fb | ||
|
|
ba0bba2202 | ||
|
|
29d5ce5f0e | ||
|
|
b9ebfc17ed | ||
|
|
2e28792c92 | ||
|
|
648d15403f | ||
|
|
3fe3f521ee | ||
|
|
0ff638a0ca | ||
|
|
485b5f46f6 | ||
|
|
b7c2063510 | ||
|
|
94d7ae5290 | ||
|
|
d75d5da250 | ||
|
|
d3cd1be24e | ||
|
|
d1f11316ec | ||
|
|
1e50bd999b | ||
|
|
0257f6c6a0 | ||
|
|
a3bc1cf72b | ||
|
|
e236632c67 | ||
|
|
4730d97898 | ||
|
|
36994a134d | ||
|
|
97899b3fa9 | ||
|
|
713bd6d6ef | ||
|
|
48736fad1f | ||
|
|
8fe2042127 | ||
|
|
538ad883ab | ||
|
|
5a47deb9a7 | ||
|
|
4b01facb4f | ||
|
|
158d4d6aed | ||
|
|
ab91776d97 | ||
|
|
136cb86492 | ||
|
|
e4eb1251d1 | ||
|
|
286ffe7219 | ||
|
|
79da4cb8a8 | ||
|
|
32f3c75d45 | ||
|
|
acc81d60ad | ||
|
|
4b093a0072 | ||
|
|
e0c57007db | ||
|
|
66b3579a9b | ||
|
|
0981bb71ce | ||
|
|
6b762cd6d3 | ||
|
|
581c466c0e | ||
|
|
5622c65fca | ||
|
|
51c6ea576b | ||
|
|
b7b8fe1fb9 | ||
|
|
a9ed3750ad | ||
|
|
24fdae725e | ||
|
|
1634a20464 | ||
|
|
7190c33dab | ||
|
|
8ea20925d3 | ||
|
|
d4c7ce4eb9 | ||
|
|
71fc844905 | ||
|
|
625237457a | ||
|
|
0f21173f5f | ||
|
|
7fda4570c6 | ||
|
|
e0aae17f37 | ||
|
|
32b4459e19 | ||
|
|
9072a7ac3c | ||
|
|
0e39874f9a | ||
|
|
aa5d116910 | ||
|
|
1f49d0d21b | ||
|
|
05a612bf79 | ||
|
|
ab0d839006 | ||
|
|
56b061c93d | ||
|
|
ec97e16609 | ||
|
|
e4ce58414c | ||
|
|
b07856ed58 | ||
|
|
b7d2f38490 | ||
|
|
295185c1cf | ||
|
|
f0d8ee21d9 | ||
|
|
b203020b4d | ||
|
|
5962149da8 | ||
|
|
1bc83d9045 | ||
|
|
24101bed08 | ||
|
|
98775ffc1e | ||
|
|
24910778d4 | ||
|
|
363c3e5f0a | ||
|
|
321736657e | ||
|
|
e50309871a | ||
|
|
8d336fca3e | ||
|
|
36cd7e426a | ||
|
|
ff27676187 | ||
|
|
6660747b31 | ||
|
|
c021f28dc7 | ||
|
|
a7a2eceda6 | ||
|
|
a4cac592e6 | ||
|
|
b29c6e0d9c | ||
|
|
ba9ea5b793 | ||
|
|
1fd5d0ff4b | ||
|
|
47d5ac4108 | ||
|
|
c6df8bbb61 | ||
|
|
97055b7ede | ||
|
|
df64ac268e | ||
|
|
541a3e257b | ||
|
|
1a995dfca8 | ||
|
|
9aef6b02ad | ||
|
|
f914f20283 | ||
|
|
03e558efbb | ||
|
|
925a0551b2 | ||
|
|
1677f9fe89 | ||
|
|
1db4c90479 | ||
|
|
e3beeff5a8 | ||
|
|
52a6d84041 | ||
|
|
84f2183f36 | ||
|
|
492cd7bc9e | ||
|
|
c21a25610c | ||
|
|
4eed3c06a7 | ||
|
|
bbeb3d45f0 | ||
|
|
7f804445c4 | ||
|
|
89eee30488 | ||
|
|
b386a20351 | ||
|
|
ac06bc6103 | ||
|
|
cda8697dd9 | ||
|
|
f7f7400163 | ||
|
|
ea0c4731d8 | ||
|
|
204b923289 | ||
|
|
46752a3911 | ||
|
|
6f34b6347d | ||
|
|
a935edbb55 | ||
|
|
e58c3b9422 | ||
|
|
a5ddc556f3 | ||
|
|
a541cc3e55 | ||
|
|
e355bdd68a | ||
|
|
d687d91090 | ||
|
|
6b38147c23 | ||
|
|
0241dbcfa1 | ||
|
|
8fd854f7f7 | ||
|
|
f449cf27c5 | ||
|
|
b2e641e269 | ||
|
|
63f32cb79c | ||
|
|
7b05868c5a | ||
|
|
c4fd0d6fd7 | ||
|
|
a4f0eb999c | ||
|
|
85b7231ff6 | ||
|
|
0f3d0008e9 | ||
|
|
76ad22b53d | ||
|
|
a2ddcaebf8 | ||
|
|
74addf45c3 | ||
|
|
f97a8a8475 | ||
|
|
e8cc212968 | ||
|
|
7918924c1c | ||
|
|
28a41860b9 | ||
|
|
20ef700422 | ||
|
|
c017863ef8 | ||
|
|
d28ac2facf | ||
|
|
b391f13b11 | ||
|
|
c2f29a0dc3 | ||
|
|
0c4a148c52 | ||
|
|
5c4aa543fa | ||
|
|
d3a9b50c03 | ||
|
|
6fc725b6ff | ||
|
|
01efc8d9e0 | ||
|
|
46962d95fc | ||
|
|
ea50837750 | ||
|
|
b03fe17e8c | ||
|
|
16cf5ecbb7 | ||
|
|
1b34278ec4 | ||
|
|
045d5a8a5e | ||
|
|
5729c9d5be | ||
|
|
a286584c32 | ||
|
|
a5895aaa7c | ||
|
|
0ab6fef566 | ||
|
|
a973d21bc0 | ||
|
|
e149d3f4c8 | ||
|
|
adfde3e236 | ||
|
|
18cdf705ed | ||
|
|
e5730a5119 | ||
|
|
b295cd7bef | ||
|
|
a168715b3c | ||
|
|
55f8212451 | ||
|
|
c5e7c79c2a | ||
|
|
d4a44b4977 | ||
|
|
f9f0668f6b | ||
|
|
d01beb3ba8 | ||
|
|
3cac052772 | ||
|
|
84bc8bc426 | ||
|
|
98a25908c2 | ||
|
|
4ed3d41eb1 | ||
|
|
672fd7365f | ||
|
|
39a16beb14 | ||
|
|
3a05bd5e2e | ||
|
|
32dbd1f8c9 | ||
|
|
bcc23ec4fc | ||
|
|
439c9647ca | ||
|
|
50c567d264 | ||
|
|
eb952319e0 | ||
|
|
d4964e41d3 | ||
|
|
41b1c169c3 | ||
|
|
49e2001004 | ||
|
|
bf5fd5eed8 | ||
|
|
facead5f0b | ||
|
|
143fc8256b | ||
|
|
66393f9293 | ||
|
|
7b3b6146a1 | ||
|
|
e1452244c2 | ||
|
|
8913d3df11 | ||
|
|
3a55965704 | ||
|
|
70d753d1d3 | ||
|
|
00a67b22df | ||
|
|
12811fe504 | ||
|
|
40ffb99928 | ||
|
|
78fb8fb834 | ||
|
|
614663a49c | ||
|
|
4787c1d35b | ||
|
|
5358414a0c | ||
|
|
ca9955f4cd | ||
|
|
2f40c5d71b | ||
|
|
1a84ca4ba0 | ||
|
|
5f29986d41 | ||
|
|
bfb63088c1 | ||
|
|
626bd7f4f4 | ||
|
|
bff941264c | ||
|
|
10b472e980 | ||
|
|
7888a8ac31 | ||
|
|
d79adfc0be | ||
|
|
e4baf5fe3e | ||
|
|
3013c30084 | ||
|
|
fc10b550cd | ||
|
|
514787a1c4 | ||
|
|
c32f3c5581 | ||
|
|
94b9b7ade3 | ||
|
|
ee33b4292c | ||
|
|
271e74d6f2 | ||
|
|
2ea41c3dae | ||
|
|
a6d93aba17 | ||
|
|
db1711b76f | ||
|
|
ab5b2e8fdf | ||
|
|
efa4028948 | ||
|
|
65529474cb | ||
|
|
7d756249ae | ||
|
|
98394333da | ||
|
|
d691373919 | ||
|
|
653b9be4a3 | ||
|
|
a3460a4b8f | ||
|
|
038f13e6fa | ||
|
|
fd74f157a8 | ||
|
|
dd288a3b0c | ||
|
|
885cde045a | ||
|
|
bfcaa4bda4 | ||
|
|
7370841e62 | ||
|
|
3c347214a8 | ||
|
|
7112c74bf2 | ||
|
|
faa1906290 | ||
|
|
592b4276c8 | ||
|
|
a73cdfbb4f | ||
|
|
770a2e52f6 | ||
|
|
6629b27f33 | ||
|
|
73b06d2f99 | ||
|
|
a07a9a75c0 | ||
|
|
d6fdb4c6da | ||
|
|
3fcfd2ff6d | ||
|
|
98545541e0 | ||
|
|
56820ad626 | ||
|
|
c5e036934a | ||
|
|
d9938a5cfd | ||
|
|
fc5d9615fc | ||
|
|
e160a42b83 | ||
|
|
fa68aa44c5 | ||
|
|
f3de9840b5 | ||
|
|
64e3909cea | ||
|
|
735c4b910e | ||
|
|
26a9a1f9e1 | ||
|
|
832ab8db95 | ||
|
|
1d9029ef51 | ||
|
|
a875ba7536 | ||
|
|
93de4785b4 | ||
|
|
765f0e5494 | ||
|
|
4fc232ff31 | ||
|
|
a4d75e9f32 | ||
|
|
a86ae09dc9 | ||
|
|
a5fbafe64d | ||
|
|
1de93b4933 | ||
|
|
f8dfc7c6cc | ||
|
|
accbed9c2b | ||
|
|
8b0e615777 | ||
|
|
746f12c724 | ||
|
|
a11d306a1b | ||
|
|
40d140e84d | ||
|
|
ffdb4842ac | ||
|
|
6baf60d07c | ||
|
|
cb3b7784b0 | ||
|
|
ee4f3b1629 | ||
|
|
518a7daa0e | ||
|
|
64546b25f2 | ||
|
|
d5496fb465 | ||
|
|
bcd2474d5f | ||
|
|
e331b959c8 | ||
|
|
ce159ac742 | ||
|
|
3e4eaf0397 | ||
|
|
2a2308b4a4 | ||
|
|
47511bac89 | ||
|
|
c6a5e69f91 | ||
|
|
32a9185cc1 | ||
|
|
ec54aeb1fd | ||
|
|
9aab1113fd | ||
|
|
86578cd266 | ||
|
|
566d74a638 | ||
|
|
23988b55a1 | ||
|
|
d5418ed5c7 | ||
|
|
5318b1470d | ||
|
|
0ca91eb071 | ||
|
|
7d31719cd1 | ||
|
|
25ed3d28f4 | ||
|
|
5df64d038b | ||
|
|
ec6d838ea6 | ||
|
|
6bea8aafe6 | ||
|
|
5bbf5d2d85 | ||
|
|
6d09590374 | ||
|
|
0e0ebc0b48 | ||
|
|
0c4a4ddda1 | ||
|
|
1efeddc875 | ||
|
|
82c6e8f42d | ||
|
|
5ff522bb85 | ||
|
|
b2b73575d4 | ||
|
|
d7bbccab08 | ||
|
|
21b8fe8474 | ||
|
|
94c210efd4 | ||
|
|
d3100be95a | ||
|
|
3353c15af6 | ||
|
|
1cced11431 | ||
|
|
646ad5606a | ||
|
|
8214e848f9 | ||
|
|
ece9c63121 | ||
|
|
ce81f07aa2 | ||
|
|
9bcaa6dfad | ||
|
|
295efe8c11 | ||
|
|
5cff811aab | ||
|
|
00e721d714 | ||
|
|
0c602027cb | ||
|
|
7070369cea |
@@ -0,0 +1,13 @@
|
||||
### Additions
|
||||
- Rebuilt Pokémon AI to use Minecraft's Brain system, allowing for more complex behaviours and interactions.
|
||||
- As an early pass of this, pastured Pokémon will now sleep when appropriate, and may come up to you when they see you.
|
||||
- Probably also added a whole bunch of bugs.
|
||||
- Added a Behaviour Editor to the NPC editing screen.
|
||||
- Added /behaviouredit command for opening the Behaviour Editor on Pokémon and NPCs.
|
||||
- Editing variables for Pokémon is not yet supported.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- Added a `behaviours` datapack folder which motivates the Behaviour Editor screen on NPCs and Pokémon.
|
||||
- Added many default behaviours.
|
||||
- Removed many NPC presets that now exist as behaviours. This is a breaking change if you are using NPCs with these presets.
|
||||
- NPCs with these presets should be modified to instead list under `"behaviours"` all the equivalent behaviours.
|
||||
@@ -0,0 +1,12 @@
|
||||
### Additions
|
||||
- Added functionality for marks.
|
||||
- Added data for all marks and all title ribbons from Pokémon.
|
||||
- Added marks screen within the summary UI.
|
||||
- Added `/givemark <player> <partySlot> <mark>` command to give a mark to a Pokémon.
|
||||
- Added `/takemark <player> <partySlot> <mark>` command to remove a mark from a Pokémon.
|
||||
- Added `/giveallmarks <player> <partySlot>` command to give all available marks to a Pokémon.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- Added Flows for `bobber_spawn_pokemon_post`, `pokemon_entity_spawn`, and `fossil_revived`.
|
||||
- Added `marks` datapack folder.
|
||||
- Added MoLang functions `entity.is_in_rain`, `pokemon.add_marks(Mark...)`, `pokemon.add_potential_marks(Mark...)`, `pokemon.add_marks_with_chance(Mark...)`, `pokemon.apply_potential_marks`, and `world.is_snowing_at(x, y, z)`.
|
||||
+125
@@ -2,6 +2,7 @@
|
||||
## [1.7.0 (Month xth, 2025)](#1-7-0)
|
||||
|
||||
### Additions
|
||||
- Added `/spectateBattle <player>` command to spectate battles without having to manually walk up to the target.
|
||||
- Added an in-game configuration screen, allowing all settings from `main.json` to be edited directly in-game.
|
||||
- Added `/cobblemonconfig reload` command to reload `main.json` configuration. **Note:** Some settings require a server restart to take effect; use this command cautiously.
|
||||
- Added `blacklisted_items_to_hold` and `whitelisted_items_to_hold` tags to allow for controlling which items players can give to their Pokémon. If the whitelist is empty, it will consider all item as allowed (unless they are in the blacklist).
|
||||
@@ -10,13 +11,122 @@
|
||||
- Added cosmetic item functionality for Pokémon. Certain cosmetic items can be given to applicable Pokémon via the interact menu.
|
||||
- Added the various log blocks as cosmetic items for Timburr and Komala.
|
||||
- Added `visibility/hidden`, `visibility/hat` and `visibility/face` tags to control where and how certain items are rendered.
|
||||
- Added Pokémon markings, toggleable within the summary.
|
||||
- Added `/boxcount` command to change PC boxes amount
|
||||
- Added cosmetics for Gurdurr, Conkeldurr, Squirtle Line, Sneasler, Sandile line, Treecko line, Braixen, Delphox, and Dragonite.
|
||||
- Added cosmetics for Gurdurr, Conkeldurr, Squirtle Line, Sneasler, Sandle line, Treecko line, Braixen, Delphox, and Dragonite.
|
||||
- Added `/transformmodelpart (position|rotation|scale) <modelPart> <transform: x y z>` command that can add transformations to a pokemon's model part.
|
||||
- The player executing the command must be facing the target pokemon entity. Transformations are not persistent and will revert when resources are reloaded.
|
||||
- Added lang keys for all moves and abilities up to Generation 9.
|
||||
- Fixed Moon Ball moon phase logic to actually work correctly
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
#### Gen 2
|
||||
- Dunsparce
|
||||
|
||||
#### Gen 3
|
||||
- Spoink
|
||||
- Grumpig
|
||||
- Snorunt
|
||||
- Glalie
|
||||
|
||||
#### Gen 4
|
||||
- Bronzor
|
||||
- Bronzong
|
||||
- Croagunk
|
||||
- Froslass
|
||||
|
||||
#### Gen 5
|
||||
- Pansage
|
||||
- Simisage
|
||||
- Pansear
|
||||
- Simisear
|
||||
- Panpour
|
||||
- Simipour
|
||||
- Munna
|
||||
- Musharna
|
||||
- Blitzle
|
||||
- Zebstrika
|
||||
- Trubbish
|
||||
- Garbodor
|
||||
|
||||
#### Gen 6
|
||||
- Noibat
|
||||
- Noivern
|
||||
|
||||
#### Gen 7
|
||||
- Drampa
|
||||
|
||||
#### Gen 8
|
||||
- Silicobra
|
||||
- Sandaconda
|
||||
|
||||
#### Gen 9
|
||||
- Smoliv
|
||||
- Dolliv
|
||||
- Arboliva
|
||||
- Orthworm
|
||||
- Dudunsparce
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Garchomp
|
||||
- Tropius
|
||||
- Torpius
|
||||
- Nosepass
|
||||
- Probopass
|
||||
- Sneasler
|
||||
- Braixen
|
||||
- Delphox
|
||||
- Cinderace
|
||||
- Kangaskhan
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Gyarados
|
||||
- Dragonite
|
||||
- Eevee
|
||||
- Vaporeon
|
||||
- Jolteon
|
||||
- Flareon
|
||||
- Espeon
|
||||
- Umbreon
|
||||
- Leafeon
|
||||
- Glaceon
|
||||
- Sylveon
|
||||
- Treecko
|
||||
- Grovyle
|
||||
- Sceptile
|
||||
- Honchkrow
|
||||
- Garchomp
|
||||
- Pidgeot
|
||||
- Nosepass
|
||||
- Probopass
|
||||
- Kangaskhan
|
||||
- Cinderace
|
||||
- Magnezone
|
||||
- Metagross
|
||||
- Added Syrupy Apples.
|
||||
|
||||
### Changes
|
||||
- Renamed `chargeGainedPerTick` config to `secondsToChargeHealingMachine`.
|
||||
- Made Blocks of Gold count as Big Nuggets when held by a Pokémon (for Fling functionality)
|
||||
- Players can now eat Sweet and Tart Apples, Whipped Dreams, and the Alcremie Sweets.
|
||||
- Updated Sweet and Tart Apple sprites
|
||||
- Updated the following recipes: Air Balloon, Assault Vest, Binding Band, Black Belt, Blunder Policy, Choice Band, Choice Scarf, Cleanse Tag, Covert Cloak, Destiny Knot, Eject Button, Expert Belt, Focus Band, Focus Sash, Magnet, Metronome, Muscle Band, Power Anklet, Power Band, Power Belt, Power Bracer, Power Lens, Power Weight, Protective Pads, Protein, Punching Glove, Reaper Cloth, Rocky Helmet, Room Service, Sachet, Safety Goggles, Silk Scarf, Spell Tag, Utility Umbrella, Weakness Policy, Zinc
|
||||
- Added alternate ingredient options to the following recipes: Cell Battery, Charcoal Stick, Dragon Fang, Miracle Seed, Mystic Water, Never Melt Ice, Twisted Spoon, Damp Rock, Heat Rock, Icy Rock, Smooth Rock
|
||||
- Grouped together some recipes within the Recipe Book. Groups include: the seven basic Poké Balls, the seven basic Ancient Poké Balls, Gilded Chests, Pokedexes, and the Weather Rocks.
|
||||
- Updated some item tags to better integrate behaviours between Cobblemon, Vanilla Minecraft, and other mods
|
||||
- Removed Cooked Meat, Raw Meat, Protein Ingredients, and Zinc Ingredients, the first two are now using `c` namespace tags, the latter have better integrated use of tags within their recipes which removes need for custom tags.
|
||||
- Added our seeds tag into `#c:seeds`, which is now made use of for the Miracle Seed recipe.
|
||||
- Tweaked the Natural Materials Vanilla file to fit with the changes to tags
|
||||
- Substantially optimised spawning checks mainly by front-loading biome filtering.
|
||||
- When using the `cobblemon` or `generation_9` capture calculators a critical capture with a single shake will always play for successful captures when you've already registered the Pokémon as caught in your Pokédex.
|
||||
- Improved the performance of saving Pokédex and player data.
|
||||
- Pokémon hitbox now scales with entity attribute `generic.scale`.
|
||||
- Removed Shulker aspect and replaced it with cosmetic_item-shulker_shell.
|
||||
- Shulker shell Forretress is now a cosmetic rather than a special evo and thus all shulker Forretress will revert back to normal until a shulker shell is put in their cosmetic slot.
|
||||
- Updated `doPokemonSpawning` gamerule to support per-dimension configurations.
|
||||
- The Pokedex now displays a form name of a "normal" Pokémon for when the base form is still a named form.
|
||||
|
||||
### Fixes
|
||||
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
|
||||
@@ -39,11 +149,15 @@
|
||||
- Fixed field name in evolution requirements for Spewpa Pokeball.
|
||||
- Fixed LevelUpCriterion logic to correctly check that the Pokémon is a preEvo.
|
||||
- Fixed `hide_additional_tooltip` vanilla flag not properly hiding tooltips on pokerod and bait items
|
||||
- Removed a number of scenarios in which a Pokémon battle may send out a Pokémon into collision geometry.
|
||||
- Fixed NPCs using Pokémon outside of their pool when a Pokémon name had a typo.
|
||||
- Fixed an issue with datapacked species features not being applied properly when relogging.
|
||||
- Fixed Pokémon marked as silent still playing shiny sounds and effects.
|
||||
- Fixed an issue with newer versions of Fabric API where underground Pokémon were spawning in The End.
|
||||
- Fixed spawning not working well when you're at high points surrounded by lower altitude spawning areas, such as flying.
|
||||
- Fixed certain Pokémon with forms not having appropriate stock Pokédex entries.
|
||||
- Fixed dragon's breath not being usable on the restoration tank when it should be
|
||||
- Fixed Moon Stones not interacting properly with dripstone blocks.
|
||||
|
||||
### Developer
|
||||
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
|
||||
@@ -61,6 +175,7 @@
|
||||
- Updated NPCEntity beam positioning to properly account for the baseScale property.
|
||||
- Updated NPCEntity pokeball throw positioning to properly account for the baseScale property.
|
||||
- Fixed `[Pokemon].copyFrom` error causing forms, IVs, and EVs to not be applied properly when using `[Pokemon].loadFromJSON` or `[Pokemon].loadFromNBT`
|
||||
- Added new item class, `WearableItem`. Instances of this class should have a corresponding 3D model. These models render when the items display context is `HEAD`.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- The following usages for item predicates can now use item conditions like advancements do, you can learn about them in the [Minecraft wiki](https://minecraft.wiki/w/Advancement_definition#minecraft:filled_bucket)
|
||||
@@ -71,6 +186,15 @@
|
||||
- Added `interpolate` boolean property to animated textures to allow gradual colour changes between frames.
|
||||
- Fixed species additions not being capable of changing implemented status.
|
||||
- Added support for action effects that are triggered by `|-activate|` Showdown instructions. `activate_{effect_id}` is the syntax.
|
||||
- Added MoLang functions for rendering items `render_item(item_id, locator_name)` and `clear_items()`.
|
||||
- Fixed location spawn filter components causing crashes
|
||||
- Added `pokemon` as an available MoLang function for the `battleActor` functions.
|
||||
- Added `spawn_pokemon` as an available MoLang function for the `worldHolder` functions.
|
||||
- Added `attempt_wild_battle` as an available MoLang function.
|
||||
- Added `pokemon` as an available Molang function for the `battleActor` functions.
|
||||
- Fixed `heldItem` property inside spawn files not working and causing crashes
|
||||
- Fixed `spawn_bedrock_particles` MoLang causing crashes when used in a server environment
|
||||
- The Pokédex form lang key definition now follows `cobblemon.ui.pokedex.info.form.{species}-{formname}` instead of `cobblemon.ui.pokedex.info.form.{formname}`.
|
||||
|
||||
## [1.6.1 (January 26th, 2025)](#1-6-1)
|
||||
|
||||
@@ -176,6 +300,7 @@
|
||||
- Geodude
|
||||
- Graveler
|
||||
- Golem
|
||||
- Magnezone
|
||||
|
||||
### Cry updates for the following Pokémon
|
||||
- Sceptile
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
- Nodemaker bug, it thinks jumps are possible from water up an entire block - they aint
|
||||
https://gyazo.com/759b8285e7c07046ff2e54adf0d7a7ac
|
||||
|
||||
- Why is magikarp trying to path through ice
|
||||
https://gyazo.com/ae230758c529f885eeb0dd91e60530d2
|
||||
|
||||
- We should use mixins to put the path node filtering from OmniPathNodeMaker in the base classes otherwise
|
||||
NPC wandering will be jank too.
|
||||
+1
-1
@@ -5,7 +5,7 @@ plugins {
|
||||
|
||||
version = "${project.property("mod_version")}+${project.property("mc_version")}"
|
||||
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") == true
|
||||
if (isSnapshot) {
|
||||
val fixedBranchName = versioning.info.branch.substringAfter("/")
|
||||
version = "$version-${fixedBranchName}-${versioning.info.build}"
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common;
|
||||
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface OrientationControllable {
|
||||
OrientationController getOrientationController();
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface Rollable {
|
||||
|
||||
// From Minecraft's Camera
|
||||
Vector3f FORWARDS = new Vector3f(0.0F, 0.0F, -1.0F);
|
||||
Vector3f UP = new Vector3f(0.0F, 1.0F, 0.0F);
|
||||
Vector3f LEFT = new Vector3f(-1.0F, 0.0F, 0.0F);
|
||||
|
||||
@Nullable Matrix3f getOrientation();
|
||||
|
||||
Rollable updateOrientation(Function<Matrix3f, Matrix3f> update);
|
||||
|
||||
/**
|
||||
* @return The forward vector (0, 0, -1) after the rotation matrix is applied.
|
||||
*/
|
||||
default Vector3f getForwardVector() {
|
||||
if (getOrientation() == null) return new Vector3f(FORWARDS);
|
||||
return getOrientation().transform(FORWARDS, new Vector3f());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The left vector (-1, 0, 0) after the rotation matrix is applied.
|
||||
*/
|
||||
default Vector3f getLeftVector() {
|
||||
if (getOrientation() == null) return new Vector3f(LEFT);
|
||||
return getOrientation().transform(LEFT, new Vector3f());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The up vector (0, 1, 0) after the rotation matrix is applied.
|
||||
*/
|
||||
default Vector3f getUpVector() {
|
||||
if (getOrientation() == null) return new Vector3f(UP);
|
||||
return getOrientation().transform(UP, new Vector3f());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param yaw change in degrees
|
||||
* @return The Rollable object this method was called on
|
||||
*/
|
||||
|
||||
default Rollable rotateYaw(float yaw) {
|
||||
return updateOrientation(prev -> prev.rotateY((float) Math.toRadians(-yaw)));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pitch change in degrees
|
||||
* @return The Rollable object this method was called on
|
||||
*/
|
||||
|
||||
default Rollable rotatePitch(float pitch) {
|
||||
return updateOrientation(prev -> prev.rotateX((float) Math.toRadians(-pitch)));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param roll change in degrees
|
||||
* @return The Rollable object this method was called on
|
||||
*/
|
||||
default Rollable rotateRoll(float roll) {
|
||||
return updateOrientation(prev -> prev.rotateZ((float) Math.toRadians(-roll)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Order matters when rotating an object. If you need a different order, individually call rotateYaw, rotatePitch, and rotateRoll
|
||||
*
|
||||
* @param yaw change in degrees
|
||||
* @param pitch change in degrees
|
||||
* @param roll change in degrees
|
||||
* @return The Rollable object this method was called on
|
||||
*/
|
||||
default Rollable rotate(float yaw, float pitch, float roll) {
|
||||
return rotateYaw(yaw).rotatePitch(pitch).rotateRoll(roll);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The pitch angle in degrees as a float.
|
||||
* Value is between [-180, 180] with 0 being South, 90 being West, 180/-180 being North, and -90 being East
|
||||
*/
|
||||
default float getYaw() {
|
||||
return (float) Mth.wrapDegrees(-Math.toDegrees(FORWARDS.angleSigned(getForwardVector(), UP)) + 180);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The yaw angle in degrees as a float.
|
||||
* Value is between [-90, 90] with 0 being straight forward, 90 being straight down, and -90 being straight up
|
||||
*/
|
||||
default float getPitch() {
|
||||
return (float) Mth.wrapDegrees(-Math.toDegrees(Math.asin(getForwardVector().y)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The roll angle in degrees as a float.
|
||||
* Value is between [-180, 180] with 0 being no roll (normal), 90 being 90 degrees CW, 180/-180 being 180 degrees CW/CCW, and -90 being 90 degrees CCW
|
||||
*/
|
||||
default float getRoll() {
|
||||
//Cobblemon.LOGGER.info("{}", (float) Math.toDegrees(getUpVector().angleSigned(UP, getForwardVector())));
|
||||
return (float) Mth.wrapDegrees(-Math.toDegrees(getUpVector().angleSigned(UP, getForwardVector())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the angular velocity in degrees per second as a Vec3
|
||||
*/
|
||||
Vec3 angRollVel( double deltaTime );
|
||||
|
||||
public Vec3 rotationOnMouseXY(
|
||||
double yMouse,
|
||||
double xMouse,
|
||||
SmoothDouble yMouseSmoother,
|
||||
SmoothDouble xMouseSmoother,
|
||||
double sensitivity,
|
||||
double deltaTime
|
||||
);
|
||||
|
||||
boolean shouldRoll();
|
||||
|
||||
boolean useAngVelSmoothing();
|
||||
|
||||
void clearRotation();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokemon.ai.EntityBehaviour;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
|
||||
import net.minecraft.world.entity.monster.Creeper;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Creeper.class)
|
||||
public class EntityCreeperMixin extends Mob {
|
||||
|
||||
private EntityCreeperMixin(net.minecraft.world.entity.EntityType<? extends Creeper> entityType, Level world) {
|
||||
super(entityType, world);
|
||||
}
|
||||
|
||||
@Inject(method = "registerGoals", at = @At(value = "TAIL"), cancellable = false)
|
||||
private void cobblemon$initGoals(CallbackInfo callbackInfo) {
|
||||
final Creeper creeper = (Creeper) (Object) this;
|
||||
// Pokemon Entities
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
creeper,
|
||||
PokemonEntity.class,
|
||||
6.0f,
|
||||
1.0,
|
||||
1.2,
|
||||
entity -> ((PokemonEntity)entity).getBehaviour().getEntityInteract().getAvoidedByCreeper() && ((PokemonEntity)entity).getBeamMode() != 1
|
||||
)
|
||||
);
|
||||
|
||||
// Players with shoulder mounted Pokemon
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
creeper,
|
||||
ServerPlayer.class,
|
||||
6.0f,
|
||||
1.0,
|
||||
1.2,
|
||||
entity -> EntityBehaviour.Companion.hasCreeperFearedShoulderMount((ServerPlayer)entity)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import net.minecraft.world.entity.monster.Phantom;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
@Mixin(targets = "net/minecraft/world/entity/monster/Phantom$PhantomSweepAttackGoal")
|
||||
public class EntityPhantomMixin {
|
||||
// TODO: Figure out how to access the outer class that wraps SwoopMovementGoal
|
||||
// Need to find the cat mons that are near the phantom
|
||||
|
||||
// @Inject(method = "shouldContinue", at = @At(value = "RETURN"), cancellable = true)
|
||||
// public void cobblemon$shouldContinue(CallbackInfoReturnable<Boolean> ci) {
|
||||
//// var goalSelectorField = PhantomEntity.class.getClasses();// PhantomEntity.class.getFields();// .class.getDeclaredField("goalSelector");
|
||||
//
|
||||
//// goalSelectorField.setAccessible(true);
|
||||
//// GoalSelector goalSelector = (GoalSelector) goalSelectorField.get(mobEntity);
|
||||
//// final SwoopMovementGoal phantom = (SwoopMovementGoal) (Object) this;
|
||||
//// if(ci.getReturnValue() == false) {
|
||||
//// var result = this$0.getWorld().getEntitiesByClass(
|
||||
//// PokemonEntity.class,
|
||||
//// this$0.getBoundingBox().expand(16.0),
|
||||
//// entity -> {
|
||||
//// return ((PokemonEntity) entity).getBehaviour().getEntityInteract().getAvoidedByPhantom();
|
||||
//// }
|
||||
//// ).isEmpty();
|
||||
////
|
||||
//// ci.setReturnValue(result);
|
||||
//// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokemon.ai.EntityBehaviour;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
|
||||
import net.minecraft.world.entity.monster.AbstractSkeleton;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(AbstractSkeleton.class)
|
||||
public class EntitySkeletonMixin extends Mob {
|
||||
|
||||
private EntitySkeletonMixin(EntityType<? extends Mob> entityType, Level world) {
|
||||
super(entityType, world);
|
||||
}
|
||||
|
||||
@Inject(method = "registerGoals", at = @At(value = "TAIL"), cancellable = false)
|
||||
private void cobblemon$initGoals(CallbackInfo callbackInfo) {
|
||||
final AbstractSkeleton skeleton = (AbstractSkeleton) (Object) this;
|
||||
// Pokemon Entities
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
skeleton,
|
||||
PokemonEntity.class,
|
||||
6.0f,
|
||||
1.0,
|
||||
1.2,
|
||||
entity -> ((PokemonEntity)entity).getBehaviour().getEntityInteract().getAvoidedBySkeleton() && ((PokemonEntity)entity).getBeamMode() != 1
|
||||
)
|
||||
);
|
||||
|
||||
// Players with shoulder mounted Pokemon
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
skeleton,
|
||||
ServerPlayer.class,
|
||||
6.0f,
|
||||
1.0,
|
||||
1.2,
|
||||
entity -> EntityBehaviour.Companion.hasSkeletonFearedShoulderMount((ServerPlayer)entity)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public abstract class EntityVillagerMixin {
|
||||
@Inject(method = "wantsToPickUp", at = @At(value = "RETURN"), cancellable = true)
|
||||
private void cobblemon$canGather(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
final Villager villager = (Villager) (Object) this;
|
||||
if(ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canAddItem(stack)) {
|
||||
if (ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canAddItem(stack)) {
|
||||
if(VillagerGatherableItems.INSTANCE.getVillagerGatherableItems().contains(stack.getItem()))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
|
||||
@@ -23,16 +23,15 @@ public abstract class LocalPlayerMixin {
|
||||
|
||||
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
|
||||
public void modifyJumpRidingScale(CallbackInfoReturnable<Float> cir) {
|
||||
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
|
||||
//Use custom jump bar logic if the current ride does not jump using it.
|
||||
if( !ride.getRiding().canJump(ride, player))
|
||||
{
|
||||
cir.setReturnValue(ride.setRideBar());
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity pokemonEntity) {
|
||||
var rideValue = pokemonEntity.<Float>ifRidingAvailableSupply(null, (behaviour, settings, state) -> {
|
||||
if (behaviour.canJump(settings, state, pokemonEntity, player)) return null;
|
||||
return behaviour.setRideBar(settings, state, pokemonEntity, player);
|
||||
});
|
||||
if (rideValue != null) {
|
||||
cir.setReturnValue(rideValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ public class PiglinBarterMixin {
|
||||
|
||||
@Inject(method = "isBarterCurrency", at = @At(value = "RETURN"), cancellable = true)
|
||||
private static void cobblemon$acceptsForBarter(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
if(!ci.getReturnValue()) {
|
||||
if (!ci.getReturnValue()) {
|
||||
//TODO: Make a tag?
|
||||
if(stack.is(CobblemonItems.RELIC_COIN_POUCH))
|
||||
if (stack.is(CobblemonItems.RELIC_COIN_POUCH))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,17 @@ package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents;
|
||||
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.api.riding.Seat;
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
|
||||
@@ -31,45 +34,39 @@ import com.cobblemon.mod.common.util.DataKeys;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.*;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class PlayerMixin extends LivingEntity implements Rollable, ScannableEntity {
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable {
|
||||
|
||||
@Shadow public abstract CompoundTag getShoulderEntityLeft();
|
||||
|
||||
@@ -87,7 +84,10 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
|
||||
@Shadow public abstract void displayClientMessage(Component message, boolean overlay);
|
||||
|
||||
@Unique private Matrix3f orientation = null;
|
||||
@Shadow @Final private static Map<Pose, EntityDimensions> POSES;
|
||||
@Shadow @Final public static EntityDimensions STANDING_DIMENSIONS;
|
||||
@Unique
|
||||
private final OrientationController cobblemon$orientationController = new OrientationController(this);
|
||||
|
||||
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, Level p_20967_) {
|
||||
super(p_20966_, p_20967_);
|
||||
@@ -115,6 +115,19 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRenderOrientation(CallbackInfo ci) {
|
||||
this.cobblemon$orientationController.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDimensions getDefaultDimensions(Pose pose) {
|
||||
if (this.getVehicle() instanceof PokemonEntity) {
|
||||
return STANDING_DIMENSIONS;
|
||||
}
|
||||
return POSES.getOrDefault(pose, STANDING_DIMENSIONS);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "removeEntitiesOnShoulder",
|
||||
at = @At(
|
||||
@@ -241,7 +254,7 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
|
||||
@Override
|
||||
public void absMoveTo(double x, double y, double z, float yaw, float pitch) {
|
||||
if (shouldRoll()) {
|
||||
if (cobblemon$orientationController.getActive()) {
|
||||
this.absMoveTo(x, y, z);
|
||||
this.setYRot(yaw % 360.0f);
|
||||
this.setXRot(pitch % 360.0f);
|
||||
@@ -254,120 +267,58 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
public void tick(CallbackInfo ci) {
|
||||
if (this.shouldRoll()) {
|
||||
// Proof of concept for yaw movement
|
||||
if (this.getMainHandItem().is(Items.STICK)) {
|
||||
this.rotateYaw(2);
|
||||
}
|
||||
else if (this.getMainHandItem().is(Items.BLAZE_ROD)) {
|
||||
this.rotateYaw(-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matrix3f getOrientation() {
|
||||
return orientation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rollable updateOrientation(Function<Matrix3f, Matrix3f> update) {
|
||||
//Disabled to allow non mouse inputs to modify roll
|
||||
if (!shouldRoll()) return this;
|
||||
|
||||
if (this.orientation == null) {
|
||||
this.orientation = new Matrix3f();
|
||||
this.rotate(getYRot() - 180, getXRot(), 0);
|
||||
}
|
||||
this.orientation = update.apply(this.orientation);
|
||||
setYRot(this.getYaw());
|
||||
setXRot(this.getPitch());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRoll() {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return false;
|
||||
if (player.isHolding(Items.DIAMOND)) return true;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
|
||||
return pokemonEntity.getRiding().shouldRoll(pokemonEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 rotationOnMouseXY(
|
||||
double yMouse,
|
||||
double xMouse,
|
||||
SmoothDouble yMouseSmoother,
|
||||
SmoothDouble xMouseSmoother,
|
||||
double sensitivity,
|
||||
double deltaTime
|
||||
) {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return Vec3.ZERO;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return Vec3.ZERO;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
|
||||
return pokemonEntity.getRiding().rotationOnMouseXY(
|
||||
pokemonEntity,
|
||||
player,
|
||||
yMouse,
|
||||
xMouse,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAngVelSmoothing() {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return true;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return true;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return true;
|
||||
|
||||
return pokemonEntity.getRiding().useAngVelSmoothing(pokemonEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 angRollVel( double deltaTime ) {
|
||||
var ret = new Vec3(0.0, 0.0, 0.0);
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return ret;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return ret;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return ret;
|
||||
|
||||
return pokemonEntity.getRiding().angRollVel( pokemonEntity, player, deltaTime );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clearRotation() {
|
||||
this.orientation = null;
|
||||
}
|
||||
|
||||
@WrapOperation(
|
||||
method = "rideTick()V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;wantsToStopRiding()Z")
|
||||
)
|
||||
public boolean delegateDismountToController(Player instance, Operation<Boolean> original) {
|
||||
if (this.getVehicle() instanceof Rideable vehicle) {
|
||||
return vehicle.getRiding().dismountOnShift() && original.call(instance);
|
||||
if (this.getVehicle() instanceof PokemonEntity pokemonEntity) {
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.dismountOnShift(settings, state, pokemonEntity) && original.call(instance);
|
||||
});
|
||||
}
|
||||
return original.call(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrientationController getOrientationController() {
|
||||
return cobblemon$orientationController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity) {
|
||||
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
|
||||
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemonEntity.getDelegate();
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
|
||||
|
||||
if (locator == null) {
|
||||
super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
|
||||
OrientationController controller = this.getOrientationController();
|
||||
|
||||
float currEyeHeight = this.getEyeHeight();
|
||||
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
|
||||
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(new Vector3f(0f, currEyeHeight - (this.getBbHeight() / 2), 0f)));
|
||||
|
||||
Vec3 eyePosition = locatorOffset.add(pokemonEntity.position()).add(rotatedEyeHeight);
|
||||
|
||||
Vec3 viewVector = this.getViewVector(partialTicks);
|
||||
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
|
||||
return this.level()
|
||||
.clip(
|
||||
new ClipContext(
|
||||
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ import org.spongepowered.asm.mixin.injection.Slice;
|
||||
public abstract class PointedDripstoneBlockMixin {
|
||||
|
||||
@Redirect(
|
||||
method = "canTipGrow(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;)Z",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/Block;)Z", ordinal = 0),
|
||||
slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/level/block/Blocks;DRIPSTONE_BLOCK:Lnet/minecraft/world/level/Block;"))
|
||||
method = "canGrow(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)Z",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/block/Block;)Z", ordinal = 0),
|
||||
slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/level/block/Blocks;DRIPSTONE_BLOCK:Lnet/minecraft/world/level/block/Block;"))
|
||||
)
|
||||
private static boolean cobblemon$validateMoonStoneDripstone(BlockState instance, Block block) {
|
||||
return instance.is(CobblemonBlockTags.DRIPSTONE_GROWABLE);
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.mixin.accessor.ChunkMapAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.TrackedEntityAccessor;
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.ClientboundUpdateRidingStatePacket;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.joml.Matrix3f;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(ServerEntity.class)
|
||||
public abstract class ServerEntityMixin {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private Consumer<Packet<?>> broadcast;
|
||||
@Shadow
|
||||
@Final
|
||||
private Entity entity;
|
||||
@Unique
|
||||
private Matrix3f cobblemon$lastSentOrientation;
|
||||
@Unique
|
||||
private boolean cobblemon$lastSentActive;
|
||||
|
||||
@Inject(method = "sendChanges", at = @At("TAIL"))
|
||||
private void cobblemon$sendChanges(CallbackInfo ci) {
|
||||
cobblemon$sendOrientationChanges();
|
||||
cobblemon$sendRidingStateChanges();
|
||||
}
|
||||
|
||||
private void cobblemon$sendRidingStateChanges() {
|
||||
if (!(this.entity instanceof PokemonEntity pokemonEntity)) return;
|
||||
if (pokemonEntity.getRidingState() == null) return;
|
||||
if (pokemonEntity.getRiding() == null) return;
|
||||
var ridingBehaviour = pokemonEntity.getRiding();
|
||||
var ridingState = pokemonEntity.getRidingState();
|
||||
var previousRidingState = pokemonEntity.getPreviousRidingState();
|
||||
if (previousRidingState != null && !ridingState.shouldSync(previousRidingState)) return;
|
||||
cobblemon$broadcast(new ClientboundUpdateRidingStatePacket(pokemonEntity.getId(), ridingBehaviour.getKey(), pokemonEntity.getRidingState(), null));
|
||||
}
|
||||
|
||||
private void cobblemon$sendOrientationChanges() {
|
||||
if (!(this.entity instanceof OrientationControllable controllable)) return;
|
||||
OrientationController controller = controllable.getOrientationController();
|
||||
Matrix3f currOrientation = controller.getOrientation();
|
||||
boolean currActive = controller.getActive();
|
||||
|
||||
if (currOrientation == null || currOrientation.equals(cobblemon$lastSentOrientation) && (currActive == cobblemon$lastSentActive))
|
||||
return;
|
||||
cobblemon$lastSentOrientation = new Matrix3f(currOrientation);
|
||||
cobblemon$lastSentActive = currActive;
|
||||
|
||||
cobblemon$broadcast(new ClientboundUpdateOrientationPacket(currOrientation, currActive, entity.getId()));
|
||||
}
|
||||
|
||||
private void cobblemon$broadcast(NetworkPacket<?> packet) {
|
||||
if (!(entity.level() instanceof ServerLevel level)) return;
|
||||
ChunkMap chunkMap = level.getChunkSource().chunkMap;
|
||||
Int2ObjectMap<?> entityMap = ((ChunkMapAccessor) chunkMap).getEntityMap();
|
||||
Object tracked = entityMap.get(entity.getId());
|
||||
if (!(tracked instanceof TrackedEntityAccessor tracker)) return;
|
||||
|
||||
Set<ServerPlayerConnection> seenBy = tracker.getSeenBy();
|
||||
for (ServerPlayerConnection conn : seenBy) {
|
||||
ServerPlayer player = conn.getPlayer();
|
||||
if (player == entity) continue;
|
||||
CobblemonNetwork.INSTANCE.sendPacketToPlayer(player, packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class ServerPlayerMixin {
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((ServerPlayer)(Object)this);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(ServerPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(method = "stopRiding", at = @At("HEAD"))
|
||||
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,12 +8,10 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.sound.BlockEntitySoundTracker;
|
||||
import com.cobblemon.mod.common.client.sound.EntitySoundTracker;
|
||||
import com.cobblemon.mod.common.client.sound.BattleMusicController;
|
||||
import com.cobblemon.mod.common.client.sound.SoundTracker;
|
||||
import com.cobblemon.mod.common.duck.SoundManagerDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundEngineDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundManagerDuck;
|
||||
import net.minecraft.client.resources.sounds.BiomeAmbientSoundsHandler;
|
||||
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.client.resources.sounds.UnderwaterAmbientSoundInstances;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(ChunkMap.class)
|
||||
public interface ChunkMapAccessor {
|
||||
@Accessor("entityMap")
|
||||
Int2ObjectMap<?> getEntityMap();
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(targets = "net.minecraft.server.level.ChunkMap$TrackedEntity")
|
||||
public interface TrackedEntityAccessor {
|
||||
@Accessor("seenBy")
|
||||
Set<ServerPlayerConnection> getSeenBy();
|
||||
}
|
||||
@@ -8,10 +8,29 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.api.riding.Seat;
|
||||
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
@@ -23,10 +42,10 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public abstract class CameraMixin {
|
||||
@Shadow @Final private static float DEFAULT_CAMERA_DISTANCE;
|
||||
|
||||
@Shadow private Entity entity;
|
||||
@Shadow @Final private Quaternionf rotation;
|
||||
@Shadow @Final private Vector3f forwards;
|
||||
@@ -35,10 +54,15 @@ public abstract class CameraMixin {
|
||||
@Shadow private float xRot;
|
||||
@Shadow private float yRot;
|
||||
|
||||
@Shadow public abstract float getXRot();
|
||||
@Shadow private float eyeHeight;
|
||||
@Shadow private float eyeHeightOld;
|
||||
|
||||
@Shadow public abstract float getYRot();
|
||||
@Shadow protected abstract void setPosition(Vec3 pos);
|
||||
|
||||
@Shadow
|
||||
private BlockGetter level;
|
||||
|
||||
@Shadow private float partialTickTime;
|
||||
@Unique private float returnTimer = 0;
|
||||
@Unique private float rollAngleStart = 0;
|
||||
@Unique Minecraft minecraft = Minecraft.getInstance();
|
||||
@@ -46,52 +70,165 @@ public abstract class CameraMixin {
|
||||
@Unique boolean disableRollableCameraDebug = false;
|
||||
|
||||
@Inject(method = "setRotation", at = @At("HEAD"), cancellable = true)
|
||||
public void open_camera$setRotation(float f, float g, CallbackInfo ci) {
|
||||
if (!(this.entity instanceof Rollable rollable) || disableRollableCameraDebug) return;
|
||||
if (!rollable.shouldRoll() && rollable.getOrientation() != null) {
|
||||
public void cobblemon$setRotation(float f, float g, CallbackInfo ci) {
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || disableRollableCameraDebug) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() && controller.getOrientation() != null) {
|
||||
if(this.returnTimer < 1) {
|
||||
//Rotation is taken from entity since we no longer handle mouse ourselves
|
||||
//Stops a period of time when you can't input anything.
|
||||
rollable.getOrientation().set(
|
||||
controller.getOrientation().set(
|
||||
new Matrix3f()
|
||||
.rotateY((float) Math.toRadians(180 - this.entity.getYRot()))
|
||||
.rotateX((float) Math.toRadians(-this.entity.getXRot()))
|
||||
);
|
||||
if(rollAngleStart == 0){
|
||||
this.returnTimer = 1;
|
||||
rollable.clearRotation();
|
||||
controller.reset();
|
||||
return;
|
||||
}
|
||||
rollable.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
|
||||
applyRotation();
|
||||
controller.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
|
||||
cobblemon$applyRotation();
|
||||
this.returnTimer += .05F;
|
||||
ci.cancel();
|
||||
} else {
|
||||
this.returnTimer = 1;
|
||||
rollable.clearRotation();
|
||||
controller.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (rollable.getOrientation() == null) return;
|
||||
applyRotation();
|
||||
if (controller.getOrientation() == null) return;
|
||||
cobblemon$applyRotation();
|
||||
|
||||
this.returnTimer = 0;
|
||||
this.rollAngleStart = rollable.getRoll();
|
||||
this.rollAngleStart = controller.getRoll();
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
//If you want to move this to a delagate you need an AW for position
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setPosition(DDD)V"))
|
||||
public void cobblemon$positionCamera(Camera instance, double x, double y, double z, Operation<Void> original, @Local(ordinal = 1, argsOnly = true) boolean thirdPersonReverse) {
|
||||
Entity entity = instance.getEntity();
|
||||
Entity vehicle = entity.getVehicle();
|
||||
MountedPokemonAnimationRenderController.INSTANCE.reset();
|
||||
|
||||
if(vehicle instanceof Rideable){
|
||||
//RidingCameraDelagate.INSTANCE.positionCamera(instance, x, y, z, original);
|
||||
if (!(vehicle instanceof PokemonEntity pokemon)) {
|
||||
original.call(instance, x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemon.getDelegate();
|
||||
Vec3 entityPos = new Vec3(
|
||||
Mth.lerp(instance.getPartialTickTime(), pokemon.xOld, pokemon.getX()),
|
||||
Mth.lerp(instance.getPartialTickTime(), pokemon.yOld, pokemon.getY()),
|
||||
Mth.lerp(instance.getPartialTickTime(), pokemon.zOld, pokemon.getZ())
|
||||
);
|
||||
MountedPokemonAnimationRenderController.INSTANCE.setup(pokemon, partialTickTime);
|
||||
int seatIndex = pokemon.getPassengers().indexOf(entity);
|
||||
Seat seat = pokemon.getSeats().get(seatIndex);
|
||||
|
||||
OrientationControllable rollable = (OrientationControllable) entity;
|
||||
OrientationController controller = rollable.getOrientationController();
|
||||
|
||||
if (!instance.isDetached() || Cobblemon.config.getThirdPartyViewBobbing()) {
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
|
||||
|
||||
if (locator == null) {
|
||||
original.call(instance, x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
|
||||
float currEyeHeight = Mth.lerp(instance.getPartialTickTime(), eyeHeightOld, eyeHeight);
|
||||
var rotatedEyeHeight = new Vector3f(0f, currEyeHeight - (entity.getBbHeight() / 2), 0f);
|
||||
if (controller.isActive()) {
|
||||
rotatedEyeHeight = controller.getRenderOrientation(partialTickTime).transform(rotatedEyeHeight);
|
||||
}
|
||||
|
||||
Vec3 position = locatorOffset.add(entityPos).add(new Vec3(rotatedEyeHeight));
|
||||
setPosition(position);
|
||||
} else {
|
||||
Vector3f pos = entityPos.add(new Vec3(0, pokemon.getBbHeight() / 2, 0)).toVector3f();
|
||||
|
||||
PosableModel model = VaryingModelRepository.INSTANCE.getPoser(pokemon.getPokemon().getSpecies().getResourceIdentifier(), new FloatingState());
|
||||
Map<String, Vec3> cameraOffsets = model.getSeatToCameraOffset();
|
||||
|
||||
Vec3 cameraOffset;
|
||||
if (thirdPersonReverse && cameraOffsets.containsKey(seat.getLocator() + "_reverse")) {
|
||||
cameraOffset = cameraOffsets.get(seat.getLocator() + "_reverse");
|
||||
} else if (cameraOffsets.containsKey(seat.getLocator())) {
|
||||
cameraOffset = cameraOffsets.get(seat.getLocator());
|
||||
} else {
|
||||
cameraOffset = new Vec3(0f, 2f, 4f);
|
||||
}
|
||||
|
||||
Vector3f offset = cameraOffset.toVector3f();
|
||||
|
||||
if (thirdPersonReverse) offset.z *= -1;
|
||||
float xRot = (float) (-1 * Math.toRadians(instance.getXRot()));
|
||||
|
||||
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f().rotateY((float) Math.toRadians(180f - instance.getYRot())).rotateX(xRot);
|
||||
Vector3f rotatedOffset = orientation.transform(offset);
|
||||
float offsetDistance = rotatedOffset.length();
|
||||
Vector3f offsetDirection = rotatedOffset.mul(1 / offsetDistance);
|
||||
|
||||
float maxZoom = cobblemon$getMaxZoom(offsetDistance, offsetDirection, pos);
|
||||
|
||||
setPosition(new Vec3(offsetDirection.mul(maxZoom).add(pos)));
|
||||
}
|
||||
} else {
|
||||
original.call(instance, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void applyRotation(){
|
||||
if (!(this.entity instanceof Rollable rollable) || rollable.getOrientation() == null) return;
|
||||
var newRotation = rollable.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
private void cobblemon$applyRotation(){
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || controllable.getOrientationController().getOrientation() == null) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
var newRotation = controller.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
if (this.minecraft.options.getCameraType().isMirrored()) {
|
||||
newRotation.rotateY((float)Math.toRadians(180));
|
||||
}
|
||||
this.rotation.set(newRotation);
|
||||
this.xRot = rollable.getPitch();
|
||||
this.yRot = rollable.getYaw();
|
||||
this.forwards.set(rollable.getForwardVector());
|
||||
this.up.set(rollable.getUpVector());
|
||||
this.left.set(rollable.getLeftVector());
|
||||
this.xRot = controller.getPitch();
|
||||
this.yRot = controller.getYaw();
|
||||
this.forwards.set(controller.getForwardVector());
|
||||
this.up.set(controller.getUpVector());
|
||||
this.left.set(controller.getLeftVector());
|
||||
}
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;move(FFF)V", ordinal = 0))
|
||||
public void stopMoveIfRolling(Camera instance, float zoom, float dy, float dx, Operation<Void> original) {
|
||||
Entity entity = instance.getEntity();
|
||||
Entity vehicle = entity.getVehicle();
|
||||
|
||||
if (!(vehicle instanceof PokemonEntity) || Cobblemon.config.getThirdPartyViewBobbing()) {
|
||||
original.call(instance, zoom, dy, dx);
|
||||
}
|
||||
}
|
||||
|
||||
//Modified vanilla code
|
||||
@Unique
|
||||
private float cobblemon$getMaxZoom(float maxZoom, Vector3f directionVector, Vector3f positionVector) {
|
||||
Vec3 pos = new Vec3(positionVector);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
float g = (float) ((i & 1) * 2 - 1);
|
||||
float h = (float) ((i >> 1 & 1) * 2 - 1);
|
||||
float j = (float) ((i >> 2 & 1) * 2 - 1);
|
||||
Vec3 vec3 = pos.add(g * 0.1F, h * 0.1F, j * 0.1F);
|
||||
Vec3 vec32 = vec3.add(new Vec3(directionVector).scale(maxZoom));
|
||||
HitResult hitResult = this.level.clip(new ClipContext(vec3, vec32, ClipContext.Block.VISUAL, ClipContext.Fluid.NONE, this.entity));
|
||||
if (hitResult.getType() != HitResult.Type.MISS) {
|
||||
float k = (float) hitResult.getLocation().distanceToSqr(pos);
|
||||
if (k < Mth.square(maxZoom)) {
|
||||
maxZoom = Mth.sqrt(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxZoom;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,21 @@ public class HumanoidModelMixin {
|
||||
}
|
||||
|
||||
Entity vehicle = entity.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity && entity instanceof AbstractClientPlayer) {
|
||||
MountedPlayerRenderer.INSTANCE.animate((PokemonEntity) vehicle, (AbstractClientPlayer) entity, relevantPartsByName, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity && entity instanceof AbstractClientPlayer) {
|
||||
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRotatePlayerHead(settings, state, pokemonEntity);
|
||||
});
|
||||
|
||||
if (!shouldRotatePlayerHead) {
|
||||
netHeadYaw = 0f;
|
||||
headPitch = 0f;
|
||||
if (this.head != null) {
|
||||
this.head.yRot = 0f;
|
||||
this.head.xRot = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
MountedPlayerRenderer.INSTANCE.animate(pokemonEntity, (AbstractClientPlayer) entity, relevantPartsByName, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -8,7 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -31,14 +31,14 @@ public class ItemInHandRendererMixin {
|
||||
if (abstractClientPlayer.isUsingItem() && abstractClientPlayer.getUseItem().getItem() instanceof PokedexItem) {
|
||||
ci.cancel();
|
||||
}
|
||||
else if (abstractClientPlayer instanceof Rollable rollable && rollable.shouldRoll()) {
|
||||
else if (abstractClientPlayer instanceof OrientationControllable controllable && controllable.getOrientationController().isActive()) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V", ordinal = 1))
|
||||
private void cobblemon$renderHandswithItems(PoseStack instance, Quaternionf quaternion) {
|
||||
if (!(Minecraft.getInstance().player instanceof Rollable rollable && rollable.shouldRoll())) {
|
||||
if (!(Minecraft.getInstance().player instanceof OrientationControllable controllable && controllable.getOrientationController().isActive())) {
|
||||
instance.mulPose(quaternion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.ModAPI;
|
||||
import com.cobblemon.mod.common.item.PokeBallItem;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.cobblemon.mod.common.item.WearableItem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.ItemModelShaper;
|
||||
@@ -54,17 +55,18 @@ public abstract class ItemRendererMixin {
|
||||
)
|
||||
private void cobblemon$overrideItemModel(ItemStack stack, ItemDisplayContext renderMode, boolean leftHanded, PoseStack matrices, MultiBufferSource multiBufferSource, int light, int overlay, BakedModel model, CallbackInfo ci) {
|
||||
boolean shouldBe2d = renderMode == ItemDisplayContext.GUI || renderMode == ItemDisplayContext.FIXED;
|
||||
ResourceLocation resourceLocation = null;
|
||||
if (shouldBe2d) {
|
||||
ResourceLocation resourceLocation = null;
|
||||
if (stack.getItem() instanceof PokeBallItem pokeBallItem) resourceLocation = pokeBallItem.getPokeBall().getModel2d();
|
||||
else if (stack.getItem() instanceof PokedexItem pokedexItem) resourceLocation = pokedexItem.getType().getItemSpritePath();
|
||||
}
|
||||
if (renderMode != ItemDisplayContext.HEAD && stack.getItem() instanceof WearableItem wearableItem) resourceLocation = wearableItem.getModel2d();
|
||||
|
||||
if (resourceLocation != null) {
|
||||
BakedModel replacementModel = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, "inventory"));
|
||||
if (!cobblemon$isSameModel(model, replacementModel)) {
|
||||
ci.cancel();
|
||||
render(stack, renderMode, leftHanded, matrices, multiBufferSource, light, overlay, replacementModel);
|
||||
}
|
||||
if (resourceLocation != null) {
|
||||
BakedModel replacementModel = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, "inventory"));
|
||||
if (!cobblemon$isSameModel(model, replacementModel)) {
|
||||
ci.cancel();
|
||||
render(stack, renderMode, leftHanded, matrices, multiBufferSource, light, overlay, replacementModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,6 +80,7 @@ public abstract class ItemRendererMixin {
|
||||
boolean canOpenScreen = entity != null && ((entity.getOffhandItem() == stack && !(entity.getMainHandItem().getItem() instanceof PokedexItem)) || entity.getMainHandItem() == stack);
|
||||
resourceLocation = pokedexItem.getType().getItemModelPath(isScanModel ? "scanning" : (canOpenScreen ? null : "off"));
|
||||
}
|
||||
else if (stack.getItem() instanceof WearableItem wearableItem) resourceLocation = wearableItem.getModel3d();
|
||||
|
||||
if (resourceLocation != null) {
|
||||
BakedModel model = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, MODEL_PATH));
|
||||
|
||||
@@ -9,9 +9,14 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.C2SUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.joml.Matrix3f;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
@@ -20,24 +25,55 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(LocalPlayer.class)
|
||||
public class LocalPlayerMixin {
|
||||
public abstract class LocalPlayerMixin extends LivingEntity {
|
||||
|
||||
@Unique Matrix3f cobblemon$lastOrientation;
|
||||
|
||||
@Inject(method = "sendPosition", at = @At("TAIL"))
|
||||
private void cobblemon_updateRotationMatrix(CallbackInfo ci) {
|
||||
if (!(this instanceof Rollable rollable)) return;
|
||||
if (rollable.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = rollable.getOrientation() != null ? new Matrix3f(rollable.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new C2SUpdateOrientationPacket(rollable.getOrientation()));
|
||||
protected LocalPlayerMixin(EntityType<? extends LivingEntity> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
}
|
||||
|
||||
// @Inject(method = "sendPosition", at = @At("TAIL"))
|
||||
// private void cobblemon$updateRotationMatrix(CallbackInfo ci) {
|
||||
// if (!(this instanceof OrientationControllable controllable)) return;
|
||||
// var controller = controllable.getOrientationController();
|
||||
// if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
|
||||
// cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
|
||||
// CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
|
||||
// }
|
||||
|
||||
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
private void cobblemon_updateRotationMatrixPassenger(CallbackInfo ci) {
|
||||
if (!(this instanceof Rollable rollable)) return;
|
||||
if (rollable.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = rollable.getOrientation() != null ? new Matrix3f(rollable.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new C2SUpdateOrientationPacket(rollable.getOrientation()));
|
||||
private void cobblemon$updateRotationMatrixPassenger(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((LocalPlayer)(Object)this);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(LocalPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopRiding() {
|
||||
super.stopRiding();
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
|
||||
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
@@ -29,9 +30,10 @@ import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
@Mixin(MouseHandler.class)
|
||||
public class MouseHandlerMixin {
|
||||
public abstract class MouseHandlerMixin {
|
||||
@Shadow private double accumulatedScrollY;
|
||||
@Shadow @Final private Minecraft minecraft;
|
||||
|
||||
@@ -49,7 +51,13 @@ public class MouseHandlerMixin {
|
||||
|
||||
@Shadow private double accumulatedDY;
|
||||
|
||||
@Shadow private double accumulatedScrollX;
|
||||
@Shadow private double lastHandleMovementTime;
|
||||
|
||||
@Shadow public abstract boolean isMouseGrabbed();
|
||||
|
||||
@Shadow protected abstract void turnPlayer(double movementTime);
|
||||
|
||||
@Unique private double cobblemon$timeDelta;
|
||||
|
||||
@Inject(
|
||||
method = "onScroll",
|
||||
@@ -121,9 +129,9 @@ public class MouseHandlerMixin {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(player instanceof Rollable rollable)) return true;
|
||||
if (!(player instanceof OrientationControllable controllable)) return true;
|
||||
|
||||
if (!rollable.shouldRoll()) {
|
||||
if (!controllable.getOrientationController().isActive()) {
|
||||
xMouseSmoother.reset();
|
||||
yMouseSmoother.reset();
|
||||
pitchSmoother.reset();
|
||||
@@ -132,68 +140,110 @@ public class MouseHandlerMixin {
|
||||
return true;
|
||||
}
|
||||
|
||||
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6000000238418579 + 0.20000000298023224;
|
||||
var ridingSensitivity = Math.pow(defaultSensitivity, 3);
|
||||
|
||||
//Send mouse input to be interpreted into rotation
|
||||
//deltas by the ride controller
|
||||
Vec3 angVecMouse = rollable.rotationOnMouseXY(
|
||||
cursorDeltaY,
|
||||
cursorDeltaX ,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
ridingSensitivity,
|
||||
movementTime
|
||||
);
|
||||
Vec3 angVecMouse = cobblemon$getRideMouseRotation(cursorDeltaX, cursorDeltaY, movementTime);
|
||||
|
||||
//Perform Rotation using mouse influenced rotation deltas.
|
||||
rollable.rotate(
|
||||
controllable.getOrientationController().rotate(
|
||||
(float) angVecMouse.x,
|
||||
(float) angVecMouse.y,
|
||||
(float) angVecMouse.z
|
||||
);
|
||||
|
||||
|
||||
//Gather and apply the current rotation deltas
|
||||
var angRot = rollable.angRollVel(movementTime);
|
||||
var angRot = cobblemon$getAngularVelocity(movementTime);
|
||||
|
||||
//Apply smoothing if requested by the controller.
|
||||
//This Might be best if done by the controller itself?
|
||||
if( rollable.useAngVelSmoothing() )
|
||||
if(cobblemon$shouldUseAngVelSmoothing())
|
||||
{
|
||||
if( angRot != null ) {
|
||||
var yaw = yawSmoother.getNewDeltaValue(angRot.x * 0.5f, d);
|
||||
var pitch = pitchSmoother.getNewDeltaValue(angRot.y * 0.5f, d);
|
||||
var roll = rollSmoother.getNewDeltaValue(angRot.z * 0.5f, d);
|
||||
rollable.rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
var yaw = yawSmoother.getNewDeltaValue(angRot.x * 0.5f, d);
|
||||
var pitch = pitchSmoother.getNewDeltaValue(angRot.y * 0.5f, d);
|
||||
var roll = rollSmoother.getNewDeltaValue(angRot.z * 0.5f, d);
|
||||
controllable.getOrientationController().rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
//Otherwise simply apply the smoothing
|
||||
else
|
||||
{
|
||||
if( angRot != null ) {
|
||||
rollable.rotate((float) (
|
||||
angRot.x * 10 * d),
|
||||
(float) (angRot.y * 10 * d),
|
||||
(float) (angRot.z * 10 * d)
|
||||
);
|
||||
}
|
||||
controllable.getOrientationController().rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
}
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHandler;isMouseGrabbed()Z", ordinal = 0))
|
||||
private void cobblemon$maintainMovementWhenInScreens(CallbackInfo ci, @Local(ordinal = 1) double e) {
|
||||
if (minecraft.player == null) return;
|
||||
if (!(minecraft.player instanceof Rollable rollable)) return;
|
||||
if (!rollable.shouldRoll()) return;
|
||||
if (minecraft.isPaused()) return;
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At("HEAD"))
|
||||
private void cobblemon$maintainMovementWhenInScreens2(CallbackInfo ci) {
|
||||
double time = Blaze3D.getTime();
|
||||
cobblemon$timeDelta = time - this.lastHandleMovementTime;
|
||||
}
|
||||
|
||||
var pitch = pitchSmoother.getNewDeltaValue(0, e);
|
||||
var roll = rollSmoother.getNewDeltaValue(0, e);
|
||||
rollable.rotate(0.0F, (float)pitch, (float)roll);
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At("TAIL"))
|
||||
private void cobblemon$maintainMovementWhenInScreens(CallbackInfo ci) {
|
||||
if (minecraft.player == null) return;
|
||||
if (!(minecraft.player instanceof OrientationControllable controllable)) return;
|
||||
if (!controllable.getOrientationController().isActive()) return;
|
||||
if (minecraft.isPaused()) return;
|
||||
if (isMouseGrabbed()) return;
|
||||
|
||||
this.turnPlayer(cobblemon$timeDelta);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Vec3 cobblemon$getAngularVelocity(double deltaTime) {
|
||||
var player = minecraft.player;
|
||||
if (player == null) return Vec3.ZERO;
|
||||
if (!(player instanceof OrientationControllable)) return Vec3.ZERO;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return Vec3.ZERO;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
return pokemonEntity.ifRidingAvailableSupply(Vec3.ZERO, (behaviour, settings, state) -> {
|
||||
return behaviour.angRollVel(settings, state, pokemonEntity, player, deltaTime);
|
||||
});
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Vec3 cobblemon$getRideMouseRotation(double mouseX, double mouseY, double deltaTime) {
|
||||
var player = minecraft.player;
|
||||
if (player == null) return Vec3.ZERO;
|
||||
var vehicle = player.getVehicle();
|
||||
if (vehicle == null) return Vec3.ZERO;
|
||||
if (!(vehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
|
||||
var sensitivity = cobblemon$getRidingSensitivity();
|
||||
return pokemonEntity.ifRidingAvailableSupply(Vec3.ZERO, (behaviour, settings, state) -> {
|
||||
return behaviour.rotationOnMouseXY(
|
||||
settings,
|
||||
state,
|
||||
pokemonEntity,
|
||||
player,
|
||||
mouseY,
|
||||
mouseX,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Unique
|
||||
private double cobblemon$getRidingSensitivity() {
|
||||
var sensitivity = this.minecraft.options.sensitivity().get() * 0.6000000238418579 + 0.20000000298023224;
|
||||
return Math.pow(sensitivity, 3);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseAngVelSmoothing() {
|
||||
var player = minecraft.player;
|
||||
if (player == null) return true;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return true;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return true;
|
||||
return pokemonEntity.ifRidingAvailableSupply(true, (behaviour, settings, state) -> {
|
||||
return behaviour.useAngVelSmoothing(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.api.riding.RidingManager;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.model.PlayerModel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PlayerModel.class)
|
||||
public class PlayerModelMixin {
|
||||
@Inject(method = "setupAnim(Lnet/minecraft/world/entity/LivingEntity;FFFFF)V", at = @At(value = "HEAD"))
|
||||
private void cobblemon$setHeadRotation(LivingEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, CallbackInfo ci){
|
||||
if (!(entity instanceof Player)) return;
|
||||
Entity vehicle = entity.getVehicle();
|
||||
|
||||
if (!(vehicle instanceof PokemonEntity)) return;
|
||||
RidingManager ridingManager = ((Rideable) vehicle).getRiding();
|
||||
if (ridingManager.shouldRotatePlayerHead((PokemonEntity) vehicle)) return;
|
||||
|
||||
netHeadYaw = 0f;
|
||||
headPitch = 0f;
|
||||
}
|
||||
}
|
||||
+28
-1
@@ -11,9 +11,15 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
import com.cobblemon.mod.common.client.render.ClientPlayerIcon;
|
||||
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.model.EntityModel;
|
||||
import net.minecraft.client.model.PlayerModel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
@@ -23,12 +29,33 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PlayerRenderer.class)
|
||||
public class PlayerRendererMixin {
|
||||
public abstract class PlayerRendererMixin extends LivingEntityRenderer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> {
|
||||
|
||||
public PlayerRendererMixin(EntityRendererProvider.Context context, PlayerModel<AbstractClientPlayer> model, float shadowRadius) {
|
||||
super(context, model, shadowRadius);
|
||||
}
|
||||
|
||||
@Inject(method = "render(Lnet/minecraft/world/entity/LivingEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "TAIL"))
|
||||
public void cobblemon$clientPlayerIcon(LivingEntity entity, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource buffer, int packedLight, CallbackInfo ci) {
|
||||
ClientPlayerIcon.Companion.onRenderPlayer((Player) entity);
|
||||
}
|
||||
|
||||
@WrapOperation(method = "getRenderOffset(Lnet/minecraft/client/player/AbstractClientPlayer;F)Lnet/minecraft/world/phys/Vec3;", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/AbstractClientPlayer;isCrouching()Z"))
|
||||
private boolean cobblemon$disableCrouchOffset(AbstractClientPlayer instance, Operation<Boolean> original) {
|
||||
if (instance.isPassenger() && instance.getVehicle() instanceof PokemonEntity) {
|
||||
return false;
|
||||
}
|
||||
return original.call(instance);
|
||||
}
|
||||
|
||||
@Inject(method = "setModelProperties", at = @At("TAIL"))
|
||||
private void cobblemon$setModelProperties(AbstractClientPlayer player, CallbackInfo ci) {
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
PlayerModel<AbstractClientPlayer> playerModel = this.getModel();
|
||||
playerModel.crouching = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "setupRotations(Lnet/minecraft/client/player/AbstractClientPlayer;Lcom/mojang/blaze3d/vertex/PoseStack;FFFF)V",
|
||||
at = @At("HEAD")
|
||||
|
||||
@@ -194,6 +194,8 @@ object Cobblemon {
|
||||
this.LOGGER.info(" - Branch: ${CobblemonBuildDetails.BRANCH}")
|
||||
}
|
||||
|
||||
this.loadConfig()
|
||||
|
||||
implementation.registerPermissionValidator()
|
||||
implementation.registerSoundEvents()
|
||||
implementation.registerDataComponents()
|
||||
@@ -216,7 +218,6 @@ object Cobblemon {
|
||||
ExperienceGroups.registerDefaults()
|
||||
CaptureCalculators.registerDefaults()
|
||||
|
||||
this.loadConfig()
|
||||
// CobblemonBlockPredicates.touch()
|
||||
CobblemonOrePlacedFeatures.register()
|
||||
CobblemonPlacedFeatures.register()
|
||||
@@ -562,6 +563,9 @@ object Cobblemon {
|
||||
this.implementation.registerCommandArgument(cobblemonResource("dex"), DexArgumentType::class, SingletonArgumentInfo.contextFree (DexArgumentType::dex))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("npc_class"), NPCClassArgumentType::class, SingletonArgumentInfo.contextFree(NPCClassArgumentType::npcClass))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("wallpaper"), UnlockablePCBoxWallpaperArgumentType::class, SingletonArgumentInfo.contextFree(UnlockablePCBoxWallpaperArgumentType::wallpaper))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("mark"), MarkArgumentType::class, SingletonArgumentInfo.contextFree(MarkArgumentType::mark))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("transform_type"), TransformTypeArgumentType::class, SingletonArgumentInfo.contextFree(TransformTypeArgumentType::transformType))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("model_part"), ModelPartArgumentType::class, SingletonArgumentInfo.contextFree(ModelPartArgumentType::modelPart))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ object CobblemonActivities {
|
||||
val BATTLING = register(Activity("battling"))
|
||||
val ACTION_EFFECT = register(Activity("action_effect"))
|
||||
val NPC_CHATTING = register(Activity("npc_chatting"))
|
||||
val POKEMON_SLEEPING_ACTIVITY = register(Activity("pokemon_sleeping"))
|
||||
val POKEMON_GROW_CROP = register(Activity("pokemon_grow_crop"))
|
||||
val POKEMON_SLEEP_ON_TRAINER_BED = register(Activity("pokemon_sleep_on_trainer_bed"))
|
||||
val GUARD_NEST = register(Activity("guard_nest"))
|
||||
|
||||
fun register(activity: Activity): Activity {
|
||||
activities.add(activity)
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonBehaviour
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.task.TaskConfig
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry.Companion.JSON_EXTENSION
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.BehaviourSyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.ActivityAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.BrainConfigAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionOrEntityVariableAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TaskConfigAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TranslatedTextAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.endsWith
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.mojang.datafixers.util.Either
|
||||
import java.io.File
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.server.packs.resources.ResourceManager
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
object CobblemonBehaviours : JsonDataRegistry<CobblemonBehaviour> {
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(Activity::class.java, ActivityAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(BehaviourConfig::class.java, BrainConfigAdapter)
|
||||
.registerTypeAdapter(TaskConfig::class.java, TaskConfigAdapter)
|
||||
.registerTypeAdapter(
|
||||
TypeToken.getParameterized(Either::class.java, Expression::class.java, MoLangConfigVariable::class.java).type,
|
||||
ExpressionOrEntityVariableAdapter
|
||||
)
|
||||
.registerTypeAdapter(Component::class.java, TranslatedTextAdapter)
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.create()
|
||||
|
||||
override val typeToken = TypeToken.get(CobblemonBehaviour::class.java)
|
||||
override val resourcePath = "behaviours"
|
||||
override val id: ResourceLocation = cobblemonResource("behaviours")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<CobblemonBehaviours>()
|
||||
|
||||
/**
|
||||
* Any behaviours that are put into /pokemon/auto will be automatically
|
||||
* applied to all Pokémon species/forms that don't define a baseAI list of
|
||||
* behaviour configurations. This is an addon-friendly way of defining the general
|
||||
* rules of Pokémon AI without it being unavoidable for specific
|
||||
* species.
|
||||
*/
|
||||
val autoPokemonBehaviours = mutableListOf<CobblemonBehaviour>()
|
||||
|
||||
val behaviours = mutableMapOf<ResourceLocation, CobblemonBehaviour>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
player.sendPacket(BehaviourSyncPacket(behaviours.filter { it.value.visible }))
|
||||
}
|
||||
|
||||
override fun reload(manager: ResourceManager) {
|
||||
autoPokemonBehaviours.clear()
|
||||
val data = mutableMapOf<ResourceLocation, CobblemonBehaviour>()
|
||||
manager.listResources(resourcePath) { path -> path.endsWith(JSON_EXTENSION) }.forEach { (identifier, resource) ->
|
||||
resource.open().use { stream ->
|
||||
stream.bufferedReader().use { reader ->
|
||||
val resolvedIdentifier = ResourceLocation.fromNamespaceAndPath(identifier.namespace, File(identifier.path).nameWithoutExtension)
|
||||
val behaviour = parse(reader, resolvedIdentifier)
|
||||
if ("pokemon/auto/" in identifier.path) {
|
||||
autoPokemonBehaviours.add(behaviour)
|
||||
}
|
||||
data[resolvedIdentifier] = behaviour
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reload(data)
|
||||
Cobblemon.LOGGER.info("Loaded ${behaviours.size} entity behaviours")
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, CobblemonBehaviour>) {
|
||||
behaviours.clear()
|
||||
behaviours.putAll(data)
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,11 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
@JvmField
|
||||
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.of(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN).build(null))
|
||||
|
||||
@JvmField
|
||||
val GROTTO_BLOCK: BlockEntityType<GrottoBlockEntity> = this.create("grotto_block",
|
||||
BlockEntityType.Builder.of(::GrottoBlockEntity, CobblemonBlocks.GROTTO_BLOCK).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST: BlockEntityType<GildedChestBlockEntity> = this.create("chest", BlockEntityType.Builder.of(::GildedChestBlockEntity,
|
||||
CobblemonBlocks.GILDED_CHEST,
|
||||
@@ -82,6 +87,46 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
).build(null)
|
||||
)
|
||||
|
||||
val NEST: BlockEntityType<NestBlockEntity> = this.create("nest",
|
||||
BlockEntityType.Builder.of(
|
||||
::NestBlockEntity,
|
||||
CobblemonBlocks.NEST_STICK,
|
||||
CobblemonBlocks.NEST_LEAF,
|
||||
CobblemonBlocks.NEST_STONE,
|
||||
CobblemonBlocks.NEST_DEEPSLATE,
|
||||
CobblemonBlocks.NEST_BASALT,
|
||||
CobblemonBlocks.NEST_SNOW,
|
||||
CobblemonBlocks.NEST_NETHER,
|
||||
CobblemonBlocks.NEST_SOUL_SAND,
|
||||
CobblemonBlocks.NEST_WARM_OCEAN,
|
||||
CobblemonBlocks.NEST_SEAGRASS,
|
||||
CobblemonBlocks.NEST_LUSH,
|
||||
CobblemonBlocks.NEST_HAY,
|
||||
CobblemonBlocks.NEST_SAND,
|
||||
CobblemonBlocks.NEST_RED_SAND,
|
||||
CobblemonBlocks.NEST_CHORUS,
|
||||
|
||||
CobblemonBlocks.WATER_NEST,
|
||||
CobblemonBlocks.CAVE_NEST,
|
||||
CobblemonBlocks.BASIC_NEST
|
||||
).build(null))
|
||||
|
||||
val EGG: BlockEntityType<EggBlockEntity> = this.create("egg",
|
||||
BlockEntityType.Builder.of(
|
||||
::EggBlockEntity,
|
||||
CobblemonBlocks.EGG
|
||||
).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val INCUBATOR: BlockEntityType<IncubatorBlockEntity> = this.create("incubator",
|
||||
BlockEntityType.Builder.of(
|
||||
::IncubatorBlockEntity,
|
||||
CobblemonBlocks.INCUBATOR
|
||||
).build(null)
|
||||
)
|
||||
|
||||
|
||||
@JvmField
|
||||
val DISPLAY_CASE: BlockEntityType<DisplayCaseBlockEntity> = this.create("display_case",
|
||||
BlockEntityType.Builder.of(::DisplayCaseBlockEntity, CobblemonBlocks.DISPLAY_CASE).build(null)
|
||||
|
||||
@@ -478,6 +478,61 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
val YACHE_BERRY = this.berryBlock("yache")
|
||||
//val BINDING_SOIL = this.create("binding_soil", BindingSoilBlock(BlockBehaviour.Properties.of()))
|
||||
|
||||
val NEST_STICK = nestBlock(NestBlock.NestVariant.STICK)
|
||||
val NEST_LEAF = nestBlock(NestBlock.NestVariant.LEAF)
|
||||
val NEST_STONE = nestBlock(NestBlock.NestVariant.STONE)
|
||||
val NEST_DEEPSLATE = nestBlock(NestBlock.NestVariant.DEEPSLATE)
|
||||
val NEST_BASALT = nestBlock(NestBlock.NestVariant.BASALT)
|
||||
val NEST_SNOW = nestBlock(NestBlock.NestVariant.SNOW)
|
||||
|
||||
val NEST_NETHER = this.create(
|
||||
"nest_nether",
|
||||
NestBlock(NestBlock.NestVariant.NETHER, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY).lightLevel { 2 })
|
||||
)
|
||||
val NEST_SOUL_SAND = nestBlock(NestBlock.NestVariant.SOUL_SAND)
|
||||
val NEST_WARM_OCEAN = this.create(
|
||||
"nest_warm_ocean",
|
||||
NestBlock(NestBlock.NestVariant.WARM_OCEAN, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY).lightLevel { 6 })
|
||||
)
|
||||
val NEST_SEAGRASS = nestBlock(NestBlock.NestVariant.SEAGRASS)
|
||||
val NEST_LUSH = nestBlock(NestBlock.NestVariant.LUSH)
|
||||
val NEST_HAY = nestBlock(NestBlock.NestVariant.HAY)
|
||||
val NEST_SAND = nestBlock(NestBlock.NestVariant.SAND)
|
||||
val NEST_RED_SAND = nestBlock(NestBlock.NestVariant.RED_SAND)
|
||||
val NEST_CHORUS = nestBlock(NestBlock.NestVariant.CHORUS)
|
||||
|
||||
|
||||
|
||||
val BASIC_NEST = nestBlock(NestBlock.NestVariant.BASIC)
|
||||
val CAVE_NEST = nestBlock(NestBlock.NestVariant.CAVE)
|
||||
//val NETHER_NEST = nestBlock(NestBlock.NestVariant.NETHER)
|
||||
val WATER_NEST = nestBlock(NestBlock.NestVariant.WATER)
|
||||
|
||||
val EGG = this.create("egg", EggBlock(BlockBehaviour.Properties
|
||||
.ofFullCopy(Blocks.DRAGON_EGG)
|
||||
.pushReaction(PushReaction.BLOCK)
|
||||
.sound(SoundType.BONE_BLOCK)
|
||||
))
|
||||
|
||||
@JvmField
|
||||
val GROTTO_BLOCK = this.create("grotto_block", GrottoBlock(BlockBehaviour.Properties.of()
|
||||
.mapColor(MapColor.STONE)
|
||||
.strength(1.5F)
|
||||
.pushReaction(PushReaction.BLOCK)
|
||||
))
|
||||
|
||||
@JvmField
|
||||
val INCUBATOR = this.create("incubator", IncubatorBlock(BlockBehaviour.Properties.of()
|
||||
.mapColor(MapColor.COLOR_LIGHT_GRAY)
|
||||
.sound(SoundType.METAL)
|
||||
.strength(Blocks.COAL_BLOCK.defaultDestroyTime(), Blocks.DIAMOND_ORE.explosionResistance)
|
||||
.noOcclusion()
|
||||
.pushReaction(PushReaction.BLOCK)
|
||||
.lightLevel { state ->
|
||||
if (state.getValue(IncubatorBlock.HAS_EGG)) 5 else 0 // Emit 5 light when HAS_EGG is true
|
||||
}
|
||||
))
|
||||
|
||||
init {
|
||||
/**
|
||||
* Makes all blocks in array flammable by adding them to FireBlock's flammableRegistry.
|
||||
@@ -506,6 +561,12 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
return block
|
||||
}
|
||||
|
||||
private fun nestBlock(variant: NestBlock.NestVariant): NestBlock {
|
||||
val identifier = cobblemonResource(variant.serializedName)
|
||||
val block = NestBlock(variant, BlockBehaviour.Properties.of().noOcclusion().pushReaction(PushReaction.DESTROY))
|
||||
return this.create(identifier.path, block)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls helper method from Vanilla
|
||||
*/
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.ai.config.BrainConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.task.TaskConfig
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.util.adapters.ActivityAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.BrainConfigAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TaskConfigAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
object CobblemonBrainConfigs : JsonDataRegistry<List<BrainConfig>> {
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(Activity::class.java, ActivityAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(BrainConfig::class.java, BrainConfigAdapter)
|
||||
.registerTypeAdapter(TaskConfig::class.java, TaskConfigAdapter)
|
||||
.create()
|
||||
|
||||
override val typeToken = TypeToken.getParameterized(List::class.java, BrainConfig::class.java) as TypeToken<List<BrainConfig>>
|
||||
override val resourcePath = "brain_presets"
|
||||
override val id: ResourceLocation = cobblemonResource("brain_presets")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<CobblemonBrainConfigs>()
|
||||
|
||||
val presets = mutableMapOf<ResourceLocation, List<BrainConfig>>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
// TODO implement probs ay
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, List<BrainConfig>>) {
|
||||
presets.clear()
|
||||
presets.putAll(data)
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ object CobblemonCommands {
|
||||
ChangeEyeHeight.register(dispatcher)
|
||||
ChangeScaleAndSize.register(dispatcher)
|
||||
ChangeWalkSpeed.register(dispatcher)
|
||||
ChangeJointScaleCommand.register(dispatcher)
|
||||
TransformModelPartCommand.register(dispatcher)
|
||||
TestCommand.register(dispatcher)
|
||||
ReloadShowdownCommand.register(dispatcher)
|
||||
ClickTextCommand.register(dispatcher)
|
||||
@@ -60,8 +60,16 @@ object CobblemonCommands {
|
||||
RenameBoxCommand.register(dispatcher)
|
||||
ChangeBoxWallpaperCommand.register(dispatcher)
|
||||
RunMolangScriptCommand.register(dispatcher)
|
||||
GivePokemonEggCommand.register(dispatcher)
|
||||
GiveAllPokemonEggCommand.register(dispatcher)
|
||||
SpectateBattleCommand.register(dispatcher)
|
||||
CobblemonConfigCommand.register(dispatcher)
|
||||
UnlockPCBoxWallpaperCommand.register(dispatcher)
|
||||
BehaviourEditCommand.register(dispatcher)
|
||||
ChangePCBoxesCommand.register(dispatcher)
|
||||
MarkGiveCommand.register(dispatcher)
|
||||
MarkTakeCommand.register(dispatcher)
|
||||
MarkGiveAllCommand.register(dispatcher)
|
||||
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.breeding.Egg
|
||||
import com.cobblemon.mod.common.block.entity.EggBlockEntity
|
||||
import com.cobblemon.mod.common.item.components.HeldItemCapableComponent
|
||||
import com.cobblemon.mod.common.item.components.PokemonItemComponent
|
||||
import com.cobblemon.mod.common.item.RodBaitComponent
|
||||
import com.cobblemon.mod.common.item.components.EggComponent
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.component.DataComponentType
|
||||
@@ -36,11 +39,18 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
.networkSynchronized(RodBaitComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
val EGG_DATA: DataComponentType<EggComponent> = create("egg", DataComponentType.builder<EggComponent>()
|
||||
.persistent(EggComponent.CODEC) // For saving/loading
|
||||
.networkSynchronized(EggComponent.PACKET_CODEC) // For network synchronization
|
||||
.build())
|
||||
|
||||
|
||||
|
||||
|
||||
fun register() {
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:pokemon_item"), POKEMON_ITEM)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:bait"), BAIT)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:egg_data"), EGG_DATA)
|
||||
}
|
||||
|
||||
override val registry = BuiltInRegistries.DATA_COMPONENT_TYPE
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.api.text.gray
|
||||
import com.cobblemon.mod.common.block.BerryBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
import com.cobblemon.mod.common.block.NestBlock
|
||||
import com.cobblemon.mod.common.client.pokedex.PokedexType
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
||||
import com.cobblemon.mod.common.item.*
|
||||
@@ -41,6 +42,7 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.effect.MobEffectInstance
|
||||
import net.minecraft.world.item.Item.Properties
|
||||
import net.minecraft.world.effect.MobEffects
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.food.FoodProperties
|
||||
@@ -281,7 +283,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
// Evolution items
|
||||
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
|
||||
@JvmField val DRAGON_SCALE = noSettingsItem("dragon_scale")
|
||||
@JvmField val KINGS_ROCK = noSettingsItem("kings_rock")
|
||||
@JvmField val METAL_COAT = noSettingsItem("metal_coat")
|
||||
@JvmField val UPGRADE = noSettingsItem("upgrade")
|
||||
@JvmField val DUBIOUS_DISC = noSettingsItem("dubious_disc")
|
||||
@@ -294,20 +295,21 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField val REAPER_CLOTH = noSettingsItem("reaper_cloth")
|
||||
@JvmField val PRISM_SCALE = noSettingsItem("prism_scale")
|
||||
@JvmField val SACHET = noSettingsItem("sachet")
|
||||
@JvmField val WHIPPED_DREAM = noSettingsItem("whipped_dream")
|
||||
@JvmField val STRAWBERRY_SWEET = noSettingsItem("strawberry_sweet")
|
||||
@JvmField val LOVE_SWEET = noSettingsItem("love_sweet")
|
||||
@JvmField val BERRY_SWEET = noSettingsItem("berry_sweet")
|
||||
@JvmField val CLOVER_SWEET = noSettingsItem("clover_sweet")
|
||||
@JvmField val FLOWER_SWEET = noSettingsItem("flower_sweet")
|
||||
@JvmField val STAR_SWEET = noSettingsItem("star_sweet")
|
||||
@JvmField val RIBBON_SWEET = noSettingsItem("ribbon_sweet")
|
||||
@JvmField val WHIPPED_DREAM = create("whipped_dream", foodItem(8, 0.3f))
|
||||
@JvmField val STRAWBERRY_SWEET = create("strawberry_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val LOVE_SWEET = create("love_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val BERRY_SWEET = create("berry_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val CLOVER_SWEET = create("clover_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val FLOWER_SWEET = create("flower_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val STAR_SWEET = create("star_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val RIBBON_SWEET = create("ribbon_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
|
||||
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
|
||||
@JvmField val MASTERPIECE_TEACUP = noSettingsItem("masterpiece_teacup")
|
||||
@JvmField val UNREMARKABLE_TEACUP = noSettingsItem("unremarkable_teacup")
|
||||
@JvmField val SWEET_APPLE = noSettingsItem("sweet_apple")
|
||||
@JvmField val TART_APPLE = noSettingsItem("tart_apple")
|
||||
@JvmField val SWEET_APPLE = create("sweet_apple", foodItem(4, 0.3f))
|
||||
@JvmField val TART_APPLE = create("tart_apple", foodItem(4, 0.3f))
|
||||
@JvmField val SYRUPY_APPLE = create("syrupy_apple", foodItem(4, 0.3f))
|
||||
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
|
||||
@JvmField val GALARICA_WREATH = noSettingsItem("galarica_wreath")
|
||||
@JvmField val BLACK_AUGURITE = noSettingsItem("black_augurite")
|
||||
@@ -392,6 +394,33 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
|
||||
@JvmField val BERRY_JUICE = this.create("berry_juice", BerryJuiceItem())
|
||||
|
||||
val NEST_STICK = blockItem(NestBlock.NestVariant.STICK.serializedName, CobblemonBlocks.NEST_STICK)
|
||||
val NEST_LEAF = blockItem(NestBlock.NestVariant.LEAF.serializedName, CobblemonBlocks.NEST_LEAF)
|
||||
val NEST_STONE = blockItem(NestBlock.NestVariant.STONE.serializedName, CobblemonBlocks.NEST_STONE)
|
||||
val NEST_DEEPSLATE = blockItem(NestBlock.NestVariant.DEEPSLATE.serializedName, CobblemonBlocks.NEST_DEEPSLATE)
|
||||
val NEST_BASALT = blockItem(NestBlock.NestVariant.BASALT.serializedName, CobblemonBlocks.NEST_BASALT)
|
||||
val NEST_SNOW = blockItem(NestBlock.NestVariant.SNOW.serializedName, CobblemonBlocks.NEST_SNOW)
|
||||
|
||||
val NEST_NETHER = blockItem(NestBlock.NestVariant.NETHER.serializedName, CobblemonBlocks.NEST_NETHER)
|
||||
val NEST_SOUL_SAND = blockItem(NestBlock.NestVariant.SOUL_SAND.serializedName, CobblemonBlocks.NEST_SOUL_SAND)
|
||||
val NEST_WARM_OCEAN = blockItem(NestBlock.NestVariant.WARM_OCEAN.serializedName, CobblemonBlocks.NEST_WARM_OCEAN)
|
||||
val NEST_SEAGRASS = blockItem(NestBlock.NestVariant.SEAGRASS.serializedName, CobblemonBlocks.NEST_SEAGRASS)
|
||||
val NEST_LUSH = blockItem(NestBlock.NestVariant.LUSH.serializedName, CobblemonBlocks.NEST_LUSH)
|
||||
val NEST_HAY = blockItem(NestBlock.NestVariant.HAY.serializedName, CobblemonBlocks.NEST_HAY)
|
||||
val NEST_SAND = blockItem(NestBlock.NestVariant.SAND.serializedName, CobblemonBlocks.NEST_SAND)
|
||||
val NEST_RED_SAND = blockItem(NestBlock.NestVariant.RED_SAND.serializedName, CobblemonBlocks.NEST_RED_SAND)
|
||||
val NEST_CHORUS = blockItem(NestBlock.NestVariant.CHORUS.serializedName, CobblemonBlocks.NEST_CHORUS)
|
||||
|
||||
val BASIC_NEST = blockItem(NestBlock.NestVariant.BASIC.serializedName, CobblemonBlocks.BASIC_NEST)
|
||||
val CAVE_NEST = blockItem(NestBlock.NestVariant.CAVE.serializedName, CobblemonBlocks.CAVE_NEST)
|
||||
val WATER_NEST = blockItem(NestBlock.NestVariant.WATER.serializedName, CobblemonBlocks.WATER_NEST)
|
||||
|
||||
@JvmField
|
||||
val INCUBATOR = blockItem("incubator", CobblemonBlocks.INCUBATOR)
|
||||
|
||||
@JvmField
|
||||
val GROTTO_BLOCK = blockItem("grotto_block", CobblemonBlocks.GROTTO_BLOCK)
|
||||
|
||||
@JvmField
|
||||
val GALARICA_NUTS = create("galarica_nuts", GalaricaNutItem())
|
||||
|
||||
@@ -660,6 +689,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val WATER_STONE = noSettingsItem("water_stone")
|
||||
|
||||
val wearables = mutableListOf<WearableItem>()
|
||||
//Wearable items (these items should have a corresponding 3D model)
|
||||
@JvmField val BLACK_GLASSES = wearableItem("black_glasses")
|
||||
@JvmField val CHOICE_BAND = wearableItem("choice_band")
|
||||
@JvmField val CHOICE_SPECS = wearableItem("choice_specs")
|
||||
@JvmField val EXP_SHARE = wearableItem("exp_share")
|
||||
@JvmField val FOCUS_BAND = wearableItem("focus_band")
|
||||
@JvmField val KINGS_ROCK = wearableItem("kings_rock")
|
||||
@JvmField val MUSCLE_BAND = wearableItem("muscle_band")
|
||||
@JvmField val ROCKY_HELMET = wearableItem("rocky_helmet")
|
||||
@JvmField val SAFETY_GOGGLES = wearableItem("safety_goggles")
|
||||
@JvmField val WISE_GLASSES = wearableItem("wise_glasses")
|
||||
|
||||
// Held Items
|
||||
@JvmField
|
||||
val ABILITY_SHIELD = heldItem("ability_shield")
|
||||
@@ -676,8 +718,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val BLACK_BELT = heldItem("black_belt")
|
||||
@JvmField
|
||||
val BLACK_GLASSES = heldItem("black_glasses")
|
||||
@JvmField
|
||||
val BLACK_SLUDGE = heldItem("black_sludge")
|
||||
@JvmField
|
||||
val BLUNDER_POLICY = heldItem("blunder_policy")
|
||||
@@ -686,19 +726,15 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val CHARCOAL = heldItem("charcoal_stick", remappedName = "charcoal")
|
||||
@JvmField
|
||||
val CHOICE_BAND = heldItem("choice_band")
|
||||
@JvmField
|
||||
val CHOICE_SCARF = heldItem("choice_scarf")
|
||||
@JvmField
|
||||
val CHOICE_SPECS = heldItem("choice_specs")
|
||||
@JvmField
|
||||
val CLEANSE_TAG = heldItem("cleanse_tag")
|
||||
// @JvmField
|
||||
// val CLEAR_AMULET = heldItem("clear_amulet")
|
||||
@JvmField
|
||||
val COVERT_CLOAK = heldItem("covert_cloak")
|
||||
@JvmField
|
||||
val DESTINY_KNOT = heldItem("destiny_knot")
|
||||
val DESTINY_KNOT = heldItem("destiny_knot", null, if (Cobblemon.config.canDestinyKnotBreak) Properties().durability(Cobblemon.config.destinyKnotDurability) else Properties())
|
||||
@JvmField
|
||||
val DRAGON_FANG = heldItem("dragon_fang")
|
||||
@JvmField
|
||||
@@ -712,8 +748,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val EVIOLITE = heldItem("eviolite")
|
||||
@JvmField
|
||||
val EXP_SHARE = heldItem("exp_share")
|
||||
@JvmField
|
||||
val EXPERT_BELT = heldItem("expert_belt")
|
||||
@JvmField
|
||||
val FAIRY_FEATHER = heldItem("fairy_feather")
|
||||
@@ -722,8 +756,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val FLOAT_STONE = heldItem("float_stone")
|
||||
@JvmField
|
||||
val FOCUS_BAND = heldItem("focus_band")
|
||||
@JvmField
|
||||
val FOCUS_SASH = heldItem("focus_sash")
|
||||
@JvmField
|
||||
val GRASSY_SEED = heldItem("grassy_seed")
|
||||
@@ -758,8 +790,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val MIRACLE_SEED = heldItem("miracle_seed")
|
||||
@JvmField
|
||||
val MUSCLE_BAND = heldItem("muscle_band")
|
||||
@JvmField
|
||||
val MYSTIC_WATER = heldItem("mystic_water")
|
||||
@JvmField
|
||||
val NEVER_MELT_ICE = heldItem("never_melt_ice")
|
||||
@@ -790,12 +820,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val RING_TARGET = heldItem("ring_target")
|
||||
@JvmField
|
||||
val ROCKY_HELMET = heldItem("rocky_helmet")
|
||||
@JvmField
|
||||
val ROOM_SERVICE = heldItem("room_service")
|
||||
@JvmField
|
||||
val SAFETY_GOGGLES = heldItem("safety_goggles")
|
||||
@JvmField
|
||||
val SCOPE_LENS = heldItem("scope_lens")
|
||||
@JvmField
|
||||
val SHARP_BEAK = heldItem("sharp_beak")
|
||||
@@ -832,8 +858,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val WIDE_LENS = heldItem("wide_lens")
|
||||
@JvmField
|
||||
val WISE_GLASSES = heldItem("wise_glasses")
|
||||
@JvmField
|
||||
val ZOOM_LENS = heldItem("zoom_lens")
|
||||
@JvmField
|
||||
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 1F)
|
||||
@@ -1230,6 +1254,10 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
val FAIRY_GEM = noSettingsItem("fairy_gem")
|
||||
//@JvmField
|
||||
//val BINDING_SOIL = blockItem("binding_soil", CobblemonBlocks.BINDING_SOIL)
|
||||
@JvmField
|
||||
val POKEMON_EGG = eggItem("egg", CobblemonBlocks.EGG, Item.Properties().stacksTo(1))
|
||||
|
||||
private fun eggItem(name: String, block: Block, settings: Item.Properties = Item.Properties()): BlockItem = this.create(name, BlockItem(block, settings))
|
||||
|
||||
private fun blockItem(name: String, block: Block, rarity: Rarity = Rarity.COMMON): BlockItem = this.create(name, BlockItem(block, Item.Properties().rarity(rarity)))
|
||||
|
||||
@@ -1263,9 +1291,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return item
|
||||
}
|
||||
|
||||
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
|
||||
private fun wearableItem(name: String, heldItemRemappedName: String? = null): CobblemonItem = create(
|
||||
name,
|
||||
CobblemonItem(Item.Properties()).also {
|
||||
WearableItem(name).also {
|
||||
wearables.add(it)
|
||||
if (heldItemRemappedName != null) {
|
||||
CobblemonHeldItemManager.registerRemap(it, heldItemRemappedName)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
private fun heldItem(name: String, remappedName: String? = null, settings:Item.Properties = Item.Properties()): CobblemonItem = create(
|
||||
name,
|
||||
CobblemonItem(settings).also {
|
||||
if (remappedName != null) {
|
||||
CobblemonHeldItemManager.registerRemap(it, remappedName)
|
||||
}
|
||||
@@ -1354,4 +1392,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return createdItem
|
||||
}
|
||||
|
||||
private fun foodItem(nutrition: Int, saturationModifier: Float): Item {
|
||||
return Item(Item.Properties().food(FoodProperties.Builder().nutrition(nutrition).saturationModifier(saturationModifier).build()))
|
||||
}
|
||||
}
|
||||
@@ -10,20 +10,56 @@ package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.dialogue.ActiveDialogue
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.ListCodec
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.UUIDUtil
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
|
||||
object CobblemonMemories {
|
||||
val memories = mutableMapOf<String, MemoryModuleType<*>>()
|
||||
|
||||
/*
|
||||
* When a memory doesn't have a codec provided, it's because it doesn't
|
||||
* get serialized during relogs. This makes sense for things like battles which
|
||||
* do not survive a relog therefore any memory of it should be temporary.
|
||||
*/
|
||||
|
||||
val BATTLING_POKEMON = register("battling_pokemon", ListCodec(UUIDUtil.CODEC, 0, 31))
|
||||
val NPC_BATTLING = register("npc_battling", PrimitiveCodec.BOOL)
|
||||
val DIALOGUES = register<List<ActiveDialogue>>("npc_dialogues")
|
||||
val ACTIVE_ACTION_EFFECT = register<ActionEffectContext>("active_action_effect")
|
||||
val POTENTIAL_MATE = register<PokemonEntity>("potential_mate")
|
||||
val MATE_SCAN_COOLDOWN = register("mate_scan_cooldown", PrimitiveCodec.BOOL)
|
||||
val NEST_LOCATION = register<BlockPos>("nest_location")
|
||||
val PATERNAL_NEST_LOCATION = register<BlockPos>("paternal_nest")
|
||||
val IRRITATED_AT = register<UUID>("irritated_at")
|
||||
val POKEMON_FLYING = register("pokemon_flying", PrimitiveCodec.BOOL)
|
||||
val POKEMON_DROWSY = register("pokemon_drowsy", PrimitiveCodec.BOOL)
|
||||
val POKEMON_SLEEPING = register("pokemon_sleeping", PrimitiveCodec.BOOL)
|
||||
val POKEMON_BATTLE = register<UUID>("pokemon_battle")
|
||||
val PATH_COOLDOWN = register<Boolean>("path_cooldown")
|
||||
val TARGETED_BATTLE_POKEMON = register<UUID>("targeted_battle_pokemon")
|
||||
val NEAREST_VISIBLE_ATTACKER = register<LivingEntity>("nearest_visible_attacker")
|
||||
val NEARBY_GROWABLE_CROPS = register<BlockPos>("nearby_growable_crops")
|
||||
val EGG_THIEF = register<Player>("egg_thief") // Stores the player stealing the egg
|
||||
val EGG_LOCATION = register<BlockPos>("egg_location") // Stores the last known location of the egg
|
||||
val EGG_IN_NEST = register("egg_in_nest", PrimitiveCodec.BOOL)
|
||||
val READY_TO_GRAB_EGG = register("ready_to_grab_egg", PrimitiveCodec.BOOL)
|
||||
val HOLDING_EGG = register("holding_egg", PrimitiveCodec.BOOL)
|
||||
val EGG_SEARCH_COUNTDOWN = register ("egg_search_countdown", PrimitiveCodec.BOOL)
|
||||
val NESTING_MATERIAL_LOCATION = register<BlockPos>("nesting_material_location")
|
||||
val SENSED_NEST_MATERIAL = register<ItemEntity>("sensed_nest_material")
|
||||
val IDEAL_NEST_LOCATION = register<BlockPos>("ideal_nest_location")
|
||||
val READY_TO_BUILD_NEST = register("ready_to_build_nest", PrimitiveCodec.BOOL)
|
||||
val RECENTLY_ATE_GRASS = register<Boolean>("recently_ate_grass")
|
||||
|
||||
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType(Optional.of(codec))
|
||||
@@ -36,4 +72,4 @@ object CobblemonMemories {
|
||||
memories[id] = memoryModule
|
||||
return memoryModule
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.client.net.OpenBehaviourEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.CalculateSeatPositionsHandler
|
||||
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
|
||||
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
|
||||
@@ -29,11 +30,13 @@ import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.orientation.S2CUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pokedex.ServerConfirmedRegisterHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundUpdateRidingStateHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
|
||||
import com.cobblemon.mod.common.client.net.settings.OpenCobblemonConfigEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
|
||||
@@ -57,11 +60,13 @@ import com.cobblemon.mod.common.client.net.trade.TradeProcessStartedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
|
||||
import com.cobblemon.mod.common.net.PacketRegisterInfo
|
||||
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.CalculateSeatPositionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.client.breeding.BreedingRuleRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
|
||||
@@ -73,6 +78,7 @@ import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityP
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.CloseNPCEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.OpenNPCEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
|
||||
@@ -100,9 +106,9 @@ import com.cobblemon.mod.common.net.messages.client.storage.pc.ClosePCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.InitializePCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.MoveClientPCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.RenamePCBoxPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.ChangePCBoxWallpaperPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.RequestPCBoxWallpapersPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.SetPCBoxWallpapersPacket
|
||||
@@ -132,7 +138,9 @@ import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPack
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.behaviour.SetEntityBehaviourPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.breeding.TriggerEggHatchPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonSelectedPacket
|
||||
@@ -142,7 +150,7 @@ import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPoke
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.C2SUpdateOrientationPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPacket
|
||||
@@ -151,12 +159,21 @@ import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.StartScannin
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHiddenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePCPokemonToPartyPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePartyPokemonToPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.ReleasePCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.SwapPCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.UnlinkPlayerFromPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
|
||||
@@ -173,7 +190,10 @@ import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamLeaveHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestResponseHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.behaviour.SetEntityBehaviourHandler
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.breeding.TriggerEggHatchHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectedHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSelectedHandler
|
||||
@@ -193,6 +213,9 @@ import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.StartScanning
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetItemHiddenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.ServerboundUpdateRidingStateHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.RequestStarterScreenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.SelectStarterPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.BenchMoveHandler
|
||||
@@ -202,6 +225,12 @@ import com.cobblemon.mod.common.net.serverhandling.storage.SwapPCPartyPokemonHan
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.MovePartyPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.ReleasePCPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.SwapPartyPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.MovePCPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.MovePCPokemonToPartyHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.MovePartyPokemonToPCHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.ReleasePartyPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.SwapPCPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.UnlinkPlayerFromPCHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
|
||||
@@ -209,6 +238,7 @@ import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHa
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.*
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
@@ -265,6 +295,13 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(DmaxLevelUpdatePacket.ID, DmaxLevelUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(GmaxFactorUpdatePacket.ID, GmaxFactorUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(CosmeticItemUpdatePacket.ID, CosmeticItemUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(ActiveMarkUpdatePacket.ID, ActiveMarkUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkAddUpdatePacket.ID, MarkAddUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkRemoveUpdatePacket.ID, MarkRemoveUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkPotentialAddUpdatePacket.ID, MarkPotentialAddUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarksUpdatePacket.ID, MarksUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarksPotentialUpdatePacket.ID, MarksPotentialUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkingsUpdatePacket.ID, MarkingsUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
|
||||
// Evolution start
|
||||
list.add(PacketRegisterInfo(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler()))
|
||||
@@ -355,8 +392,12 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(PokedexDexSyncPacket.ID, PokedexDexSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(DexEntrySyncPacket.ID, DexEntrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(FishingBaitRegistrySyncPacket.ID, FishingBaitRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(BreedingRuleRegistrySyncPacket.ID, BreedingRuleRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(HabitatSyncPacket.ID, HabitatSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(FlowRegistrySyncPacket.ID, FlowRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(CosmeticItemAssignmentSyncPacket.ID, CosmeticItemAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(BehaviourSyncPacket.ID, BehaviourSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
|
||||
// Effects
|
||||
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
|
||||
@@ -387,6 +428,9 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(PokemonPasturedPacket.ID, PokemonPasturedPacket::decode, PokemonPasturedHandler))
|
||||
list.add(PacketRegisterInfo(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler))
|
||||
|
||||
// Orientation
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, S2CUpdateOrientationHandler))
|
||||
|
||||
// Behaviours
|
||||
list.add(PacketRegisterInfo(PlayPosableAnimationPacket.ID, PlayPosableAnimationPacket::decode, PlayPosableAnimationHandler))
|
||||
|
||||
@@ -407,12 +451,18 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(CloseNPCEditorPacket.ID, CloseNPCEditorPacket::decode, CloseNPCEditorHandler))
|
||||
list.add(PacketRegisterInfo(OpenNPCEditorPacket.ID, OpenNPCEditorPacket::decode, OpenNPCEditorHandler))
|
||||
|
||||
// Behaviours
|
||||
list.add(PacketRegisterInfo(OpenBehaviourEditorPacket.ID, OpenBehaviourEditorPacket::decode, OpenBehaviourEditorHandler))
|
||||
|
||||
// Pokédex scanning
|
||||
list.add(PacketRegisterInfo(ServerConfirmedRegisterPacket.ID, ServerConfirmedRegisterPacket::decode, ServerConfirmedRegisterHandler))
|
||||
|
||||
// Debug / cheats
|
||||
list.add(PacketRegisterInfo(CalculateSeatPositionsPacket.ID, CalculateSeatPositionsPacket::decode, CalculateSeatPositionsHandler))
|
||||
|
||||
// Riding
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
@@ -421,6 +471,8 @@ object CobblemonNetwork {
|
||||
// Pokemon Update Packets
|
||||
list.add(PacketRegisterInfo(SetNicknamePacket.ID, SetNicknamePacket::decode, SetNicknameHandler))
|
||||
list.add(PacketRegisterInfo(SetItemHiddenPacket.ID, SetItemHiddenPacket::decode, SetItemHiddenHandler))
|
||||
list.add(PacketRegisterInfo(SetActiveMarkPacket.ID, SetActiveMarkPacket::decode, SetActiveMarkHandler))
|
||||
list.add(PacketRegisterInfo(SetMarkingsPacket.ID, SetMarkingsPacket::decode, SetMarkingsHandler))
|
||||
|
||||
// Evolution Packets
|
||||
list.add(PacketRegisterInfo(AcceptEvolutionPacket.ID, AcceptEvolutionPacket::decode, AcceptEvolutionHandler))
|
||||
@@ -508,8 +560,15 @@ object CobblemonNetwork {
|
||||
// NPC packets
|
||||
list.add(PacketRegisterInfo(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler))
|
||||
|
||||
// Orientation packet(s)
|
||||
list.add(PacketRegisterInfo(C2SUpdateOrientationPacket.ID, C2SUpdateOrientationPacket::decode, OrientationPacketHandler))
|
||||
// Riding packet(s)
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, OrientationPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
|
||||
|
||||
// Breeding Packets
|
||||
list.add(PacketRegisterInfo(TriggerEggHatchPacket.ID, TriggerEggHatchPacket::decode, TriggerEggHatchHandler))
|
||||
|
||||
// Behaviour Packets
|
||||
list.add(PacketRegisterInfo(SetEntityBehaviourPacket.ID, SetEntityBehaviourPacket::decode, SetEntityBehaviourHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
+6
-1
@@ -19,7 +19,7 @@ import net.minecraft.world.entity.ai.village.poi.PoiType
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
|
||||
object CobblemonVillagerPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Registry<PoiType>>, PoiType>() {
|
||||
object CobblemonPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Registry<PoiType>>, PoiType>() {
|
||||
override val registry: Registry<PoiType> = BuiltInRegistries.POINT_OF_INTEREST_TYPE
|
||||
override val resourceKey: ResourceKey<Registry<PoiType>> = Registries.POINT_OF_INTEREST_TYPE
|
||||
|
||||
@@ -27,6 +27,11 @@ object CobblemonVillagerPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKe
|
||||
val NURSE_KEY: ResourceKey<PoiType> = createKey("nurse")
|
||||
@JvmField
|
||||
val NURSE = create(NURSE_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.HEALING_MACHINE), 1, 1))
|
||||
@JvmField
|
||||
val GROTTO_BLOCK_KEY: ResourceKey<PoiType> = createKey("grotto_block")
|
||||
@JvmField
|
||||
val GROTTO_BLOCK = create(GROTTO_BLOCK_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.GROTTO_BLOCK), 0, 1))
|
||||
|
||||
|
||||
private fun createKey(string: String): ResourceKey<PoiType> = ResourceKey.create(Registries.POINT_OF_INTEREST_TYPE, cobblemonResource(string))
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.*
|
||||
import com.cobblemon.mod.common.pokemon.ai.PokemonDisturbancesSensor
|
||||
import com.cobblemon.mod.common.entity.sensor.BattlingPokemonSensor
|
||||
import com.cobblemon.mod.common.entity.sensor.NPCBattlingSensor
|
||||
import java.util.function.Supplier
|
||||
@@ -20,10 +22,25 @@ object CobblemonSensors {
|
||||
|
||||
val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
|
||||
val BATTLING_POKEMON = register("battling_pokemon", ::BattlingPokemonSensor)
|
||||
val MATE_SENSOR = register("mate_sensor", ::MateSensor)
|
||||
val NEST_SENSOR = register("nest_sensor", ::NestSensor)
|
||||
val EGG_SENSOR = register("egg_sensor", :: EggSensor)
|
||||
val NEST_MATERIAL_SENSOR = register("nest_material_sensor", :: NestMaterialSensor)
|
||||
val IDEAL_NEST_LOCATION_SENSOR = register("ideal_nest_location_sensor", ::IdealNestPlacementSensor)
|
||||
// val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
|
||||
val POKEMON_DROWSY = register("pokemon_drowsy", ::DrowsySensor)
|
||||
|
||||
val POKEMON_ADULT = register("pokemon_adult_sensor", ::PokemonAdultSensor)
|
||||
|
||||
val POKEMON_DISTURBANCE = register("pokemon_disturbance_sensor", ::PokemonDisturbancesSensor)
|
||||
|
||||
val POKEMON_DEFEND_OWNER = register("pokemon_owner_under_attack", ::DefendOwnerSensor)
|
||||
|
||||
val NEARBY_GROWABLE_CROPS = register("nearby_growable_crops", ::PokemonGrowableCropSensor)
|
||||
|
||||
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
|
||||
val sensor = SensorType(supplier)
|
||||
sensors[id] = sensor
|
||||
return sensor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,9 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val POKEDEX_SCAN_ZOOM_INCREMENT = this.create("item.pokedex.scan_zoom_increment")
|
||||
|
||||
@JvmField
|
||||
val BREEDING_EGG_HATCH = this.create("breeding.egg_hatch")
|
||||
|
||||
@JvmField
|
||||
val ITEM_USE = this.create("item.use")
|
||||
@JvmField
|
||||
|
||||
@@ -24,7 +24,7 @@ object CobblemonVillagerProfessions: PlatformRegistry<Registry<VillagerProfessio
|
||||
override val resourceKey: ResourceKey<Registry<VillagerProfession>> = Registries.VILLAGER_PROFESSION
|
||||
|
||||
@JvmField
|
||||
val NURSE = profession(CobblemonVillagerPoiTypes.NURSE_KEY, CobblemonSounds.VILLAGER_WORK_NURSE)
|
||||
val NURSE = profession(CobblemonPoiTypes.NURSE_KEY, CobblemonSounds.VILLAGER_WORK_NURSE)
|
||||
|
||||
/**
|
||||
* Register a villager profession texture override for Cobblemon villagers of the given [VillagerProfession] for specified names.
|
||||
|
||||
+12
-4
@@ -8,12 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.config.BrainConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
import net.minecraft.world.entity.schedule.Schedule
|
||||
|
||||
class BrainConfigurationContext {
|
||||
class BehaviourConfigurationContext {
|
||||
var appliedBehaviours: MutableSet<ResourceLocation> = mutableSetOf()
|
||||
|
||||
var defaultActivity = Activity.IDLE
|
||||
var coreActivities = setOf(Activity.CORE)
|
||||
@@ -24,11 +27,16 @@ class BrainConfigurationContext {
|
||||
return activities.firstOrNull { it.activity == activity } ?: ActivityConfigurationContext(activity).also(activities::add)
|
||||
}
|
||||
|
||||
fun apply(entity: LivingEntity, brainConfigs: List<BrainConfig>) {
|
||||
fun apply(entity: LivingEntity, behaviourConfigs: List<BehaviourConfig>) {
|
||||
val brain = entity.brain
|
||||
|
||||
if (entity is MoLangScriptingEntity) {
|
||||
entity.registerVariables(behaviourConfigs.flatMap { it.getVariables(entity) })
|
||||
entity.initializeScripting()
|
||||
}
|
||||
|
||||
// Setup the brain config
|
||||
brainConfigs.forEach { it.configure(entity, this) }
|
||||
behaviourConfigs.forEach { it.configure(entity, this) }
|
||||
|
||||
// Apply the brain config
|
||||
activities.forEach { it.apply(entity) }
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class CobblemonBehaviour(
|
||||
val name: Component = "".asTranslated(),
|
||||
val description: Component = "".asTranslated(),
|
||||
/** Some behaviours aren't really worth showing on the client, namely ones that are simply conditional bundles of other behaviours. */
|
||||
val visible: Boolean = true,
|
||||
val entityType: ResourceLocation? = null,
|
||||
val configurations: List<BehaviourConfig> = mutableListOf(),
|
||||
val undo: ExpressionLike? = null,
|
||||
val undoScript: ResourceLocation? = null,
|
||||
) {
|
||||
fun canBeApplied(entity: LivingEntity) = entityType?.let { entityType == entity.type.builtInRegistryHolder().unwrapKey().get().location() } != false
|
||||
fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
configurations.forEach { it.configure(entity, behaviourConfigurationContext) }
|
||||
}
|
||||
|
||||
/** Undoes anything that needs undoing once this configuration is being removed from an entity that had it before. */
|
||||
fun undo(entity: LivingEntity) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (undoScript != null) {
|
||||
CobblemonScripts.run(undoScript, runtime)
|
||||
}
|
||||
if (undo != null) {
|
||||
runtime.resolve(undo)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.mojang.datafixers.util.Either
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
typealias ExpressionOrEntityVariable = Either<Expression, MoLangConfigVariable>
|
||||
|
||||
fun List<ExpressionOrEntityVariable>.asVariables() = mapNotNull { it.right().getOrNull() }
|
||||
|
||||
|
||||
+20
-18
@@ -8,32 +8,34 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.TaskConfig
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
class AddTasksToActivity : BrainConfig {
|
||||
val activity = Activity.IDLE
|
||||
val condition = "true".asExpressionLike()
|
||||
class AddTasksToActivity : BehaviourConfig {
|
||||
val activity: Activity? = null
|
||||
// Can be useful to add to multiple activities at once
|
||||
val activities = mutableListOf<Activity>()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val tasksByPriority = mutableMapOf<Int, List<TaskConfig>>()
|
||||
override fun getVariables(entity: LivingEntity) = tasksByPriority.values.flatten().flatMap { it.getVariables(entity) } + listOf(condition).asVariables()
|
||||
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
if (!checkCondition(entity, condition)) return
|
||||
|
||||
val activities = if (activity != null) (activities + activity) else activities
|
||||
|
||||
val activity = brainConfigurationContext.getOrCreateActivity(activity)
|
||||
tasksByPriority.forEach { (priority, taskConfigs) ->
|
||||
val tasks = taskConfigs.flatMap { it.createTasks(entity, brainConfigurationContext) }
|
||||
activity.addTasks(priority, *tasks.toTypedArray())
|
||||
val tasks = taskConfigs.flatMap { it.createTasks(entity, behaviourConfigurationContext) }
|
||||
for (activity in activities) {
|
||||
val activityContext = behaviourConfigurationContext.getOrCreateActivity(activity)
|
||||
activityContext.addTasks(priority, *tasks.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class AddVariablesConfig(val variables: List<MoLangConfigVariable> = emptyList()) : BehaviourConfig {
|
||||
override fun getVariables(entity: LivingEntity) = variables
|
||||
|
||||
// Configuration happens naturally through the override on variables
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonBehaviours
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class ApplyBehaviours : BehaviourConfig {
|
||||
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
@SerializedName("behaviours", alternate = ["behaviors"])
|
||||
val behaviours = mutableListOf<ResourceLocation>()
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return if (checkCondition(entity, condition)) {
|
||||
behaviours.flatMap {
|
||||
CobblemonBehaviours.behaviours[it]?.configurations?.flatMap { it.getVariables(entity) } ?: emptyList()
|
||||
} + listOf(condition).asVariables()
|
||||
} else {
|
||||
listOf(condition).asVariables()
|
||||
}
|
||||
}
|
||||
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
if (!checkCondition(entity, condition)) return
|
||||
|
||||
val configurations = behaviours.map { CobblemonBehaviours.behaviours[it]?.takeIf { it.canBeApplied(entity) } ?: return Cobblemon.LOGGER.warn("Behaviour $it not found") }
|
||||
// Why not just add the presets to the context directly?
|
||||
// Nested preset application is a thing, and I only want to track the top level presets.
|
||||
// i.e. if a preset applies another preset, I don't want to track the inner preset, since it's redundant if we track the top one.
|
||||
val originalContextBehaviours = behaviourConfigurationContext.appliedBehaviours.toMutableSet()
|
||||
configurations.forEach {
|
||||
it.configure(entity, behaviourConfigurationContext)
|
||||
}
|
||||
originalContextBehaviours.addAll(behaviours)
|
||||
behaviourConfigurationContext.appliedBehaviours = originalContextBehaviours
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonBrainConfigs
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class ApplyPresets : BrainConfig {
|
||||
val condition = "true".asExpressionLike()
|
||||
val presets = mutableListOf<ResourceLocation>()
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return
|
||||
|
||||
val presetConfigs = presets.flatMap { CobblemonBrainConfigs.presets[it] ?: return Cobblemon.LOGGER.warn("Preset $it not found") }
|
||||
presetConfigs.forEach { it.configure(entity, brainConfigurationContext) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* Something that contributes to the construction of an entity's brain. Implementations are expected to make
|
||||
* their changes using the provided [BehaviourConfigurationContext] which helps stage the details of the entity's
|
||||
* brain before locking into the highly immutable structure that Mojang uses.
|
||||
*
|
||||
* A brain config has access to the [LivingEntity] it's for but note that this is, in most cases, an extremely
|
||||
* young version of the entity that is not fully initialized and might die if you try getting exotic with it.
|
||||
*
|
||||
* @see BehaviourConfigurationContext
|
||||
* @author Hiroku
|
||||
* @since October 13th, 2024
|
||||
*/
|
||||
interface BehaviourConfig {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out BehaviourConfig>>(
|
||||
"script" to ScriptBehaviourConfig::class.java,
|
||||
"custom_script" to CustomScriptBehaviourConfig::class.java,
|
||||
"add_tasks_to_activity" to AddTasksToActivity::class.java,
|
||||
"apply_behaviours" to ApplyBehaviours::class.java,
|
||||
"set_default_activity" to SetDefaultActivity::class.java,
|
||||
"set_core_activities" to SetCoreActivities::class.java,
|
||||
"add_variables" to AddVariablesConfig::class.java,
|
||||
"set_variables" to SetVariablesConfig::class.java,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
fun checkCondition(entity: LivingEntity, expressionOrEntityVariable: ExpressionOrEntityVariable): Boolean {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
return runtime.resolveBoolean(expressionOrEntityVariable.map({ it }, { "q.entity.config.${it.variableName}".asExpression() }))
|
||||
}
|
||||
|
||||
fun getVariables(entity: LivingEntity): List<MoLangConfigVariable>
|
||||
fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext)
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* Something that contributes to the construction of an entity's brain. Implementations are expected to make
|
||||
* their changes using the provided [BrainConfigurationContext] which helps stage the details of the entity's
|
||||
* brain before locking into the highly immutable structure that Mojang uses.
|
||||
*
|
||||
* A brain config has access to the [LivingEntity] it's for but note that this is, in most cases, an extremely
|
||||
* young version of the entity that is not fully initialized and might die if you try getting exotic with it.
|
||||
*
|
||||
* @see BrainConfigurationContext
|
||||
* @author Hiroku
|
||||
* @since October 13th, 2024
|
||||
*/
|
||||
interface BrainConfig {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out BrainConfig>>(
|
||||
"script" to ScriptBrainConfig::class.java,
|
||||
"add_tasks_to_activity" to AddTasksToActivity::class.java,
|
||||
"apply_presets" to ApplyPresets::class.java,
|
||||
"set_default_activity" to SetDefaultActivity::class.java,
|
||||
"set_core_activities" to SetCoreActivities::class.java
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// fun encode(buffer: RegistryFriendlyByteBuf)
|
||||
// fun decode(buffer: RegistryFriendlyByteBuf)
|
||||
fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext)
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class CustomScriptBehaviourConfig : BehaviourConfig {
|
||||
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val variables: List<MoLangConfigVariable> = emptyList()
|
||||
val script: ExpressionLike = "0".asExpressionLike()
|
||||
|
||||
companion object {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
}
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = variables
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
if (!checkCondition(entity, condition)) return
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
runtime.resolve(script)
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
object DummyBrainConfig : BrainConfig {
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
# Brain Configuration
|
||||
# Behaviour Configuration
|
||||
|
||||
A "Brain" is a Java Edition AI concept for more modern entities. It has tasks that are listed inside of 'activities',
|
||||
A "Brain" is a Java Edition AI concept for more modern entities. It has tasks that are listed inside 'activities',
|
||||
and in some cases a schedule which determines which activities will occur during different times of the day. There is
|
||||
also a set of core activities, and a default activity. In Minecraft, the most complex usage of the Brain AI system
|
||||
is on villagers which have schedules that control their behaviour during the day and night as well as child villager play behaviours.
|
||||
|
||||
Cobblemon's NPCs use the Brain AI system. As part of that, Cobblemon added the concept of a Brain Configuration
|
||||
that allows Java Edition brains to be configured in a more data-driven way.
|
||||
Cobblemon's Pokémon and NPCs use the Brain AI system. As part of that, Cobblemon added the concept of a Behaviour Configuration
|
||||
that allows Java Edition brains to be configured in a more data-driven way, as well as to support the configuration of
|
||||
other logical properties of entities that are configured at the same initialization step.
|
||||
|
||||
By default, without any brain configuration, the default activity will be `minecraft:idle` and the core activities will be `[minecraft:core]`.
|
||||
The activities would not have any tasks though.
|
||||
@@ -48,18 +49,18 @@ The activities that were added by Cobblemon are:
|
||||
- `cobblemon:action_effect`: For when the entity is performing an action effect. Usually registered as an almost empty activity that simply prevents the entity from doing other things.
|
||||
- `cobblemon:npc_chatting`: Intended for NPC entities using dialogue so that they look at their chat partner and do nothing else.
|
||||
|
||||
## Brain Configuration Format
|
||||
A brain is configured using a series of "Brain Configurations". Each configuration is a JSON object that contains
|
||||
a "type" field which determines the action to perform when configuring a brain. Many different types are available.
|
||||
## Behaviour Configuration Format
|
||||
A Behaviour is configured using a series of "Behaviour Configurations". Each configuration is a JSON object that contains
|
||||
a "type" field which determines the action to perform when configuring an entity. Many different types are available.
|
||||
|
||||
### script
|
||||
The `script` type executes a MoLang script which will apply some changes to the brain.
|
||||
The `script` type executes a MoLang script which will apply some changes to the entity or brain.
|
||||
- `script`: The MoLang script to execute. This will be a resource location for the `molang` datapack folder. Something like `cobblemon:some_script`.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the script should be executed. Defaults to `"true"`.
|
||||
|
||||
### add_tasks_to_activity
|
||||
The 'add_tasks_to_activity' type adds a list of tasks to an activity.
|
||||
- `activity`: The activity to add the tasks to. This must be a pre-existing activity - a brain configuration cannot
|
||||
- `activity`: The activity to add the tasks to. This must be a pre-existing activity - a behaviour configuration cannot
|
||||
create new activities.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the tasks should be added. If this
|
||||
is not present, the tasks will always be added.
|
||||
@@ -96,24 +97,107 @@ The `set_core_activities` type sets the core activities of the brain. It has onl
|
||||
### set_default_activity
|
||||
The `set_default_activity` type sets the default activity of the brain. It has only one property, `activity`, which is the activity to set as the default.
|
||||
|
||||
### apply_preset
|
||||
The `apply_preset` type applies a preset to the brain. Brain presets are JSON arrays under the `brain_presets` datapack folder.
|
||||
This is a way to apply a set of configurations to the brain.
|
||||
- `preset`: The name of the preset to apply. This is the name of the file in the `brain_presets` folder without the `.json` extension.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the preset should be applied. Defaults to `"true"`.
|
||||
### apply_behaviours
|
||||
The `apply_behaviours` type applies some number of other Behaviours to the entity. These behaviours are JSONs under the `behaviours` datapack folder.
|
||||
This is a way to apply a set of configurations to the entity.
|
||||
- `behaviours`: A list of behaviour resource locations to apply. This is the name of the file in the `behaviours` folder without the `.json` extension.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the behaviour should be applied. Defaults to `"true"`.
|
||||
- `visible`: Whether the behaviour should be visible in the UI. Defaults to `true`. If it is not visible, name and description can be left out.
|
||||
- `name`: The name of the behaviour. This is used in the UI to label the behaviour. This can be a translation key.
|
||||
- `description`: A description of the behaviour. This is used in the UI to describe what the behaviour does. This can be a translation key.
|
||||
- `entityType`: The entity type that the behaviour applies to. Defaults to null. This is used to determine if the behaviour should be applied to the entity type..
|
||||
|
||||
Example brain preset (`uses_healing_machine.json`):
|
||||
Example behaviour (`uses_healing_machine.json`):
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": "add_tasks_to_activity",
|
||||
"activity": "idle",
|
||||
"tasksByPriority": {
|
||||
"1": [
|
||||
"heal_using_healing_machine",
|
||||
"go_to_healing_machine"
|
||||
]
|
||||
{
|
||||
"name": "cobblemon.behaviour.uses_healing_machine.name",
|
||||
"description": "cobblemon.behaviour.uses_healing_machine.desc",
|
||||
"entityType": "cobblemon:npc",
|
||||
"visible": true,
|
||||
"configurations": [
|
||||
{
|
||||
"type": "add_tasks_to_activity",
|
||||
"activity": "idle",
|
||||
"tasksByPriority": {
|
||||
"1": [
|
||||
"heal_using_healing_machine",
|
||||
"go_to_healing_machine"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### add_variables
|
||||
The `add_variables` type adds some number of MoLang variables to the entity that can be configured in-game or left with defaults.
|
||||
- `variables`: A list of objects, each representing a variable that can be configured.
|
||||
|
||||
Each variable has the following properties:
|
||||
- `variableName`: The name of the variable. This is the name that will be accessible from MoLang scripts.
|
||||
- `defaultValue`: The default value of the variable. This is a MoLang expression that will be used if the variable is not set.
|
||||
- `displayName`: The display name of the variable. This is used in the UI to label the variable. This can be a translation key.
|
||||
- `description`: A description of the variable. This is used in the UI to describe what the variable does. This can be a translation key.
|
||||
- `type`: The type of the variable. This can be `TEXT`, `NUMBER`, or `BOOLEAN`.
|
||||
|
||||
Example:
|
||||
```json
|
||||
{
|
||||
"type": "add_variables",
|
||||
"variables": [
|
||||
{
|
||||
"variableName": "can_heal_using_machine",
|
||||
"defaultValue": "false",
|
||||
"displayName": "Can Use Healing Machine",
|
||||
"description": "Whether or not the entity can use a healing machine.",
|
||||
"type": "BOOLEAN"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### set_variables
|
||||
The `set_variables` type sets some values for pre-established variables. This is useful in cases where a preset has defined a variable
|
||||
but it's locked in by a specific entity using that preset. This strongly forces the variable to a specific value. In future this
|
||||
probably should deregister the variable so that the client cannot edit them once they've been forced, as currently that will
|
||||
be possible yet the value will get repeatedly overwritten.
|
||||
|
||||
The values inside the variables map can be MoLang expressions (with `q.entity` as the entity) or simple JSON primitives.
|
||||
|
||||
Example:
|
||||
```json
|
||||
{
|
||||
"type": "set_variables",
|
||||
"variables": {
|
||||
"aggressive": true,
|
||||
"attack_range": "10"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### script
|
||||
The `script` type executes a registered MoLang script which will apply some changes to the brain or entity. This can be
|
||||
useful if the goal is to apply some kind of configuration to the entity that would otherwise be performed by an NPC preset
|
||||
or NPC class. `q.entity` will refer to the entity. This is powerful when combined with [add_variables](#add_variables)
|
||||
configs in the same behaviour preset.
|
||||
|
||||
Example:
|
||||
```json
|
||||
{
|
||||
"type": "script",
|
||||
"script": "cobblemon:configure_npc_party"
|
||||
}
|
||||
```
|
||||
|
||||
### custom_script
|
||||
The `custom_script` type executes a custom MoLang script from this config which will apply some changes to the brain or
|
||||
entity. This is useful for when you want to apply some kind of configuration to the entity that would otherwise be
|
||||
by an NPC preset or NPC class. `q.entity` will refer to the entity.
|
||||
|
||||
Example:
|
||||
```json
|
||||
{
|
||||
"type": "custom_script",
|
||||
"script": "q.entity.set_pathfinding_malus('WATER', -1);"
|
||||
}
|
||||
```
|
||||
+15
-11
@@ -13,12 +13,13 @@ import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.ai.ActivityConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.activityRegistry
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
@@ -30,13 +31,16 @@ import com.mojang.datafixers.util.Pair
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class ScriptBrainConfig : BrainConfig {
|
||||
class ScriptBehaviourConfig : BehaviourConfig {
|
||||
val condition = "true".asExpressionLike()
|
||||
val script = cobblemonResource("dummy")
|
||||
val variables = mutableListOf<MoLangConfigVariable>()
|
||||
|
||||
override fun configure(entity: LivingEntity, context: BrainConfigurationContext) {
|
||||
override fun getVariables(entity: LivingEntity) = variables
|
||||
|
||||
override fun configure(entity: LivingEntity, context: BehaviourConfigurationContext) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!runtime.resolveBoolean(condition)) return
|
||||
|
||||
val struct = createBrainStruct(entity, context)
|
||||
@@ -48,30 +52,30 @@ class ScriptBrainConfig : BrainConfig {
|
||||
runtime.resolve(script, mapOf("brain" to struct))
|
||||
}
|
||||
|
||||
fun createBrainStruct(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): QueryStruct {
|
||||
fun createBrainStruct(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): QueryStruct {
|
||||
return QueryStruct(hashMapOf()).addStandardFunctions()
|
||||
.addFunction("entity") { (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()) }
|
||||
.addFunction("entity") { entity.asMostSpecificMoLangValue() }
|
||||
.addFunction("create_activity") { params ->
|
||||
val name = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
val activity = entity.level().activityRegistry.get(name) ?: return@addFunction run {
|
||||
Cobblemon.LOGGER.error("Tried loading activity $name as part of an entity brain but that activity does not exist")
|
||||
DoubleValue.ZERO
|
||||
}
|
||||
val existingActivityBuilder = brainConfigurationContext.activities.find { it.activity == activity }
|
||||
val existingActivityBuilder = behaviourConfigurationContext.activities.find { it.activity == activity }
|
||||
if (existingActivityBuilder != null) {
|
||||
return@addFunction createActivityStruct(existingActivityBuilder)
|
||||
} else {
|
||||
val activityConfigurationContext = ActivityConfigurationContext(activity)
|
||||
brainConfigurationContext.activities.add(activityConfigurationContext)
|
||||
behaviourConfigurationContext.activities.add(activityConfigurationContext)
|
||||
return@addFunction createActivityStruct(activityConfigurationContext)
|
||||
}
|
||||
}
|
||||
.addFunction("set_core_activities") { params ->
|
||||
brainConfigurationContext.coreActivities = params.params.map { (it as ObjectValue<ActivityConfigurationContext>).obj.activity }.toSet()
|
||||
behaviourConfigurationContext.coreActivities = params.params.map { (it as ObjectValue<ActivityConfigurationContext>).obj.activity }.toSet()
|
||||
return@addFunction DoubleValue.ONE
|
||||
}
|
||||
.addFunction("set_default_activity") { params ->
|
||||
brainConfigurationContext.defaultActivity = params.get<ObjectValue<ActivityConfigurationContext>>(0).obj.activity
|
||||
behaviourConfigurationContext.defaultActivity = params.get<ObjectValue<ActivityConfigurationContext>>(0).obj.activity
|
||||
return@addFunction DoubleValue.ONE
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
class SetCoreActivities : BrainConfig {
|
||||
class SetCoreActivities : BehaviourConfig {
|
||||
val activities = mutableListOf<Activity>()
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
|
||||
brainConfigurationContext.coreActivities = activities.toSet()
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
behaviourConfigurationContext.coreActivities = activities.toSet()
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
class SetDefaultActivity : BrainConfig {
|
||||
class SetDefaultActivity : BehaviourConfig {
|
||||
val activity: Activity = Activity.IDLE
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
|
||||
brainConfigurationContext.defaultActivity = activity
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
behaviourConfigurationContext.defaultActivity = activity
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class SetVariablesConfig : BehaviourConfig {
|
||||
var variableValues = mutableMapOf<String, ExpressionLike>()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (entity is MoLangScriptingEntity) {
|
||||
variableValues.forEach { (variableName, valueExpression) ->
|
||||
entity.config.setDirectly(variableName, runtime.resolve(valueExpression))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.WanderTaskConfig.Companion.WANDER
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.ai.util.HoverRandomPos
|
||||
|
||||
class AirWanderTaskConfig : SingleTaskConfig {
|
||||
val condition = booleanVariable(WANDER, "air_wanders", true).asExpressible()
|
||||
val wanderChance = numberVariable(WANDER, "air_wander_chance", 1/(20 * 1F)).asExpressible()
|
||||
val horizontalRange = numberVariable(WANDER, "horizontal_wander_range", 20).asExpressible()
|
||||
val verticalRange = numberVariable(WANDER, "vertical_wander_range", 5).asExpressible()
|
||||
val speedMultiplier = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
val minUpwardsMovement: ExpressionOrEntityVariable = Either.left("3.0".asExpression())
|
||||
val minDownwardsMovement: ExpressionOrEntityVariable = Either.left("3.0".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(condition, wanderChance, horizontalRange, verticalRange, speedMultiplier, minUpwardsMovement, minDownwardsMovement).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.registered(MemoryModuleType.LOOK_TARGET)
|
||||
).apply(it) { walkTarget, lookTarget ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || entity.isInWater) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val wanderChance = wanderChance.resolveFloat()
|
||||
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance) return@Trigger false
|
||||
|
||||
val rotVec = entity.getViewVector(0F)
|
||||
val target = HoverRandomPos.getPos(entity, horizontalRange.resolveInt(), verticalRange.resolveInt(), rotVec.x, rotVec.y, 1.5707964f, minUpwardsMovement.resolveInt(), minDownwardsMovement.resolveInt())
|
||||
?: return@Trigger false
|
||||
walkTarget.set(WalkTarget(target, speedMultiplier.resolveFloat(), 3))
|
||||
lookTarget.set(BlockPosTracker(target))
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-10
@@ -8,25 +8,34 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class AllOfTaskConfig : TaskConfig {
|
||||
val condition = "true".asExpressionLike()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val tasks: List<TaskConfig> = emptyList()
|
||||
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return if (checkCondition(entity, condition))
|
||||
tasks.flatMap { it.getVariables(entity) } + listOf(condition).asVariables()
|
||||
else
|
||||
listOf(condition).asVariables()
|
||||
}
|
||||
|
||||
override fun createTasks(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<BehaviorControl<in LivingEntity>> {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return emptyList()
|
||||
return tasks.flatMap { it.createTasks(entity, brainConfigurationContext) }
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return emptyList()
|
||||
return tasks.flatMap { it.createTasks(entity, behaviourConfigurationContext) }
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -8,24 +8,24 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.ai.AttackAngryAtTask
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class AttackAngryAtTaskConfig : SingleTaskConfig {
|
||||
val condition = "true".asExpressionLike()
|
||||
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "should_attack_angry_at", true).asExpressible()
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return AttackAngryAtTask.create()
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.pokemon.breeding.Egg
|
||||
import com.cobblemon.mod.common.api.text.green
|
||||
import com.cobblemon.mod.common.block.entity.NestBlockEntity
|
||||
import com.cobblemon.mod.common.breeding.BreedingLogicManager
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.AttackEggThiefTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.BreedAtNestTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.SearchForEggTask
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.kinds.IdF
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class AttackEggThiefTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val BREED = "breed_at_nest" // Category
|
||||
}
|
||||
|
||||
val condition = booleanVariable(BREED, "can_breed", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(AttackEggThiefTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
/*override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PokemonEntity) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(CobblemonMemories.NEST_LOCATION),
|
||||
it.present(CobblemonMemories.POTENTIAL_MATE),
|
||||
it.absent(MemoryModuleType.WALK_TARGET)
|
||||
).apply(it) { nestMemory, mateMemory, walkTarget ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive) return@Trigger false
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
|
||||
// Retrieve nest location and mate entity from memory
|
||||
val nestLocation: BlockPos = (nestMemory.value() as? IdF<BlockPos>)?.value() ?: return@Trigger false
|
||||
val mate = (mateMemory.value() as? IdF<PokemonEntity>)?.value() ?: return@Trigger false
|
||||
|
||||
// Convert nest location to Vec3
|
||||
val targetVec = Vec3.atCenterOf(nestLocation)
|
||||
|
||||
// Check proximity to the nest
|
||||
if (entity.distanceToSqr(targetVec) > 2.0 && mate.distanceToSqr(targetVec) > 2.0) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
// Access the nest block entity
|
||||
val nestBlockEntity = world.getBlockEntity(nestLocation) as? NestBlockEntity
|
||||
?: return@Trigger false
|
||||
|
||||
// double check to make sure the nest is not taken yet and cancel if it is
|
||||
if (nestBlockEntity.getItem(0) != ItemStack.EMPTY) return@Trigger false
|
||||
|
||||
// Generate the egg using BreedingLogicManager
|
||||
val parentOne = (entity as PokemonEntity).pokemon
|
||||
val parentTwo = mate.pokemon
|
||||
val breedingResult = BreedingLogicManager.breed(parentOne, parentTwo)
|
||||
val form = BreedingLogicManager.calculateForm(parentOne, parentTwo)
|
||||
|
||||
// Ensure the breeding result is valid
|
||||
val egg = breedingResult.pokemon?.let { result ->
|
||||
Egg(
|
||||
species = result.species.resourceIdentifier,
|
||||
parentOne = parentOne,
|
||||
parentTwo = parentTwo,
|
||||
form = form.name.lowercase(),
|
||||
timeToHatch = 6000F
|
||||
)
|
||||
} ?: return@Trigger false
|
||||
|
||||
// Set the egg in the nest
|
||||
nestBlockEntity.setItem(egg.createEggItemStack())
|
||||
|
||||
// set the parents of the nest if it/they are wild so they guard it
|
||||
if (nestBlockEntity.ownerUUID == null)
|
||||
nestBlockEntity.parents = Pair((entity as PokemonEntity).uuid, mate.uuid)
|
||||
|
||||
|
||||
// set breeding cooldown for both
|
||||
parentOne.breedingCooldown = BreedingLogicManager.resetBreedingCooldown(parentOne)
|
||||
parentTwo.breedingCooldown = BreedingLogicManager.resetBreedingCooldown(parentTwo)
|
||||
|
||||
// Display heart particles above parents
|
||||
|
||||
(world as net.minecraft.server.level.ServerLevel).sendParticles(
|
||||
net.minecraft.core.particles.ParticleTypes.HEART,
|
||||
entity.getRandomX(1.0), // Particle X position with slight randomness
|
||||
entity.getRandomY() + 0.5, // Slightly raised Y position
|
||||
entity.getRandomZ(1.0), // Particle Z position with slight randomness
|
||||
4 + kotlin.random.Random.nextInt(2), // Particle count
|
||||
0.2 * entity.random.nextGaussian(), // X velocity with slight variance
|
||||
0.1 * entity.random.nextGaussian(), // Y velocity with upwards variance
|
||||
0.2 * entity.random.nextGaussian(), // Z velocity with slight variance
|
||||
0.02 // Particle speed
|
||||
)
|
||||
(world as net.minecraft.server.level.ServerLevel).sendParticles(
|
||||
net.minecraft.core.particles.ParticleTypes.HEART,
|
||||
mate.getRandomX(1.0), // Particle X position with slight randomness
|
||||
mate.getRandomY() + 0.5, // Slightly raised Y position
|
||||
mate.getRandomZ(1.0), // Particle Z position with slight randomness
|
||||
4 + kotlin.random.Random.nextInt(2), // Particle count
|
||||
0.2 * mate.random.nextGaussian(), // X velocity with slight variance
|
||||
0.1 * mate.random.nextGaussian(), // Y velocity with upwards variance
|
||||
0.2 * mate.random.nextGaussian(), // Z velocity with slight variance
|
||||
0.02 // Particle speed
|
||||
)
|
||||
|
||||
// Notify nearby players
|
||||
world.players().forEach { player ->
|
||||
player.displayClientMessage("An egg has been laid in the nest!".green(), true)
|
||||
}
|
||||
|
||||
// todo maybe have them fall asleep after?
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}*/
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.pokemon.breeding.Egg
|
||||
import com.cobblemon.mod.common.api.text.green
|
||||
import com.cobblemon.mod.common.block.entity.NestBlockEntity
|
||||
import com.cobblemon.mod.common.breeding.BreedingLogicManager
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.BreedAtNestTask
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.kinds.IdF
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class BreedAtNestTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val BREED = "breed_at_nest" // Category
|
||||
}
|
||||
|
||||
val condition = booleanVariable(BREED, "can_breed", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(BreedAtNestTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
/*override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PokemonEntity) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(CobblemonMemories.NEST_LOCATION),
|
||||
it.present(CobblemonMemories.POTENTIAL_MATE),
|
||||
it.absent(MemoryModuleType.WALK_TARGET)
|
||||
).apply(it) { nestMemory, mateMemory, walkTarget ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive) return@Trigger false
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
|
||||
// Retrieve nest location and mate entity from memory
|
||||
val nestLocation: BlockPos = (nestMemory.value() as? IdF<BlockPos>)?.value() ?: return@Trigger false
|
||||
val mate = (mateMemory.value() as? IdF<PokemonEntity>)?.value() ?: return@Trigger false
|
||||
|
||||
// Convert nest location to Vec3
|
||||
val targetVec = Vec3.atCenterOf(nestLocation)
|
||||
|
||||
// Check proximity to the nest
|
||||
if (entity.distanceToSqr(targetVec) > 2.0 && mate.distanceToSqr(targetVec) > 2.0) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
// Access the nest block entity
|
||||
val nestBlockEntity = world.getBlockEntity(nestLocation) as? NestBlockEntity
|
||||
?: return@Trigger false
|
||||
|
||||
// double check to make sure the nest is not taken yet and cancel if it is
|
||||
if (nestBlockEntity.getItem(0) != ItemStack.EMPTY) return@Trigger false
|
||||
|
||||
// Generate the egg using BreedingLogicManager
|
||||
val parentOne = (entity as PokemonEntity).pokemon
|
||||
val parentTwo = mate.pokemon
|
||||
val breedingResult = BreedingLogicManager.breed(parentOne, parentTwo)
|
||||
val form = BreedingLogicManager.calculateForm(parentOne, parentTwo)
|
||||
|
||||
// Ensure the breeding result is valid
|
||||
val egg = breedingResult.pokemon?.let { result ->
|
||||
Egg(
|
||||
species = result.species.resourceIdentifier,
|
||||
parentOne = parentOne,
|
||||
parentTwo = parentTwo,
|
||||
form = form.name.lowercase(),
|
||||
timeToHatch = 6000F
|
||||
)
|
||||
} ?: return@Trigger false
|
||||
|
||||
// Set the egg in the nest
|
||||
nestBlockEntity.setItem(egg.createEggItemStack())
|
||||
|
||||
// set the parents of the nest if it/they are wild so they guard it
|
||||
if (nestBlockEntity.ownerUUID == null)
|
||||
nestBlockEntity.parents = Pair((entity as PokemonEntity).uuid, mate.uuid)
|
||||
|
||||
|
||||
// set breeding cooldown for both
|
||||
parentOne.breedingCooldown = BreedingLogicManager.resetBreedingCooldown(parentOne)
|
||||
parentTwo.breedingCooldown = BreedingLogicManager.resetBreedingCooldown(parentTwo)
|
||||
|
||||
// Display heart particles above parents
|
||||
|
||||
(world as net.minecraft.server.level.ServerLevel).sendParticles(
|
||||
net.minecraft.core.particles.ParticleTypes.HEART,
|
||||
entity.getRandomX(1.0), // Particle X position with slight randomness
|
||||
entity.getRandomY() + 0.5, // Slightly raised Y position
|
||||
entity.getRandomZ(1.0), // Particle Z position with slight randomness
|
||||
4 + kotlin.random.Random.nextInt(2), // Particle count
|
||||
0.2 * entity.random.nextGaussian(), // X velocity with slight variance
|
||||
0.1 * entity.random.nextGaussian(), // Y velocity with upwards variance
|
||||
0.2 * entity.random.nextGaussian(), // Z velocity with slight variance
|
||||
0.02 // Particle speed
|
||||
)
|
||||
(world as net.minecraft.server.level.ServerLevel).sendParticles(
|
||||
net.minecraft.core.particles.ParticleTypes.HEART,
|
||||
mate.getRandomX(1.0), // Particle X position with slight randomness
|
||||
mate.getRandomY() + 0.5, // Slightly raised Y position
|
||||
mate.getRandomZ(1.0), // Particle Z position with slight randomness
|
||||
4 + kotlin.random.Random.nextInt(2), // Particle count
|
||||
0.2 * mate.random.nextGaussian(), // X velocity with slight variance
|
||||
0.1 * mate.random.nextGaussian(), // Y velocity with upwards variance
|
||||
0.2 * mate.random.nextGaussian(), // Z velocity with slight variance
|
||||
0.02 // Particle speed
|
||||
)
|
||||
|
||||
// Notify nearby players
|
||||
world.players().forEach { player ->
|
||||
player.displayClientMessage("An egg has been laid in the nest!".green(), true)
|
||||
}
|
||||
|
||||
// todo maybe have them fall asleep after?
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}*/
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.BuildNestTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToNestTask
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.kinds.IdF
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class BuildNestTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val BREED = "breed" // Category
|
||||
}
|
||||
|
||||
val condition = booleanVariable(BREED, "breeds", true).asExpressible()
|
||||
val speedMultiplier = numberVariable(BREED, "speed_multiplier", 0.6).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
speedMultiplier
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(BuildNestTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
/*override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PokemonEntity) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(MemoryModuleType.LOOK_TARGET), // todo This might need to be it.absent but only it.present works atm
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(CobblemonMemories.NEST_LOCATION),
|
||||
it.present(CobblemonMemories.POTENTIAL_MATE)
|
||||
).apply(it) { lookTarget, walkTarget, nestMemory, mateMemory ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive) return@Trigger false
|
||||
|
||||
// Don't do anything if the pokemon has a breeding cooldown
|
||||
if ((entity as PokemonEntity).pokemon.breedingCooldown != 0) return@Trigger false
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
|
||||
// Retrieve nest location and mate entity from memory
|
||||
//val nestLocation = it.get(nestMemory)
|
||||
val nestLocation: BlockPos = (nestMemory.value() as? IdF<BlockPos>)?.value() ?: return@Trigger false
|
||||
|
||||
//val mate = it.get(mateMemory) as? PokemonEntity ?: return@Trigger false
|
||||
val mate = (mateMemory.value() as? IdF<PokemonEntity>)?.value() ?: return@Trigger false
|
||||
|
||||
// todo try to find a way to only have pairs of mates instead of an orgy
|
||||
|
||||
// Create a target vector at the nest location
|
||||
val targetVec = Vec3.atCenterOf(nestLocation)
|
||||
|
||||
// Check if Pokémon are close enough to the nest
|
||||
if (entity.distanceToSqr(targetVec) <= 2.0 && mate.distanceToSqr(targetVec) <= 2.0) {
|
||||
return@Trigger false // Task ends when both are close enough
|
||||
}
|
||||
|
||||
*//*if ((entity as PokemonEntity).tethering.tetheringId != null) {
|
||||
val test1 = 1 // for breakpointing here to test my pastured mons
|
||||
}*//*
|
||||
|
||||
// try to get the main pokemon to path and look at the nest
|
||||
|
||||
walkTarget.set(WalkTarget(targetVec, speedMultiplier.resolveFloat(), 1))
|
||||
lookTarget.set(BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
// try to find a way to get the mate to pathfind and look at the nest too...
|
||||
mate.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
WalkTarget(targetVec, speedMultiplier.resolveFloat(), 1)
|
||||
)
|
||||
mate.brain.setMemory(MemoryModuleType.LOOK_TARGET, BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
+10
-8
@@ -8,24 +8,26 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.VillagerCalmDown
|
||||
|
||||
class CalmDownTaskConfig : SingleTaskConfig {
|
||||
var condition = "true".asExpression()
|
||||
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return VillagerCalmDown.create()
|
||||
}
|
||||
}
|
||||
+13
-14
@@ -8,30 +8,29 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.DoNothing
|
||||
|
||||
class DoNothingTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val minDurationTicks = "40".asExpression()
|
||||
val maxDurationTicks = "80".asExpression()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val minDurationTicks: ExpressionOrEntityVariable = Either.left("40".asExpression())
|
||||
val maxDurationTicks: ExpressionOrEntityVariable = Either.left("80".asExpression())
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition, minDurationTicks, maxDurationTicks).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return DoNothing(runtime.resolveInt(minDurationTicks), runtime.resolveInt(maxDurationTicks))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return DoNothing(minDurationTicks.resolveInt(), maxDurationTicks.resolveInt())
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.EatGrassTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class EatGrassTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val EATING_GRASS = "eating_grass"
|
||||
const val COOLDOWN = "eating_grass_cooldown_ticks"
|
||||
const val EAT_GRASS_CHANCE = "eat_grass_chance"
|
||||
}
|
||||
|
||||
val cooldown = numberVariable(category = EATING_GRASS, name = COOLDOWN, default = 20 * 20).asExpressible()
|
||||
val eatGrassChance = numberVariable(category = EATING_GRASS, name = EAT_GRASS_CHANCE, default = 1 / (20 * 20F)).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(
|
||||
cooldown,
|
||||
eatGrassChance
|
||||
).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
|
||||
val chance = eatGrassChance.resolveFloat()
|
||||
if (chance == 0F) {
|
||||
return null
|
||||
}
|
||||
|
||||
return WrapperLivingEntityTask(
|
||||
EatGrassTask(
|
||||
chance,
|
||||
cooldown.resolveInt().toLong()
|
||||
),
|
||||
PokemonEntity::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
+21
-14
@@ -8,14 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
@@ -24,15 +23,21 @@ import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
|
||||
var condition = "true".asExpression()
|
||||
var includePassiveDamage = true
|
||||
var condition = booleanVariable(SharedEntityVariables.BATTLING_CATEGORY, "exit_battle_when_hurt", true).asExpressible()
|
||||
var includePassiveDamage = booleanVariable(SharedEntityVariables.BATTLING_CATEGORY, "exit_battle_from_passive_damage", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
includePassiveDamage
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val includePassiveDamage = includePassiveDamage.resolveBoolean()
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
if (entity is NPCEntity) {
|
||||
fun cancelNPCBattles(npcEntity: NPCEntity): Boolean {
|
||||
@@ -52,7 +57,7 @@ class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
|
||||
.apply(it) { _, _ -> Trigger { world, entity, _ -> return@Trigger cancelNPCBattles(entity as NPCEntity) } }
|
||||
}
|
||||
}
|
||||
} else { return null }/* else if (entity is PokemonEntity) { TODO uncomment when pokemon have brain :)
|
||||
} else if (entity is PokemonEntity) {
|
||||
fun cancelPokemonBattle(pokemonEntity: PokemonEntity): Boolean {
|
||||
val battle = BattleRegistry.getBattle(pokemonEntity.battleId ?: return false)
|
||||
battle?.end()
|
||||
@@ -61,15 +66,17 @@ class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
|
||||
|
||||
return if (includePassiveDamage) {
|
||||
BehaviorBuilder.create {
|
||||
it.group(it.present(MemoryModuleType.HURT_BY), it.present(CobblemonMemories.POKEMON_BATTLING))
|
||||
it.group(it.present(MemoryModuleType.HURT_BY), it.present(CobblemonMemories.POKEMON_BATTLE))
|
||||
.apply(it) { _, _ -> Trigger { world, entity, _ -> return@Trigger cancelPokemonBattle(entity as PokemonEntity) } }
|
||||
}
|
||||
} else {
|
||||
BehaviorBuilder.create {
|
||||
it.group(it.present(MemoryModuleType.HURT_BY_ENTITY), it.present(CobblemonMemories.POKEMON_BATTLING))
|
||||
it.group(it.present(MemoryModuleType.HURT_BY_ENTITY), it.present(CobblemonMemories.POKEMON_BATTLE))
|
||||
.apply(it) { _, _ -> Trigger { world, entity, _ -> return@Trigger cancelPokemonBattle(entity as PokemonEntity) } }
|
||||
}
|
||||
}
|
||||
}*/
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.closestPosition
|
||||
import com.cobblemon.mod.common.util.getIsSubmerged
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.level.LevelReader
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
|
||||
/**
|
||||
* Moves to the nearest surface it can find so it can breathe.
|
||||
*/
|
||||
class FindAirTaskConfig : SingleTaskConfig {
|
||||
val walkSpeed = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(walkSpeed).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PathfinderMob) {
|
||||
return null
|
||||
}
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.absent(CobblemonMemories.PATH_COOLDOWN)
|
||||
).apply(it) { walkTarget, pathCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (!entity.getIsSubmerged()) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
val iterable = BlockPos.betweenClosed(
|
||||
Mth.floor(entity.x - 4.0),
|
||||
entity.blockY - 1,
|
||||
Mth.floor(entity.z - 4.0),
|
||||
Mth.floor(entity.x + 4.0),
|
||||
Mth.floor(entity.y + 8.0),
|
||||
Mth.floor(entity.z + 4.0)
|
||||
)
|
||||
|
||||
pathCooldown.setWithExpiry(true, 20L)
|
||||
|
||||
val blockPos = entity.closestPosition(iterable) { isAirPos(entity.level(), it) }
|
||||
?: return@Trigger false
|
||||
|
||||
walkTarget.set(WalkTarget(blockPos.above(), 0.35F, 0))
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isAirPos(world: LevelReader, pos: BlockPos): Boolean {
|
||||
val blockState = world.getBlockState(pos)
|
||||
val aboveState = world.getBlockState(pos.above())
|
||||
val notFluid = world.getFluidState(pos.above()).isEmpty || blockState.`is`(Blocks.BUBBLE_COLUMN)
|
||||
val canPathfindThroughAbove = aboveState.isPathfindable(PathComputationType.LAND)
|
||||
val solidBelow = !blockState.isPathfindable(PathComputationType.LAND)
|
||||
|
||||
return notFluid && canPathfindThroughAbove && solidBelow
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.FindRestingPlaceTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class FindRestingPlaceTaskConfig : SingleTaskConfig {
|
||||
val horizontalSearchDistance: ExpressionOrEntityVariable = Either.left("16".asExpression())
|
||||
val verticalSearchDistance: ExpressionOrEntityVariable = Either.left("5".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(horizontalSearchDistance, verticalSearchDistance).asVariables()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(
|
||||
FindRestingPlaceTask.create(horizontalSearchDistance.resolveInt(), verticalSearchDistance.resolveInt()),
|
||||
PokemonEntity::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
+19
-15
@@ -8,14 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_DESIRED_DISTANCE
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_SPEED_MULTIPLIER
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
@@ -24,18 +22,24 @@ import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
class FleeAttackerTaskConfig : SingleTaskConfig {
|
||||
var condition = "true".asExpression()
|
||||
var speedMultiplier = "0.5".asExpression()
|
||||
var desiredDistance = "9".asExpression()
|
||||
var condition = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "flee_attacker", true).asExpressible()
|
||||
var speedMultiplier = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_SPEED_MULTIPLIER, 0.5).asExpressible()
|
||||
var desiredDistance = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_DESIRED_DISTANCE, 9).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
speedMultiplier,
|
||||
desiredDistance
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition) || entity !is PathfinderMob) return null
|
||||
val speedMultiplier = runtime.resolveFloat(speedMultiplier)
|
||||
val desiredDistance = runtime.resolveInt(desiredDistance)
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PathfinderMob) return null
|
||||
val speedMultiplier = speedMultiplier.resolveFloat()
|
||||
val desiredDistance = desiredDistance.resolveInt()
|
||||
return WrapperLivingEntityTask(
|
||||
SetWalkTargetAwayFrom.entity(MemoryModuleType.HURT_BY_ENTITY, speedMultiplier, desiredDistance, false),
|
||||
PathfinderMob::class.java
|
||||
|
||||
+15
-15
@@ -8,14 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_DESIRED_DISTANCE
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_SPEED_MULTIPLIER
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
@@ -24,18 +22,20 @@ import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
class FleeNearestHostileTaskConfig : SingleTaskConfig {
|
||||
var condition = "true".asExpression()
|
||||
var speedMultiplier = "0.5".asExpression()
|
||||
var desiredDistance = "9".asExpression()
|
||||
var condition = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "flee_nearest_hostile", true).asExpressible()
|
||||
var speedMultiplier = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_SPEED_MULTIPLIER, 0.5).asExpressible()
|
||||
var desiredDistance = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_DESIRED_DISTANCE, 9).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition, speedMultiplier, desiredDistance).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition) || entity !is PathfinderMob) return null
|
||||
val speedMultiplier = runtime.resolveFloat(speedMultiplier)
|
||||
val desiredDistance = runtime.resolveInt(desiredDistance)
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PathfinderMob) return null
|
||||
val speedMultiplier = speedMultiplier.resolveFloat()
|
||||
val desiredDistance = desiredDistance.resolveInt()
|
||||
return WrapperLivingEntityTask(
|
||||
SetWalkTargetAwayFrom.entity(MemoryModuleType.NEAREST_HOSTILE, speedMultiplier, desiredDistance, false),
|
||||
PathfinderMob::class.java
|
||||
|
||||
+13
-15
@@ -8,32 +8,30 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.ai.FollowWalkTargetTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class FollowWalkTargetTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val minRunTicks: Expression = "150".asExpression()
|
||||
val maxRunTicks: Expression = "250".asExpression()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val minRunTicks: ExpressionOrEntityVariable = Either.left("150".asExpression())
|
||||
val maxRunTicks: ExpressionOrEntityVariable = Either.left("250".asExpression())
|
||||
|
||||
override fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
override fun getVariables(entity: LivingEntity) = listOf(minRunTicks, maxRunTicks).asVariables()
|
||||
|
||||
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
return WrapperLivingEntityTask(
|
||||
FollowWalkTargetTask(runtime.resolveInt(minRunTicks), runtime.resolveInt(maxRunTicks)),
|
||||
FollowWalkTargetTask(minRunTicks.resolveInt(), maxRunTicks.resolveInt()),
|
||||
PathfinderMob::class.java
|
||||
)
|
||||
}
|
||||
|
||||
+14
-10
@@ -8,26 +8,30 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.ATTACKING_CATEGORY
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.ai.GetAngryAtAttackerTask
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class GetAngryAtAttackerTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
companion object {
|
||||
const val GET_ANGRY_AT_ATTACKER = "get_angry_at_attacker"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(ATTACKING_CATEGORY, GET_ANGRY_AT_ATTACKER, true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return GetAngryAtAttackerTask.create()
|
||||
}
|
||||
}
|
||||
+26
-21
@@ -8,38 +8,43 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.npc.ai.GoToHealingMachineTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class GoToHealingMachineTaskConfig(
|
||||
val condition: ExpressionLike = "true".asExpressionLike(),
|
||||
val horizontalSearchRange: Expression = "10".asExpression(),
|
||||
val verticalSearchRange: Expression = "5".asExpression(),
|
||||
val speedMultiplier: Expression = "0.35".asExpression(),
|
||||
val completionRange: Expression = "1".asExpression()
|
||||
) : SingleTaskConfig {
|
||||
class GoToHealingMachineTaskConfig : SingleTaskConfig {
|
||||
val condition = booleanVariable(SELF_HEALING, USE_HEALING_MACHINES, true).asExpressible()
|
||||
val horizontalSearchRange: ExpressionOrEntityVariable = Either.left("10".asExpression())
|
||||
val verticalSearchRange: ExpressionOrEntityVariable = Either.left("5".asExpression())
|
||||
val completionRange: ExpressionOrEntityVariable = Either.left("1".asExpression())
|
||||
val walkSpeed = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition, walkSpeed, horizontalSearchRange, verticalSearchRange, completionRange).asVariables()
|
||||
|
||||
companion object {
|
||||
const val SELF_HEALING = "self_healing"
|
||||
const val USE_HEALING_MACHINES = "use_healing_machines"
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
return GoToHealingMachineTask.create(
|
||||
horizontalSearchRange = horizontalSearchRange,
|
||||
verticalSearchRange = verticalSearchRange,
|
||||
speedMultiplier = speedMultiplier,
|
||||
completionRange = completionRange
|
||||
horizontalSearchRange = horizontalSearchRange.asExpression(),
|
||||
verticalSearchRange = verticalSearchRange.asExpression(),
|
||||
speedMultiplier = walkSpeed.asExpression(),
|
||||
completionRange = completionRange.asExpression()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.closestPosition
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.floor
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
|
||||
/**
|
||||
* Seeks land if it's underwater.
|
||||
*/
|
||||
class GoToLandTaskConfig : SingleTaskConfig {
|
||||
val walkSpeed = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(walkSpeed).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PathfinderMob) {
|
||||
return null
|
||||
}
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.absent(CobblemonMemories.PATH_COOLDOWN)
|
||||
).apply(it) { walkTarget, pathCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (!entity.isInLiquid) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
entity as PathfinderMob
|
||||
|
||||
val iterable = BlockPos.betweenClosed(
|
||||
Mth.floor(entity.x - 8.0),
|
||||
entity.blockY,
|
||||
Mth.floor(entity.z - 8.0),
|
||||
Mth.floor(entity.x + 8.0),
|
||||
Mth.floor(entity.y + 2.0),
|
||||
Mth.floor(entity.z + 8.0)
|
||||
)
|
||||
|
||||
pathCooldown.setWithExpiry(true, 40L)
|
||||
|
||||
val blockPos = entity.closestPosition(iterable) {
|
||||
isSafeLandPosAround(entity.level() as ServerLevel, it, entity)
|
||||
} ?: return@Trigger false
|
||||
|
||||
walkTarget.set(WalkTarget(blockPos.above(), 0.35F, 1))
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isSafeLandPos(world: ServerLevel, pos: BlockPos, mob: PathfinderMob): Boolean {
|
||||
val blockState = world.getBlockState(pos)
|
||||
|
||||
val isFluid = world.getFluidState(pos.above()).isEmpty.not()
|
||||
val solidBelow = blockState.isSolid
|
||||
|
||||
if (isFluid || !solidBelow) {
|
||||
return false
|
||||
} else {
|
||||
val mutable = BlockPos.MutableBlockPos()
|
||||
val minY = pos.y + 1
|
||||
val maxY = minY + ceil(mob.bbHeight).toInt()
|
||||
for (y in minY..maxY) {
|
||||
val aboveState = world.getBlockState(mutable.set(pos.x, y, pos.z))
|
||||
val canPathfindThroughAbove = aboveState.isPathfindable(PathComputationType.LAND)
|
||||
if (!canPathfindThroughAbove) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
fun isSafeLandPosAround(world: ServerLevel, pos: BlockPos, mob: PathfinderMob): Boolean {
|
||||
val minX = pos.x
|
||||
val maxX = minX + floor(mob.bbWidth).toInt()
|
||||
val minZ = pos.z
|
||||
val maxZ = minZ + floor(mob.bbWidth).toInt()
|
||||
|
||||
val mutable = BlockPos.MutableBlockPos()
|
||||
for (x in minX..maxX) {
|
||||
for (z in minZ..maxZ) {
|
||||
if (!isSafeLandPos(world, mutable.set(x, pos.y, z), mob)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.GoToSleepTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class GoToSleepTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(GoToSleepTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.GuardNestTask
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.kinds.IdF
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class GuardNestTaskConfig : SingleTaskConfig {
|
||||
// todo make new variables
|
||||
companion object {
|
||||
const val BREED = "breed"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(BREED, "breeds", true).asExpressible()
|
||||
val speedMultiplier = numberVariable(BREED, "speed_multiplier", 0.6).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
speedMultiplier
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(GuardNestTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
|
||||
/*override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PokemonEntity) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(MemoryModuleType.LOOK_TARGET),
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(CobblemonMemories.PATERNAL_NEST_LOCATION),
|
||||
it.registered(MemoryModuleType.NEAREST_VISIBLE_PLAYER), // if player is invisible they do not patrol
|
||||
it.registered(MemoryModuleType.ANGRY_AT),
|
||||
it.absent(MemoryModuleType.ATTACK_TARGET),
|
||||
it.registered(CobblemonMemories.IRRITATED_AT)
|
||||
).apply(it) { lookTarget, walkTarget, paternalNest, nearestVisiblePlayer, angryAt, attackTarget, irritatedAt ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive || entity !is PokemonEntity) return@Trigger false
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
|
||||
// Retrieve nest location and mate entity from memory
|
||||
//val nestLocation = it.get(nestMemory)
|
||||
val nestLocation: BlockPos = (paternalNest.value() as? IdF<BlockPos>)?.value() ?: return@Trigger false
|
||||
val nestCenter = Vec3.atCenterOf(nestLocation)
|
||||
|
||||
// todo maybe cancel task if player is close to nest and set angry at task to that player
|
||||
val nearestPlayerOptional = entity.brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER)
|
||||
val player = nearestPlayerOptional.orElse(null) as? ServerPlayer
|
||||
val irritatedAtTarget = entity.brain.getMemory(CobblemonMemories.IRRITATED_AT)
|
||||
|
||||
if (player != null) {
|
||||
val playerDistanceSquared = player.position().distanceToSqr(nestCenter)
|
||||
|
||||
if (!irritatedAtTarget.isPresent && playerDistanceSquared <= 15 * 15) {
|
||||
// Player is within 15 blocks, set angry and cry
|
||||
entity.cry()
|
||||
|
||||
// set irritated at target to player near egg
|
||||
irritatedAt.set(player.uuid)
|
||||
|
||||
// Display angry particles above parent
|
||||
(world as net.minecraft.server.level.ServerLevel).sendParticles(
|
||||
net.minecraft.core.particles.ParticleTypes.ANGRY_VILLAGER,
|
||||
entity.getRandomX(1.0), // Particle X position with slight randomness
|
||||
entity.getRandomY() + 0.5, // Slightly raised Y position
|
||||
entity.getRandomZ(1.0), // Particle Z position with slight randomness
|
||||
4 + kotlin.random.Random.nextInt(2), // Particle count
|
||||
0.2 * entity.random.nextGaussian(), // X velocity with slight variance
|
||||
0.1 * entity.random.nextGaussian(), // Y velocity with upwards variance
|
||||
0.2 * entity.random.nextGaussian(), // Z velocity with slight variance
|
||||
0.02 // Particle speed
|
||||
)
|
||||
}
|
||||
|
||||
if (playerDistanceSquared <= 8 * 8) {
|
||||
// Player is within 8 blocks, attack
|
||||
entity.cry()
|
||||
|
||||
// Display angry particles above parent
|
||||
(world as net.minecraft.server.level.ServerLevel).sendParticles(
|
||||
net.minecraft.core.particles.ParticleTypes.ANGRY_VILLAGER,
|
||||
entity.getRandomX(1.0), // Particle X position with slight randomness
|
||||
entity.getRandomY() + 0.5, // Slightly raised Y position
|
||||
entity.getRandomZ(1.0), // Particle Z position with slight randomness
|
||||
4 + kotlin.random.Random.nextInt(2), // Particle count
|
||||
0.2 * entity.random.nextGaussian(), // X velocity with slight variance
|
||||
0.1 * entity.random.nextGaussian(), // Y velocity with upwards variance
|
||||
0.2 * entity.random.nextGaussian(), // Z velocity with slight variance
|
||||
0.02 // Particle speed
|
||||
)
|
||||
angryAt.set(player.uuid)
|
||||
attackTarget.set(player)
|
||||
return@Trigger false // Cancel the task
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Scan for a valid walkable position within an 8-block sphere
|
||||
val validPosition = findValidWalkablePosition(world, nestCenter, entity, 8)
|
||||
if (validPosition == null) {
|
||||
return@Trigger false // No valid position found
|
||||
}
|
||||
|
||||
// Set the entity's walk and look targets
|
||||
walkTarget.set(WalkTarget(validPosition, speedMultiplier.resolveFloat(), 1))
|
||||
lookTarget.set(BlockPosTracker(validPosition.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun findValidWalkablePosition(
|
||||
world: ServerLevel,
|
||||
center: Vec3,
|
||||
entity: PathfinderMob,
|
||||
radius: Int
|
||||
): Vec3? {
|
||||
val random = world.random
|
||||
|
||||
// Try a number of random positions within the radius
|
||||
repeat(20) { // Attempt up to 20 random positions
|
||||
val offsetX = random.nextDouble() * 2 * radius - radius
|
||||
val offsetY = random.nextDouble() * 2 * radius - radius
|
||||
val offsetZ = random.nextDouble() * 2 * radius - radius
|
||||
val candidate = center.add(offsetX, offsetY, offsetZ)
|
||||
|
||||
// Convert to block position
|
||||
val blockPos = BlockPos(candidate.x.toInt(), candidate.y.toInt(), candidate.z.toInt())
|
||||
|
||||
// Check if the position is walkable and not inside a solid block
|
||||
if (world.getBlockState(blockPos).isSolidRender(world, blockPos).not() &&
|
||||
entity.navigation.isStableDestination(blockPos)
|
||||
) {
|
||||
return Vec3.atCenterOf(blockPos) // Return the valid position
|
||||
}
|
||||
}
|
||||
|
||||
return null // No valid position found
|
||||
}*/
|
||||
}
|
||||
+16
-13
@@ -8,29 +8,32 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.GoToHealingMachineTaskConfig.Companion.SELF_HEALING
|
||||
import com.cobblemon.mod.common.api.ai.config.task.GoToHealingMachineTaskConfig.Companion.USE_HEALING_MACHINES
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.npc.ai.HealUsingHealingMachineTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class HealUsingHealingMachineTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val horizontalUseRange = "3".asExpression()
|
||||
val verticalUseRange = "2".asExpression()
|
||||
val condition = booleanVariable(SELF_HEALING, USE_HEALING_MACHINES, true).asExpressible()
|
||||
val horizontalUseRange: ExpressionOrEntityVariable = Either.left("2".asExpression())
|
||||
val verticalUseRange: ExpressionOrEntityVariable = Either.left("1".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition, horizontalUseRange, verticalUseRange).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return HealUsingHealingMachineTask(horizontalUseRange, verticalUseRange)
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return HealUsingHealingMachineTask(horizontalUseRange.asExpression(), verticalUseRange.asExpression())
|
||||
}
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.kinds.IdF
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.UUID
|
||||
|
||||
class HuntPlayerTaskConfig : SingleTaskConfig {
|
||||
// todo make new variables
|
||||
companion object {
|
||||
const val BREED = "breed"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(BREED, "breeds", true).asExpressible()
|
||||
val speedMultiplier = numberVariable(BREED, "speed_multiplier", 0.6).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
speedMultiplier
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PokemonEntity) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(MemoryModuleType.LOOK_TARGET),
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(MemoryModuleType.NEAREST_PLAYERS), // this will be null most of the time
|
||||
it.present(MemoryModuleType.ANGRY_AT),
|
||||
it.registered(MemoryModuleType.ATTACK_TARGET),
|
||||
it.registered(MemoryModuleType.DISTURBANCE_LOCATION),
|
||||
).apply(it) { lookTarget, walkTarget, nearestPlayers, angryAt, attackTarget, disturbanceLocation ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive || entity !is PokemonEntity) return@Trigger false
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
|
||||
val angryAtUuid = (angryAt.value() as? IdF<UUID?>)?.value() ?: return@Trigger false
|
||||
val disturbancePos = (disturbanceLocation.value() as? IdF<BlockPos>)?.value()
|
||||
|
||||
val players = (nearestPlayers.value() as? IdF<List<Player?>?>)?.value()
|
||||
val targetPlayer = players?.find { it?.uuid == angryAtUuid }
|
||||
|
||||
if (targetPlayer != null) {
|
||||
// If the angry player is nearby, set them as the attack target
|
||||
entity.cry()
|
||||
attackTarget.set(targetPlayer)
|
||||
return@Trigger true
|
||||
}
|
||||
|
||||
// If the angry player is not nearby, search around the Pokémon
|
||||
val maxTicksToSearch = 200L
|
||||
if (time > maxTicksToSearch) {
|
||||
// Timeout after 200 ticks
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
// If no disturbance location or it is caused by a nearby player, skip
|
||||
if (disturbancePos != null) {
|
||||
val disturberCausingDisturbance = players?.any {
|
||||
it?.position()?.distanceToSqr(Vec3.atCenterOf(disturbancePos))!! <= 4.0 * 4.0
|
||||
}
|
||||
disturberCausingDisturbance?.let { it1 ->
|
||||
if (!it1) {
|
||||
// Pathfind toward disturbance location
|
||||
walkTarget.set(WalkTarget(Vec3.atCenterOf(disturbancePos), speedMultiplier.resolveFloat(), 1))
|
||||
lookTarget.set(BlockPosTracker(Vec3.atCenterOf(disturbancePos)))
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no valid disturbance location, pathfind randomly within proximity
|
||||
val validPosition = findValidWalkablePosition(world, entity.position(), entity, 8)
|
||||
if (validPosition == null) {
|
||||
return@Trigger false // No valid position found
|
||||
}
|
||||
|
||||
walkTarget.set(WalkTarget(validPosition, speedMultiplier.resolveFloat(), 1))
|
||||
lookTarget.set(BlockPosTracker(validPosition.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun findValidWalkablePosition(
|
||||
world: ServerLevel,
|
||||
center: Vec3,
|
||||
entity: PathfinderMob,
|
||||
radius: Int
|
||||
): Vec3? {
|
||||
val random = world.random
|
||||
|
||||
// Try a number of random positions within the radius
|
||||
repeat(20) { // Attempt up to 20 random positions
|
||||
val offsetX = random.nextDouble() * 2 * radius - radius
|
||||
val offsetY = random.nextDouble() * 2 * radius - radius
|
||||
val offsetZ = random.nextDouble() * 2 * radius - radius
|
||||
val candidate = center.add(offsetX, offsetY, offsetZ)
|
||||
|
||||
// Convert to block position
|
||||
val blockPos = BlockPos(candidate.x.toInt(), candidate.y.toInt(), candidate.z.toInt())
|
||||
|
||||
// Check if the position is walkable and not inside a solid block
|
||||
if (world.getBlockState(blockPos).isSolidRender(world, blockPos).not() &&
|
||||
entity.navigation.isStableDestination(blockPos)
|
||||
) {
|
||||
return Vec3.atCenterOf(blockPos) // Return the valid position
|
||||
}
|
||||
}
|
||||
|
||||
return null // No valid position found
|
||||
}
|
||||
}
|
||||
+23
-11
@@ -8,29 +8,41 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.npc.ai.LookAtBattlingPokemonTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class LookAtBattlingPokemonTaskConfig : SingleTaskConfig {
|
||||
val minDurationTicks = "40".asExpression()
|
||||
val maxDurationTicks = "80".asExpression()
|
||||
companion object {
|
||||
const val LOOK_AT_BATTLING_POKEMON = "look_at_battling_pokemon"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(SharedEntityVariables.BATTLING_CATEGORY, LOOK_AT_BATTLING_POKEMON, true).asExpressible()
|
||||
val minDurationTicks: ExpressionOrEntityVariable = Either.left("40".asExpression())
|
||||
val maxDurationTicks: ExpressionOrEntityVariable = Either.left("80".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
minDurationTicks,
|
||||
maxDurationTicks
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!resolveBooleanVariable(LOOK_AT_BATTLING_POKEMON)) return null
|
||||
return LookAtBattlingPokemonTask.create(
|
||||
minDurationTicks = runtime.resolveInt(minDurationTicks),
|
||||
maxDurationTicks = runtime.resolveInt(maxDurationTicks)
|
||||
minDurationTicks = minDurationTicks.resolveInt(),
|
||||
maxDurationTicks = maxDurationTicks.resolveInt()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
+19
-14
@@ -8,29 +8,34 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.SEE_DISTANCE
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.SetEntityLookTarget
|
||||
|
||||
class LookAtEntitiesTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val maxDistance = "15".asExpression()
|
||||
companion object {
|
||||
const val LOOK_AT_ENTITIES = "look_at_entities"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(SharedEntityVariables.LOOKING_CATEGORY, LOOK_AT_ENTITIES, true).asExpressible()
|
||||
val maxDistance = numberVariable(SharedEntityVariables.LOOKING_CATEGORY, SEE_DISTANCE, 15).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
maxDistance
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return SetEntityLookTarget.create(runtime.resolveFloat(maxDistance))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return SetEntityLookTarget.create(maxDistance.resolveFloat())
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -8,13 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.npc.ai.LookAtSpeakerTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class LookAtSpeakerTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = LookAtSpeakerTask.create()
|
||||
}
|
||||
+18
-15
@@ -8,33 +8,36 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.Mob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.LookAtTargetSink
|
||||
|
||||
class LookAtTargetTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val minDurationTicks: Expression = "40".asExpression()
|
||||
val maxDurationTicks: Expression = "80".asExpression()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val minDurationTicks: ExpressionOrEntityVariable = Either.left("80".asExpression())
|
||||
val maxDurationTicks: ExpressionOrEntityVariable = Either.left("160".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
minDurationTicks,
|
||||
maxDurationTicks
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return WrapperLivingEntityTask(LookAtTargetSink(runtime.resolveInt(minDurationTicks), runtime.resolveInt(maxDurationTicks)), Mob::class.java)
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return WrapperLivingEntityTask(LookAtTargetSink(minDurationTicks.resolveInt(), maxDurationTicks.resolveInt()), Mob::class.java)
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.LookAtTargetedBattlePokemonTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class LookAtTargetedBattlePokemonTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity> {
|
||||
return WrapperLivingEntityTask(LookAtTargetedBattlePokemonTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
+18
-7
@@ -8,18 +8,29 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.LOOKING_CATEGORY
|
||||
import com.cobblemon.mod.common.entity.ai.LookInDirectionTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class LookInDirectionTaskConfig : SingleTaskConfig {
|
||||
var yaw: Expression = "0".asExpression()
|
||||
var pitch: Expression = "0".asExpression()
|
||||
var condition = booleanVariable(LOOKING_CATEGORY, "locked_rotation", true).asExpressible()
|
||||
var yaw = numberVariable(LOOKING_CATEGORY, "locked_yaw", 0F).asExpressible()
|
||||
var pitch = numberVariable(LOOKING_CATEGORY, "locked_pitch", 0F).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
yaw,
|
||||
pitch
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
) = LookInDirectionTask(yaw, pitch)
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = LookInDirectionTask(
|
||||
shouldLock = condition.asExpression(),
|
||||
yaw = yaw.asExpression(),
|
||||
pitch = pitch.asExpression()
|
||||
)
|
||||
}
|
||||
+17
-14
@@ -8,32 +8,35 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.npc.ai.MeleeAttackTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class MeleeAttackTaskConfig : SingleTaskConfig {
|
||||
val condition = "true".asExpressionLike()
|
||||
val range = "1.5".asExpression()
|
||||
val cooldownTicks = "30".asExpression()
|
||||
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "attacks_melee", true).asExpressible()
|
||||
val range = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "melee_range", 1.5F).asExpressible()
|
||||
val cooldownTicks = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "melee_cooldown", 30).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
range,
|
||||
cooldownTicks
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
return MeleeAttackTask.create(
|
||||
range = range,
|
||||
cooldownTicks = cooldownTicks
|
||||
range = range.asExpression(),
|
||||
cooldownTicks = cooldownTicks.asExpression()
|
||||
)
|
||||
}
|
||||
}
|
||||
+14
-6
@@ -8,20 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.ai.MoveToAttackTargetTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class MoveToAttackTargetTaskConfig : SingleTaskConfig {
|
||||
val speedMultiplier = "0.5".asExpression()
|
||||
val closeEnoughDistance = "1".asExpression()
|
||||
val speedMultiplier = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "attacking_movement_speed", 0.5).asExpressible()
|
||||
val closeEnoughDistance: ExpressionOrEntityVariable = Either.left("1".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
speedMultiplier,
|
||||
closeEnoughDistance
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = MoveToAttackTargetTask.create(
|
||||
speedMultiplier = speedMultiplier,
|
||||
closeEnoughDistance = closeEnoughDistance
|
||||
speedMultiplier = speedMultiplier.asExpression(),
|
||||
closeEnoughDistance = closeEnoughDistance.asExpression()
|
||||
)
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.MoveToOwnerTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class MoveToOwnerTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
var completionRange: ExpressionOrEntityVariable = Either.left("4.0".asExpression())
|
||||
var speedMultiplier: ExpressionOrEntityVariable = Either.left("0.4".asExpression())
|
||||
var teleportDistance: ExpressionOrEntityVariable = Either.left("24.0".asExpression())
|
||||
var maxDistance: ExpressionOrEntityVariable = Either.left("14.0".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
completionRange,
|
||||
speedMultiplier,
|
||||
teleportDistance,
|
||||
maxDistance
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(
|
||||
MoveToOwnerTask.create(
|
||||
condition = condition.asExpression(),
|
||||
completionRange = completionRange.asExpression(),
|
||||
speedMultiplier = speedMultiplier.asExpression(),
|
||||
teleportDistance = teleportDistance.asExpression(),
|
||||
maxDistance = maxDistance.asExpression()
|
||||
),
|
||||
PokemonEntity::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -8,17 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.toDF
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.DoNothing
|
||||
import net.minecraft.world.entity.ai.behavior.RunOne
|
||||
|
||||
/**
|
||||
@@ -34,15 +32,17 @@ import net.minecraft.world.entity.ai.behavior.RunOne
|
||||
class OneOfTaskConfig : SingleTaskConfig {
|
||||
class OneOfTaskOption {
|
||||
val weight: Int = 1
|
||||
val task: TaskConfig = SingleTaskConfig { _, _ -> DoNothing(0, 1) }
|
||||
val task: TaskConfig = SingleTaskConfig.nothing()
|
||||
}
|
||||
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val options = mutableListOf<OneOfTaskOption>()
|
||||
|
||||
override fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
override fun getVariables(entity: LivingEntity) = options.flatMap { it.task.getVariables(entity) }
|
||||
|
||||
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return RunOne(options.map { it.task.createTasks(entity, brainConfigurationContext).first() toDF it.weight })
|
||||
return RunOne(options.map { it.task.createTasks(entity, behaviourConfigurationContext).first() toDF it.weight })
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToIdealNestLocationTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToNestMaterialTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToNestTask
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.kinds.IdF
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PathToIdealNestLocationTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val BREED = "breed" // Category
|
||||
}
|
||||
|
||||
val condition = booleanVariable(BREED, "breeds", true).asExpressible()
|
||||
val speedMultiplier = numberVariable(BREED, "speed_multiplier", 0.6).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
speedMultiplier
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(PathToIdealNestLocationTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToNestMaterialTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToNestTask
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.kinds.IdF
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PathToNestMaterialTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val BREED = "breed" // Category
|
||||
}
|
||||
|
||||
val condition = booleanVariable(BREED, "breeds", true).asExpressible()
|
||||
val speedMultiplier = numberVariable(BREED, "speed_multiplier", 0.6).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
speedMultiplier
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(PathToNestMaterialTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
/*override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PokemonEntity) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(MemoryModuleType.LOOK_TARGET), // todo This might need to be it.absent but only it.present works atm
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(CobblemonMemories.NEST_LOCATION),
|
||||
it.present(CobblemonMemories.POTENTIAL_MATE)
|
||||
).apply(it) { lookTarget, walkTarget, nestMemory, mateMemory ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive) return@Trigger false
|
||||
|
||||
// Don't do anything if the pokemon has a breeding cooldown
|
||||
if ((entity as PokemonEntity).pokemon.breedingCooldown != 0) return@Trigger false
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
|
||||
// Retrieve nest location and mate entity from memory
|
||||
//val nestLocation = it.get(nestMemory)
|
||||
val nestLocation: BlockPos = (nestMemory.value() as? IdF<BlockPos>)?.value() ?: return@Trigger false
|
||||
|
||||
//val mate = it.get(mateMemory) as? PokemonEntity ?: return@Trigger false
|
||||
val mate = (mateMemory.value() as? IdF<PokemonEntity>)?.value() ?: return@Trigger false
|
||||
|
||||
// todo try to find a way to only have pairs of mates instead of an orgy
|
||||
|
||||
// Create a target vector at the nest location
|
||||
val targetVec = Vec3.atCenterOf(nestLocation)
|
||||
|
||||
// Check if Pokémon are close enough to the nest
|
||||
if (entity.distanceToSqr(targetVec) <= 2.0 && mate.distanceToSqr(targetVec) <= 2.0) {
|
||||
return@Trigger false // Task ends when both are close enough
|
||||
}
|
||||
|
||||
*//*if ((entity as PokemonEntity).tethering.tetheringId != null) {
|
||||
val test1 = 1 // for breakpointing here to test my pastured mons
|
||||
}*//*
|
||||
|
||||
// try to get the main pokemon to path and look at the nest
|
||||
|
||||
walkTarget.set(WalkTarget(targetVec, speedMultiplier.resolveFloat(), 1))
|
||||
lookTarget.set(BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
// try to find a way to get the mate to pathfind and look at the nest too...
|
||||
mate.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
WalkTarget(targetVec, speedMultiplier.resolveFloat(), 1)
|
||||
)
|
||||
mate.brain.setMemory(MemoryModuleType.LOOK_TARGET, BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToNestTask
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.kinds.IdF
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PathToNestTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val BREED = "breed" // Category
|
||||
}
|
||||
|
||||
val condition = booleanVariable(BREED, "breeds", true).asExpressible()
|
||||
val speedMultiplier = numberVariable(BREED, "speed_multiplier", 0.6).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
speedMultiplier
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(PathToNestTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
/*override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PokemonEntity) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(MemoryModuleType.LOOK_TARGET), // todo This might need to be it.absent but only it.present works atm
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(CobblemonMemories.NEST_LOCATION),
|
||||
it.present(CobblemonMemories.POTENTIAL_MATE)
|
||||
).apply(it) { lookTarget, walkTarget, nestMemory, mateMemory ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive) return@Trigger false
|
||||
|
||||
// Don't do anything if the pokemon has a breeding cooldown
|
||||
if ((entity as PokemonEntity).pokemon.breedingCooldown != 0) return@Trigger false
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
|
||||
// Retrieve nest location and mate entity from memory
|
||||
//val nestLocation = it.get(nestMemory)
|
||||
val nestLocation: BlockPos = (nestMemory.value() as? IdF<BlockPos>)?.value() ?: return@Trigger false
|
||||
|
||||
//val mate = it.get(mateMemory) as? PokemonEntity ?: return@Trigger false
|
||||
val mate = (mateMemory.value() as? IdF<PokemonEntity>)?.value() ?: return@Trigger false
|
||||
|
||||
// todo try to find a way to only have pairs of mates instead of an orgy
|
||||
|
||||
// Create a target vector at the nest location
|
||||
val targetVec = Vec3.atCenterOf(nestLocation)
|
||||
|
||||
// Check if Pokémon are close enough to the nest
|
||||
if (entity.distanceToSqr(targetVec) <= 2.0 && mate.distanceToSqr(targetVec) <= 2.0) {
|
||||
return@Trigger false // Task ends when both are close enough
|
||||
}
|
||||
|
||||
*//*if ((entity as PokemonEntity).tethering.tetheringId != null) {
|
||||
val test1 = 1 // for breakpointing here to test my pastured mons
|
||||
}*//*
|
||||
|
||||
// try to get the main pokemon to path and look at the nest
|
||||
|
||||
walkTarget.set(WalkTarget(targetVec, speedMultiplier.resolveFloat(), 1))
|
||||
lookTarget.set(BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
// try to find a way to get the mate to pathfind and look at the nest too...
|
||||
mate.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
WalkTarget(targetVec, speedMultiplier.resolveFloat(), 1)
|
||||
)
|
||||
mate.brain.setMemory(MemoryModuleType.LOOK_TARGET, BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.pokemon.breeding.Egg
|
||||
import com.cobblemon.mod.common.api.text.green
|
||||
import com.cobblemon.mod.common.block.entity.NestBlockEntity
|
||||
import com.cobblemon.mod.common.breeding.BreedingLogicManager
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.BreedAtNestTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PickUpEggTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PlaceEggInNestTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.SearchForEggTask
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.kinds.IdF
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PickUpEggTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val BREED = "breed_at_nest" // Category
|
||||
}
|
||||
|
||||
val condition = booleanVariable(BREED, "can_breed", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(PickUpEggTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
/*override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PokemonEntity) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(CobblemonMemories.NEST_LOCATION),
|
||||
it.present(CobblemonMemories.POTENTIAL_MATE),
|
||||
it.absent(MemoryModuleType.WALK_TARGET)
|
||||
).apply(it) { nestMemory, mateMemory, walkTarget ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive) return@Trigger false
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
|
||||
// Retrieve nest location and mate entity from memory
|
||||
val nestLocation: BlockPos = (nestMemory.value() as? IdF<BlockPos>)?.value() ?: return@Trigger false
|
||||
val mate = (mateMemory.value() as? IdF<PokemonEntity>)?.value() ?: return@Trigger false
|
||||
|
||||
// Convert nest location to Vec3
|
||||
val targetVec = Vec3.atCenterOf(nestLocation)
|
||||
|
||||
// Check proximity to the nest
|
||||
if (entity.distanceToSqr(targetVec) > 2.0 && mate.distanceToSqr(targetVec) > 2.0) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
// Access the nest block entity
|
||||
val nestBlockEntity = world.getBlockEntity(nestLocation) as? NestBlockEntity
|
||||
?: return@Trigger false
|
||||
|
||||
// double check to make sure the nest is not taken yet and cancel if it is
|
||||
if (nestBlockEntity.getItem(0) != ItemStack.EMPTY) return@Trigger false
|
||||
|
||||
// Generate the egg using BreedingLogicManager
|
||||
val parentOne = (entity as PokemonEntity).pokemon
|
||||
val parentTwo = mate.pokemon
|
||||
val breedingResult = BreedingLogicManager.breed(parentOne, parentTwo)
|
||||
val form = BreedingLogicManager.calculateForm(parentOne, parentTwo)
|
||||
|
||||
// Ensure the breeding result is valid
|
||||
val egg = breedingResult.pokemon?.let { result ->
|
||||
Egg(
|
||||
species = result.species.resourceIdentifier,
|
||||
parentOne = parentOne,
|
||||
parentTwo = parentTwo,
|
||||
form = form.name.lowercase(),
|
||||
timeToHatch = 6000F
|
||||
)
|
||||
} ?: return@Trigger false
|
||||
|
||||
// Set the egg in the nest
|
||||
nestBlockEntity.setItem(egg.createEggItemStack())
|
||||
|
||||
// set the parents of the nest if it/they are wild so they guard it
|
||||
if (nestBlockEntity.ownerUUID == null)
|
||||
nestBlockEntity.parents = Pair((entity as PokemonEntity).uuid, mate.uuid)
|
||||
|
||||
|
||||
// set breeding cooldown for both
|
||||
parentOne.breedingCooldown = BreedingLogicManager.resetBreedingCooldown(parentOne)
|
||||
parentTwo.breedingCooldown = BreedingLogicManager.resetBreedingCooldown(parentTwo)
|
||||
|
||||
// Display heart particles above parents
|
||||
|
||||
(world as net.minecraft.server.level.ServerLevel).sendParticles(
|
||||
net.minecraft.core.particles.ParticleTypes.HEART,
|
||||
entity.getRandomX(1.0), // Particle X position with slight randomness
|
||||
entity.getRandomY() + 0.5, // Slightly raised Y position
|
||||
entity.getRandomZ(1.0), // Particle Z position with slight randomness
|
||||
4 + kotlin.random.Random.nextInt(2), // Particle count
|
||||
0.2 * entity.random.nextGaussian(), // X velocity with slight variance
|
||||
0.1 * entity.random.nextGaussian(), // Y velocity with upwards variance
|
||||
0.2 * entity.random.nextGaussian(), // Z velocity with slight variance
|
||||
0.02 // Particle speed
|
||||
)
|
||||
(world as net.minecraft.server.level.ServerLevel).sendParticles(
|
||||
net.minecraft.core.particles.ParticleTypes.HEART,
|
||||
mate.getRandomX(1.0), // Particle X position with slight randomness
|
||||
mate.getRandomY() + 0.5, // Slightly raised Y position
|
||||
mate.getRandomZ(1.0), // Particle Z position with slight randomness
|
||||
4 + kotlin.random.Random.nextInt(2), // Particle count
|
||||
0.2 * mate.random.nextGaussian(), // X velocity with slight variance
|
||||
0.1 * mate.random.nextGaussian(), // Y velocity with upwards variance
|
||||
0.2 * mate.random.nextGaussian(), // Z velocity with slight variance
|
||||
0.02 // Particle speed
|
||||
)
|
||||
|
||||
// Notify nearby players
|
||||
world.players().forEach { player ->
|
||||
player.displayClientMessage("An egg has been laid in the nest!".green(), true)
|
||||
}
|
||||
|
||||
// todo maybe have them fall asleep after?
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}*/
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToNestTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PickUpNestMaterialTask
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.kinds.IdF
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PickUpNestMaterialTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val BREED = "breed" // Category
|
||||
}
|
||||
|
||||
val condition = booleanVariable(BREED, "breeds", true).asExpressible()
|
||||
val speedMultiplier = numberVariable(BREED, "speed_multiplier", 0.6).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
speedMultiplier
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(PickUpNestMaterialTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
/*override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PokemonEntity) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(MemoryModuleType.LOOK_TARGET), // todo This might need to be it.absent but only it.present works atm
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(CobblemonMemories.NEST_LOCATION),
|
||||
it.present(CobblemonMemories.POTENTIAL_MATE)
|
||||
).apply(it) { lookTarget, walkTarget, nestMemory, mateMemory ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive) return@Trigger false
|
||||
|
||||
// Don't do anything if the pokemon has a breeding cooldown
|
||||
if ((entity as PokemonEntity).pokemon.breedingCooldown != 0) return@Trigger false
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
|
||||
// Retrieve nest location and mate entity from memory
|
||||
//val nestLocation = it.get(nestMemory)
|
||||
val nestLocation: BlockPos = (nestMemory.value() as? IdF<BlockPos>)?.value() ?: return@Trigger false
|
||||
|
||||
//val mate = it.get(mateMemory) as? PokemonEntity ?: return@Trigger false
|
||||
val mate = (mateMemory.value() as? IdF<PokemonEntity>)?.value() ?: return@Trigger false
|
||||
|
||||
// todo try to find a way to only have pairs of mates instead of an orgy
|
||||
|
||||
// Create a target vector at the nest location
|
||||
val targetVec = Vec3.atCenterOf(nestLocation)
|
||||
|
||||
// Check if Pokémon are close enough to the nest
|
||||
if (entity.distanceToSqr(targetVec) <= 2.0 && mate.distanceToSqr(targetVec) <= 2.0) {
|
||||
return@Trigger false // Task ends when both are close enough
|
||||
}
|
||||
|
||||
*//*if ((entity as PokemonEntity).tethering.tetheringId != null) {
|
||||
val test1 = 1 // for breakpointing here to test my pastured mons
|
||||
}*//*
|
||||
|
||||
// try to get the main pokemon to path and look at the nest
|
||||
|
||||
walkTarget.set(WalkTarget(targetVec, speedMultiplier.resolveFloat(), 1))
|
||||
lookTarget.set(BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
// try to find a way to get the mate to pathfind and look at the nest too...
|
||||
mate.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
WalkTarget(targetVec, speedMultiplier.resolveFloat(), 1)
|
||||
)
|
||||
mate.brain.setMemory(MemoryModuleType.LOOK_TARGET, BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.pokemon.breeding.Egg
|
||||
import com.cobblemon.mod.common.api.text.green
|
||||
import com.cobblemon.mod.common.block.entity.NestBlockEntity
|
||||
import com.cobblemon.mod.common.breeding.BreedingLogicManager
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.BreedAtNestTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PlaceEggInNestTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.SearchForEggTask
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.kinds.IdF
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PlaceEggInNestTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val BREED = "breed_at_nest" // Category
|
||||
}
|
||||
|
||||
val condition = booleanVariable(BREED, "can_breed", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(PlaceEggInNestTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
/*override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PokemonEntity) return null
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(CobblemonMemories.NEST_LOCATION),
|
||||
it.present(CobblemonMemories.POTENTIAL_MATE),
|
||||
it.absent(MemoryModuleType.WALK_TARGET)
|
||||
).apply(it) { nestMemory, mateMemory, walkTarget ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive) return@Trigger false
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
|
||||
// Retrieve nest location and mate entity from memory
|
||||
val nestLocation: BlockPos = (nestMemory.value() as? IdF<BlockPos>)?.value() ?: return@Trigger false
|
||||
val mate = (mateMemory.value() as? IdF<PokemonEntity>)?.value() ?: return@Trigger false
|
||||
|
||||
// Convert nest location to Vec3
|
||||
val targetVec = Vec3.atCenterOf(nestLocation)
|
||||
|
||||
// Check proximity to the nest
|
||||
if (entity.distanceToSqr(targetVec) > 2.0 && mate.distanceToSqr(targetVec) > 2.0) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
// Access the nest block entity
|
||||
val nestBlockEntity = world.getBlockEntity(nestLocation) as? NestBlockEntity
|
||||
?: return@Trigger false
|
||||
|
||||
// double check to make sure the nest is not taken yet and cancel if it is
|
||||
if (nestBlockEntity.getItem(0) != ItemStack.EMPTY) return@Trigger false
|
||||
|
||||
// Generate the egg using BreedingLogicManager
|
||||
val parentOne = (entity as PokemonEntity).pokemon
|
||||
val parentTwo = mate.pokemon
|
||||
val breedingResult = BreedingLogicManager.breed(parentOne, parentTwo)
|
||||
val form = BreedingLogicManager.calculateForm(parentOne, parentTwo)
|
||||
|
||||
// Ensure the breeding result is valid
|
||||
val egg = breedingResult.pokemon?.let { result ->
|
||||
Egg(
|
||||
species = result.species.resourceIdentifier,
|
||||
parentOne = parentOne,
|
||||
parentTwo = parentTwo,
|
||||
form = form.name.lowercase(),
|
||||
timeToHatch = 6000F
|
||||
)
|
||||
} ?: return@Trigger false
|
||||
|
||||
// Set the egg in the nest
|
||||
nestBlockEntity.setItem(egg.createEggItemStack())
|
||||
|
||||
// set the parents of the nest if it/they are wild so they guard it
|
||||
if (nestBlockEntity.ownerUUID == null)
|
||||
nestBlockEntity.parents = Pair((entity as PokemonEntity).uuid, mate.uuid)
|
||||
|
||||
|
||||
// set breeding cooldown for both
|
||||
parentOne.breedingCooldown = BreedingLogicManager.resetBreedingCooldown(parentOne)
|
||||
parentTwo.breedingCooldown = BreedingLogicManager.resetBreedingCooldown(parentTwo)
|
||||
|
||||
// Display heart particles above parents
|
||||
|
||||
(world as net.minecraft.server.level.ServerLevel).sendParticles(
|
||||
net.minecraft.core.particles.ParticleTypes.HEART,
|
||||
entity.getRandomX(1.0), // Particle X position with slight randomness
|
||||
entity.getRandomY() + 0.5, // Slightly raised Y position
|
||||
entity.getRandomZ(1.0), // Particle Z position with slight randomness
|
||||
4 + kotlin.random.Random.nextInt(2), // Particle count
|
||||
0.2 * entity.random.nextGaussian(), // X velocity with slight variance
|
||||
0.1 * entity.random.nextGaussian(), // Y velocity with upwards variance
|
||||
0.2 * entity.random.nextGaussian(), // Z velocity with slight variance
|
||||
0.02 // Particle speed
|
||||
)
|
||||
(world as net.minecraft.server.level.ServerLevel).sendParticles(
|
||||
net.minecraft.core.particles.ParticleTypes.HEART,
|
||||
mate.getRandomX(1.0), // Particle X position with slight randomness
|
||||
mate.getRandomY() + 0.5, // Slightly raised Y position
|
||||
mate.getRandomZ(1.0), // Particle Z position with slight randomness
|
||||
4 + kotlin.random.Random.nextInt(2), // Particle count
|
||||
0.2 * mate.random.nextGaussian(), // X velocity with slight variance
|
||||
0.1 * mate.random.nextGaussian(), // Y velocity with upwards variance
|
||||
0.2 * mate.random.nextGaussian(), // Z velocity with slight variance
|
||||
0.02 // Particle speed
|
||||
)
|
||||
|
||||
// Notify nearby players
|
||||
world.players().forEach { player ->
|
||||
player.displayClientMessage("An egg has been laid in the nest!".green(), true)
|
||||
}
|
||||
|
||||
// todo maybe have them fall asleep after?
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}*/
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PointToSpawnTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>? {
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.registered(MemoryModuleType.LOOK_TARGET),
|
||||
it.absent(MemoryModuleType.WALK_TARGET)
|
||||
).apply(it) { lookTargetMemory, _ ->
|
||||
Trigger { world, entity, _ ->
|
||||
val lookTarget = entity.brain.getMemory(MemoryModuleType.LOOK_TARGET).orElse(null)
|
||||
if (lookTarget == null) {
|
||||
lookTargetMemory.set(BlockPosTracker(Vec3.atCenterOf(entity.level().sharedSpawnPos).with(Direction.Axis.Y, entity.eyeY)))
|
||||
return@Trigger true
|
||||
} else {
|
||||
return@Trigger false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,4 +183,17 @@ the script to avoid lagging the game.
|
||||
### look_in_direction
|
||||
The 'look_in_direction' type creates a task that will make the entity look in a specific direction at all times where they aren't being told to look elsewhere.
|
||||
- `yaw`: A MoLang expression that determines the yaw angle (degrees) of the entity. Defaults to `0`.
|
||||
- `pitch`: A MoLang expression that determines the pitch angle (degrees) of the entity. Defaults to `0`.
|
||||
- `pitch`: A MoLang expression that determines the pitch angle (degrees) of the entity. Defaults to `0`.
|
||||
|
||||
### move_to_owner
|
||||
The 'move_to_owner' type creates a task that will make the entity move to its owner. This will only work for entities that
|
||||
can be owned, like Pokémon.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if this entire task should exist on the entity or not. This runs at the time of entity creation, not on tick.
|
||||
- `completionRange`: A MoLang expression that determines the distance from the owner that the entity needs to be for the path to be considered complete. Defaults to 4.
|
||||
- `speedMultiplier`: A MoLang expression that determines the speed multiplier for moving to the owner. Defaults to 0.4 which is slightly above the normal walk speed.
|
||||
- `teleportDistance`: A MoLang expression that determines the distance from the owner the entity must be before it resorts to teleporting. A value of -1 will cause it to never teleport. Defaults to 24.
|
||||
- `maxDistance`: A MoLang expression that determines the maximum distance from the owner that the entity can be to move to them. Defaults to 14.
|
||||
|
||||
### point_to_spawn
|
||||
The 'point_to_spawn' type creates a task that will make the entity point to the spawn point of the world whenever they
|
||||
are not moving and are idling. This is basically only here for Nosepass.
|
||||
+8
-8
@@ -8,17 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.weightedSelection
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.DoNothing
|
||||
|
||||
/**
|
||||
* Randomly chooses one of the possible tasks to add to the brain. This differs from [OneOfTaskConfig] in that
|
||||
@@ -34,19 +32,21 @@ import net.minecraft.world.entity.ai.behavior.DoNothing
|
||||
class RandomTaskConfig : TaskConfig {
|
||||
class RandomTaskChoice {
|
||||
val weight = 1.0
|
||||
val task: TaskConfig = SingleTaskConfig { _, _ -> DoNothing(0, 1) }
|
||||
val task: TaskConfig = SingleTaskConfig.nothing()
|
||||
}
|
||||
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val choices = mutableListOf<RandomTaskChoice>()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = choices.flatMap { it.task.getVariables(entity) }
|
||||
|
||||
override fun createTasks(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<BehaviorControl<in LivingEntity>> {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!runtime.resolveBoolean(condition)) return emptyList()
|
||||
val task = choices.weightedSelection { it.weight }?.task ?: throw IllegalStateException("No tasks to choose from in random_task config")
|
||||
return task.createTasks(entity, brainConfigurationContext)
|
||||
return task.createTasks(entity, behaviourConfigurationContext)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user