mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-22 07:06:23 -04:00
Compare commits
765
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d4eaa464a | ||
|
|
ac3628d907 | ||
|
|
4563770835 | ||
|
|
cc80f69c47 | ||
|
|
128366f9c2 | ||
|
|
ddd63ac841 | ||
|
|
118a682451 | ||
|
|
d202efc0a9 | ||
|
|
81a1314493 | ||
|
|
a316329359 | ||
|
|
ea59981b58 | ||
|
|
960460ec08 | ||
|
|
8d587c5287 | ||
|
|
e0b79c9bab | ||
|
|
6206330b76 | ||
|
|
7b137fbe14 | ||
|
|
4d472d0b36 | ||
|
|
fd442211d3 | ||
|
|
144f857a3b | ||
|
|
80131e57f8 | ||
|
|
30d89a2704 | ||
|
|
5e147545b7 | ||
|
|
e962079cda | ||
|
|
6f934cfbd4 | ||
|
|
47ecef81a6 | ||
|
|
16762ae933 | ||
|
|
ba47f6a833 | ||
|
|
522ffefd0a | ||
|
|
e17ca360df | ||
|
|
e18d5837af | ||
|
|
65ae67d9ac | ||
|
|
05c77a6156 | ||
|
|
8ae6792785 | ||
|
|
5f67fc167a | ||
|
|
0eee6e8634 | ||
|
|
a16a7c31fe | ||
|
|
a4254df0ca | ||
|
|
21df52daf7 | ||
|
|
5e81e26c69 | ||
|
|
d103629fd2 | ||
|
|
6e2a0cd3b9 | ||
|
|
37f6010381 | ||
|
|
798dd64f84 | ||
|
|
c1acf8494c | ||
|
|
d4601326a7 | ||
|
|
a037af6948 | ||
|
|
517ac94b8d | ||
|
|
b5ec2b28fd | ||
|
|
f45a4b784b | ||
|
|
91dda046d8 | ||
|
|
49577d2518 | ||
|
|
2bad8ec673 | ||
|
|
1524e9c476 | ||
|
|
c8ad0cd7e7 | ||
|
|
db1108f7ef | ||
|
|
33a4e31b60 | ||
|
|
7cb4e96a64 | ||
|
|
ef0f997682 | ||
|
|
2988a29e28 | ||
|
|
fe59748bf6 | ||
|
|
0235bc108e | ||
|
|
1526c2f037 | ||
|
|
408cf8c5ca | ||
|
|
895f8877b1 | ||
|
|
aab4f3c7aa | ||
|
|
ceb70dbf2d | ||
|
|
6d46992ad7 | ||
|
|
84242194ba | ||
|
|
529e4bef46 | ||
|
|
aa1658bb5d | ||
|
|
068df2b138 | ||
|
|
6fe68e117f | ||
|
|
0724c21509 | ||
|
|
3499758203 | ||
|
|
330f60f2d9 | ||
|
|
7d97df3407 | ||
|
|
dfb8ff5aa2 | ||
|
|
22b0e0612a | ||
|
|
e52c63d565 | ||
|
|
fe7f72cb3d | ||
|
|
8187905987 | ||
|
|
11b3043e6c | ||
|
|
8d871ac949 | ||
|
|
8f7a523404 | ||
|
|
7a74c72df2 | ||
|
|
31b136af05 | ||
|
|
592e438c56 | ||
|
|
bb98992635 | ||
|
|
abdc03be8c | ||
|
|
bfcc4516ff | ||
|
|
a4a46d20cd | ||
|
|
12ec7b1e3d | ||
|
|
6fcbbb1e73 | ||
|
|
d3984843e2 | ||
|
|
7a14c51df2 | ||
|
|
a7b023203f | ||
|
|
81a241d4a1 | ||
|
|
7ccb05fcb9 | ||
|
|
32e81eff4e | ||
|
|
4ea704bd95 | ||
|
|
497a686599 | ||
|
|
b986823b2c | ||
|
|
534a7e67e1 | ||
|
|
e47f014ebd | ||
|
|
651ba5b9ba | ||
|
|
2b64174cfe | ||
|
|
918282893c | ||
|
|
74435945e9 | ||
|
|
6bf5e1491d | ||
|
|
488f38c690 | ||
|
|
dbbca02619 | ||
|
|
c50d5841d8 | ||
|
|
5489cfb4b0 | ||
|
|
e421de547f | ||
|
|
075dcdb9e9 | ||
|
|
2ebe8d6434 | ||
|
|
d7c77f5f3f | ||
|
|
572682a23a | ||
|
|
6241865f95 | ||
|
|
67dbda3113 | ||
|
|
c50d3183e6 | ||
|
|
9eae394ff5 | ||
|
|
76b640984c | ||
|
|
72d142a781 | ||
|
|
af1df22e4d | ||
|
|
d1b7dc6934 | ||
|
|
e2fdf3cffc | ||
|
|
4a68e53968 | ||
|
|
282bb4784e | ||
|
|
66787bfea4 | ||
|
|
c113e68488 | ||
|
|
a8267b8ee0 | ||
|
|
81f36b2b15 | ||
|
|
73e96740d6 | ||
|
|
d53f9e5c63 | ||
|
|
560bd75fd0 | ||
|
|
8850d38820 | ||
|
|
8284b04426 | ||
|
|
ca91d42ddf | ||
|
|
34232b33c7 | ||
|
|
03c5a34fc8 | ||
|
|
866db3d350 | ||
|
|
ee51a8a34b | ||
|
|
2769733c51 | ||
|
|
f1bdaad97d | ||
|
|
f725e5fcba | ||
|
|
8ae79d8e44 | ||
|
|
2237e1eeca | ||
|
|
6f08d610eb | ||
|
|
75f3db16aa | ||
|
|
e4ee6b29ab | ||
|
|
cb6b2b9ec5 | ||
|
|
8eafe14f66 | ||
|
|
8176e14981 | ||
|
|
7d956500f2 | ||
|
|
c6853b84a6 | ||
|
|
bb54f8414e | ||
|
|
99c7d39705 | ||
|
|
3cb4984d51 | ||
|
|
930ed59234 | ||
|
|
3ea1918bc2 | ||
|
|
bdd27078b5 | ||
|
|
1dee9bc630 | ||
|
|
d761f2b4dc | ||
|
|
0d6028706d | ||
|
|
63d6851482 | ||
|
|
7c3fdbc921 | ||
|
|
9596f08957 | ||
|
|
d9433960cd | ||
|
|
89b6fd56b6 | ||
|
|
10c441e3cd | ||
|
|
461b22efa8 | ||
|
|
57a19909aa | ||
|
|
dc1473919e | ||
|
|
ee20986ee0 | ||
|
|
436aa5ea75 | ||
|
|
e49f761417 | ||
|
|
95e3ab213a | ||
|
|
7c3158c63b | ||
|
|
e9e41933fe | ||
|
|
7c7fd6c982 | ||
|
|
6ec2820dd8 | ||
|
|
b1054bdf11 | ||
|
|
3b227ba3a2 | ||
|
|
96049abb98 | ||
|
|
d661e88a96 | ||
|
|
8510e05177 | ||
|
|
af4fe4d09d | ||
|
|
8b2ffd0f29 | ||
|
|
18cebc794b | ||
|
|
64e84dab64 | ||
|
|
9c5535a014 | ||
|
|
5993c1e588 | ||
|
|
e8f7983dd2 | ||
|
|
bdd172bd2d | ||
|
|
13842de7d6 | ||
|
|
f05e059445 | ||
|
|
038d9e858c | ||
|
|
9913826e24 | ||
|
|
8f971cc3d6 | ||
|
|
33c74372a4 | ||
|
|
5f11f4bdd6 | ||
|
|
13b4bdc204 | ||
|
|
451ae00da1 | ||
|
|
0c33de61b9 | ||
|
|
91a3fb5031 | ||
|
|
3a46b2c218 | ||
|
|
2f631ddc64 | ||
|
|
a8cc8278d3 | ||
|
|
2a2ef6ff7d | ||
|
|
d3d94a3614 | ||
|
|
f34cc3072b | ||
|
|
68bff6a40b | ||
|
|
58c0136ad1 | ||
|
|
45238058cb | ||
|
|
a326befcef | ||
|
|
52d8887514 | ||
|
|
02ae8065ac | ||
|
|
2a6381d610 | ||
|
|
93dba4f3b8 | ||
|
|
c37c608010 | ||
|
|
a7e7c2e814 | ||
|
|
09c4ae96bf | ||
|
|
be466d1610 | ||
|
|
d75faae1a0 | ||
|
|
367264b06e | ||
|
|
3631fa909d | ||
|
|
fc29826bc7 | ||
|
|
202bee5690 | ||
|
|
730dc88ede | ||
|
|
4f0a667f23 | ||
|
|
f1186f469c | ||
|
|
91eeecf6e4 | ||
|
|
f6cae9d52e | ||
|
|
ed94d76e98 | ||
|
|
6e2b76d6a1 | ||
|
|
2b70b222df | ||
|
|
e9f0ef6497 | ||
|
|
6bf62b3f9d | ||
|
|
00be470281 | ||
|
|
8fb93dd488 | ||
|
|
57afbe79c2 | ||
|
|
d5f336ce73 | ||
|
|
b863554c84 | ||
|
|
699d6fea17 | ||
|
|
a4dd34235a | ||
|
|
8501fd3b18 | ||
|
|
52896b208e | ||
|
|
6ad6487dbe | ||
|
|
2cd066a4c1 | ||
|
|
703ccb9d8e | ||
|
|
c33d4b591e | ||
|
|
e31f2a2598 | ||
|
|
68b44db35c | ||
|
|
513c958da1 | ||
|
|
18d3fb288a | ||
|
|
725b4b7e48 | ||
|
|
28ae27b926 | ||
|
|
21e9e73eee | ||
|
|
6bfb318e2d | ||
|
|
9e1fde04ef | ||
|
|
b79a0b1b6f | ||
|
|
6e4565d49b | ||
|
|
91f1523ef5 | ||
|
|
e949626f06 | ||
|
|
9678fcc009 | ||
|
|
4fbe3e406d | ||
|
|
00a1e77a9f | ||
|
|
e055dede73 | ||
|
|
b7550f7699 | ||
|
|
57721d1696 | ||
|
|
b0711528d6 | ||
|
|
7e968fcff9 | ||
|
|
98cfa0ac91 | ||
|
|
f2441e7b27 | ||
|
|
46c247c742 | ||
|
|
9770d8ca6b | ||
|
|
04c3e182e7 | ||
|
|
3d99db64b9 | ||
|
|
bbcfe95bac | ||
|
|
4f07746355 | ||
|
|
82088651c2 | ||
|
|
e399130fda | ||
|
|
0083e54f6a | ||
|
|
2f0a201cf1 | ||
|
|
778f24acf1 | ||
|
|
9512252b72 | ||
|
|
73028d4c2a | ||
|
|
e3ead8e3e5 | ||
|
|
9c4b9b35ab | ||
|
|
aa9c7b4f55 | ||
|
|
96e2e4a6fe | ||
|
|
20d903cffe | ||
|
|
d4383fa317 | ||
|
|
1687fa12db | ||
|
|
cf599de339 | ||
|
|
c5f92c1ad4 | ||
|
|
1d99da78e0 | ||
|
|
2f5910c436 | ||
|
|
d1197cbc0b | ||
|
|
2ccf699a86 | ||
|
|
d767420814 | ||
|
|
77100300b1 | ||
|
|
5c80fc03e2 | ||
|
|
aa39bb84fe | ||
|
|
a767b3d0fe | ||
|
|
3dbcbc34d0 | ||
|
|
0bdadb3794 | ||
|
|
050a2a6a4b | ||
|
|
c80e7f4a51 | ||
|
|
f4fbdf8735 | ||
|
|
ae6091fc01 | ||
|
|
f2aa4141c0 | ||
|
|
aeded69b25 | ||
|
|
16b25a2e6e | ||
|
|
e66ebfb7a8 | ||
|
|
05b5782cd5 | ||
|
|
0c220a8990 | ||
|
|
70e79e6fe4 | ||
|
|
b905888a0b | ||
|
|
5917e52ffc | ||
|
|
deb20cb418 | ||
|
|
797e0704e9 | ||
|
|
0b184a722b | ||
|
|
1a34c2942f | ||
|
|
2a20398b42 | ||
|
|
929e4b2391 | ||
|
|
3931295086 | ||
|
|
c593a8b7e6 | ||
|
|
d0fc166e09 | ||
|
|
78f752b4a1 | ||
|
|
b4c971398d | ||
|
|
f0f78a01e0 | ||
|
|
8c36ee15cd | ||
|
|
3231d97cd3 | ||
|
|
9fce4d3b6b | ||
|
|
550e579190 | ||
|
|
e7d710e0a3 | ||
|
|
acb86b1935 | ||
|
|
fd8e9b49b5 | ||
|
|
0f031545c1 | ||
|
|
1fdbee91df | ||
|
|
2b80189a79 | ||
|
|
2e88b0194e | ||
|
|
b0e278d1a7 | ||
|
|
9c646d9d53 | ||
|
|
bfab1d7070 | ||
|
|
e61e1390cb | ||
|
|
18151ff2f0 | ||
|
|
dd19140a83 | ||
|
|
d5b1dfa9da | ||
|
|
9f0ddf4dd3 | ||
|
|
ef3ea62ae0 | ||
|
|
6b43bf9f48 | ||
|
|
a4012895f3 | ||
|
|
7f6a3e8e87 | ||
|
|
7a84ea723f | ||
|
|
2aad33ded5 | ||
|
|
254c95fa15 | ||
|
|
5aab7f67e1 | ||
|
|
ae4decacc7 | ||
|
|
da787bf9bf | ||
|
|
ae5a9be626 | ||
|
|
05faea4ec8 | ||
|
|
05edd34db6 | ||
|
|
c198f8fccd | ||
|
|
521f9aaafa | ||
|
|
8d38505993 | ||
|
|
57a839d000 | ||
|
|
e77e49c8b1 | ||
|
|
ce6d142bd4 | ||
|
|
7c5fab02a8 | ||
|
|
7e5a267c89 | ||
|
|
5b23b0cfbe | ||
|
|
778ceff183 | ||
|
|
f32050c8b5 | ||
|
|
3522bac72a | ||
|
|
ecf037666f | ||
|
|
618d062ca9 | ||
|
|
49841b40ec | ||
|
|
87141e1137 | ||
|
|
1f962d664f | ||
|
|
09797f25b1 | ||
|
|
3911413c69 | ||
|
|
e075e60231 | ||
|
|
acdd98573b | ||
|
|
12f3e7b78b | ||
|
|
a462fe5efc | ||
|
|
2390662fc8 | ||
|
|
1bd5d2372f | ||
|
|
12f6bb55c2 | ||
|
|
fdb37ba5e8 | ||
|
|
7a99845d0f | ||
|
|
54d183c8d3 | ||
|
|
f2db63164c | ||
|
|
29713bbe1f | ||
|
|
604b4d39ea | ||
|
|
247052ee67 | ||
|
|
14b7e93965 | ||
|
|
85a4793a1e | ||
|
|
29f6524c49 | ||
|
|
1e617a684b | ||
|
|
c9a0352a7c | ||
|
|
1a5808e5a6 | ||
|
|
f14d242907 | ||
|
|
4998ee2c5b | ||
|
|
be96e45c4e | ||
|
|
015402d54b | ||
|
|
6f697d2b9a | ||
|
|
f18752d484 | ||
|
|
5876c02d44 | ||
|
|
c890f6910c | ||
|
|
d157536e1e | ||
|
|
dac2d9e96e | ||
|
|
5c71680db9 | ||
|
|
5f5c036f8d | ||
|
|
1f16c2d542 | ||
|
|
2da9dc50f7 | ||
|
|
092f9ef9f9 | ||
|
|
2f12b05d43 | ||
|
|
42eb08e715 | ||
|
|
03470aa623 | ||
|
|
4299aff1bf | ||
|
|
fb90ccb86e | ||
|
|
c112f9615c | ||
|
|
fc882190fe | ||
|
|
15d7cd815d | ||
|
|
6b5969fff6 | ||
|
|
5053c633b7 | ||
|
|
c4294697e6 | ||
|
|
dfa1c5e369 | ||
|
|
51f3b4357d | ||
|
|
220a9741ae | ||
|
|
48a9446f73 | ||
|
|
f1edfc453e | ||
|
|
8d612ec395 | ||
|
|
6d9daf3cf6 | ||
|
|
c7ecfc74de | ||
|
|
fefdfd877b | ||
|
|
35fb170225 | ||
|
|
d2e405131f | ||
|
|
b6ec0205ef | ||
|
|
e57a42e755 | ||
|
|
f34a03c8d6 | ||
|
|
8b1599705f | ||
|
|
e7f6fc32c4 | ||
|
|
5119617f00 | ||
|
|
6e84efb53c | ||
|
|
de3191b768 | ||
|
|
76ec4b4d5a | ||
|
|
25702ade61 | ||
|
|
c6da88d0b2 | ||
|
|
c4acc09fbd | ||
|
|
53b434906b | ||
|
|
b22a31909d | ||
|
|
cbbbacc215 | ||
|
|
d22d81209d | ||
|
|
89b989c46c | ||
|
|
714d51b26e | ||
|
|
8571d78894 | ||
|
|
72c57fde39 | ||
|
|
fc5c479f31 | ||
|
|
d3c54924be | ||
|
|
65c5e95ddf | ||
|
|
fc1dec6b4b | ||
|
|
7604af9308 | ||
|
|
5d3741f2e5 | ||
|
|
ab1e138ace | ||
|
|
62ee94c71d | ||
|
|
0fae95aabc | ||
|
|
bbfd864b33 | ||
|
|
b107d76762 | ||
|
|
8d4f10349c | ||
|
|
f36787e67f | ||
|
|
fc198c599e | ||
|
|
26f753880c | ||
|
|
a9ebb0b6f2 | ||
|
|
a7158ee57a | ||
|
|
06c3fd3f09 | ||
|
|
4e196e8a29 | ||
|
|
871f33f442 | ||
|
|
21c1f912a7 | ||
|
|
a0d9ce12a6 | ||
|
|
c07173fc0f | ||
|
|
3faf8ac302 | ||
|
|
e85b3f3cc5 | ||
|
|
251a09f78c | ||
|
|
776fb5413f | ||
|
|
f645fd9b60 | ||
|
|
ac161ae5b4 | ||
|
|
fc3542e3eb | ||
|
|
7c44dd204e | ||
|
|
88932c8c41 | ||
|
|
411f98d0ae | ||
|
|
02a1929ede | ||
|
|
ff90059eec | ||
|
|
eca14f61ac | ||
|
|
9ccf2bb9ad | ||
|
|
d09d636113 | ||
|
|
ff335f779f | ||
|
|
b70316e347 | ||
|
|
eacb0fe587 | ||
|
|
1752588cbc | ||
|
|
9e09ac52fc | ||
|
|
845ade1aeb | ||
|
|
f6bd04f016 | ||
|
|
afa1d9af8b | ||
|
|
bf6db8b745 | ||
|
|
a352e67c1b | ||
|
|
71297dfb3a | ||
|
|
9141694c2a | ||
|
|
9aef7b9c3b | ||
|
|
c5bebb1abb | ||
|
|
990fed2fe0 | ||
|
|
4a30bb3b04 | ||
|
|
fe77a3cd30 | ||
|
|
de9e1949fe | ||
|
|
fac8c5f510 | ||
|
|
2d077c607a | ||
|
|
f75e3d11da | ||
|
|
f46968f878 | ||
|
|
3439aeff1e | ||
|
|
1f8fa8cae3 | ||
|
|
42e405530c | ||
|
|
2ada7e0b68 | ||
|
|
b8f73f277d | ||
|
|
7f6197ab8b | ||
|
|
6df2b996e2 | ||
|
|
ddc4bd358d | ||
|
|
e197287775 | ||
|
|
be019c79df | ||
|
|
73fe851c58 | ||
|
|
8544744530 | ||
|
|
32d7bfcef3 | ||
|
|
27263cd057 | ||
|
|
55f0962205 | ||
|
|
63143832e0 | ||
|
|
29215f5c0c | ||
|
|
5e21ac94dc | ||
|
|
70bf3e7805 | ||
|
|
40c5df46ce | ||
|
|
b4d9d1b963 | ||
|
|
e753c75c31 | ||
|
|
4e96222a4d | ||
|
|
4ee90d4cfb | ||
|
|
540cd612c1 | ||
|
|
c76dfc3130 | ||
|
|
1b1d22fdf3 | ||
|
|
1ee1001774 | ||
|
|
533272ef09 | ||
|
|
cf5e1bf142 | ||
|
|
4b8196685a | ||
|
|
d1053468bf | ||
|
|
f0c41865db | ||
|
|
cca9de04a7 | ||
|
|
2b2264bdca | ||
|
|
78d47004bf | ||
|
|
30f97e6243 | ||
|
|
d117d79d28 | ||
|
|
1e32f7b80a | ||
|
|
3d4d797e7f | ||
|
|
39feb9cf6c | ||
|
|
8f53757879 | ||
|
|
e1d2f125d6 | ||
|
|
cfc8edfa9e | ||
|
|
fa3ed69ee2 | ||
|
|
417b49beda | ||
|
|
a2f6a35227 | ||
|
|
b9f1cc5883 | ||
|
|
ad132fe729 | ||
|
|
f33892fcd1 | ||
|
|
91300e4d03 | ||
|
|
2a56709395 | ||
|
|
fc135faf57 | ||
|
|
8c02ca3576 | ||
|
|
cdd72c664e | ||
|
|
5f025d0f68 | ||
|
|
6af2c807ab | ||
|
|
c45c90c6c7 | ||
|
|
1ec97c4c90 | ||
|
|
f0bcd38ac7 | ||
|
|
f4ba446c79 | ||
|
|
60f98ebfce | ||
|
|
08c2a0d07b | ||
|
|
1f68fdac8c | ||
|
|
e8d4f0fcf4 | ||
|
|
36a93bda5a | ||
|
|
5d522bd608 | ||
|
|
8d60b07c54 | ||
|
|
5f9cc86044 | ||
|
|
35436c1d09 | ||
|
|
a6b7e07cf5 | ||
|
|
0ba6215b8d | ||
|
|
e2f6fae689 | ||
|
|
296aa01d0f | ||
|
|
12ab3f2d07 | ||
|
|
5a7a374bc9 | ||
|
|
ceece45ad4 | ||
|
|
b344ad66c5 | ||
|
|
d66793d186 | ||
|
|
cc00962752 | ||
|
|
dbc7af4ad4 | ||
|
|
5f5bf01cb5 | ||
|
|
04f2af22f3 | ||
|
|
ea916a0db8 | ||
|
|
3f03afc7eb | ||
|
|
e940483863 | ||
|
|
9e3d3df3a9 | ||
|
|
c18368d777 | ||
|
|
3894a99bc4 | ||
|
|
aab5b55204 | ||
|
|
3e6e346eb9 | ||
|
|
3a83ed424f | ||
|
|
7bef6db7b7 | ||
|
|
71775328ef | ||
|
|
cbccc612a4 | ||
|
|
63fd5d90c1 | ||
|
|
92336d6107 | ||
|
|
727785b0b3 | ||
|
|
762241420e | ||
|
|
93011f084b | ||
|
|
7c90a8425e | ||
|
|
8674cbe788 | ||
|
|
8075fe0bae | ||
|
|
f3f29ca0ea | ||
|
|
0152803192 | ||
|
|
2544cbc252 | ||
|
|
5e094241e3 | ||
|
|
bd028c328d | ||
|
|
598cb1d964 | ||
|
|
79d264fd94 | ||
|
|
5f691d3f1c | ||
|
|
7be0163e76 | ||
|
|
c0b3068824 | ||
|
|
9036a2f317 | ||
|
|
dd35adc05d | ||
|
|
26b5707317 | ||
|
|
75e39f5595 | ||
|
|
7fdeaeabef | ||
|
|
c75ab28002 | ||
|
|
809ffd8b90 | ||
|
|
da7610951d | ||
|
|
62a8320068 | ||
|
|
f21b38f66a | ||
|
|
76fdd1fa98 | ||
|
|
596765bb52 | ||
|
|
297aafba45 | ||
|
|
156983bf58 | ||
|
|
c69930b836 | ||
|
|
1d055253d2 | ||
|
|
6926932340 | ||
|
|
221b3308fa | ||
|
|
66840670b6 | ||
|
|
28887d9116 | ||
|
|
6ef1bac1d7 | ||
|
|
5d6a7807e5 | ||
|
|
20b7eb17f3 | ||
|
|
a0a682e224 | ||
|
|
103ac86345 | ||
|
|
8f705a698d | ||
|
|
f4fb09947e | ||
|
|
97e31e341b | ||
|
|
813789235d | ||
|
|
d161b11892 | ||
|
|
5a82e7e185 | ||
|
|
3bc8d3ce75 | ||
|
|
d9e9fd0f4e | ||
|
|
d56c5520f9 | ||
|
|
89bc893f06 | ||
|
|
fddb203db3 | ||
|
|
8a8cace5e8 | ||
|
|
acc8d066e5 | ||
|
|
5f5b4ee3c1 | ||
|
|
aa6581ae39 | ||
|
|
8aa9e0191f | ||
|
|
8dc09796f8 | ||
|
|
8f93712edb | ||
|
|
b91d1b931e | ||
|
|
6608268117 | ||
|
|
bdecab25a6 | ||
|
|
9d84cbb3ac | ||
|
|
8e730f2b5c | ||
|
|
7b5809fd55 | ||
|
|
bc682ddf62 | ||
|
|
990ead0544 | ||
|
|
4cf55dc95d | ||
|
|
27a9f3c704 | ||
|
|
d70bb243b2 | ||
|
|
301a3efb7c | ||
|
|
05b7cbe20a | ||
|
|
48cbbc1bef | ||
|
|
f8f7c28274 | ||
|
|
0ebb53888a | ||
|
|
83aba7e4a6 | ||
|
|
c0071c1525 | ||
|
|
71f7b3b3d8 | ||
|
|
bd6d7b7149 | ||
|
|
73275626a3 | ||
|
|
0686428138 | ||
|
|
81ed97a68b | ||
|
|
f05e6008e5 | ||
|
|
63de8fe44a | ||
|
|
1e051deb9e | ||
|
|
38c54e255a | ||
|
|
4450164d9c | ||
|
|
b99899353c | ||
|
|
e7ad38d1df | ||
|
|
67c0abea8f | ||
|
|
85c1543df1 | ||
|
|
608b711833 | ||
|
|
3adc1b9f30 | ||
|
|
478cbc2489 | ||
|
|
f38a1f83e2 | ||
|
|
03edb5a385 | ||
|
|
cf77713860 | ||
|
|
0494193c9b | ||
|
|
7bee34170d | ||
|
|
28785a01f6 | ||
|
|
3a22e387b6 | ||
|
|
956b3bfcbd | ||
|
|
01c4260763 | ||
|
|
150b3eb178 | ||
|
|
5ab52d37f2 | ||
|
|
a9ceddd94a | ||
|
|
ce191fd4c7 | ||
|
|
e99c55e812 | ||
|
|
5053d559bc | ||
|
|
1a30109f1c | ||
|
|
9a7e349101 | ||
|
|
07a7d2a51a | ||
|
|
d2b192cb07 | ||
|
|
d8e3e93a87 | ||
|
|
af12df38ed | ||
|
|
5088497575 | ||
|
|
31129ef14d | ||
|
|
17c71efb17 | ||
|
|
e80eb91e69 | ||
|
|
a5b6a954fd | ||
|
|
2a295a8796 | ||
|
|
245226f4f6 | ||
|
|
d3e1c2c79d | ||
|
|
e04e82c6de | ||
|
|
95589dd48b | ||
|
|
4cb17135bd | ||
|
|
8dc23160fc | ||
|
|
4a96a41c8e | ||
|
|
3f18e7c0bf | ||
|
|
3c3a23a397 | ||
|
|
438de6ed6d | ||
|
|
95399a32a8 | ||
|
|
7089ff68d4 | ||
|
|
c754d820a5 | ||
|
|
81c819ddd3 | ||
|
|
ec3e0bfd04 | ||
|
|
b61d739e46 | ||
|
|
7a050d5374 | ||
|
|
52076de76a | ||
|
|
7fb8268fae | ||
|
|
8b49eb1526 | ||
|
|
c6cdcf83a9 | ||
|
|
be8dfd7fa2 | ||
|
|
4bf82083b4 | ||
|
|
6579fd8ebe | ||
|
|
4d62ef771a | ||
|
|
7784a3a20c |
+2
-1
@@ -12,7 +12,8 @@ out
|
||||
*.ipr
|
||||
*.iws
|
||||
*.iml
|
||||
.idea
|
||||
.idea/*
|
||||
!.idea/icon.png
|
||||
|
||||
# gradle
|
||||
build
|
||||
|
||||
Generated
BIN
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -12,6 +12,14 @@
|
||||
- SpawningContext is now SpawnablePosition
|
||||
- WorldSlice is SpawningZone
|
||||
- SpawningProspector is now SpawningZoneGenerator
|
||||
- Majorly refactored the hierarchy of Spawner
|
||||
- The base Spawner interface provides more functions to allow single-point and area spawning given appropriate inputs.
|
||||
- TickingSpawner is removed in favour of outside code handling ticking logic.
|
||||
- AreaSpawner is removed.
|
||||
- BasicSpawner is the first implementation of Spawner which can be used for any purpose.
|
||||
- PlayerSpawners are now mixin'd into ServerPlayer and ticked from ServerPlayer#tick.
|
||||
- A hierarchy diagram can be found at `./docs/spawner-hierarchy.png` in the mod repository.
|
||||
- The SpawnerManager class has been removed as its functionality is all now handled elsewhere.
|
||||
- Renamed things in Spawn Rules to go with the other renames:
|
||||
- contextSelector is now spawnablePositionSelector
|
||||
- contextSelector is now spawnablePositionSelector
|
||||
- context is now spawnable_position
|
||||
+121
-7
@@ -34,25 +34,36 @@
|
||||
- Added Hyper Training items (IV Modification) as well as some additional candy items to do so (Health Candy, Sickly Candy)
|
||||
- Added Galarica Nut Bushes
|
||||
- Many Pokémon (mostly cats) are now feared by phantoms
|
||||
- Combees are now capable of gathering nectar from flowers and delivering it to either Saccharine leaves or hives. (Hive interactions are restricted to wild Combees)
|
||||
- Lightning is now affected by a Pokemon's ability/typing
|
||||
- Pokémon with the ability Lightning Rod draw in lightning similar to a lightning rod block albeit with a lower priority and range, gain immunity to lightning damage, and receive a temporary damage buff.
|
||||
- Pokémon with the ability Motor Drive are immune to lightning damage and receive a temporary speed buff when struck by lightning
|
||||
- Pokémon with the ability Volt Absorb are immune to lightning damage and receive Regeneration II for a short duration
|
||||
- Pokémon with the ability Volt Absorb are immune to lightning damage and receive Instant Health II for a short duration
|
||||
- Ground type Pokémon are immune to lightning damage
|
||||
- Added functionality to Everstone when held by a Pokémon; suppresses evolution notification and hides evolve button in summary interface.
|
||||
- Added optional `filePath` parameter to MoLang functions to allow for global stores (ex. `../global/`). Path must end in a forward slash.
|
||||
- Added new optional property `attachment_options` for most EmitterShapes to be attached to the locator/entities scale, rotation, and/or position. Position is true by default.
|
||||
- Added Statistics for battles won, fled, and total, Pokémon captured (shiny and total), Pokémon released, dex entries added, trades completed, Pokémon levels gained, Pokémon evolved, fossils revived, PokéRod casts and reel-ins and Pokémon times ridden.
|
||||
- Galarica Nut bushes now generate on beaches.
|
||||
- Some Pokémon now pitch their bodies in the direction they're moving.
|
||||
- Added new advancements Didn't Stop To Think, We Need To Cook, and Pokémon Jockey!.
|
||||
- Added new advancements Didn't Stop To Think, We Need To Cook, Pokémon Jockey!, Souped-Up Stats, Culinary World Tour, Mochi Mochi!, A Luring Aroma, That's Bait, Star Pokéathlete, Home on the Range, and Just a Smackerel.
|
||||
- Berries can now be smelted into their respective dyes.
|
||||
- Added Syrupy Apples.
|
||||
- Added `/runmolang <molang> [<npc>|<player>|<pokemon>]` command that executes a MoLang expression with the provided options as environment variables, as well as the entity (as `q.entity`) that executed the command.
|
||||
- Added new 69th berry, Eggant.
|
||||
- Added bubble quirk to Kingler; like Krabby, Kingler will blows bubbles during dusk.
|
||||
- Added `.Pre` and `.Post` to the following events:
|
||||
- `PokemonRecallEvent`
|
||||
- `TradeEvent`
|
||||
- Added a new gamerule, 'healerHealsPC', when set to true a successful use of a healer will also heal all of the Pokemon in that player's PC.
|
||||
- Mooshtanks will switch between their red and brown variant when hit by lightning
|
||||
- Smeargle spawns with differing tail colour depending on its [Characteristic](https://bulbapedia.bulbagarden.net/wiki/Characteristic) stat
|
||||
- Added smooth level-up animations to the party overlay to replace chat messages.
|
||||
- Added `min_perfect_ivs` property to PokemonProperties to specify the minimum number of perfect IVs of the Pokemon.
|
||||
- Added `defaultKeyItems` config option to specify which key items players always have.
|
||||
- Added `scale_modifier` property to PokemonProperties to modify the scale of the Pokemon.
|
||||
- Added advancement trigger to check riding stat boosts.
|
||||
- Added Tasty Tail which you can get from Slowpokes if you happen to have a pair of shears. They don't mind, we asked.
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
@@ -84,6 +95,8 @@
|
||||
- Altaria
|
||||
- Snorunt
|
||||
- Glalie
|
||||
- Shuppet
|
||||
- Banette
|
||||
- Latias
|
||||
- Latios
|
||||
|
||||
@@ -132,6 +145,11 @@
|
||||
- Swadloon
|
||||
- Leavanny
|
||||
- Druddigon
|
||||
- Minccino
|
||||
- Cinccino
|
||||
- Vanillite
|
||||
- Vanillish
|
||||
- Vanilluxe
|
||||
|
||||
#### Gen 6
|
||||
- Skiddo
|
||||
@@ -293,6 +311,23 @@
|
||||
- Tauros - Paldea Blaze
|
||||
- Tauros - Paldea Combat
|
||||
- Dewgong
|
||||
- Corphish (updated placeholders for crustaceous tripod gait legs)
|
||||
- Crawdaunt (updated placeholders for crustaceous bipedal legs)
|
||||
- Dragapult
|
||||
- Camerupt
|
||||
- Relicanth
|
||||
- Heracross
|
||||
- Salamence
|
||||
- Staraptor
|
||||
- Dusknoir
|
||||
- Arcanine
|
||||
- Carvanha
|
||||
- Sharpedo
|
||||
- Mimikyu
|
||||
- Dewgong
|
||||
- Mime Jr
|
||||
- Gyarados
|
||||
- Lapras
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Cleffa
|
||||
@@ -320,6 +355,8 @@
|
||||
- Nosepass
|
||||
- Probopass
|
||||
- Kangaskhan
|
||||
- Scorbunny
|
||||
- Raboot
|
||||
- Cinderace
|
||||
- Magnemite
|
||||
- Magneton
|
||||
@@ -403,6 +440,21 @@
|
||||
- Revavroom
|
||||
- Nickit
|
||||
- Thievul
|
||||
- Litwick
|
||||
- Lampent
|
||||
- Chandelure
|
||||
- Rayquaza
|
||||
- Aerodactyl
|
||||
- Basculin
|
||||
- Basculegion
|
||||
- Shroodle
|
||||
- Grafaiai
|
||||
- Steelix
|
||||
- Dratini
|
||||
- Dragonair
|
||||
- Dragonite
|
||||
- Cutiefly
|
||||
- Ribombee
|
||||
|
||||
### Changes
|
||||
- Changed pokemon caught and seen count to update based on the current pokedex being looked
|
||||
@@ -416,14 +468,15 @@
|
||||
- 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.
|
||||
- Updated the `#cobblemon:berries` tag to use subtags located in `data/cobblemon/tags/item/berries`, such as `#cobblemon:berries/hp_recovery` for sorting purposes
|
||||
- Moved the tag `#cobblemon:mutated_berries` to `#cobblemon:berries/mutation_result`
|
||||
- Added herbs and snowballs to the consumable in PvE and Wild battle tags
|
||||
- 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.
|
||||
- Removed Shulker shell Forretress.
|
||||
- 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.
|
||||
- Improved the zoom functionality of the Pokédex Scanner by giving the levels logarithmic scaling.
|
||||
@@ -432,7 +485,7 @@
|
||||
- Quirk animations no longer play in the battle GUI since they were pretty distracting.
|
||||
- A number of Pokemon that float above the ground visually (Gastly, Klingklang, etc.) are no longer considered to be touching the ground
|
||||
- Changed the recipes for Level, Lure, and Moon Balls to be cleaner
|
||||
- Renamed `pokemonId` and `type` to `species` in relevant Advancement triggers for conformity, this is a breaking change.
|
||||
- Renamed `pokemonId` and `type` to `species` and `evolved` to `has_evolved` in relevant Advancement triggers for conformity, this is a breaking change.
|
||||
- Added a separate `species` argument to the `pick_starter`, `pasture_use` and `resurrect_pokemon` Advancement triggers.
|
||||
- Made `CobblemonAgingDespawner` thresholds configurable via the config file.
|
||||
- Tweaked Berry flavor data to balance cooking pot mechanics
|
||||
@@ -467,6 +520,16 @@
|
||||
- Updated `HatchEggEvent.Post` to include the Pokemon that hatched.
|
||||
- Roseli Berry Trees now naturally generate in their preferred biomes.
|
||||
- Refactored dynamic lights compat to be more future proof. The dynamic light support is only tested with LambDynamicLights, on NeoForged use that mod in combination with Sinytra Connector
|
||||
- Renamed Masterful Dedication advancement to This will affect the Whiscash Population
|
||||
- Changed icon for the following advancements: New Angles for Angling, Researcher Recruit, Doing my Part, Reapriforestation
|
||||
- Disabled advancement Mother Nature's Bounty from appearing in chat when obtained, now only appears as a toast and in the advancements menu
|
||||
- Removed Oki-Doki Vivichokey advancement
|
||||
- Shulker Boxes and Traveler's Backpacks can no longer be held by Pokémon. Thanks Monocle ;) You could re-enable this with a datapack but you'd be crazy.
|
||||
- Shulker Boxes and Traveler's Backpacks AND Packed Up backpacks can no longer be held by Pokémon. Thanks Monocle ;) You could re-enable this with our datapack (but you'd be crazy).
|
||||
- Moomoo Milk now clears Pokémon stat changes when used in battle.
|
||||
- Updated Evolution Stone Block light levels
|
||||
- Added light levels to Evolution Stone Ores. These levels are reduced versions of the full blocks light levels
|
||||
- Added a steps counter to the summary screen for Pokémon that require walking a certain number of steps to evolve.
|
||||
|
||||
### Fixes
|
||||
- Fixed game crashing when removing national pokedex using datapacks
|
||||
@@ -551,6 +614,17 @@
|
||||
- Fixed singular Pokémon corruption causing entire storage corruption. Storages will now skip corrupted Pokémon and print an error to console.
|
||||
- Fixed species additions not being able to properly mark a species as implemented.
|
||||
- Fixed Pokémon item models not showing a glint when enchanted.
|
||||
- Fixed the missing Terracotta Sun Stone Ore smelting and blasting recipes
|
||||
- Improved experience gain from smelting evolution stone ores to better match other ore types
|
||||
- Fixed some specific bag items not being dropped when used in battle.
|
||||
- The Corphish line will now sink in water.
|
||||
- Fixed the "use all berry bait" achievement not being progressed
|
||||
- Fixed bobber hook and berry sprouts texture sizes causing mipmap issues.
|
||||
- Fixed head locator not taking into account scale for positioning.
|
||||
- Fixed Pokémon step counts not being saved when recalling them to a Pokéball or reentering the world.
|
||||
- Fixed NPC pokémon not being linked to their NPC, which previously caused NPC pokémon to be catchable.
|
||||
- Fixed an uncommon error caused by scanning a pokémon on a player's shoulder.
|
||||
- Fixed a case where spawning could fail and log warnings when nothing wrong was happening.
|
||||
|
||||
### Developer
|
||||
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
|
||||
@@ -588,10 +662,36 @@
|
||||
- Added a `hoverText` option to PartySelectCallback, to display a tooltip on hovering over a Pokémon in the selection screen.
|
||||
- `PokemonEntity` instances spawned into the world now appropriately finalize the spawn for mod compatibility.
|
||||
- Added PokedexManager.obtain as a replacement for .catch which is not a friendly function name in Java.
|
||||
|
||||
- Added `Pokemon#hyperTrainIV()` and `IVs#setHyperTrainedIV(Stat, Int)`
|
||||
- `ElementalType` now implements `ShowdownIdentifiable` to ensure the communcation with showdown stays consistent (also in regards to TeraTypes)
|
||||
- Pokemon no longer have a change observable
|
||||
- Pokémon can now have a behaviour changing the value of a species feature on lightning hit:
|
||||
```JSON
|
||||
{
|
||||
"behaviour": {
|
||||
"lightningHit": {
|
||||
"rotateFeatures": [
|
||||
{
|
||||
"key": "mooshtank",
|
||||
"chain": ["red", "brown"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
This will change the value of `mooshtank` from `red` to `brown` and vice versa when a lightning strikes this Pokémon. Only chains of which a value is the current value will be considered, so multiple entries for the same key with different chains can be added.
|
||||
- Removed Npc interface from NPCEntity, the interface is unused and in vanilla is only implemented by VillagerEntity as a means to disable villagers with the `spawn-npcs` server property.
|
||||
- Added new `Observable#subscribe` methods that take Java Consumers to make usage in Java a little cleaner.
|
||||
- Annotated a bunch of Kotlin methods and fields for cleaner Java names.
|
||||
- Added `PartyStore#isEmpty()`.
|
||||
- Added `ElementalTypes#getRandomType()`.
|
||||
- Added `IVs#getEffectiveBattleTotal()`.
|
||||
- Added `IVs.MAX_TOTAL` constant.
|
||||
- Added `PokemonStats#total()`.
|
||||
- Add `NatureAdapter` for serializing and deserializing Natures using Gson.
|
||||
- Added `Pokemon.getBaseRideStat(RidingStat)` for getting the base value of the given stat.
|
||||
- Fixed `Species#create` using the species name instead of identifier, which had led to certain mismatches generating random pokémon.
|
||||
|
||||
### 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)
|
||||
@@ -632,6 +732,7 @@
|
||||
- Adds Flows for `POKEMON_HEALED`, `POKEMON_SCANNED`, `BERRY_HARVEST`, `LOOT_DROPPED`, `POKEMON_SEEN`, `COLLECT_EGG`, `HATCH_EGG`, and `EXPERIENCE_GAINED`.
|
||||
- Adds Flows for `POKEMON_CATCH_RATE`, `BAIT_SET`, `BAIT_SET_PRE`, `BAIT_CONSUMED`, `POKEROD_CAST_PRE`, `POKEROD_CAST_POST`, `POKEROD_REEL`, and `BOBBER_SPAWN_POKEMON_PRE`.
|
||||
- Adds Flows for `POKEMON_ASPECTS_CHANGED`, `FRIENDSHIP_UPDATED`, `CHANGE_PC_BOX_WALLPAPER_EVENT_PRE`, `CHANGE_PC_BOX_WALLPAPER_EVENT_POST`, and `FULLNESS_UPDATED`.
|
||||
- Added Callback for `SERVER_STOPPING`
|
||||
- MoLang triggered battles may now set the battle format, whether to clone the player's party, set level, or heal prior.
|
||||
- Added Molang function for Player: `inventory`
|
||||
- Adds Flows for `STARTER_CHOSEN`, `EV_GAINED`, `POKEMON_RELEASED`, `POKEMON_NICKNAMED`, `HELD_ITEM`, and `TRADE_COMPLETED` events
|
||||
@@ -695,6 +796,18 @@
|
||||
- Mechanics
|
||||
- Unlockable Wallpapers
|
||||
- Starter Data
|
||||
- Fixed `cobblemon:reel_in_pokemon` criteria not working when used together with a `baitId`
|
||||
- Also changed the default from `cobblemon:empty_bait` to `any`
|
||||
- The previous default is still available by using the above as baitId
|
||||
- Added support for species-specific move action effects, using the format `{move_id}_{species}.json`.
|
||||
- Added `look_at_entity_types` variable for look_at_entities to specify what entity type or entity tag to look at.
|
||||
- Added `Looks At Players` behaviour preset that only sets the look target to players.
|
||||
- Added various functions to `q.file` for JSON file handling in MoLang, strictly for `./config` and `./data` folders that have `/molang/` in the path:
|
||||
- `q.file.save(<path>, <struct>)` Saves to the given file path with the given variable struct.
|
||||
- `q.file.load(<path>)` Loads a variable struct from the given path, or gets it from the cache if it's already been loaded.
|
||||
- `q.file.exists(<path>)` Returns 1 if the given file path exists.
|
||||
- `q.file.clear(<path>)` Clears the given file from the cache.
|
||||
- Using `q.run_script` will now allow additional arguments which will be put into `c.arg_1`, `c.arg_2`, etc.
|
||||
|
||||
### Particles
|
||||
Added new/updated particles for the following moves:
|
||||
@@ -990,6 +1103,7 @@ Added new/updated particles for the following moves:
|
||||
- Parametric particle motion now works.
|
||||
- Event-spawned particles now work.
|
||||
- Particles can now have independent coordinate spaces.
|
||||
- Fixed suffocation of Pokémon when a pokeball breaks near a wall
|
||||
|
||||
### Developer
|
||||
- Updated the Pokédex data updated events to always include a `Pokemon` instance, and optionally a `DisguiseData` instance.
|
||||
@@ -2926,4 +3040,4 @@ Thank you so much to all of our community translators that bring the mod to the
|
||||
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
|
||||
|
||||
## [1.0.0 (November 12th, 2022)](#1-0-0)
|
||||
- Initial release.
|
||||
- Initial release.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.spawning.spawner.PlayerSpawner;
|
||||
|
||||
/**
|
||||
* Used for mixin shenanigans. ServerPlayers now store their Cobblemon spawner
|
||||
* inside, so this interface helps execute that.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 27th, 2025
|
||||
*/
|
||||
public interface PlayerSpawnerAccessor {
|
||||
PlayerSpawner getPlayerSpawner();
|
||||
void setPlayerSpawner(PlayerSpawner spawner);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.duck;
|
||||
|
||||
import com.mongodb.lang.Nullable;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public interface CameraDuck {
|
||||
BlockGetter cobblemon$getLevel();
|
||||
|
||||
@Nullable
|
||||
Entity cobblemon$getEntity();
|
||||
|
||||
Vector3f cobblemon$getForwards();
|
||||
|
||||
Vector3f cobblemon$getUp();
|
||||
|
||||
Vector3f cobblemon$getLeft();
|
||||
|
||||
float cobblemon$getXRot();
|
||||
void cobblemon$setXRot(float xRot);
|
||||
|
||||
float cobblemon$getYRot();
|
||||
void cobblemon$setYRot(float yRot);
|
||||
}
|
||||
@@ -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.duck;
|
||||
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public interface RidePassenger {
|
||||
void cobblemon$setRideXRot(float rideXRot);
|
||||
float cobblemon$getRideXRot();
|
||||
void cobblemon$setRideYRot(float rideYRot);
|
||||
float cobblemon$getRideYRot();
|
||||
void cobblemon$setRideEyePos(Vec3 rideEyePos);
|
||||
Vec3 cobblemon$getRideEyePos();
|
||||
}
|
||||
@@ -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.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
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(AbstractArrow.class)
|
||||
public abstract class AbstractArrowMixin {
|
||||
|
||||
@Inject(
|
||||
method = "<init>(Lnet/minecraft/world/entity/EntityType;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)V",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
private void cobblemon$adjustSpawnPosition(
|
||||
EntityType<? extends AbstractArrow> entityType,
|
||||
LivingEntity owner,
|
||||
Level level,
|
||||
ItemStack pickupItemStack,
|
||||
@Nullable ItemStack firedFromWeapon,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
AbstractArrow arrow = (AbstractArrow)(Object)this;
|
||||
if(!(owner.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
if(!(vehicle instanceof PokemonEntity)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
|
||||
// If this is a pokemon ride passenger then use the rider eye position to set the arrow spawn position.
|
||||
if (owner instanceof RidePassenger ridePassenger && vehicleController != null ) {
|
||||
var eyePos = ridePassenger.cobblemon$getRideEyePos(); //.add(0.0, -2.0, 0.0);
|
||||
arrow.setPos(eyePos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.mixin;
|
||||
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories;
|
||||
import com.cobblemon.mod.common.api.ai.config.task.PathToBeeHiveTaskConfig;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.item.component.CustomData;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.BeehiveBlock;
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.Occupant.class)
|
||||
public abstract class BeeOccupantMixin {
|
||||
|
||||
@Inject(method = "createEntity", at = @At("RETURN"), cancellable = true)
|
||||
private void cobblemon$createEntity(Level level, BlockPos pos, CallbackInfoReturnable<Entity> cir) {
|
||||
// Needing to replicate all the post op stuff on the hive isn't great
|
||||
if (cir.getReturnValue() == null) {
|
||||
final BeehiveBlockEntity.Occupant occupant = (BeehiveBlockEntity.Occupant) (Object) this;
|
||||
CompoundTag compoundTag = occupant.entityData().copyTag();
|
||||
Entity entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
var state = level.getBlockState(pos);
|
||||
var newPos = Vec3.ZERO;
|
||||
var newYaw = 0f;
|
||||
var brain = pokemonEntity.getBrain();
|
||||
if (state.is(BlockTags.BEEHIVES)) {
|
||||
// position in front of the entrance, face away from the block
|
||||
var facing = state.getValue(HorizontalDirectionalBlock.FACING);
|
||||
newPos = pos.relative(facing).getCenter();
|
||||
newYaw = facing.toYRot();
|
||||
brain.setMemory(CobblemonMemories.HIVE_LOCATION, pos); // This needs to be set in the case that the hive was picked up and moved.
|
||||
} else {
|
||||
// Block has likely been destroyed
|
||||
var center = pos.getCenter();
|
||||
newPos = new Vec3(
|
||||
center.x + level.random.nextFloat() * 0.6 - 0.3,
|
||||
center.y + level.random.nextFloat() * 0.6 - 0.3,
|
||||
center.z + level.random.nextFloat() * 0.6 - 0.3
|
||||
);
|
||||
newYaw = level.random.nextFloat() * 360F;
|
||||
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION);
|
||||
}
|
||||
entity.yRotO = newYaw;
|
||||
entity.setPos(newPos);
|
||||
// Do honey logic
|
||||
var hasNectar = brain.getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
|
||||
if (hasNectar) {
|
||||
// Remove nectar and reset got to hive cooldown
|
||||
brain.eraseMemory(CobblemonMemories.HAS_NECTAR);
|
||||
brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, PathToBeeHiveTaskConfig.STAY_OUT_OF_HIVE_COOLDOWN);
|
||||
// Increment honey level of the hive
|
||||
if (state.is(BlockTags.BEEHIVES, (blockStateBase) -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL))) {
|
||||
int i = state.getValue(BeehiveBlock.HONEY_LEVEL);
|
||||
if (i < 5) {
|
||||
int j = level.random.nextInt(100) == 0 ? 2 : 1;
|
||||
if (i + j > 5) {
|
||||
--j;
|
||||
}
|
||||
level.setBlockAndUpdate(pos, state.setValue(BeehiveBlock.HONEY_LEVEL, i + j));
|
||||
}
|
||||
}
|
||||
}
|
||||
cir.setReturnValue(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "of", at = @At("HEAD"), cancellable = true)
|
||||
private static void cobblemon$of(Entity entity, CallbackInfoReturnable<BeehiveBlockEntity.Occupant> cir) {
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
List<String> IGNORED_BEE_TAGS = Arrays.asList("Air", "ArmorDropChances", "ArmorItems", "Brain", "CanPickUpLoot", "DeathTime", "FallDistance", "FallFlying", "Fire", "HandDropChances", "HandItems", "HurtByTimestamp", "HurtTime", "LeftHanded", "Motion", "NoGravity", "OnGround", "PortalCooldown", "Pos", "Rotation", "Passengers", "leash", "UUID");
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
entity.save(compoundTag);
|
||||
Objects.requireNonNull(compoundTag);
|
||||
IGNORED_BEE_TAGS.forEach(compoundTag::remove);
|
||||
Boolean hasNectar = pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
|
||||
cir.setReturnValue(new BeehiveBlockEntity.Occupant(CustomData.of(compoundTag), 0, hasNectar ? 2400 : 600));
|
||||
cir.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.mixin.accessor.BeeDataAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BeehiveBlockEntityAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BlockEntityAccessor;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.class)
|
||||
public abstract class BeehiveBlockEntityMixin {
|
||||
|
||||
|
||||
// Accessor for the private 'stored' field in BeehiveBlockEntity
|
||||
@Accessor("stored")
|
||||
public abstract List<BeeDataAccessor> getStored();
|
||||
|
||||
@Inject(method = "emptyAllLivingFromHive", at = @At("HEAD"))
|
||||
private void cobblemon$emptyAllLivingFromHive(@Nullable Player player, BlockState state, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, CallbackInfo ci) {
|
||||
if (player != null) {
|
||||
final BeehiveBlockEntity blockEntity = (BeehiveBlockEntity) (Object) this;
|
||||
// if the block is sedated or the player is too far away, no aggro should be applied
|
||||
if (blockEntity.isSedated() || player.position().distanceToSqr(blockEntity.getBlockPos().getCenter()) > 16.0)
|
||||
return;
|
||||
// from this point need to access private members of the block entity
|
||||
final BeehiveBlockEntityAccessor blockEntityAccessor = (BeehiveBlockEntityAccessor) this;
|
||||
List<Object> storedList = blockEntityAccessor.getStored();
|
||||
|
||||
List<Entity> list = Lists.newArrayList();
|
||||
storedList.removeIf((beeData) -> {
|
||||
BeehiveBlockEntity.Occupant occupant = ((BeeDataAccessor) beeData).invokeToOccupant();
|
||||
// Checking the for the tag allows us to make sure it's one of our pokemon before trying to rehydrate it into an entity
|
||||
boolean isPokemon = false;
|
||||
if (occupant.entityData().contains("id")) {
|
||||
isPokemon = "cobblemon:pokemon".equals(occupant.entityData().getUnsafe().getString("id"));
|
||||
}
|
||||
if (isPokemon) {
|
||||
return BeehiveBlockEntityAccessor.releaseOccupant(
|
||||
((BlockEntityAccessor) blockEntityAccessor).getLevel(),
|
||||
((BlockEntityAccessor) blockEntityAccessor).getWorldPosition(),
|
||||
state,
|
||||
occupant,
|
||||
list,
|
||||
releaseStatus,
|
||||
blockEntityAccessor.savedFlowerPos());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
for (Entity entity : list) {
|
||||
if (entity instanceof PokemonEntity) {
|
||||
((PokemonEntity) entity).getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "releaseOccupant",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/Level;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z"
|
||||
)
|
||||
)
|
||||
private static boolean cobblemon$captureReleasedEntity(
|
||||
Level level, Entity entity,
|
||||
Level lvl, BlockPos pos, BlockState state,
|
||||
BeehiveBlockEntity.Occupant occupant, @Nullable List<Entity> bees,
|
||||
BeehiveBlockEntity.BeeReleaseStatus releaseStatus, @Nullable BlockPos flowerPos) {
|
||||
|
||||
if (bees != null && !bees.contains(entity)) {
|
||||
// Avoid duplicates if vanilla also adds bees to the list on your version
|
||||
bees.add(entity);
|
||||
}
|
||||
return level.addFreshEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.duck.ChannelDuck;
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import org.lwjgl.openal.AL10;
|
||||
|
||||
@@ -8,18 +8,25 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry;
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.riding.Seat;
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineBehaviour;
|
||||
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.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
@@ -32,6 +39,7 @@ 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.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class LivingEntityMixin extends Entity implements OrientationControllable {
|
||||
@@ -55,6 +63,14 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "baseTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;isInWall()Z"))
|
||||
public boolean cobblemon$preventMountSuffocation(LivingEntity instance, Operation<Boolean> original) {
|
||||
if (instance.getVehicle() instanceof PokemonEntity) {
|
||||
return false;
|
||||
}
|
||||
return original.call(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
@@ -116,4 +132,31 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "decreaseAirSupply", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$conditionalWaterBreathing(
|
||||
int currentAir,
|
||||
CallbackInfoReturnable<Integer> cir
|
||||
) {
|
||||
var entity = (LivingEntity) (Object) this;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player.getVehicle() instanceof PokemonEntity vehicle)) return;
|
||||
|
||||
var ridingController = vehicle.getRidingController();
|
||||
if (ridingController == null) return;
|
||||
|
||||
var activeContext = ridingController.getContext();
|
||||
if (activeContext == null) return;
|
||||
|
||||
// If the rider is currently on a submarine and the ride still has stamina.
|
||||
var stamina = activeContext.getState().getStamina().get();
|
||||
if (
|
||||
activeContext.getStyle() == RidingStyle.LIQUID &&
|
||||
activeContext.getBehaviour().equals(SubmarineBehaviour.Companion.getKEY()) &&
|
||||
stamina > 0.0f
|
||||
) {
|
||||
cir.setReturnValue(currentAir);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ 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.duck.PlayerDuck;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
|
||||
@@ -37,6 +38,7 @@ 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.Mth;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.EntityDimensions;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
@@ -47,6 +49,7 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Vector3f;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
@@ -63,7 +66,7 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck {
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger {
|
||||
|
||||
@Unique
|
||||
private Vector3f cobblemon$driverInput;
|
||||
@@ -91,6 +94,12 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
@Shadow protected int jumpTriggerTime;
|
||||
@Unique private final OrientationController cobblemon$orientationController = new OrientationController(this);
|
||||
|
||||
@Unique private float cobblemon$rideXRot = 0.0f;
|
||||
|
||||
@Unique private float cobblemon$rideYRot = 0.0f;
|
||||
|
||||
@Unique private Vec3 cobblemon$rideEyePos = Vec3.ZERO;
|
||||
|
||||
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, Level p_20967_) {
|
||||
super(p_20966_, p_20967_);
|
||||
}
|
||||
@@ -117,11 +126,6 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
@@ -218,24 +222,25 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
|
||||
@Nullable @Unique
|
||||
private PokedexEntityData getDataFromShoulderPokemon(CompoundTag shoulderTag) {
|
||||
CompoundTag pokemonTag = shoulderTag.getCompound(DataKeys.POKEMON);
|
||||
if (pokemonTag.isEmpty()) return null;
|
||||
Species species = PokemonSpecies.INSTANCE.getByIdentifier(ResourceLocation.parse(pokemonTag.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER)));
|
||||
if (species == null) return null;
|
||||
String formId = pokemonTag.getString(DataKeys.POKEMON_FORM_ID);
|
||||
FormData form = species.getStandardForm();
|
||||
List<FormData> formList = species.getForms().stream().filter(it -> it.formOnlyShowdownId().equals(formId)).toList();
|
||||
if (!formList.isEmpty()) form = formList.getFirst();
|
||||
if (form == null) return null;
|
||||
String genderString = pokemonTag.getString(DataKeys.POKEMON_GENDER);
|
||||
if (genderString.isEmpty()) return null;
|
||||
Gender gender = Gender.valueOf(genderString);
|
||||
boolean shiny = pokemonTag.getBoolean(DataKeys.POKEMON_SHINY);
|
||||
int level = pokemonTag.getInt(DataKeys.POKEMON_LEVEL);
|
||||
Set<String> aspects = shoulderTag.getList(DataKeys.SHOULDER_ASPECTS, Tag.TAG_STRING).stream().map(Tag::getAsString).collect(Collectors.toSet());
|
||||
|
||||
Pokemon pokemon = new Pokemon();
|
||||
Pokemon pokemon;
|
||||
if (level().isClientSide) {
|
||||
CompoundTag pokemonTag = shoulderTag.getCompound(DataKeys.POKEMON);
|
||||
if (pokemonTag.isEmpty()) return null;
|
||||
Species species = PokemonSpecies.getByIdentifier(ResourceLocation.parse(pokemonTag.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER)));
|
||||
if (species == null) return null;
|
||||
String formId = pokemonTag.getString(DataKeys.POKEMON_FORM_ID);
|
||||
FormData form = species.getStandardForm();
|
||||
List<FormData> formList = species.getForms().stream().filter(it -> it.formOnlyShowdownId().equals(formId)).toList();
|
||||
if (!formList.isEmpty()) form = formList.getFirst();
|
||||
if (form == null) return null;
|
||||
String genderString = pokemonTag.getString(DataKeys.POKEMON_GENDER);
|
||||
if (genderString.isEmpty()) return null;
|
||||
Gender gender = Gender.valueOf(genderString);
|
||||
boolean shiny = pokemonTag.getBoolean(DataKeys.POKEMON_SHINY);
|
||||
int level = pokemonTag.getInt(DataKeys.POKEMON_LEVEL);
|
||||
Set<String> aspects = shoulderTag.getList(DataKeys.SHOULDER_ASPECTS, Tag.TAG_STRING).stream().map(Tag::getAsString).collect(Collectors.toSet());
|
||||
|
||||
pokemon = new Pokemon();
|
||||
pokemon.setSpecies(species);
|
||||
pokemon.setForm(form);
|
||||
pokemon.setGender(gender);
|
||||
@@ -246,7 +251,7 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
PlayerPartyStore party = Cobblemon.INSTANCE.getStorage().getParty(this.getUUID(), this.registryAccess());
|
||||
pokemon = party.get(shoulderTag.getUUID(DataKeys.SHOULDER_UUID));
|
||||
}
|
||||
return new PokedexEntityData(pokemon, null);
|
||||
return (pokemon == null) ? null : new PokedexEntityData(pokemon, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -307,4 +312,34 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
return cobblemon$lastSentDriverInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float cobblemon$getRideXRot() {
|
||||
return this.cobblemon$rideXRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideXRot(float rideXRot) {
|
||||
this.cobblemon$rideXRot = Mth.wrapDegrees(rideXRot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float cobblemon$getRideYRot() {
|
||||
return this.cobblemon$rideYRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideYRot(float rideYRot) {
|
||||
this.cobblemon$rideYRot = Mth.wrapDegrees(rideYRot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 cobblemon$getRideEyePos() {
|
||||
return this.cobblemon$rideEyePos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideEyePos(Vec3 rideEyePos) {
|
||||
this.cobblemon$rideEyePos = rideEyePos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,5 +29,4 @@ public class RecipeBookSettingsMixin {
|
||||
private void cobblemon$init(CallbackInfo ci) {
|
||||
states.put(RecipeBookType.valueOf("COOKING_POT"), new RecipeBookSettings.TypeSettings(true, true));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,33 +8,70 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.PlayerSpawnerAccessor;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
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;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class ServerPlayerMixin {
|
||||
public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
@Shadow
|
||||
public abstract ServerLevel serverLevel();
|
||||
|
||||
@Unique
|
||||
public PlayerSpawner cobblemon$spawner;
|
||||
|
||||
@Override
|
||||
public PlayerSpawner getPlayerSpawner() {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
if (cobblemon$spawner == null) {
|
||||
cobblemon$spawner = PlayerSpawnerFactory.INSTANCE.create(player);
|
||||
}
|
||||
return cobblemon$spawner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerSpawner(PlayerSpawner spawner) {
|
||||
this.cobblemon$spawner = spawner;
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("TAIL"))
|
||||
private void cobblemon$tickSpawner(CallbackInfo ci) {
|
||||
if (!Cobblemon.config.getEnableSpawning()) {
|
||||
return;
|
||||
} else if (!serverLevel().getGameRules().getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING)) {
|
||||
return;
|
||||
}
|
||||
getPlayerSpawner().tick();
|
||||
}
|
||||
|
||||
@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);
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
Entity vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation(vehicle);
|
||||
controllableVehicle.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;
|
||||
private boolean cobblemon$shouldUseCustomOrientation(Entity entity) {
|
||||
if (entity == null) return false;
|
||||
if (!(entity instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
@@ -42,8 +79,9 @@ public abstract class ServerPlayerMixin {
|
||||
|
||||
@Inject(method = "stopRiding", at = @At("HEAD"))
|
||||
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
controllableVehicle.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
//TODO: Switch to sending out on load instead of preventing saving
|
||||
@@ -51,5 +89,4 @@ public abstract class ServerPlayerMixin {
|
||||
private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(ordinal=0) Entity entity) {
|
||||
return original && !(entity instanceof PokemonEntity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,86 +55,6 @@ public abstract class SoundEngineMixin implements SoundEngineDuck {
|
||||
@Shadow
|
||||
public abstract boolean isActive(SoundInstance sound);
|
||||
|
||||
@Inject(method = "play",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/sounds/ChannelAccess$ChannelHandle;execute(Ljava/util/function/Consumer;)V"
|
||||
),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$overrideChannelExecute(
|
||||
SoundInstance sound,
|
||||
CallbackInfo ci,
|
||||
@Local(name = "h") float h,
|
||||
@Local(name = "i") float i,
|
||||
@Local(name = "g") float g,
|
||||
@Local(name = "bl2") boolean bl2,
|
||||
@Local(name = "bl3") boolean bl3,
|
||||
@Local(name = "bl") boolean bl,
|
||||
@Local(name = "vec3") Vec3 vec3,
|
||||
@Local(name = "channelHandle") ChannelAccess.ChannelHandle handle
|
||||
) {
|
||||
if (!(sound instanceof RideLoopSound rideSound)) return;
|
||||
|
||||
if (handle == null) return;
|
||||
|
||||
handle.execute((channel) -> {
|
||||
channel.setPitch(i);
|
||||
channel.setVolume(h);
|
||||
|
||||
if (rideSound.getRideAttenuation() == RideAttenuationModel.LINEAR) {
|
||||
channel.linearAttenuation(g);
|
||||
} else if (rideSound.getRideAttenuation() == RideAttenuationModel.EXPONENTIAL){
|
||||
((ChannelDuck) channel).cobblemon$inverseAttenuation(g);
|
||||
} else {
|
||||
channel.disableAttenuation();
|
||||
}
|
||||
|
||||
// Apply low pass filter if the rideSound dictate that it should be muffled
|
||||
if (rideSound.getShouldMuffle()) {
|
||||
((ChannelDuck) channel).cobblemon$applyLowPassFilter(1.0f, rideSound.getMuffleAmount());
|
||||
} else {
|
||||
((ChannelDuck) channel).cobblemon$clearFilters();
|
||||
}
|
||||
|
||||
channel.setLooping(bl2 && !bl3);
|
||||
channel.setSelfPosition(vec3);
|
||||
channel.setRelative(bl);
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "tickNonPaused",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/sounds/ChannelAccess$ChannelHandle;execute(Ljava/util/function/Consumer;)V",
|
||||
ordinal = 0
|
||||
)
|
||||
)
|
||||
private void cobblemon$tickableSoundTick(
|
||||
CallbackInfo ci,
|
||||
@Local(name = "tickableSoundInstance") TickableSoundInstance instance,
|
||||
@Local(name = "channelHandle", ordinal = 0) ChannelAccess.ChannelHandle handle,
|
||||
@Local(name = "f", ordinal = 0) float volume,
|
||||
@Local(name = "g", ordinal = 0) float pitch,
|
||||
@Local(name = "vec3", ordinal = 0) Vec3 vec3
|
||||
) {
|
||||
if (!(instance instanceof RideLoopSound rideSound)) return;
|
||||
|
||||
handle.execute(channel -> {
|
||||
channel.setVolume(volume);
|
||||
channel.setPitch(pitch);
|
||||
channel.setSelfPosition(vec3);
|
||||
|
||||
// Apply low pass filter if the rideSound dictate that it should be muffled
|
||||
if (rideSound.getShouldMuffle()) {
|
||||
((ChannelDuck) channel).cobblemon$applyLowPassFilter(1.0f, rideSound.getMuffleAmount());
|
||||
} else {
|
||||
((ChannelDuck) channel).cobblemon$clearFilters();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Resumes the Source belonging to the queried SoundInstance. */
|
||||
private void resume(SoundInstance sound) {
|
||||
ChannelAccess.ChannelHandle sourceManager = this.instanceToChannel.get(sound);
|
||||
|
||||
@@ -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.world.level.block.entity.BeehiveBlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(targets = "net.minecraft.world.level.block.entity.BeehiveBlockEntity$BeeData")
|
||||
public interface BeeDataAccessor {
|
||||
@Invoker("toOccupant")
|
||||
BeehiveBlockEntity.Occupant invokeToOccupant();
|
||||
}
|
||||
|
||||
+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.mixin.accessor;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.class)
|
||||
public interface BeehiveBlockEntityAccessor {
|
||||
@Accessor("stored")
|
||||
List<Object> getStored();
|
||||
@Accessor("savedFlowerPos")
|
||||
BlockPos savedFlowerPos();
|
||||
|
||||
|
||||
/**
|
||||
* Access the private static method:
|
||||
* private static void releaseOccupant(Level level, BlockPos pos, BeeData beeData, ...)
|
||||
*/
|
||||
@Invoker("releaseOccupant")
|
||||
static boolean releaseOccupant(Level level, BlockPos pos, BlockState state, BeehiveBlockEntity.Occupant occupant, @Nullable List<Entity> storedInHives, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, @Nullable BlockPos storedFlowerPos) {
|
||||
throw new AssertionError(); // Mixin will overwrite
|
||||
}
|
||||
}
|
||||
|
||||
+8
-7
@@ -8,13 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public interface CameraAccessor {
|
||||
@Accessor("level")
|
||||
BlockGetter getLevel();
|
||||
}
|
||||
@Mixin(BlockEntity.class)
|
||||
public interface BlockEntityAccessor {
|
||||
@Accessor("level") Level getLevel();
|
||||
@Accessor("worldPosition") BlockPos getWorldPosition();
|
||||
}
|
||||
@@ -27,7 +27,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(BrewingStandMenu.class)
|
||||
public abstract class BrewingStandMenuMixin {
|
||||
|
||||
@Inject(method = "<init>(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/Container;Lnet/minecraft/world/inventory/ContainerData;)V", at = @At("TAIL"))
|
||||
private void captureLevel(int containerId, Inventory playerInventory, Container brewingStandContainer, ContainerData brewingStandData, CallbackInfo ci) {
|
||||
var recipeManager = playerInventory.player.level().getRecipeManager();
|
||||
@@ -37,9 +36,4 @@ public abstract class BrewingStandMenuMixin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "quickMoveStack", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/BrewingStandMenu$PotionSlot;mayPlaceItem(Lnet/minecraft/world/item/ItemStack;)Z"))
|
||||
private boolean cobblemon$isPotionBottle(ItemStack stack, Operation<Boolean> original, @Local(argsOnly = true) Player player) {
|
||||
return BrewingStandRecipe.Companion.isBottle(stack, player.level().getRecipeManager()) || original.call(stack);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -34,7 +34,8 @@ public class AbstractClientPlayerMixin {
|
||||
} else {
|
||||
// Only modify fov through riding if the pokedex is not open
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
// Only modify fov for the driver and not the passengers
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity && player.getVehicle().getControllingPassenger() == player) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
|
||||
// Return custom fov mult for riding
|
||||
|
||||
@@ -8,87 +8,58 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
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.client.MountedPokemonAnimationRenderController;
|
||||
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.duck.CameraDuck;
|
||||
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.world.entity.Entity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
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;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public abstract class CameraMixin {
|
||||
@Shadow private Entity entity;
|
||||
@Shadow @Final private Quaternionf rotation;
|
||||
@Shadow @Final private Vector3f forwards;
|
||||
@Shadow @Final private Vector3f up;
|
||||
@Shadow @Final private Vector3f left;
|
||||
@Shadow private float xRot;
|
||||
@Shadow private float yRot;
|
||||
|
||||
public abstract class CameraMixin implements CameraDuck {
|
||||
@Shadow private float eyeHeight;
|
||||
@Shadow private float eyeHeightOld;
|
||||
@Shadow private BlockGetter level;
|
||||
@Shadow private Entity entity;
|
||||
@Final @Shadow private Vector3f forwards;
|
||||
@Final @Shadow private Vector3f up;
|
||||
@Final @Shadow private Vector3f left;
|
||||
@Shadow private float yRot;
|
||||
@Shadow private float xRot;
|
||||
|
||||
@Shadow protected abstract void setPosition(Vec3 pos);
|
||||
|
||||
@Unique private float returnTimer = 0;
|
||||
@Unique private float rollAngleStart = 0;
|
||||
@Unique Minecraft minecraft = Minecraft.getInstance();
|
||||
|
||||
@Inject(method = "setRotation", at = @At("HEAD"), cancellable = true)
|
||||
|
||||
public void cobblemon$setRotation(float f, float g, CallbackInfo ci) {
|
||||
if (!(this.entity instanceof OrientationControllable controllable)) 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.
|
||||
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;
|
||||
controller.reset();
|
||||
return;
|
||||
}
|
||||
controller.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
|
||||
cobblemon$applyRotation();
|
||||
this.returnTimer += .05F;
|
||||
ci.cancel();
|
||||
} else {
|
||||
this.returnTimer = 1;
|
||||
controller.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (controller.getOrientation() == null) return;
|
||||
cobblemon$applyRotation();
|
||||
|
||||
this.returnTimer = 0;
|
||||
this.rollAngleStart = controller.getRoll();
|
||||
ci.cancel();
|
||||
@Override public BlockGetter cobblemon$getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override public Entity cobblemon$getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override public Vector3f cobblemon$getForwards() { return forwards; }
|
||||
|
||||
@Override public Vector3f cobblemon$getUp() { return up; }
|
||||
|
||||
@Override public Vector3f cobblemon$getLeft() { return left; }
|
||||
|
||||
@Override public float cobblemon$getXRot() { return xRot; }
|
||||
@Override public void cobblemon$setXRot(float xRot) { this.xRot = xRot; }
|
||||
|
||||
@Override public float cobblemon$getYRot() { return yRot; }
|
||||
@Override public void cobblemon$setYRot(float yRot) { this.yRot = yRot; }
|
||||
|
||||
@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();
|
||||
@@ -97,49 +68,22 @@ public abstract class CameraMixin {
|
||||
|
||||
if(vehicle instanceof Rideable){
|
||||
Vec3 position = MountedCameraRenderer.INSTANCE.getCameraPosition(
|
||||
instance,
|
||||
entity,
|
||||
vehicle,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
thirdPersonReverse,
|
||||
eyeHeightOld,
|
||||
eyeHeight
|
||||
instance,
|
||||
entity,
|
||||
vehicle,
|
||||
thirdPersonReverse,
|
||||
eyeHeight,
|
||||
eyeHeightOld
|
||||
);
|
||||
|
||||
if(position != null){
|
||||
if(position != null) {
|
||||
setPosition(position);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// reset the rotation values if it is now not being ridden.
|
||||
MountedCameraRenderer.INSTANCE.setSmoothRotation(null);
|
||||
original.call(instance, x, y, z);
|
||||
}
|
||||
|
||||
@Unique
|
||||
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 = controller.getPitch();
|
||||
this.yRot = controller.getYaw();
|
||||
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
|
||||
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
|
||||
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
|
||||
}
|
||||
|
||||
@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.getThirdPersonViewBobbing()) {
|
||||
original.call(instance, zoom, dy, dx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,15 +9,21 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
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.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Mixin(GameRenderer.class)
|
||||
public class GameRendererMixin {
|
||||
@Unique
|
||||
@@ -42,4 +48,16 @@ public class GameRendererMixin {
|
||||
lastTime = newTime;
|
||||
}
|
||||
|
||||
@ModifyArg(
|
||||
method = "pick(Lnet/minecraft/world/entity/Entity;DDF)Lnet/minecraft/world/phys/HitResult;",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getEntityHitResult(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;D)Lnet/minecraft/world/phys/EntityHitResult;"
|
||||
),
|
||||
index = 4
|
||||
)
|
||||
private Predicate<Entity> filterPokemonVehicle(Predicate<Entity> original, @Local(ordinal = 0, argsOnly = true) Entity entity) {
|
||||
return (entityX) -> !(entity.getVehicle() == entityX && entityX instanceof PokemonEntity) && original.test(entityX);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.model.geom.ModelPart;
|
||||
@@ -68,6 +69,18 @@ public class HumanoidModelMixin {
|
||||
behaviour.shouldRotateRiderHead(settings, state, pokemonEntity)
|
||||
);
|
||||
|
||||
// If the player is on a rollable ride then use the ride local rotations to rotate the head
|
||||
// This is to allow the player head to face the correct direction when "freelooking"
|
||||
// TODO: find a way for this to work on built jars without borking head rotations.
|
||||
// if (entity instanceof RidePassenger playerRotater &&
|
||||
// vehicle instanceof OrientationControllable controller &&
|
||||
// controller.getOrientationController().isActive()) {
|
||||
// this.head.xRot = playerRotater.cobblemon$getRideXRot();
|
||||
// headPitch = playerRotater.cobblemon$getRideXRot();
|
||||
// this.head.yRot = playerRotater.cobblemon$getRideYRot();
|
||||
// netHeadYaw = playerRotater.cobblemon$getRideYRot();
|
||||
// }
|
||||
|
||||
if (!shouldRotatePlayerHead) {
|
||||
netHeadYaw = 0f;
|
||||
headPitch = 0f;
|
||||
|
||||
+2
-2
@@ -36,9 +36,9 @@ public class ItemInHandRendererMixin {
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V", ordinal = 1))
|
||||
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V"))
|
||||
private void cobblemon$renderHandswithItems(PoseStack instance, Quaternionf quaternion) {
|
||||
if (!(Minecraft.getInstance().player instanceof OrientationControllable controllable && controllable.getOrientationController().isActive())) {
|
||||
if (!(Minecraft.getInstance().player != null && Minecraft.getInstance().player.getVehicle() instanceof OrientationControllable controllable && controllable.getOrientationController().isActive())) {
|
||||
instance.mulPose(quaternion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,11 @@ 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.duck.PlayerDuck;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.client.CameraType;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -29,12 +31,10 @@ import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.player.Input;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
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.NotNull;
|
||||
@@ -55,6 +55,10 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
|
||||
@Unique Matrix3f cobblemon$lastOrientation;
|
||||
|
||||
@Unique float cobblemon$lastRideXRot;
|
||||
@Unique float cobblemon$lastRideYRot;
|
||||
@Unique Vec3 cobblemon$lastRideEyePos;
|
||||
|
||||
@Unique boolean cobblemon$isDoubleJumping = false;
|
||||
|
||||
@Shadow
|
||||
@@ -72,30 +76,35 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
super(clientLevel, gameProfile);
|
||||
}
|
||||
|
||||
// @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 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()));
|
||||
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
if (!vehicleController.isActive() || vehicleController.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = vehicleController.getOrientation() != null ? new Matrix3f(vehicleController.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(this.getVehicle().getId(), vehicleController.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 driver = (LocalPlayer)(Object)this;
|
||||
var vehicle = driver.getVehicle();
|
||||
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((LocalPlayer)(Object)this);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
|
||||
// If the player has just switched to riding a custom orientation ride then set their
|
||||
// x and y rots local to the vehicle rots(if the controller wasn't active and will now be active)
|
||||
// This ensures that on transition your camera stays in the same spot
|
||||
if (!vehicleController.isActive() && shouldUseCustomOrientation) {
|
||||
// Set local to the vehicle x and yrot so
|
||||
var playerRotater = (RidePassenger)driver;
|
||||
playerRotater.cobblemon$setRideXRot(Mth.wrapDegrees(driver.getXRot() - vehicle.getXRot()));
|
||||
playerRotater.cobblemon$setRideYRot(Mth.wrapDegrees(driver.getYRot() - vehicle.getYRot()));
|
||||
}
|
||||
|
||||
vehicleController.setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
@@ -115,6 +124,36 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateDriverInputPacket(driverInput));
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRiderRotationsRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this.getVehicle() instanceof PokemonEntity pokemonEntity)) return;
|
||||
|
||||
var passenger = (LocalPlayer)(Object)this;
|
||||
var playerRotater = (RidePassenger)passenger;
|
||||
|
||||
// Gather Rider Rotation info
|
||||
var rideXRot = playerRotater.cobblemon$getRideXRot();
|
||||
var rideYRot = playerRotater.cobblemon$getRideYRot();
|
||||
var rideEyePos = playerRotater.cobblemon$getRideEyePos();
|
||||
|
||||
// Check for a change in the values before sending them.
|
||||
if (cobblemon$lastRideXRot != rideXRot ||
|
||||
cobblemon$lastRideYRot != rideYRot ||
|
||||
cobblemon$lastRideEyePos != rideEyePos
|
||||
) {
|
||||
|
||||
// Update 'last' values
|
||||
cobblemon$lastRideXRot = rideXRot;
|
||||
cobblemon$lastRideYRot = rideYRot;
|
||||
cobblemon$lastRideEyePos = rideEyePos;
|
||||
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateRiderRotationPacket(rideXRot, rideYRot, rideEyePos));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(LocalPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
@@ -129,8 +168,8 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
public void stopRiding() {
|
||||
super.stopRiding();
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
if (!(this instanceof OrientationControllable controllableVehicle)) return;
|
||||
controllableVehicle.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
|
||||
@@ -161,7 +200,7 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
this.cobblemon$survivalJumpTriggerTime = 0;
|
||||
}
|
||||
else {
|
||||
this.cobblemon$survivalJumpTriggerTime = 7;
|
||||
this.cobblemon$survivalJumpTriggerTime = 12;
|
||||
}
|
||||
}
|
||||
else if (this.cobblemon$survivalJumpTriggerTime > 0) {
|
||||
@@ -188,33 +227,17 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity) {
|
||||
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemonEntity.getDelegate();
|
||||
String locatorName = delegate.getSeatLocator(this);
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(locatorName);
|
||||
|
||||
if (locator == null) {
|
||||
return super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
// Get player object
|
||||
var passenger = (LocalPlayer)(Object)this;
|
||||
var playerRotater = (RidePassenger)passenger;
|
||||
|
||||
Vec3 locatorOffset = locator != null ? new Vec3(locator.getMatrix().getTranslation(new Vector3f())) : Vec3.ZERO;
|
||||
|
||||
OrientationController controller = this.getOrientationController();
|
||||
|
||||
float currEyeHeight = this.getEyeHeight();
|
||||
Vector3f offset = new Vector3f(new Vector3f(0f, currEyeHeight - (this.getBbHeight() / 2), 0f));
|
||||
|
||||
if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON) {
|
||||
PosableModel model = VaryingModelRepository.INSTANCE.getPoser(pokemonEntity.getPokemon().getSpecies().getResourceIdentifier(), new FloatingState());
|
||||
offset.add(cobblemon$getFirstPersonOffset(model, locatorName));
|
||||
}
|
||||
|
||||
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
|
||||
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(offset));
|
||||
|
||||
Vec3 eyePosition = locatorOffset.add(pokemonEntity.position()).add(rotatedEyeHeight);
|
||||
// Gather eye position from stored 1st person camera position calculation
|
||||
var eyePosition = playerRotater.cobblemon$getRideEyePos();
|
||||
|
||||
Vec3 viewVector = this.getViewVector(partialTicks);
|
||||
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
|
||||
|
||||
return this.level()
|
||||
.clip(
|
||||
new ClipContext(
|
||||
|
||||
@@ -10,13 +10,16 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
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.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
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;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
import kotlin.Pair;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.MouseHandler;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
@@ -32,6 +35,9 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import static com.google.common.primitives.Floats.min;
|
||||
import static net.minecraft.util.Mth.lerp;
|
||||
|
||||
@Mixin(MouseHandler.class)
|
||||
public abstract class MouseHandlerMixin {
|
||||
@Shadow private double accumulatedScrollY;
|
||||
@@ -116,30 +122,31 @@ public abstract class MouseHandlerMixin {
|
||||
double cursorDeltaY,
|
||||
@Local(argsOnly = true) double d,
|
||||
@Local(argsOnly = true) double movementTime
|
||||
) {
|
||||
boolean returnValue = true;
|
||||
|
||||
) {
|
||||
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
|
||||
boolean returnValue = true;
|
||||
if (usageContext.getScanningGuiOpen()) {
|
||||
this.smoothTurnY.reset();
|
||||
this.smoothTurnX.reset();
|
||||
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6 + 0.2;
|
||||
var spyglassSensitivity = Math.pow(defaultSensitivity, 3);
|
||||
var lookSensitivity = spyglassSensitivity * 8.0;
|
||||
var sensitivity = Mth.lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
|
||||
var sensitivity = lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
|
||||
var yRotationFlip = this.minecraft.options.invertYMouse().get() ? -1 : 1;
|
||||
player.turn(this.accumulatedDX * sensitivity, (this.accumulatedDY * sensitivity * yRotationFlip));
|
||||
returnValue = false;
|
||||
}
|
||||
|
||||
var vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof PokemonEntity)) return returnValue;
|
||||
|
||||
// Clamp player rotation if riding and the vehicle demands it
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity vehicle) {
|
||||
vehicle.clampPassengerRotation(player);
|
||||
if (player.isPassenger() && vehicle instanceof PokemonEntity pokeVehicle) {
|
||||
pokeVehicle.clampPassengerRotation(player);
|
||||
}
|
||||
|
||||
if (!(player instanceof OrientationControllable controllable)) return true;
|
||||
|
||||
if (!controllable.getOrientationController().isActive()) {
|
||||
// If the ride is not orientation controllable then return and perform the normal turnPlayer logic
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle) || !controllableVehicle.getOrientationController().isActive()) {
|
||||
xMouseSmoother.reset();
|
||||
yMouseSmoother.reset();
|
||||
pitchSmoother.reset();
|
||||
@@ -148,12 +155,55 @@ public abstract class MouseHandlerMixin {
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
// Send mouse input to be interpreted into rotation
|
||||
// deltas by the ride controller
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
var lookaroundButtonPressed = Minecraft.getInstance().mouseHandler.isMiddlePressed();
|
||||
Pair<Boolean, Boolean> mouseShouldModifyDriver = ((PokemonEntity) vehicle).ifRidingAvailableSupply(new Pair(false, false), (behaviour, settings, state) -> {
|
||||
return behaviour.mouseModifiesDriverRotation(
|
||||
settings,
|
||||
state,
|
||||
(PokemonEntity) vehicle
|
||||
);
|
||||
});
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// If looking around then modify the players orientation instead and zero the mouse deltas so the mouse doesn't
|
||||
// affect the vehicle orientation when looking around.
|
||||
// If the client is a passenger it will modify these rotations and return
|
||||
//-------------------------------------------------------------------------
|
||||
if (lookaroundButtonPressed || player.getControlledVehicle() == null) {
|
||||
// Modify driver rotations
|
||||
cobblemon$setDriverRotations(player, cursorDeltaX, cursorDeltaY);
|
||||
|
||||
// If the player/passenger is not the driver then return and ignore all vehicle rotation logic
|
||||
if (player.getControlledVehicle() == null) return false;
|
||||
|
||||
// Set to zero so that vehicle rotations don't also get affected by movement.
|
||||
cursorDeltaX = 0.0;
|
||||
cursorDeltaY = 0.0;
|
||||
} else if (mouseShouldModifyDriver.getFirst()) { // If not freelooking then check modification per mouse input dimension
|
||||
cobblemon$setDriverRotations(player, cursorDeltaX, 0.0);
|
||||
cursorDeltaX = 0.0;
|
||||
} else if (mouseShouldModifyDriver.getSecond()) {
|
||||
cobblemon$setDriverRotations(player, 0.0, cursorDeltaY);
|
||||
cursorDeltaY = 0.0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Smoothly return driver rotations to zero when needed
|
||||
//-------------------------------------------------------------------------
|
||||
var playerRotater = (RidePassenger)player;
|
||||
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getFirst()){
|
||||
playerRotater.cobblemon$setRideYRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideYRot()), 0.0f));
|
||||
}
|
||||
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getSecond()) {
|
||||
playerRotater.cobblemon$setRideXRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideXRot()), 0.0f));
|
||||
}
|
||||
|
||||
// Send mouse input to be interpreted into rotation deltas by the ride controller
|
||||
Vec3 angVecMouse = cobblemon$getRideMouseRotation(cursorDeltaX, cursorDeltaY, movementTime);
|
||||
|
||||
// Perform Rotation using mouse influenced rotation deltas.
|
||||
controllable.getOrientationController().rotate(
|
||||
vehicleController.rotate(
|
||||
(float) angVecMouse.x,
|
||||
(float) angVecMouse.y,
|
||||
(float) angVecMouse.z
|
||||
@@ -163,18 +213,17 @@ public abstract class MouseHandlerMixin {
|
||||
var angRot = cobblemon$getAngularVelocity(movementTime);
|
||||
|
||||
// Apply smoothing if requested by the controller.
|
||||
// This Might be best if done by the controller itself?
|
||||
if(cobblemon$shouldUseAngVelSmoothing()) {
|
||||
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);
|
||||
vehicleController.rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
// Otherwise simply apply the smoothing
|
||||
else {
|
||||
controllable.getOrientationController().rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
vehicleController.rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
}
|
||||
return false;
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At("HEAD"))
|
||||
@@ -186,10 +235,11 @@ public abstract class MouseHandlerMixin {
|
||||
@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.player.getVehicle() instanceof OrientationControllable vehicleControllable)) return;
|
||||
if (!(vehicleControllable.getOrientationController() instanceof OrientationController vehicleController)) return;
|
||||
if (vehicleController.getOrientation() == null) return;
|
||||
if (minecraft.isPaused()) return;
|
||||
if (isMouseGrabbed()) return;
|
||||
if (this.isMouseGrabbed()) return; // return if turnPlayer() has already run this pass
|
||||
|
||||
this.turnPlayer(cobblemon$timeDelta);
|
||||
}
|
||||
@@ -251,6 +301,21 @@ public abstract class MouseHandlerMixin {
|
||||
return Math.pow(sensitivity, 3);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$setDriverRotations(LocalPlayer player, double cursorDeltaX, double cursorDeltaY) {
|
||||
// the vanilla turn() method redone so that it uses rideRotations.
|
||||
float f = (float)cursorDeltaY * 0.15F; // Note: turn() uses xRot for pitch (up/down)
|
||||
float g = (float)cursorDeltaX * 0.15F; // Note: turn() uses yRot for yaw (left/right)
|
||||
var playerRotater = (RidePassenger)player;
|
||||
playerRotater.cobblemon$setRideXRot(playerRotater.cobblemon$getRideXRot() + f);
|
||||
playerRotater.cobblemon$setRideYRot(playerRotater.cobblemon$getRideYRot() + g);
|
||||
playerRotater.cobblemon$setRideXRot(Mth.clamp(playerRotater.cobblemon$getRideXRot(), -90.0F, 90.0F));
|
||||
playerRotater.cobblemon$setRideYRot(Mth.clamp(playerRotater.cobblemon$getRideYRot(), -105.0F, 105.0F));
|
||||
if (player.getVehicle() != null) {
|
||||
player.getVehicle().onPassengerTurned(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseAngVelSmoothing() {
|
||||
var player = minecraft.player;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import net.minecraft.client.CameraType;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.Options;
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Options.class)
|
||||
public abstract class OptionsMixin {
|
||||
|
||||
/**
|
||||
* Only allow third person on rollables when motion sick cam is enabled
|
||||
*/
|
||||
@Inject(
|
||||
method = "getCameraType",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$forceThirdPerson(CallbackInfoReturnable<CameraType> cir) {
|
||||
var mc = Minecraft.getInstance();
|
||||
if(!(mc.player instanceof Player player)) return;
|
||||
if(!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
if(vehicle.getOrientationController() == null) return;
|
||||
|
||||
// Force third person if on an active rollable vehicle and roll is disabled.
|
||||
if (Cobblemon.config.getDisableRoll() && vehicle.getOrientationController().isActive()) {
|
||||
cir.setReturnValue(CameraType.THIRD_PERSON_BACK);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -52,7 +52,7 @@ public class RecipeBookCategoriesMixin {
|
||||
types.add(cobblemon$createCategory("COOKING_POT_SEARCH", $VALUES.length, new ItemStack(Items.COMPASS)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_FOODS", $VALUES.length + 1, new ItemStack(CobblemonItems.LEEK_AND_POTATO_STEW)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_MEDICINES", $VALUES.length + 2, new ItemStack(CobblemonItems.POTION)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_COMPLEX_DISHES", $VALUES.length + 3, new ItemStack(CobblemonItems.POKE_PUFF)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_COMPLEX_DISHES", $VALUES.length + 3, new ItemStack(CobblemonItems.APRIJUICE_RED)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_MISC", $VALUES.length + 4, new ItemStack(CobblemonItems.PROTEIN)));
|
||||
$VALUES = types.toArray(RecipeBookCategories[]::new);
|
||||
}
|
||||
|
||||
@@ -8,20 +8,25 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.entity;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Entity.class)
|
||||
public abstract class EntityMixin {
|
||||
@@ -57,5 +62,43 @@ public abstract class EntityMixin {
|
||||
return original.call(entity);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "getEyePosition(F)Lnet/minecraft/world/phys/Vec3;",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$modifyEyePosition_partial(float partialTicks, CallbackInfoReturnable<Vec3> cir) {
|
||||
var entity = (Entity)(Object)this;
|
||||
if (entity.level().isClientSide) return;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player instanceof RidePassenger ridePassenger)) return;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
if (vehicleController == null) return;
|
||||
|
||||
|
||||
// TODO: Determine if it needs partialtick involved.
|
||||
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
|
||||
cir.setReturnValue(customEyePos);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "getEyePosition()Lnet/minecraft/world/phys/Vec3;",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$modifyEyePosition_noPartial(CallbackInfoReturnable<Vec3> cir) {
|
||||
var entity = (Entity)(Object)this;
|
||||
if (entity.level().isClientSide) return;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player instanceof RidePassenger ridePassenger)) return;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
if (vehicleController == null) return;
|
||||
|
||||
// TODO: Determine if it needs partialtick involved.
|
||||
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
|
||||
cir.setReturnValue(customEyePos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.api.drop.ItemDropEntry
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
|
||||
import com.cobblemon.mod.common.api.interaction.RequestManager
|
||||
import com.cobblemon.mod.common.api.molang.MoLangLoadedFilesCache
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.permission.PermissionValidator
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculator
|
||||
@@ -44,6 +45,7 @@ import com.cobblemon.mod.common.api.spawning.CobblemonSpawningZoneGenerator
|
||||
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePositionResolver
|
||||
import com.cobblemon.mod.common.api.spawning.SpawningZoneGenerator
|
||||
import com.cobblemon.mod.common.api.starter.StarterHandler
|
||||
import com.cobblemon.mod.common.api.stats.CobblemonStats
|
||||
import com.cobblemon.mod.common.api.storage.PokemonStoreManager
|
||||
import com.cobblemon.mod.common.api.storage.adapter.conversions.ReforgedConversion
|
||||
import com.cobblemon.mod.common.api.storage.adapter.database.MongoDBStoreAdapter
|
||||
@@ -79,14 +81,18 @@ import com.cobblemon.mod.common.events.EntityCallbackHandler
|
||||
import com.cobblemon.mod.common.events.CallbackHandler
|
||||
import com.cobblemon.mod.common.events.PokedexHandler
|
||||
import com.cobblemon.mod.common.events.ServerTickHandler
|
||||
import com.cobblemon.mod.common.events.StatHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
||||
import com.cobblemon.mod.common.permission.LaxPermissionValidator
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.aspects.CHARACTERISTIC_RAINBOW_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.COSMETIC_SLOT_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
|
||||
import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeature
|
||||
import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.properties.*
|
||||
@@ -161,6 +167,8 @@ object Cobblemon {
|
||||
|
||||
val serverPlayerStructs = mutableMapOf<UUID, ObjectValue<Player>>()
|
||||
|
||||
val statistics: CobblemonStats = CobblemonStats
|
||||
|
||||
@JvmStatic
|
||||
val builtinPacks = listOf<CobblemonPack>(
|
||||
CobblemonPack(id = "adorncompatibility", name = "Adorn Compatibility", packType = PackType.CLIENT_RESOURCES, activationBehaviour = ResourcePackActivationBehaviour.ALWAYS_ENABLED, neededMods = setOf("adorn")),
|
||||
@@ -293,6 +301,7 @@ object Cobblemon {
|
||||
SHINY_ASPECT.register()
|
||||
GENDER_ASPECT.register()
|
||||
COSMETIC_SLOT_ASPECT.register()
|
||||
CHARACTERISTIC_RAINBOW_ASPECT.register()
|
||||
|
||||
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
|
||||
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
|
||||
@@ -300,7 +309,13 @@ object Cobblemon {
|
||||
|
||||
SpeciesFeatures.register(
|
||||
DataKeys.HAS_BEEN_SHEARED,
|
||||
FlagSpeciesFeatureProvider(keys = listOf(DataKeys.HAS_BEEN_SHEARED), default = false))
|
||||
FlagSpeciesFeatureProvider(keys = listOf(DataKeys.HAS_BEEN_SHEARED), default = false)
|
||||
)
|
||||
|
||||
SpeciesFeatures.register(
|
||||
SlowpokeTailRegrowthSpeciesFeature.NAME,
|
||||
SlowpokeTailRegrowthSpeciesFeatureProvider
|
||||
)
|
||||
|
||||
CustomPokemonProperty.register(UncatchableProperty)
|
||||
CustomPokemonProperty.register(BattleCloneProperty)
|
||||
@@ -329,6 +344,7 @@ object Cobblemon {
|
||||
}
|
||||
PlatformEvents.SERVER_STARTING.subscribe { event ->
|
||||
val server = event.server
|
||||
MoLangLoadedFilesCache.initialize(server)
|
||||
playerDataManager = PlayerInstancedDataStoreManager().also { it.setup(server) }
|
||||
|
||||
val mongoClient: MongoClient?
|
||||
@@ -431,6 +447,7 @@ object Cobblemon {
|
||||
fun registerEventHandlers() {
|
||||
AdvancementHandler.registerListeners()
|
||||
PokedexHandler.registerListeners()
|
||||
StatHandler.registerListeners()
|
||||
}
|
||||
|
||||
fun getLevel(dimension: ResourceKey<Level>): Level? {
|
||||
|
||||
@@ -11,16 +11,26 @@ package com.cobblemon.mod.common
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
object CobblemonActivities {
|
||||
@JvmField
|
||||
val activities = mutableListOf<Activity>()
|
||||
@JvmField
|
||||
val BATTLING = register(Activity("battling"))
|
||||
@JvmField
|
||||
val ACTION_EFFECT = register(Activity("action_effect"))
|
||||
@JvmField
|
||||
val NPC_CHATTING = register(Activity("npc_chatting"))
|
||||
@JvmField
|
||||
val POKEMON_SLEEPING_ACTIVITY = register(Activity("pokemon_sleeping"))
|
||||
@JvmField
|
||||
val POKEMON_GROW_CROP = register(Activity("pokemon_grow_crop"))
|
||||
@JvmField
|
||||
val POKEMON_SLEEP_ON_TRAINER_BED = register(Activity("pokemon_sleep_on_trainer_bed"))
|
||||
@JvmField
|
||||
val POKEMON_HERD = register(Activity("pokemon_herd"))
|
||||
@JvmField
|
||||
val POKEMON_POLLINATION = register(Activity("pokemon_pollination"))
|
||||
|
||||
@JvmStatic
|
||||
fun register(activity: Activity): Activity {
|
||||
activities.add(activity)
|
||||
return activity
|
||||
|
||||
@@ -60,13 +60,13 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
|
||||
// Evolution Ores
|
||||
@JvmField
|
||||
val DAWN_STONE_ORE = evolutionStoneOre("dawn_stone_ore")
|
||||
val DAWN_STONE_ORE = evolutionStoneOre("dawn_stone_ore", 7)
|
||||
@JvmField
|
||||
val DUSK_STONE_ORE = evolutionStoneOre("dusk_stone_ore")
|
||||
@JvmField
|
||||
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore")
|
||||
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore", 10)
|
||||
@JvmField
|
||||
val NETHER_FIRE_STONE_ORE = evolutionStoneOre("nether_fire_stone_ore")
|
||||
val NETHER_FIRE_STONE_ORE = this.create("nether_fire_stone_ore", DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.of().mapColor(MapColor.NETHER).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(3.0F, 3.0F).sound(SoundType.NETHER_ORE).lightLevel{10}))
|
||||
@JvmField
|
||||
val ICE_STONE_ORE = evolutionStoneOre("ice_stone_ore")
|
||||
@JvmField
|
||||
@@ -74,24 +74,24 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val MOON_STONE_ORE = evolutionStoneOre("moon_stone_ore")
|
||||
@JvmField
|
||||
val DRIPSTONE_MOON_STONE_ORE = evolutionStoneOre("dripstone_moon_stone_ore")
|
||||
val DRIPSTONE_MOON_STONE_ORE = this.create("dripstone_moon_stone_ore", DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BROWN).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(3.0F, 3.0F).sound(SoundType.DRIPSTONE_BLOCK)))
|
||||
@JvmField
|
||||
val SHINY_STONE_ORE = evolutionStoneOre("shiny_stone_ore")
|
||||
val SHINY_STONE_ORE = evolutionStoneOre("shiny_stone_ore", 12)
|
||||
@JvmField
|
||||
val SUN_STONE_ORE = evolutionStoneOre("sun_stone_ore")
|
||||
val SUN_STONE_ORE = evolutionStoneOre("sun_stone_ore", 2)
|
||||
@JvmField
|
||||
val TERRACOTTA_SUN_STONE_ORE = evolutionStoneOre("terracotta_sun_stone_ore")
|
||||
val TERRACOTTA_SUN_STONE_ORE = this.create("terracotta_sun_stone_ore", DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(3.0F, 3.0F).lightLevel{2}))
|
||||
@JvmField
|
||||
val THUNDER_STONE_ORE = evolutionStoneOre("thunder_stone_ore")
|
||||
val THUNDER_STONE_ORE = evolutionStoneOre("thunder_stone_ore", 6)
|
||||
@JvmField
|
||||
val WATER_STONE_ORE = evolutionStoneOre("water_stone_ore")
|
||||
|
||||
@JvmField
|
||||
val DEEPSLATE_DAWN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_dawn_stone_ore")
|
||||
val DEEPSLATE_DAWN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_dawn_stone_ore", 7)
|
||||
@JvmField
|
||||
val DEEPSLATE_DUSK_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_dusk_stone_ore")
|
||||
@JvmField
|
||||
val DEEPSLATE_FIRE_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_fire_stone_ore")
|
||||
val DEEPSLATE_FIRE_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_fire_stone_ore", 10)
|
||||
@JvmField
|
||||
val DEEPSLATE_ICE_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_ice_stone_ore")
|
||||
@JvmField
|
||||
@@ -99,11 +99,11 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val DEEPSLATE_MOON_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_moon_stone_ore")
|
||||
@JvmField
|
||||
val DEEPSLATE_SHINY_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_shiny_stone_ore")
|
||||
val DEEPSLATE_SHINY_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_shiny_stone_ore", 12)
|
||||
@JvmField
|
||||
val DEEPSLATE_SUN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_sun_stone_ore")
|
||||
val DEEPSLATE_SUN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_sun_stone_ore", 2)
|
||||
@JvmField
|
||||
val DEEPSLATE_THUNDER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_thunder_stone_ore")
|
||||
val DEEPSLATE_THUNDER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_thunder_stone_ore", 6)
|
||||
@JvmField
|
||||
val DEEPSLATE_WATER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_water_stone_ore")
|
||||
|
||||
@@ -454,7 +454,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
|
||||
@JvmField
|
||||
val SOUL_CAMPFIRE = create("soul_campfire", CampfireBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOD).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.PODZOL).strength(2.0F).lightLevel{9}, true))
|
||||
|
||||
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH = create("relic_coin_pouch", CoinPouchBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.RELIC_COIN_POUCH_SOUNDS).pushReaction(PushReaction.DESTROY).noOcclusion(), true))
|
||||
@JvmField
|
||||
@@ -577,74 +577,145 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
|
||||
private val berries = mutableMapOf<ResourceLocation, BerryBlock>()
|
||||
|
||||
@JvmField
|
||||
val AGUAV_BERRY = this.berryBlock("aguav")
|
||||
@JvmField
|
||||
val APICOT_BERRY = this.berryBlock("apicot")
|
||||
@JvmField
|
||||
val ASPEAR_BERRY = this.berryBlock("aspear")
|
||||
@JvmField
|
||||
val BABIRI_BERRY = this.berryBlock("babiri")
|
||||
@JvmField
|
||||
val BELUE_BERRY = this.berryBlock("belue")
|
||||
@JvmField
|
||||
val BLUK_BERRY = this.berryBlock("bluk")
|
||||
@JvmField
|
||||
val CHARTI_BERRY = this.berryBlock("charti")
|
||||
@JvmField
|
||||
val CHERI_BERRY = this.berryBlock("cheri")
|
||||
@JvmField
|
||||
val CHESTO_BERRY = this.berryBlock("chesto")
|
||||
@JvmField
|
||||
val CHILAN_BERRY = this.berryBlock("chilan")
|
||||
@JvmField
|
||||
val CHOPLE_BERRY = this.berryBlock("chople")
|
||||
@JvmField
|
||||
val COBA_BERRY = this.berryBlock("coba")
|
||||
@JvmField
|
||||
val COLBUR_BERRY = this.berryBlock("colbur")
|
||||
@JvmField
|
||||
val CORNN_BERRY = this.berryBlock("cornn")
|
||||
@JvmField
|
||||
val CUSTAP_BERRY = this.berryBlock("custap")
|
||||
@JvmField
|
||||
val DURIN_BERRY = this.berryBlock("durin")
|
||||
@JvmField
|
||||
val EGGANT_BERRY = this.berryBlock("eggant")
|
||||
@JvmField
|
||||
val ENIGMA_BERRY = this.berryBlock("enigma")
|
||||
@JvmField
|
||||
val FIGY_BERRY = this.berryBlock("figy")
|
||||
@JvmField
|
||||
val GANLON_BERRY = this.berryBlock("ganlon")
|
||||
@JvmField
|
||||
val GREPA_BERRY = this.berryBlock("grepa")
|
||||
@JvmField
|
||||
val HABAN_BERRY = this.berryBlock("haban")
|
||||
@JvmField
|
||||
val HONDEW_BERRY = this.berryBlock("hondew")
|
||||
@JvmField
|
||||
val HOPO_BERRY = this.berryBlock("hopo")
|
||||
@JvmField
|
||||
val IAPAPA_BERRY = this.berryBlock("iapapa")
|
||||
@JvmField
|
||||
val JABOCA_BERRY = this.berryBlock("jaboca")
|
||||
@JvmField
|
||||
val KASIB_BERRY = this.berryBlock("kasib")
|
||||
@JvmField
|
||||
val KEBIA_BERRY = this.berryBlock("kebia")
|
||||
@JvmField
|
||||
val KEE_BERRY = this.berryBlock("kee")
|
||||
@JvmField
|
||||
val KELPSY_BERRY = this.berryBlock("kelpsy")
|
||||
@JvmField
|
||||
val LANSAT_BERRY = this.berryBlock("lansat")
|
||||
@JvmField
|
||||
val LEPPA_BERRY = this.berryBlock("leppa")
|
||||
@JvmField
|
||||
val LIECHI_BERRY = this.berryBlock("liechi")
|
||||
@JvmField
|
||||
val LUM_BERRY = this.berryBlock("lum")
|
||||
@JvmField
|
||||
val MAGO_BERRY = this.berryBlock("mago")
|
||||
@JvmField
|
||||
val MAGOST_BERRY = this.berryBlock("magost")
|
||||
@JvmField
|
||||
val MARANGA_BERRY = this.berryBlock("maranga")
|
||||
@JvmField
|
||||
val MICLE_BERRY = this.berryBlock("micle")
|
||||
@JvmField
|
||||
val NANAB_BERRY = this.berryBlock("nanab")
|
||||
@JvmField
|
||||
val NOMEL_BERRY = this.berryBlock("nomel")
|
||||
@JvmField
|
||||
val OCCA_BERRY = this.berryBlock("occa")
|
||||
@JvmField
|
||||
val ORAN_BERRY = this.berryBlock("oran")
|
||||
@JvmField
|
||||
val PAMTRE_BERRY = this.berryBlock("pamtre")
|
||||
@JvmField
|
||||
val PASSHO_BERRY = this.berryBlock("passho")
|
||||
@JvmField
|
||||
val PAYAPA_BERRY = this.berryBlock("payapa")
|
||||
@JvmField
|
||||
val PECHA_BERRY = this.berryBlock("pecha")
|
||||
@JvmField
|
||||
val PERSIM_BERRY = this.berryBlock("persim")
|
||||
@JvmField
|
||||
val PETAYA_BERRY = this.berryBlock("petaya")
|
||||
@JvmField
|
||||
val PINAP_BERRY = this.berryBlock("pinap")
|
||||
@JvmField
|
||||
val POMEG_BERRY = this.berryBlock("pomeg")
|
||||
@JvmField
|
||||
val QUALOT_BERRY = this.berryBlock("qualot")
|
||||
@JvmField
|
||||
val RABUTA_BERRY = this.berryBlock("rabuta")
|
||||
@JvmField
|
||||
val RAWST_BERRY = this.berryBlock("rawst")
|
||||
@JvmField
|
||||
val RAZZ_BERRY = this.berryBlock("razz")
|
||||
@JvmField
|
||||
val RINDO_BERRY = this.berryBlock("rindo")
|
||||
@JvmField
|
||||
val ROSELI_BERRY = this.berryBlock("roseli")
|
||||
@JvmField
|
||||
val ROWAP_BERRY = this.berryBlock("rowap")
|
||||
@JvmField
|
||||
val SALAC_BERRY = this.berryBlock("salac")
|
||||
@JvmField
|
||||
val SHUCA_BERRY = this.berryBlock("shuca")
|
||||
@JvmField
|
||||
val SITRUS_BERRY = this.berryBlock("sitrus")
|
||||
@JvmField
|
||||
val SPELON_BERRY = this.berryBlock("spelon")
|
||||
@JvmField
|
||||
val STARF_BERRY = this.berryBlock("starf")
|
||||
@JvmField
|
||||
val TAMATO_BERRY = this.berryBlock("tamato")
|
||||
@JvmField
|
||||
val TANGA_BERRY = this.berryBlock("tanga")
|
||||
@JvmField
|
||||
val TOUGA_BERRY = this.berryBlock("touga")
|
||||
@JvmField
|
||||
val WACAN_BERRY = this.berryBlock("wacan")
|
||||
@JvmField
|
||||
val WATMEL_BERRY = this.berryBlock("watmel")
|
||||
@JvmField
|
||||
val WEPEAR_BERRY = this.berryBlock("wepear")
|
||||
@JvmField
|
||||
val WIKI_BERRY = this.berryBlock("wiki")
|
||||
@JvmField
|
||||
val YACHE_BERRY = this.berryBlock("yache")
|
||||
//val BINDING_SOIL = this.create("binding_soil", BindingSoilBlock(BlockBehaviour.Properties.of()))
|
||||
|
||||
@@ -712,8 +783,10 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
}
|
||||
|
||||
private fun evolutionStoneOre(name: String) = this.create(name, DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.ofFullCopy(Blocks.IRON_ORE)))
|
||||
private fun evolutionStoneOre(name: String, lightLevel: Int) = this.create(name, DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.ofFullCopy(Blocks.IRON_ORE).lightLevel { lightLevel }))
|
||||
|
||||
private fun deepslateEvolutionStoneOre(name: String) = this.create(name, DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.ofFullCopy(Blocks.DEEPSLATE_IRON_ORE)))
|
||||
private fun deepslateEvolutionStoneOre(name: String, lightLevel: Int) = this.create(name, DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.ofFullCopy(Blocks.DEEPSLATE_IRON_ORE).lightLevel { lightLevel }))
|
||||
|
||||
/**
|
||||
* Helper method for creating leaves
|
||||
|
||||
@@ -43,6 +43,7 @@ object CobblemonCosmeticItems : JsonDataRegistry<CosmeticItemAssignment> {
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.create()
|
||||
|
||||
@JvmField
|
||||
val cosmeticItems = mutableListOf<CosmeticItemAssignment>()
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, CosmeticItemAssignment>) {
|
||||
@@ -55,7 +56,9 @@ object CobblemonCosmeticItems : JsonDataRegistry<CosmeticItemAssignment> {
|
||||
CosmeticItemAssignmentSyncPacket(cosmeticItems).sendToPlayer(player)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun findValidForPokemon(pokemon: Pokemon) = cosmeticItems.filter { it.pokemon.any { it.matches(pokemon) } }
|
||||
@JvmStatic
|
||||
fun findValidCosmeticForPokemonAndItem(registryAccess: RegistryAccess, pokemon: Pokemon, itemStack: ItemStack) = cosmeticItems
|
||||
.filter { it.pokemon.any { it.matches(pokemon) } }
|
||||
.flatMap { it.cosmeticItems }
|
||||
|
||||
@@ -21,56 +21,73 @@ import net.minecraft.resources.ResourceLocation
|
||||
|
||||
object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>, ResourceKey<Registry<DataComponentType<*>>>, DataComponentType<*>>() {
|
||||
|
||||
@JvmField
|
||||
val POKEMON_ITEM: DataComponentType<PokemonItemComponent> = create("pokemon_item", DataComponentType.builder<PokemonItemComponent>()
|
||||
.persistent(PokemonItemComponent.CODEC)
|
||||
.networkSynchronized(PokemonItemComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val HELD_ITEM_EFFECT: DataComponentType<HeldItemEffectComponent> = create("held_item_effect", DataComponentType.builder<HeldItemEffectComponent>()
|
||||
.persistent(HeldItemEffectComponent.CODEC)
|
||||
.networkSynchronized(HeldItemEffectComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val BAIT: DataComponentType<RodBaitComponent> = create("bait", DataComponentType.builder<RodBaitComponent>()
|
||||
.persistent(RodBaitComponent.CODEC)
|
||||
.networkSynchronized(RodBaitComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val POT_DATA: DataComponentType<PotComponent> = create("cooking_pot_item", DataComponentType.builder<PotComponent>()
|
||||
.persistent(PotComponent.CODEC)
|
||||
.networkSynchronized(PotComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val BAIT_EFFECTS: DataComponentType<BaitEffectsComponent> = create("bait_effects", DataComponentType.builder<BaitEffectsComponent>()
|
||||
.persistent(BaitEffectsComponent.CODEC)
|
||||
.networkSynchronized(BaitEffectsComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val FLAVOUR: DataComponentType<FlavourComponent> = create("flavour", DataComponentType.builder<FlavourComponent>()
|
||||
.persistent(FlavourComponent.CODEC)
|
||||
.networkSynchronized(FlavourComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val RIDE_BOOST: DataComponentType<RideBoostsComponent> = create("ride_boosts", DataComponentType.builder<RideBoostsComponent>()
|
||||
.persistent(RideBoostsComponent.CODEC)
|
||||
.networkSynchronized(RideBoostsComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val FOOD_COLOUR: DataComponentType<FoodColourComponent> = create("food_colour", DataComponentType.builder<FoodColourComponent>()
|
||||
.persistent(FoodColourComponent.CODEC)
|
||||
.networkSynchronized(FoodColourComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val INGREDIENT: DataComponentType<IngredientComponent> = create("ingredient", DataComponentType.builder<IngredientComponent>()
|
||||
.persistent(IngredientComponent.CODEC)
|
||||
.networkSynchronized(IngredientComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val FOOD: DataComponentType<FoodComponent> = create("food", DataComponentType.builder<FoodComponent>()
|
||||
.persistent(FoodComponent.CODEC)
|
||||
.networkSynchronized(FoodComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val MOB_EFFECTS: DataComponentType<MobEffectsComponent> = create("mob_effects", DataComponentType.builder<MobEffectsComponent>()
|
||||
.persistent(MobEffectsComponent.CODEC)
|
||||
.networkSynchronized(MobEffectsComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val CRAFTED: DataComponentType<Boolean> = create("crafted", DataComponentType.builder<Boolean>()
|
||||
.persistent(Codec.BOOL)
|
||||
.networkSynchronized(ByteBufCodecs.BOOL)
|
||||
@@ -82,6 +99,7 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:cooking_pot_item"), POT_DATA)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:bait_effects"), BAIT_EFFECTS)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:flavour"), FLAVOUR)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:ride_boosts"), RIDE_BOOST)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food_colour"), FOOD_COLOUR)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:ingredient"), INGREDIENT)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food"), FOOD)
|
||||
|
||||
@@ -36,7 +36,7 @@ import com.cobblemon.mod.common.item.berry.PPRestoringBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.food.PonigiriItem
|
||||
import com.cobblemon.mod.common.item.interactive.PonigiriItem
|
||||
import com.cobblemon.mod.common.item.food.SinisterTeaItem
|
||||
import com.cobblemon.mod.common.item.interactive.*
|
||||
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
|
||||
@@ -382,8 +382,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val SINISTER_TEA = create("sinister_tea", SinisterTeaItem())
|
||||
|
||||
@JvmField
|
||||
val POKE_PUFF = pokepuffItem("poke_puff")
|
||||
// @JvmField
|
||||
// val POKE_PUFF = pokepuffItem("poke_puff")
|
||||
|
||||
// FOODS
|
||||
@JvmField
|
||||
@@ -517,6 +517,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField val RAWST_BERRY = berryItem("rawst", StatusCuringBerryItem(CobblemonBlocks.RAWST_BERRY, Statuses.BURN))
|
||||
@JvmField val ASPEAR_BERRY = berryItem("aspear", StatusCuringBerryItem(CobblemonBlocks.ASPEAR_BERRY, Statuses.FROZEN))
|
||||
@JvmField val PERSIM_BERRY = berryItem("persim", VolatileCuringBerryItem(CobblemonBlocks.PERSIM_BERRY, "confusion"))
|
||||
@JvmField val EGGANT_BERRY = berryItem("eggant", VolatileCuringBerryItem(CobblemonBlocks.EGGANT_BERRY, "attract"))
|
||||
@JvmField val RAZZ_BERRY = berryItem("razz", CobblemonBlocks.RAZZ_BERRY)
|
||||
@JvmField val BLUK_BERRY = berryItem("bluk", CobblemonBlocks.BLUK_BERRY)
|
||||
@JvmField val NANAB_BERRY = berryItem("nanab", CobblemonBlocks.NANAB_BERRY)
|
||||
@@ -682,7 +683,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
}
|
||||
})
|
||||
@JvmField
|
||||
val ENERGY_ROOT = compostableItem("energy_root", EnergyRootItem(CobblemonBlocks.ENERGY_ROOT, Properties()), 0.60f)
|
||||
val ENERGY_ROOT = compostableItem("energy_root", EnergyRootItem(CobblemonBlocks.ENERGY_ROOT, Properties()), 0.65f)
|
||||
@JvmField
|
||||
val REVIVAL_HERB = compostableItem("revival_herb", RevivalHerbItem(CobblemonBlocks.REVIVAL_HERB))
|
||||
@JvmField
|
||||
@@ -692,11 +693,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val REMEDY = compostableItem("remedy", RemedyItem(RemedyItem.NORMAL), 0.65f)
|
||||
@JvmField
|
||||
val FINE_REMEDY = compostableItem("fine_remedy", RemedyItem(RemedyItem.FINE), 0.75f)
|
||||
val FINE_REMEDY = compostableItem("fine_remedy", RemedyItem(RemedyItem.FINE), 0.85f)
|
||||
@JvmField
|
||||
val SUPERB_REMEDY = compostableItem("superb_remedy", RemedyItem(RemedyItem.SUPERB), 0.85f)
|
||||
val SUPERB_REMEDY = compostableItem("superb_remedy", RemedyItem(RemedyItem.SUPERB), 1f)
|
||||
@JvmField
|
||||
val MOOMOO_MILK = create("moomoo_milk", CobblemonItem(Item.Properties().craftRemainder(Items.GLASS_BOTTLE).stacksTo((16))))
|
||||
val MOOMOO_MILK = create("moomoo_milk", MoomooMilk(Item.Properties().craftRemainder(Items.GLASS_BOTTLE).stacksTo((16))))
|
||||
|
||||
@JvmField
|
||||
val POTION = create("potion", PotionItem(PotionType.POTION))
|
||||
@@ -914,7 +915,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val ASSAULT_VEST = heldItem("assault_vest")
|
||||
@JvmField
|
||||
val BIG_ROOT = compostableBlockItem("big_root", CobblemonBlocks.BIG_ROOT, 0.40f)
|
||||
val BIG_ROOT = compostableBlockItem("big_root", CobblemonBlocks.BIG_ROOT, 0.30f)
|
||||
@JvmField
|
||||
val BINDING_BAND = heldItem("binding_band")
|
||||
@JvmField
|
||||
@@ -1062,15 +1063,15 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val ZOOM_LENS = heldItem("zoom_lens")
|
||||
@JvmField
|
||||
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 1F)
|
||||
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 0.85F)
|
||||
@JvmField
|
||||
val MIRROR_HERB = compostableHeldItem("mirror_herb", null, 1F)
|
||||
val MIRROR_HERB = compostableHeldItem("mirror_herb", null, 0.85F)
|
||||
@JvmField
|
||||
val MISTY_SEED = heldItem("misty_seed")
|
||||
@JvmField
|
||||
val POWER_HERB = compostableHeldItem("power_herb", null, 1F)
|
||||
val POWER_HERB = compostableHeldItem("power_herb", null, 0.85F)
|
||||
@JvmField
|
||||
val WHITE_HERB = compostableHeldItem("white_herb", null, 1F)
|
||||
val WHITE_HERB = compostableHeldItem("white_herb", null, 0.85F)
|
||||
@JvmField
|
||||
val BRIGHT_POWDER = heldItem("bright_powder")
|
||||
@JvmField
|
||||
|
||||
@@ -12,9 +12,12 @@ import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.mechanics.AprijuicesMechanic
|
||||
import com.cobblemon.mod.common.mechanics.BerriesMechanic
|
||||
import com.cobblemon.mod.common.mechanics.PotionsMechanic
|
||||
import com.cobblemon.mod.common.mechanics.RemediesMechanic
|
||||
import com.cobblemon.mod.common.mechanics.SlowpokeTailsMechanic
|
||||
import com.cobblemon.mod.common.net.messages.client.data.CobblemonMechanicsSyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -37,13 +40,25 @@ object CobblemonMechanics : DataRegistry {
|
||||
var remedies = RemediesMechanic()
|
||||
var berries = BerriesMechanic()
|
||||
var potions = PotionsMechanic()
|
||||
var aprijuices = AprijuicesMechanic()
|
||||
var slowpokeTails = SlowpokeTailsMechanic()
|
||||
|
||||
override fun sync(player: ServerPlayer) {}
|
||||
override fun sync(player: ServerPlayer) {
|
||||
CobblemonMechanicsSyncPacket(
|
||||
this.remedies,
|
||||
this.berries,
|
||||
this.potions,
|
||||
this.aprijuices,
|
||||
this.slowpokeTails
|
||||
).sendToPlayer(player)
|
||||
}
|
||||
|
||||
override fun reload(manager: ResourceManager) {
|
||||
remedies = loadMechanic(manager, "remedies", RemediesMechanic::class.java)
|
||||
berries = loadMechanic(manager, "berries", BerriesMechanic::class.java)
|
||||
potions = loadMechanic(manager, "potions", PotionsMechanic::class.java)
|
||||
aprijuices = loadMechanic(manager, "aprijuices", AprijuicesMechanic::class.java)
|
||||
slowpokeTails = loadMechanic(manager, "slowpoke_tails", SlowpokeTailsMechanic::class.java)
|
||||
}
|
||||
|
||||
private fun <T> loadMechanic(manager: ResourceManager, name: String, clazz: Class<T>): T {
|
||||
|
||||
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.ListCodec
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import net.minecraft.core.UUIDUtil
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.GlobalPos
|
||||
import net.minecraft.core.UUIDUtil
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import java.util.*
|
||||
|
||||
object CobblemonMemories {
|
||||
val memories = mutableMapOf<String, MemoryModuleType<*>>()
|
||||
@@ -30,46 +30,80 @@ object CobblemonMemories {
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@JvmField
|
||||
val BATTLING_POKEMON = register("battling_pokemon", ListCodec(UUIDUtil.CODEC, 0, 31))
|
||||
@JvmField
|
||||
val NPC_BATTLING = register("npc_battling", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val DIALOGUES = register<List<ActiveDialogue>>("npc_dialogues")
|
||||
@JvmField
|
||||
val ACTIVE_ACTION_EFFECT = register<ActionEffectContext>("active_action_effect")
|
||||
@JvmField
|
||||
val POKEMON_FLYING = register("pokemon_flying", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val POKEMON_DROWSY = register("pokemon_drowsy", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val POKEMON_SLEEPING = register("pokemon_sleeping", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val POKEMON_BATTLE = register<UUID>("pokemon_battle")
|
||||
@JvmField
|
||||
val PATH_COOLDOWN = register<Boolean>("path_cooldown")
|
||||
@JvmField
|
||||
val TARGETED_BATTLE_POKEMON = register<UUID>("targeted_battle_pokemon")
|
||||
@JvmField
|
||||
val NEAREST_VISIBLE_ATTACKER = register<LivingEntity>("nearest_visible_attacker")
|
||||
@JvmField
|
||||
val NEARBY_GROWABLE_CROPS = register<BlockPos>("nearby_growable_crops")
|
||||
@JvmField
|
||||
val NEARBY_SWEET_BERRY_BUSH = register<BlockPos>("nearest_sweet_berry_bush")
|
||||
@JvmField
|
||||
val DISABLE_WALK_TO_BERRY_BUSH = register<Boolean>("disable_walk_to_berry_bush")
|
||||
@JvmField
|
||||
val TIME_TRYING_TO_REACH_BERRY_BUSH = register<Int>("time_trying_to_reach_berry_bush")
|
||||
@JvmField
|
||||
val IS_CONSUMING_ITEM = register<Boolean>("is_consuming_item")
|
||||
@JvmField
|
||||
val RECENTLY_ATE_GRASS = register<Boolean>("recently_ate_grass")
|
||||
val HIVE_LOCATION = register<BlockPos>("hive_location")
|
||||
@JvmField
|
||||
val HIVE_LOCATION = register<BlockPos>("hive_location", BlockPos.CODEC)
|
||||
@JvmField
|
||||
val HIVE_BLACKLIST = register<List<BlockPos>>("hive_blacklist")
|
||||
@JvmField
|
||||
val HIVE_COOLDOWN = register<Boolean>("hive_cooldown")
|
||||
val NEARBY_FLOWERS = register<List<BlockPos>>("nearby_flower")
|
||||
val POLLINATED = register<Boolean>("pollinated", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val NEARBY_FLOWER = register<BlockPos>("nearby_flower", BlockPos.CODEC)
|
||||
@JvmField
|
||||
val PATH_TO_NEARBY_FLOWER_COOLDOWN = register<Boolean>("path_to_nearby_flower_cooldown")
|
||||
@JvmField
|
||||
val HAS_NECTAR = register<Boolean>("has_nectar", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val NEARBY_SACC_LEAVES = register<BlockPos>("nearby_sacc_leaves", BlockPos.CODEC)
|
||||
/** who am i following rn? */
|
||||
@JvmField
|
||||
val HERD_LEADER = register<String>("herd_leader", PrimitiveCodec.STRING)
|
||||
/** how many are following me rn? */
|
||||
@JvmField
|
||||
val HERD_SIZE = register<Int>("herd_size") // Don't bother saving it, we'll try to keep count roughly.
|
||||
@JvmField
|
||||
val ATTACK_TARGET_DATA = register<CobblemonAttackTargetData>("attack_target_data") // This is used to store additional information about the attack target, such as when to give up pursuit.
|
||||
@JvmField
|
||||
val WANDER_CONTROL = register<CobblemonWanderControl>("wander_control")
|
||||
@JvmField
|
||||
val DISABLE_WALK_TO_WANTED_ITEM = register<Boolean>("disable_walk_to_wanted_item")
|
||||
@JvmField
|
||||
val TIME_TRYING_TO_REACH_WANTED_ITEM = register<Int>("time_trying_to_wanted_item")
|
||||
|
||||
@JvmStatic
|
||||
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType(Optional.of(codec))
|
||||
memories[id] = memoryModule
|
||||
return memoryModule
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun <U> register(id: String): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType<U>(Optional.empty())
|
||||
memories[id] = memoryModule
|
||||
return memoryModule
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,10 @@ import com.cobblemon.mod.common.client.net.callback.move.OpenMoveCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.cooking.ToggleCookingPotLidHandler
|
||||
import com.cobblemon.mod.common.client.net.data.CobblemonMechanicsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.data.RideSettingsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.debug.OpenRidingStatsDebugGUIHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.PokeSnackBlockParticlesHandler
|
||||
@@ -28,12 +30,13 @@ import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SaccharineLogBlockParticlesHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.ExpGainedDataPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
|
||||
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.orientation.ClientboundUpdateOrientationHandler
|
||||
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
|
||||
@@ -77,6 +80,7 @@ import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallba
|
||||
import com.cobblemon.mod.common.net.messages.client.cooking.SeasoningRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.cooking.ToggleCookingPotLidPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.*
|
||||
import com.cobblemon.mod.common.net.messages.client.debug.RequestOpenRidingStatsDebugGUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.PokeSnackBlockParticlesPacket
|
||||
@@ -132,6 +136,7 @@ import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotification
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeProcessStartedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.ExpGainedDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
|
||||
@@ -157,6 +162,7 @@ import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonS
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.party.PartySelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyMoveSelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPokemonMoveSelectedPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.debug.OpenRidingStatsDebugGUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingSettingsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatRangePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatsPacket
|
||||
@@ -179,6 +185,7 @@ import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePa
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket
|
||||
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
|
||||
@@ -209,6 +216,7 @@ import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSe
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartySelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyMoveSelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyPokemonMoveSelectedHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.debug.RequestOpenRidingStatsDebugGUIHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingSettingsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingStatRangeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingStatsHandler
|
||||
@@ -216,7 +224,7 @@ import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandle
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.npc.SaveNPCHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.orientation.OrientationPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.orientation.ServerboundUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.SetPastureConflictHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
|
||||
@@ -231,6 +239,7 @@ import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHan
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdateRiderRotationHandler
|
||||
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
|
||||
@@ -263,10 +272,13 @@ object CobblemonNetwork {
|
||||
fun ServerPlayer.sendPacket(packet: NetworkPacket<*>) {
|
||||
sendPacketToPlayer(this, packet)
|
||||
}
|
||||
@JvmStatic
|
||||
fun sendToServer(packet: NetworkPacket<*>) {
|
||||
Cobblemon.implementation.networkManager.sendToServer(packet)
|
||||
}
|
||||
@JvmStatic
|
||||
fun sendToAllPlayers(packet: NetworkPacket<*>) = sendPacketToPlayers(server()!!.playerList.players, packet)
|
||||
@JvmStatic
|
||||
fun sendPacketToPlayers(players: Iterable<ServerPlayer>, packet: NetworkPacket<*>) = players.forEach { sendPacketToPlayer(it, packet) }
|
||||
|
||||
val s2cPayloads = generateS2CPacketInfoList()
|
||||
@@ -345,6 +357,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(InteractPokemonUIPacket.ID, InteractPokemonUIPacket::decode, InteractPokemonUIPacketHandler))
|
||||
list.add(PacketRegisterInfo(PlayerInteractOptionsPacket.ID, PlayerInteractOptionsPacket::decode, PlayerInteractOptionsHandler))
|
||||
list.add(PacketRegisterInfo(PokedexUIPacket.ID, PokedexUIPacket::decode, PokedexUIPacketHandler))
|
||||
list.add(PacketRegisterInfo(ExpGainedDataPacket.ID, ExpGainedDataPacket::decode, ExpGainedDataPacketHandler))
|
||||
|
||||
// Starter packets
|
||||
list.add(PacketRegisterInfo(OpenStarterUIPacket.ID, OpenStarterUIPacket::decode, StarterUIPacketHandler))
|
||||
@@ -387,6 +400,7 @@ object CobblemonNetwork {
|
||||
|
||||
// Data registries
|
||||
list.add(PacketRegisterInfo(AbilityRegistrySyncPacket.ID, AbilityRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(CobblemonMechanicsSyncPacket.ID, CobblemonMechanicsSyncPacket::decode, CobblemonMechanicsSyncHandler))
|
||||
list.add(PacketRegisterInfo(MovesRegistrySyncPacket.ID, MovesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
@@ -442,7 +456,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(UpdatePastureConflictFlagPacket.ID, UpdatePastureConflictFlagPacket::decode, UpdatePastureConflictFlagHandler))
|
||||
|
||||
// Orientation
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, S2CUpdateOrientationHandler))
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, ClientboundUpdateOrientationHandler))
|
||||
|
||||
// Behaviours
|
||||
list.add(PacketRegisterInfo(PlayPosableAnimationPacket.ID, PlayPosableAnimationPacket::decode, PlayPosableAnimationHandler))
|
||||
@@ -477,6 +491,9 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateDriverInputPacket.ID, ClientboundUpdateDriverInputPacket::decode, ClientboundUpdateDriverInputHandler))
|
||||
|
||||
// Debug
|
||||
list.add(PacketRegisterInfo(OpenRidingStatsDebugGUIPacket.ID, OpenRidingStatsDebugGUIPacket::decode, OpenRidingStatsDebugGUIHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
@@ -577,13 +594,14 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler))
|
||||
|
||||
// Riding packet(s)
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, OrientationPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, ServerboundUpdateOrientationHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatsPacket.ID, ServerboundUpdateRidingStatsPacket::decode, ServerboundUpdateRidingStatsHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatRangePacket.ID, ServerboundUpdateRidingStatRangePacket::decode, ServerboundUpdateRidingStatRangeHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingSettingsPacket.ID, ServerboundUpdateRidingSettingsPacket::decode, ServerboundUpdateRidingSettingsHandler))
|
||||
list.add(PacketRegisterInfo(DismountPokemonPacket.ID, DismountPokemonPacket::decode, DismountPokemonPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateDriverInputPacket.ID, ServerboundUpdateDriverInputPacket::decode, DriverInputPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRiderRotationPacket.ID, ServerboundUpdateRiderRotationPacket::decode, ServerboundUpdateRiderRotationHandler))
|
||||
|
||||
// Cooking
|
||||
list.add(PacketRegisterInfo(ToggleCookingPotLidPacket.ID, ToggleCookingPotLidPacket::decode, ToggleCookingPotLidHandler))
|
||||
@@ -592,10 +610,13 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(SetEntityBehaviourPacket.ID, SetEntityBehaviourPacket::decode, SetEntityBehaviourHandler))
|
||||
list.add(PacketRegisterInfo(DamageOnCollisionPacket.ID, DamageOnCollisionPacket::decode, DamageOnCollisionPacketHandler))
|
||||
|
||||
// Debug
|
||||
list.add(PacketRegisterInfo(RequestOpenRidingStatsDebugGUIPacket.ID, RequestOpenRidingStatsDebugGUIPacket::decode, RequestOpenRidingStatsDebugGUIHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
fun sendPacketToPlayer(player: ServerPlayer, packet: NetworkPacket<*>) {
|
||||
Cobblemon.implementation.networkManager.sendPacketToPlayer(player, packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,6 @@ object CobblemonPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Regist
|
||||
@JvmField
|
||||
val NURSE_KEY = createKey("nurse", CobblemonBlocks.HEALING_MACHINE, 1, 1)
|
||||
@JvmField
|
||||
val POKE_SNACK_KEY = createKey("poke_snack", CobblemonBlocks.POKE_SNACK, 0, 1)
|
||||
@JvmField
|
||||
val SACCHARINE_LOG_SLATHERED_KEY = createKey("saccharine_log_slathered", CobblemonBlocks.SACCHARINE_LOG_SLATHERED, 0, 1)
|
||||
// TODO after 1.7
|
||||
// @JvmField
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineSettings
|
||||
import com.cobblemon.mod.common.net.messages.client.data.RideSettingsSyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
@@ -63,6 +64,7 @@ object CobblemonRideSettings : DataRegistry {
|
||||
var boat = BoatSettings()
|
||||
var burst = BurstSettings()
|
||||
var dolphin = DolphinSettings()
|
||||
var submarine = SubmarineSettings()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
player.sendPacket(
|
||||
@@ -78,7 +80,8 @@ object CobblemonRideSettings : DataRegistry {
|
||||
vehicle = vehicle,
|
||||
boat = boat,
|
||||
burst = burst,
|
||||
dolphin = dolphin
|
||||
dolphin = dolphin,
|
||||
submarine = submarine
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -96,6 +99,7 @@ object CobblemonRideSettings : DataRegistry {
|
||||
boat = loadStyle(manager, "boat", BoatSettings::class.java)
|
||||
burst = loadStyle(manager, "burst", BurstSettings::class.java)
|
||||
dolphin = loadStyle(manager, "dolphin", DolphinSettings::class.java)
|
||||
submarine = loadStyle(manager, "submarine", SubmarineSettings::class.java)
|
||||
}
|
||||
|
||||
private fun <T : RidingBehaviourSettings> loadStyle(manager: ResourceManager, name: String, clazz: Class<T>): T {
|
||||
|
||||
@@ -20,30 +20,45 @@ import net.minecraft.world.entity.ai.sensing.SensorType
|
||||
object CobblemonSensors {
|
||||
val sensors = mutableMapOf<String, SensorType<*>>()
|
||||
|
||||
@JvmField
|
||||
val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
|
||||
@JvmField
|
||||
val BATTLING_POKEMON = register("battling_pokemon", ::BattlingPokemonSensor)
|
||||
// val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
|
||||
@JvmField
|
||||
val POKEMON_DROWSY = register("pokemon_drowsy", ::DrowsySensor)
|
||||
|
||||
@JvmField
|
||||
val POKEMON_ADULT = register("pokemon_adult_sensor", ::PokemonAdultSensor)
|
||||
|
||||
@JvmField
|
||||
val POKEMON_DISTURBANCE = register("pokemon_disturbance_sensor", ::PokemonDisturbancesSensor)
|
||||
|
||||
@JvmField
|
||||
val POKEMON_DEFEND_OWNER = register("pokemon_owner_under_attack", ::DefendOwnerSensor)
|
||||
|
||||
@JvmField
|
||||
val NEARBY_GROWABLE_CROPS = register("nearby_growable_crops", ::PokemonGrowableCropSensor)
|
||||
|
||||
@JvmField
|
||||
val NEARBY_BEE_HIVE = register("nearby_bee_hive", ::BeeHiveSensor)
|
||||
|
||||
@JvmField
|
||||
val NEARBY_FLOWER = register("nearby_flower", ::FlowerSensor)
|
||||
|
||||
@JvmField
|
||||
val NEARBY_SWEET_BERRY_BUSH = register("nearby_sweet_berry_bush", ::SweetBerryBushSensor)
|
||||
|
||||
@JvmField
|
||||
val POKEMON_NEARBY_WANTED_ITEM = register("pokemon_nearby_wanted_item", ::PokemonItemSensor)
|
||||
|
||||
@JvmField
|
||||
val NEARBY_SACC_LEAVES = register("nearby_sacc_leaves", ::SacLeavesSensor)
|
||||
|
||||
@JvmStatic
|
||||
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
|
||||
val sensor = SensorType(supplier)
|
||||
sensors[id] = sensor
|
||||
return sensor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,11 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val EVOLUTION = this.create("evolution.full")
|
||||
|
||||
@JvmField
|
||||
val LEVELUP_START = this.create("gui.levelup_start")
|
||||
@JvmField
|
||||
val LEVELUP = this.create("gui.levelup")
|
||||
|
||||
@JvmField
|
||||
val PVN_BATTLE = this.create("battle.pvn.default")
|
||||
@JvmField
|
||||
|
||||
@@ -23,43 +23,63 @@ import net.minecraft.resources.ResourceKey
|
||||
* @since October 26th, 2022
|
||||
*/
|
||||
object CobblemonCriteria : PlatformRegistry<Registry<CriterionTrigger<*>>, ResourceKey<Registry<CriterionTrigger<*>>>, CriterionTrigger<*>>(){
|
||||
@JvmField
|
||||
val PICK_STARTER = this.create("pick_starter", SimpleCriterionTrigger(PokemonCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val CATCH_POKEMON = this.create("catch_pokemon", SimpleCriterionTrigger(CaughtPokemonCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val CATCH_SHINY_POKEMON = this.create("catch_shiny_pokemon", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val EGG_COLLECT = this.create("eggs_collected", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val EGG_HATCH = this.create("eggs_hatched", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val EVOLVE_POKEMON = this.create("pokemon_evolved", SimpleCriterionTrigger(EvolvePokemonCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val WIN_BATTLE = this.create("battles_won", SimpleCriterionTrigger(BattleCountableCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val DEFEAT_POKEMON = this.create("pokemon_defeated", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val COLLECT_ASPECT = this.create("aspects_collected", SimpleCriterionTrigger(AspectCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val POKEMON_INTERACT = this.create("pokemon_interact", SimpleCriterionTrigger(PokemonInteractCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val PARTY_CHECK = this.create("party", SimpleCriterionTrigger(PartyCheckCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val LEVEL_UP = this.create("level_up", SimpleCriterionTrigger(LevelUpCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val PASTURE_USE = this.create("pasture_use", SimpleCriterionTrigger(PokemonCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val RESURRECT_POKEMON = this.create("resurrect_pokemon", SimpleCriterionTrigger(PokemonCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val TRADE_POKEMON = this.create("trade_pokemon", SimpleCriterionTrigger(TradePokemonCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val CAST_POKE_ROD = this.create("cast_poke_rod", SimpleCriterionTrigger(CastPokeRodCriterionCondition.CODEC))
|
||||
|
||||
@JvmField
|
||||
val REEL_IN_POKEMON = this.create("reel_in_pokemon", SimpleCriterionTrigger(ReelInPokemonCriterionCondition.CODEC))
|
||||
|
||||
// Advancement criteria for [grow_tumblestone.json]
|
||||
@JvmField
|
||||
val PLANT_TUMBLESTONE = this.create("plant_tumblestone", SimpleCriterionTrigger(PlantTumblestoneCriterion.CODEC))
|
||||
|
||||
val RIDING_STAT_BOOST = this.create("riding_stat_boost", SimpleCriterionTrigger(RidingStatBoostCriterion.CODEC))
|
||||
|
||||
override val registry = BuiltInRegistries.TRIGGER_TYPES
|
||||
override val resourceKey = Registries.TRIGGER_TYPE
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -32,6 +32,6 @@ class CastPokeRodCriterionCondition(
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: CastPokeRodContext): Boolean {
|
||||
return (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId.equals("empty_bait"))
|
||||
return (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "empty_bait")
|
||||
}
|
||||
}
|
||||
|
||||
+6
-4
@@ -21,23 +21,25 @@ import java.util.Optional
|
||||
* @author Hiroku
|
||||
* @since November 4th, 2022
|
||||
*/
|
||||
open class CountablePokemonTypeContext(times: Int, var species: String) : CountableContext(times)
|
||||
open class CountablePokemonTypeContext(times: Int, var type: String/*, var species: String*/) : CountableContext(times)
|
||||
|
||||
class CaughtPokemonCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val species: String,
|
||||
val type : String,
|
||||
//val species: String,
|
||||
count: Int
|
||||
): CountableCriterion<CountablePokemonTypeContext>(playerCtx, count) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<CaughtPokemonCriterion> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(CaughtPokemonCriterion::playerCtx),
|
||||
Codec.STRING.optionalFieldOf("species", "any").forGetter(CaughtPokemonCriterion::species),
|
||||
Codec.STRING.optionalFieldOf("type", "any").forGetter(CaughtPokemonCriterion::type),
|
||||
//Codec.STRING.optionalFieldOf("species", "any").forGetter(CaughtPokemonCriterion::species),
|
||||
Codec.INT.optionalFieldOf("count", 0).forGetter(CaughtPokemonCriterion::count)
|
||||
).apply(it, ::CaughtPokemonCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: CountablePokemonTypeContext): Boolean {
|
||||
return super.matches(player, context) && (context.species == species || species == "any")
|
||||
return super.matches(player, context) && (context.type == type || type == "any")// && (context.species == species || species == "any")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ class LevelUpCriterion(
|
||||
val CODEC: Codec<LevelUpCriterion> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(LevelUpCriterion::playerCtx),
|
||||
Codec.INT.optionalFieldOf("level", 0).forGetter(LevelUpCriterion::level),
|
||||
Codec.BOOL.optionalFieldOf("evolved", true).forGetter(LevelUpCriterion::evolved)
|
||||
Codec.BOOL.optionalFieldOf("has_evolved", true).forGetter(LevelUpCriterion::evolved)
|
||||
).apply(it, ::LevelUpCriterion) }
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -22,18 +22,19 @@ class ReelInPokemonContext(val species : ResourceLocation, val baitId: ResourceL
|
||||
class ReelInPokemonCriterionCondition(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val species: String,
|
||||
val baitId: String
|
||||
val baitId: String // also allows "cobblemon:empty_bait" to indicate that no bait is allowed for this criterion to match
|
||||
) : SimpleCriterionCondition<ReelInPokemonContext>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<ReelInPokemonCriterionCondition> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter { it.playerCtx },
|
||||
Codec.STRING.optionalFieldOf("species", "any").forGetter { it.species },
|
||||
Codec.STRING.optionalFieldOf("baitId", "empty_bait").forGetter { it.baitId }
|
||||
).apply(it, { playerCtx, pokemonId, baitId -> ReelInPokemonCriterionCondition(playerCtx, pokemonId, baitId.ifEmpty { "empty_bait" }) }) }
|
||||
Codec.STRING.optionalFieldOf("baitId", "any").forGetter { it.baitId }
|
||||
).apply(it, { playerCtx, pokemonId, baitId -> ReelInPokemonCriterionCondition(playerCtx, pokemonId, baitId) }) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: ReelInPokemonContext): Boolean {
|
||||
return (context.species == this.species.asIdentifierDefaultingNamespace() || this.species == "any") && (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "empty_bait")
|
||||
return (context.species == this.species.asIdentifierDefaultingNamespace() || this.species == "any")
|
||||
&& (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "any" || this.baitId == "empty_bait")
|
||||
}
|
||||
}
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.advancements.critereon.ContextAwarePredicate
|
||||
import net.minecraft.advancements.critereon.EntityPredicate
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import java.util.Optional
|
||||
|
||||
class RidingStatBoostContext(val pokemon: PokemonEntity)
|
||||
|
||||
class RidingStatBoostCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val rideStat: String,
|
||||
val statValue : Double,
|
||||
val isMax : Boolean
|
||||
) : SimpleCriterionCondition<RidingStatBoostContext>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<RidingStatBoostCriterion> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter { it.playerCtx },
|
||||
Codec.STRING.optionalFieldOf("ride_stat", "any").forGetter { it.rideStat },
|
||||
Codec.DOUBLE.optionalFieldOf("stat_value", 0.0).forGetter { it.statValue },
|
||||
Codec.BOOL.optionalFieldOf("is_max", false).forGetter { it.isMax }
|
||||
).apply(it, ::RidingStatBoostCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: RidingStatBoostContext) : Boolean {
|
||||
RidingStyle.entries.forEach { ridingStyle ->
|
||||
RidingStat.entries.forEach { rideStat ->
|
||||
if (rideStat.name.equals(this.rideStat, true) || this.rideStat == "any") {
|
||||
val max = context.pokemon.pokemon.getMaxRideBoost(rideStat).toDouble()
|
||||
val min = context.pokemon.pokemon.getBaseRideStat(rideStat).toDouble()
|
||||
val value = context.pokemon.getRideStat(rideStat, ridingStyle, min, max)
|
||||
if ((value >= this.statValue && this.statValue > 0.0) || value == max || !context.pokemon.pokemon.canAddRideBoost(rideStat)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -70,16 +70,23 @@ object Abilities : DataRegistry {
|
||||
AbilityRegistrySyncPacket(all()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun register(ability: AbilityTemplate): AbilityTemplate {
|
||||
this.abilityMap[ability.name.lowercase()] = ability
|
||||
return ability
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun all() = this.abilityMap.values.toList()
|
||||
@JvmStatic
|
||||
fun first() = this.abilityMap.values.first()
|
||||
@JvmStatic
|
||||
fun get(name: String) = abilityMap[name.lowercase()]
|
||||
@JvmStatic
|
||||
fun getOrDummy(name: String) = get(name) ?: DUMMY
|
||||
@JvmStatic
|
||||
fun getOrException(name: String) = get(name) ?: throw IllegalArgumentException("Unable to find ability of name: $name")
|
||||
@JvmStatic
|
||||
fun count() = this.abilityMap.size
|
||||
|
||||
internal fun receiveSyncPacket(abilities: Collection<AbilityTemplate>) {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
/**
|
||||
* A [Behavior] subclass that represents tasks that check that the entity is still in one
|
||||
* of the activities that this task is part of. If the entity is no longer doing any of those
|
||||
* activities, the task will be interrupted and you can handle any cleanup in [onInterrupted].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 17th, 2025
|
||||
*/
|
||||
abstract class ActivityAwareBehavior<E : LivingEntity> : Behavior<E> {
|
||||
constructor(entryCondition: Map<MemoryModuleType<*>, MemoryStatus>) : super(entryCondition)
|
||||
constructor(entryCondition: Map<MemoryModuleType<*>, MemoryStatus>, duration: Int) : super(entryCondition, duration)
|
||||
constructor(entryCondition: Map<MemoryModuleType<*>, MemoryStatus>, minDuration: Int, maxDuration: Int) : super(entryCondition, minDuration, maxDuration)
|
||||
|
||||
val activities: MutableSet<Activity> = mutableSetOf()
|
||||
|
||||
fun isStillDoingActivity(entity: E): Boolean {
|
||||
return activities.any(entity.brain::isActive)
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: E, gameTime: Long) = isStillDoingActivity(entity)
|
||||
|
||||
open fun onInterrupted(level: ServerLevel, entity: E, gameTime: Long) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: E, gameTime: Long) {
|
||||
super.stop(level, entity, gameTime)
|
||||
if (!isStillDoingActivity(entity)) {
|
||||
onInterrupted(level, entity, gameTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.ai
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.mojang.datafixers.util.Pair
|
||||
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.schedule.Activity
|
||||
|
||||
@@ -23,6 +22,13 @@ class ActivityConfigurationContext(val activity: Activity) {
|
||||
}
|
||||
|
||||
fun apply(entity: LivingEntity) {
|
||||
tasks.forEach {
|
||||
val activityAwareBehavior = it.second as? ActivityAwareBehavior<*>
|
||||
?: (it.second as? WrapperLivingEntityTask<*>)?.task as? ActivityAwareBehavior
|
||||
?: return@forEach
|
||||
activityAwareBehavior.activities += activity
|
||||
}
|
||||
|
||||
entity.brain.addActivity(activity, ImmutableList.copyOf(tasks))
|
||||
}
|
||||
}
|
||||
@@ -47,12 +47,23 @@ class ApplyBehaviours : BehaviourConfig {
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
if (!checkCondition(behaviourConfigurationContext, condition)) return
|
||||
|
||||
val configurations = behaviours.map { CobblemonBehaviours.behaviours[it]?.takeIf { it.canBeApplied(entity) } ?: return Cobblemon.LOGGER.warn("Behaviour $it not found") }
|
||||
val applicableBehaviours = behaviours.mapNotNull {
|
||||
val resolvedBehaviour = CobblemonBehaviours.behaviours[it]
|
||||
if (resolvedBehaviour == null) {
|
||||
Cobblemon.LOGGER.warn("Behaviour $it not found while configuring entity of type ${entity.type}")
|
||||
} else if (!resolvedBehaviour.canBeApplied(entity)) {
|
||||
Cobblemon.LOGGER.warn("Behaviour $it cannot be applied to entity ${entity.id}")
|
||||
} else {
|
||||
return@mapNotNull resolvedBehaviour
|
||||
}
|
||||
null
|
||||
}
|
||||
|
||||
// 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 {
|
||||
applicableBehaviours.forEach {
|
||||
it.configure(entity, behaviourConfigurationContext)
|
||||
}
|
||||
originalContextBehaviours.addAll(behaviours)
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
class ActivityChangeTaskConfig : SingleTaskConfig {
|
||||
val activity: Activity = Activity.IDLE
|
||||
val condition: ExpressionLike = "false".asExpressionLike()
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): List<MoLangConfigVariable> = emptyList()
|
||||
|
||||
|
||||
+17
-3
@@ -11,8 +11,7 @@ package com.cobblemon.mod.common.api.ai.config.task
|
||||
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 com.cobblemon.mod.common.util.resolveEntityTypes
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.SetEntityLookTarget
|
||||
@@ -22,13 +21,16 @@ import net.minecraft.world.entity.ai.sensing.SensorType
|
||||
class LookAtEntitiesTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val LOOK_AT_ENTITIES = "look_at_entities"
|
||||
const val LOOK_AT_ENTITY_TYPES = "look_at_entity_types"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(SharedEntityVariables.LOOKING_CATEGORY, LOOK_AT_ENTITIES, true).asExpressible()
|
||||
val maxDistance = numberVariable(SharedEntityVariables.LOOKING_CATEGORY, SEE_DISTANCE, 15).asExpressible()
|
||||
val entityTypes = stringVariable(SharedEntityVariables.LOOKING_CATEGORY, LOOK_AT_ENTITY_TYPES, "").asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition,
|
||||
entityTypes,
|
||||
maxDistance
|
||||
).asVariables()
|
||||
|
||||
@@ -39,6 +41,18 @@ class LookAtEntitiesTaskConfig : SingleTaskConfig {
|
||||
if (!condition.resolveBoolean(behaviourConfigurationContext.runtime)) return null
|
||||
behaviourConfigurationContext.addMemories(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.LOOK_TARGET)
|
||||
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
|
||||
return SetEntityLookTarget.create(maxDistance.resolveFloat(behaviourConfigurationContext.runtime))
|
||||
|
||||
val lookDistance = maxDistance.resolveFloat(behaviourConfigurationContext.runtime)
|
||||
val lookAtTypesText = entityTypes.resolveString(behaviourConfigurationContext.runtime)
|
||||
if (lookAtTypesText.isBlank()) {
|
||||
return SetEntityLookTarget.create(lookDistance)
|
||||
}
|
||||
|
||||
val lookAtTypes = resolveEntityTypes(entity.registryAccess(), lookAtTypesText)
|
||||
return if (lookAtTypes.isNotEmpty()) {
|
||||
SetEntityLookTarget.create({ lookAtTypes.contains(it.type) }, lookDistance)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -19,7 +19,7 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
class MeleeAttackTaskConfig : SingleTaskConfig {
|
||||
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "attacks_melee", true).asExpressible()
|
||||
val range = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "melee_range", 1.5F).asExpressible()
|
||||
val range = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "melee_range", 0.75F).asExpressible()
|
||||
val cooldownTicks = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "melee_cooldown", 20).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.resolveString
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
@@ -62,7 +63,7 @@ class MemoryAspectTaskConfig : SingleTaskConfig {
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long) = true
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
val hasMemory = !owner.brain.hasMemoryValue(memory)
|
||||
val hasMemory = owner.brain.hasMemoryValue(memory)
|
||||
if (owner is PokemonEntity) {
|
||||
if (!hasMemory && aspect in owner.pokemon.forcedAspects) {
|
||||
owner.pokemon.forcedAspects -= aspect
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ class MoveToOwnerTaskConfig : SingleTaskConfig {
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
): BehaviorControl<in LivingEntity> {
|
||||
behaviourConfigurationContext.addMemories(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
MemoryModuleType.LOOK_TARGET
|
||||
|
||||
+118
-2
@@ -8,16 +8,31 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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.PathToBeeHiveTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PlaceHoneyInHiveTask
|
||||
import com.cobblemon.mod.common.util.distanceTo
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
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.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PathToBeeHiveTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val HONEY = "honey"
|
||||
const val STAY_OUT_OF_HIVE_COOLDOWN = 400
|
||||
|
||||
}
|
||||
|
||||
val condition = booleanVariable(HONEY, "can_add_honey", true).asExpressible()
|
||||
@@ -36,6 +51,107 @@ class PathToBeeHiveTaskConfig : SingleTaskConfig {
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
return PathToBeeHiveTask.create()
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_BEE_HIVE)
|
||||
return object : Behavior<LivingEntity>(
|
||||
mapOf(
|
||||
MemoryModuleType.LOOK_TARGET to MemoryStatus.REGISTERED,
|
||||
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HAS_NECTAR to MemoryStatus.REGISTERED,
|
||||
CobblemonMemories.HIVE_LOCATION to MemoryStatus.VALUE_PRESENT,
|
||||
CobblemonMemories.HIVE_COOLDOWN to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HIVE_BLACKLIST to MemoryStatus.REGISTERED,
|
||||
),
|
||||
400,
|
||||
400
|
||||
) {
|
||||
|
||||
val maxTicks = 400
|
||||
var traveledTicks = 0
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
return (owner is PathfinderMob && owner.isAlive && (owner is PokemonEntity && PlaceHoneyInHiveTask.wantsToEnterHive(owner))) && owner.brain.checkMemory(
|
||||
MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
if (maxTicks >= traveledTicks) return false
|
||||
val pos = entity.brain.getMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
return !pos.isEmpty && entity.distanceTo(pos.get()) > 1.0
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
super.start(level, entity, gameTime)
|
||||
val hiveLocation = entity.brain.getMemorySafely(CobblemonMemories.HIVE_LOCATION).orElse(null)
|
||||
val world = entity.level()
|
||||
val sidesByClosest = listOf(
|
||||
hiveLocation.north(),
|
||||
hiveLocation.south(),
|
||||
hiveLocation.east(),
|
||||
hiveLocation.west()
|
||||
).sortedBy { it.distSqr(entity.blockPosition()) }
|
||||
|
||||
var openSide = BlockPos.ZERO
|
||||
for (side in sidesByClosest) {
|
||||
if (world.getBlockState(side).isAir) {
|
||||
openSide = side
|
||||
break
|
||||
}
|
||||
}
|
||||
if (openSide == BlockPos.ZERO) {
|
||||
if (world.getBlockState(hiveLocation.above()).isAir) {
|
||||
// If the above position is also air, we can use it
|
||||
openSide = hiveLocation.above() // Fallback to above if no open sides found
|
||||
} else if (world.getBlockState(hiveLocation.below()).isAir) {
|
||||
// If the below position is also air, we can use it
|
||||
openSide = hiveLocation.below() // Fallback to below if no open sides found
|
||||
} else {
|
||||
// If no open sides or above/below positions are found, we cannot proceed
|
||||
return
|
||||
}
|
||||
}
|
||||
val targetVec = Vec3.atCenterOf(openSide)
|
||||
|
||||
// Set path target toward hive
|
||||
if (pathfindDirectlyTowards(openSide, entity)) {
|
||||
entity.brain.setMemory(MemoryModuleType.WALK_TARGET,WalkTarget(targetVec, 0.35F, 0))
|
||||
entity.brain.setMemory(MemoryModuleType.LOOK_TARGET,BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
traveledTicks = 0
|
||||
} else {
|
||||
dropAndBlackListHive(entity)
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
traveledTicks++
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
if (maxTicks < traveledTicks) {
|
||||
dropAndBlackListHive(entity)
|
||||
entity.brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, 100)
|
||||
}
|
||||
}
|
||||
|
||||
fun dropAndBlackListHive(entity: LivingEntity) {
|
||||
val hivePos = entity.brain.getMemorySafely(CobblemonMemories.HIVE_LOCATION).orElse(null)
|
||||
if (hivePos == null) return
|
||||
val blackList = entity.brain.getMemorySafely(CobblemonMemories.HIVE_BLACKLIST).orElse(emptyList()).toMutableList()
|
||||
|
||||
blackList.add(hivePos)
|
||||
if (blackList.count() > 3) {
|
||||
blackList.removeFirst()
|
||||
}
|
||||
entity.brain.eraseMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
entity.brain.setMemory(CobblemonMemories.HIVE_BLACKLIST, blackList)
|
||||
|
||||
}
|
||||
|
||||
private fun pathfindDirectlyTowards(pos: BlockPos, entity: LivingEntity): Boolean {
|
||||
if (entity !is PathfinderMob) return false
|
||||
val nav = entity.navigation
|
||||
val path = nav. createPath(pos, 0)
|
||||
return path != null && path.canReach()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
@@ -41,12 +40,14 @@ class PathToFlowerTaskConfig : SingleTaskConfig {
|
||||
return null
|
||||
}
|
||||
behaviourConfigurationContext.addMemories(
|
||||
CobblemonMemories.NEARBY_FLOWERS,
|
||||
CobblemonMemories.NEARBY_FLOWER,
|
||||
CobblemonMemories.PATH_TO_NEARBY_FLOWER_COOLDOWN,
|
||||
CobblemonMemories.HIVE_COOLDOWN,
|
||||
CobblemonMemories.HIVE_LOCATION,
|
||||
CobblemonMemories.POLLINATED
|
||||
CobblemonMemories.HIVE_BLACKLIST,
|
||||
CobblemonMemories.HAS_NECTAR,
|
||||
)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_BEE_HIVE, CobblemonSensors.NEARBY_FLOWER)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_FLOWER)
|
||||
return PathToFlowerTask.create()
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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.PathToSacLeafTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class PathToSaccLeavesTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val POLLINATE = "pollinate"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
behaviourConfigurationContext.addMemories(
|
||||
CobblemonMemories.NEARBY_SACC_LEAVES,
|
||||
CobblemonMemories.HAS_NECTAR
|
||||
)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_SACC_LEAVES, CobblemonSensors.NEARBY_FLOWER)
|
||||
return PathToSacLeafTask.create()
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -8,8 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
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.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PlaceHoneyInHiveTask
|
||||
@@ -37,6 +37,9 @@ class PlaceHoneyInHiveTaskConfig : SingleTaskConfig {
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
return PlaceHoneyInHiveTask.create()
|
||||
return WrapperLivingEntityTask(
|
||||
PlaceHoneyInHiveTask.create(),
|
||||
PokemonEntity::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
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.block.SaccharineLeafBlock
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PlaceHoneyInSaccLeavesTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val POLLINATE = "pollinate"
|
||||
const val MIN_DURATION : Int = 300
|
||||
const val MAX_DURATION : Int = 400
|
||||
const val REQUIRED_SUCCESSFUL_POLLINATION_TICKS = 250
|
||||
}
|
||||
|
||||
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return object : Behavior<LivingEntity>(
|
||||
mapOf(
|
||||
CobblemonMemories.NEARBY_SACC_LEAVES to MemoryStatus.VALUE_PRESENT,
|
||||
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HAS_NECTAR to MemoryStatus.VALUE_PRESENT,
|
||||
),
|
||||
MIN_DURATION,
|
||||
MAX_DURATION
|
||||
) {
|
||||
var successfulPollinationTicks = 0
|
||||
var lastSoundPlayedTick = 0
|
||||
var hoverPos: Vec3? = null
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
if (level.isNight || level.isRaining || !(entity.brain.getMemorySafely(CobblemonMemories.HAS_NECTAR).orElse(false))) return false
|
||||
val optionalBlockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES)
|
||||
if (!optionalBlockPos.isPresent || level.getBlockState(optionalBlockPos.get()).block != CobblemonBlocks.SACCHARINE_LEAVES) return false
|
||||
return Vec3.atCenterOf(optionalBlockPos.get()).distanceTo(entity.position()) <= 0.6
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
return checkExtraStartConditions(level, entity) && entity.brain.activeActivities.indexOf(
|
||||
CobblemonActivities.POKEMON_POLLINATION) != -1
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
super.start(level, entity, gameTime)
|
||||
hoverPos = null
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
++successfulPollinationTicks
|
||||
if (entity.random.nextFloat() < 0.05f && successfulPollinationTicks > this.lastSoundPlayedTick + 60) {
|
||||
this.lastSoundPlayedTick = successfulPollinationTicks
|
||||
entity.playSound(SoundEvents.BEEHIVE_DRIP, 1.0f, 1.0f)
|
||||
}
|
||||
val leavesPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES).orElse(null)
|
||||
|
||||
val bl = hoverPos == null || entity.position().distanceTo(hoverPos!!) <= 0.1
|
||||
val bl3 = entity.random.nextInt(40) == 0
|
||||
if (bl && bl3) {
|
||||
// mimics the wriggling over a flower the vanilla bees do
|
||||
if (hoverPos == null) {
|
||||
hoverPos = leavesPos.bottomCenter.add(0.0, 0.4, 0.0)
|
||||
}
|
||||
if (leavesPos != null) {
|
||||
hoverPos = leavesPos.bottomCenter.add(Vec3((entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0), 0.3 + (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/7.0), (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0)))
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
entity.lookControl.setLookAt(leavesPos.bottomCenter.add(0.0,0.5,0.0))
|
||||
}
|
||||
} else if (!bl) {
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
}
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
|
||||
val blockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES).orElse(null)
|
||||
blockPos?.let {
|
||||
val blockState = level.getBlockState(blockPos)
|
||||
if (blockState.block == CobblemonBlocks.SACCHARINE_LEAVES) {
|
||||
val saccAge = blockState.getValue( SaccharineLeafBlock.AGE)
|
||||
if (saccAge < SaccharineLeafBlock.MAX_AGE) {
|
||||
entity.brain.eraseMemory(CobblemonMemories.HAS_NECTAR)
|
||||
val newBlockState = blockState.setValue(SaccharineLeafBlock.AGE, saccAge + 1)
|
||||
level.setBlock(blockPos, newBlockState, 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
successfulPollinationTicks = 0
|
||||
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
-24
@@ -8,17 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
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.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.sendParticlesServer
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.core.particles.ParticleTypes
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
@@ -29,10 +26,11 @@ import net.minecraft.world.phys.Vec3
|
||||
class PollinateFlowerTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val POLLINATE = "pollinate"
|
||||
const val PATH_TO_FLOWER_COOLDOWN_TICKS : Long = 200
|
||||
const val HAS_NECTAR_ASPECT = "has_nectar"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
|
||||
val durationTicks: ExpressionOrEntityVariable = Either.left("30".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition
|
||||
@@ -51,22 +49,28 @@ class PollinateFlowerTaskConfig : SingleTaskConfig {
|
||||
|
||||
return object : Behavior<LivingEntity>(
|
||||
mapOf(
|
||||
CobblemonMemories.NEARBY_FLOWERS to MemoryStatus.VALUE_PRESENT,
|
||||
CobblemonMemories.NEARBY_FLOWER to MemoryStatus.VALUE_PRESENT,
|
||||
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.POLLINATED to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HAS_NECTAR to MemoryStatus.REGISTERED,
|
||||
CobblemonMemories.HIVE_COOLDOWN to MemoryStatus.VALUE_ABSENT,
|
||||
),
|
||||
15,
|
||||
45
|
||||
600,
|
||||
625
|
||||
) {
|
||||
val REQUIRED_SUCCESSFUL_POLLINATION_TICKS = 400
|
||||
var successfulPollinationTicks = 0
|
||||
var lastSoundPlayedTick = 0
|
||||
var hoverPos: Vec3? = null
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
return entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWERS).orElse(emptyList()).any {
|
||||
Vec3.atCenterOf(it).distanceTo(entity.position()) <= 1.0
|
||||
}
|
||||
if (level.isNight || level.isRaining || entity.brain.getMemorySafely(CobblemonMemories.HAS_NECTAR).orElse(false)) return false
|
||||
val optionalBlockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWER)
|
||||
return optionalBlockPos.isPresent && Vec3.atCenterOf(optionalBlockPos.get()).distanceTo(entity.position()) <= 1.0
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
return checkExtraStartConditions(level, entity)
|
||||
return checkExtraStartConditions(level, entity) && entity.brain.activeActivities.indexOf(
|
||||
CobblemonActivities.POKEMON_POLLINATION) != -1
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
@@ -74,20 +78,44 @@ class PollinateFlowerTaskConfig : SingleTaskConfig {
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
level.sendParticlesServer(
|
||||
particleType = ParticleTypes.DRIPPING_HONEY,
|
||||
position = owner.eyePosition,
|
||||
particles = 3,
|
||||
offset = Vec3.ZERO,
|
||||
speed = 0.0
|
||||
)
|
||||
++successfulPollinationTicks
|
||||
if (entity.random.nextFloat() < 0.05f && successfulPollinationTicks > this.lastSoundPlayedTick + 60) {
|
||||
this.lastSoundPlayedTick = successfulPollinationTicks
|
||||
entity.playSound(SoundEvents.BEE_POLLINATE, 1.0f, 1.0f)
|
||||
}
|
||||
val flowerPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWER).orElse(null)
|
||||
|
||||
|
||||
val bl = hoverPos == null || entity.position().distanceTo(hoverPos!!) <= 0.1
|
||||
val bl3 = entity.random.nextInt(40) == 0
|
||||
if (bl && bl3) {
|
||||
// mimics the wriggling over a flower the vanilla bees do
|
||||
if (hoverPos == null) {
|
||||
hoverPos = flowerPos.bottomCenter.add(0.0, 0.4, 0.0)
|
||||
}
|
||||
|
||||
if (flowerPos != null) {
|
||||
hoverPos = flowerPos.bottomCenter.add(Vec3((entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0), 0.3 + (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/7.0), (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0)))
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
entity.lookControl.setLookAt(flowerPos.bottomCenter.add(0.0,0.5,0.0))
|
||||
}
|
||||
} else if (!bl) {
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
}
|
||||
entity.lookControl.setLookAt(flowerPos.bottomCenter.add(0.0,0.5,0.0))
|
||||
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
val flowerStillThere = canStillUse(level, entity, gameTime)
|
||||
if (flowerStillThere) {
|
||||
entity.brain.setMemory(CobblemonMemories.POLLINATED, true)
|
||||
|
||||
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
|
||||
entity.brain.setMemory(CobblemonMemories.HAS_NECTAR, true)
|
||||
}
|
||||
successfulPollinationTicks = 0
|
||||
entity.brain.setMemoryWithExpiry(CobblemonMemories.PATH_TO_NEARBY_FLOWER_COOLDOWN, true, PATH_TO_FLOWER_COOLDOWN_TICKS)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,9 @@ interface TaskConfig {
|
||||
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
|
||||
cobblemonResource("path_to_hive") to PathToBeeHiveTaskConfig::class.java,
|
||||
cobblemonResource("place_honey_in_hive") to PlaceHoneyInHiveTaskConfig::class.java,
|
||||
cobblemonResource("place_honey_in_sacc_leaves") to PlaceHoneyInSaccLeavesTaskConfig::class.java,
|
||||
cobblemonResource("path_to_flower") to PathToFlowerTaskConfig::class.java,
|
||||
cobblemonResource("path_to_sacc_leaves") to PathToSaccLeavesTaskConfig::class.java,
|
||||
cobblemonResource("pollinate_flower") to PollinateFlowerTaskConfig::class.java,
|
||||
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
|
||||
cobblemonResource("manage_flight_in_battle") to ManageFlightInBattleTaskConfig::class.java,
|
||||
|
||||
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.apricorn
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.cooking.Flavour
|
||||
import com.cobblemon.mod.common.block.ApricornBlock
|
||||
import com.cobblemon.mod.common.block.ApricornSaplingBlock
|
||||
import com.cobblemon.mod.common.item.ApricornItem
|
||||
@@ -28,43 +27,14 @@ import net.minecraft.world.level.material.MapColor
|
||||
* @author Licious
|
||||
* @since October 29th, 2022
|
||||
*/
|
||||
enum class Apricorn(
|
||||
/** A value of true means it buffs that flavour, a value of false means it weakens that flavour. */
|
||||
val flavourStrength: Map<Flavour, Boolean> = emptyMap()
|
||||
) : StringRepresentable {
|
||||
|
||||
enum class Apricorn : StringRepresentable {
|
||||
BLACK,
|
||||
BLUE(
|
||||
mapOf(
|
||||
Flavour.DRY to true,
|
||||
Flavour.BITTER to false
|
||||
)
|
||||
),
|
||||
GREEN(
|
||||
mapOf(
|
||||
Flavour.BITTER to true,
|
||||
Flavour.SWEET to false
|
||||
)
|
||||
),
|
||||
PINK(
|
||||
mapOf(
|
||||
Flavour.SWEET to true,
|
||||
Flavour.SPICY to false
|
||||
)
|
||||
),
|
||||
RED(
|
||||
mapOf(
|
||||
Flavour.SPICY to true,
|
||||
Flavour.SOUR to false
|
||||
)
|
||||
),
|
||||
BLUE,
|
||||
GREEN,
|
||||
PINK,
|
||||
RED,
|
||||
WHITE,
|
||||
YELLOW(
|
||||
mapOf(
|
||||
Flavour.SOUR to true,
|
||||
Flavour.DRY to false
|
||||
)
|
||||
);
|
||||
YELLOW;
|
||||
|
||||
fun item(): ApricornItem = when(this) {
|
||||
BLACK -> CobblemonItems.BLACK_APRICORN
|
||||
@@ -131,5 +101,4 @@ enum class Apricorn(
|
||||
companion object {
|
||||
val CODEC: Codec<Apricorn> = StringRepresentable.fromValues(::values)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -85,6 +85,7 @@ object Berries : JsonDataRegistry<Berry> {
|
||||
BerryRegistrySyncPacket(this.all()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun all() = this.berries.values.toList()
|
||||
|
||||
/**
|
||||
@@ -93,6 +94,7 @@ object Berries : JsonDataRegistry<Berry> {
|
||||
* @param identifier The identifier of the berry.
|
||||
* @return The [Berry] if loaded otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByIdentifier(identifier: ResourceLocation): Berry? = this.berries[identifier]
|
||||
|
||||
/**
|
||||
@@ -101,6 +103,7 @@ object Berries : JsonDataRegistry<Berry> {
|
||||
* @param name The path of the identifier of the berry under the [Cobblemon.MODID] namespace.
|
||||
* @return The [Berry] if loaded otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByName(name: String): Berry? = this.getByIdentifier(cobblemonResource(name))
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.berry.spawncondition
|
||||
|
||||
import com.cobblemon.mod.common.api.berry.Berry
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.Holder
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.level.biome.Biome
|
||||
|
||||
class SpecificBiomeCondition : BerrySpawnCondition {
|
||||
lateinit var biome: TagKey<Biome>
|
||||
val minGroveSize: Int = 1
|
||||
val maxGroveSize: Int = 1
|
||||
|
||||
override fun canSpawn(berry: Berry, biome: Holder<Biome>) = biome.`is`(this.biome)
|
||||
override fun getGroveSize(random: RandomSource) = random.nextIntBetweenInclusive(minGroveSize, maxGroveSize)
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("specific_biome")
|
||||
}
|
||||
}
|
||||
+105
-25
@@ -8,8 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.cooking
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.util.math.geometry.toDegrees
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.util.FastColor
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
private val colourMap = mapOf(
|
||||
Flavour.SPICY to 0xFEB37D,
|
||||
@@ -49,37 +55,111 @@ fun getColourMixFromFlavours(dominantFlavours: List<Flavour>, forBubbles: Boolea
|
||||
|
||||
if (colors.isEmpty()) return null
|
||||
|
||||
val (alphaSum, redSum, greenSum, blueSum) = colors.fold(IntArray(4)) { acc, color ->
|
||||
acc[0] += FastColor.ARGB32.alpha(color)
|
||||
acc[1] += FastColor.ARGB32.red(color)
|
||||
acc[2] += FastColor.ARGB32.green(color)
|
||||
acc[3] += FastColor.ARGB32.blue(color)
|
||||
acc
|
||||
}
|
||||
|
||||
return FastColor.ARGB32.color(
|
||||
alphaSum / colors.size,
|
||||
redSum / colors.size,
|
||||
greenSum / colors.size,
|
||||
blueSum / colors.size
|
||||
)
|
||||
return getColourMixFromColors(colors)
|
||||
}
|
||||
|
||||
fun getColourMixFromRideStatBoosts(dominantBoosts: Iterable<RidingStat>, forBubbles: Boolean = false): Int? {
|
||||
return getColourMixFromFlavours(dominantBoosts.map { it.flavour }, forBubbles)
|
||||
}
|
||||
|
||||
// Mixing RGB colors directly often gives poor results
|
||||
// Converting them to HSL and averaging hues circularly produces more natural blends
|
||||
fun getColourMixFromColors(colors: List<Int>): Int? {
|
||||
if (colors.isEmpty()) return null
|
||||
if (colors.size == 1) return colors[0]
|
||||
|
||||
val (alphaSum, redSum, greenSum, blueSum) = colors.fold(IntArray(4)) { acc, color ->
|
||||
acc[0] += FastColor.ARGB32.alpha(color)
|
||||
acc[1] += FastColor.ARGB32.red(color)
|
||||
acc[2] += FastColor.ARGB32.green(color)
|
||||
acc[3] += FastColor.ARGB32.blue(color)
|
||||
acc
|
||||
val hslColors = colors.map {
|
||||
val red = FastColor.ARGB32.red(it)
|
||||
val green = FastColor.ARGB32.green(it)
|
||||
val blue = FastColor.ARGB32.blue(it)
|
||||
|
||||
rgbToHsl(red, green, blue)
|
||||
}
|
||||
|
||||
return FastColor.ARGB32.color(
|
||||
alphaSum / colors.size,
|
||||
redSum / colors.size,
|
||||
greenSum / colors.size,
|
||||
blueSum / colors.size
|
||||
val hues = hslColors.map { it.h.toDouble() }
|
||||
val huesAverage = hueAverage(hues).toFloat()
|
||||
val saturations = hslColors.map { it.s }
|
||||
val saturationsAverage = average(saturations)
|
||||
val lightness = hslColors.map { it.l }
|
||||
val lightnessAverage = average(lightness)
|
||||
|
||||
val rgbColor = hslToRgb(huesAverage, saturationsAverage, lightnessAverage)
|
||||
|
||||
return FastColor.ARGB32.color(rgbColor.r, rgbColor.g, rgbColor.b)
|
||||
}
|
||||
|
||||
// Based on https://iter.ca/post/hue-avg
|
||||
fun hueAverage(hues: List<Double>): Float {
|
||||
val points = hues.map { hue ->
|
||||
val rad = hue.toRadians()
|
||||
Pair(cos(rad), sin(rad))
|
||||
}
|
||||
|
||||
val avgX = points.sumOf { it.first.toDouble() } / points.size
|
||||
val avgY = points.sumOf { it.second.toDouble() } / points.size
|
||||
|
||||
var degrees = atan2(avgY, avgX).toDegrees()
|
||||
if (degrees < 0) {
|
||||
degrees += 360f
|
||||
} else if (degrees > 360) {
|
||||
degrees -= 360f
|
||||
}
|
||||
|
||||
return degrees
|
||||
}
|
||||
|
||||
fun average(values: List<Float>): Float {
|
||||
if (values.isEmpty()) return 0f
|
||||
return values.sum() / values.size
|
||||
}
|
||||
|
||||
data class HSL(val h: Float, val s: Float, val l: Float)
|
||||
|
||||
fun rgbToHsl(r: Int, g: Int, b: Int): HSL {
|
||||
val rf = r / 255f
|
||||
val gf = g / 255f
|
||||
val bf = b / 255f
|
||||
|
||||
val max = maxOf(rf, gf, bf)
|
||||
val min = minOf(rf, gf, bf)
|
||||
val delta = max - min
|
||||
|
||||
var h = 0f
|
||||
val l = (max + min) / 2f
|
||||
val s = if (delta == 0f) 0f else delta / (1f - kotlin.math.abs(2f * l - 1f))
|
||||
|
||||
if (delta != 0f) {
|
||||
h = when (max) {
|
||||
rf -> ((gf - bf) / delta) % 6f
|
||||
gf -> ((bf - rf) / delta) + 2f
|
||||
else -> ((rf - gf) / delta) + 4f
|
||||
}
|
||||
h *= 60f
|
||||
if (h < 0) h += 360f
|
||||
}
|
||||
|
||||
return HSL(h, s, l)
|
||||
}
|
||||
|
||||
data class RGB(val r: Int, val g: Int, val b: Int)
|
||||
|
||||
fun hslToRgb(h: Float, s: Float, l: Float): RGB {
|
||||
val c = (1f - kotlin.math.abs(2f * l - 1f)) * s
|
||||
val x = c * (1f - kotlin.math.abs((h / 60f) % 2f - 1f))
|
||||
val m = l - c / 2f
|
||||
|
||||
val (rf, gf, bf) = when {
|
||||
h < 60f -> Triple(c, x, 0f)
|
||||
h < 120f -> Triple(x, c, 0f)
|
||||
h < 180f -> Triple(0f, c, x)
|
||||
h < 240f -> Triple(0f, x, c)
|
||||
h < 300f -> Triple(x, 0f, c)
|
||||
else -> Triple(c, 0f, x)
|
||||
}
|
||||
|
||||
return RGB(
|
||||
((rf + m) * 255).toInt().coerceIn(0, 255),
|
||||
((gf + m) * 255).toInt().coerceIn(0, 255),
|
||||
((bf + m) * 255).toInt().coerceIn(0, 255)
|
||||
)
|
||||
}
|
||||
@@ -28,12 +28,14 @@ import net.minecraft.server.level.ServerPlayer
|
||||
object DialogueManager {
|
||||
val activeDialogues = mutableMapOf<UUID, ActiveDialogue>()
|
||||
|
||||
@JvmStatic
|
||||
fun startDialogue(playerEntity: ServerPlayer, dialogue: Dialogue): ActiveDialogue {
|
||||
val activeDialogue = ActiveDialogue(playerEntity, dialogue)
|
||||
startDialogue(activeDialogue)
|
||||
return activeDialogue
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun startDialogue(playerEntity: ServerPlayer, npcEntity: NPCEntity, dialogue: Dialogue): ActiveDialogue {
|
||||
val activeDialogue = ActiveDialogue(playerEntity, dialogue)
|
||||
activeDialogue.runtime.withNPCValue("npc", npcEntity)
|
||||
@@ -42,6 +44,7 @@ object DialogueManager {
|
||||
return activeDialogue
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun startDialogue(activeDialogue: ActiveDialogue) {
|
||||
activeDialogue.initialize()
|
||||
if (!activeDialogue.completion.isDone) {
|
||||
@@ -49,6 +52,7 @@ object DialogueManager {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun stopDialogue(playerEntity: ServerPlayer) {
|
||||
val activeDialogue = playerEntity.activeDialogue ?: return
|
||||
DialogueClosedPacket(activeDialogue.dialogueId).sendToPlayer(playerEntity)
|
||||
|
||||
@@ -10,14 +10,12 @@ package com.cobblemon.mod.common.api.drop
|
||||
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.LOOT_DROPPED
|
||||
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
/**
|
||||
@@ -95,6 +93,16 @@ class DropTable {
|
||||
pokemon: Pokemon? = null,
|
||||
) {
|
||||
val drops = getDrops(amount, pokemon).toMutableList()
|
||||
postLootDroppedEvent(drops, entity, world, pos, player)
|
||||
}
|
||||
|
||||
fun postLootDroppedEvent(
|
||||
drops: MutableList<DropEntry>,
|
||||
entity: LivingEntity?,
|
||||
world: ServerLevel,
|
||||
pos: Vec3,
|
||||
player: ServerPlayer?,
|
||||
) {
|
||||
LOOT_DROPPED.postThen(
|
||||
event = LootDroppedEvent(this, player, entity, drops),
|
||||
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
|
||||
@@ -110,4 +118,4 @@ class DropTable {
|
||||
val entries = buffer.readInt()
|
||||
repeat(entries) { this.entries.add(ItemDropEntry().decode(buffer)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ interface PokemonSideDelegate : EntitySideDelegate<PokemonEntity> {
|
||||
fun handleStatus(status: Byte) {}
|
||||
fun spawnShinyParticle(player: Player) {}
|
||||
fun spawnAspectParticle() {}
|
||||
fun applyRenderRotation(partialTick: Float) {}
|
||||
fun positionRider(passenger: Entity, positionUpdater: MoveFunction)
|
||||
fun updateAge(age: Int) {}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.cobblemon.mod.common.api.events.berry.BerryHarvestEvent
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryMutationOfferEvent
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryMutationResultEvent
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryYieldCalculationEvent
|
||||
import com.cobblemon.mod.common.api.events.cooking.PokeSnackSpawnPokemonEvent
|
||||
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
|
||||
import com.cobblemon.mod.common.api.events.entity.*
|
||||
import com.cobblemon.mod.common.api.events.farming.ApricornHarvestEvent
|
||||
@@ -327,6 +328,12 @@ object CobblemonEvents {
|
||||
@JvmField
|
||||
val BOBBER_SPAWN_POKEMON_POST = EventObservable<BobberSpawnPokemonEvent.Post>()
|
||||
|
||||
@JvmField
|
||||
val POKE_SNACK_SPAWN_POKEMON_PRE = CancelableObservable<PokeSnackSpawnPokemonEvent.Pre>()
|
||||
|
||||
@JvmField
|
||||
val POKE_SNACK_SPAWN_POKEMON_POST = EventObservable<PokeSnackSpawnPokemonEvent.Post>()
|
||||
|
||||
@JvmField
|
||||
val BAIT_EFFECT_REGISTRATION = EventObservable<BaitEffectFunctionRegistryEvent>()
|
||||
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.events.cooking
|
||||
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.block.entity.PokeSnackBlockEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
|
||||
interface PokeSnackSpawnPokemonEvent {
|
||||
|
||||
data class Pre(
|
||||
val pokeSnackBlockEntity: PokeSnackBlockEntity,
|
||||
val spawnAction: SpawnAction<*>,
|
||||
) : Cancelable(), PokeSnackSpawnPokemonEvent {
|
||||
val context = mapOf<String, MoValue>()
|
||||
val functions = moLangFunctionMap(
|
||||
cancelFunc
|
||||
)
|
||||
}
|
||||
|
||||
data class Post(
|
||||
val pokeSnackBlockEntity: PokeSnackBlockEntity,
|
||||
val spawnAction: SpawnAction<*>,
|
||||
val pokemonEntity: PokemonEntity,
|
||||
) : PokeSnackSpawnPokemonEvent {
|
||||
val context = mapOf<String, MoValue>()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,6 +57,7 @@ object PokeRods : JsonDataRegistry<PokeRod> {
|
||||
* Gets a Pokerod from registry name.
|
||||
* @return the pokerod object if found otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getPokeRod(name : ResourceLocation): PokeRod? = rods[name]
|
||||
|
||||
}
|
||||
@@ -68,6 +68,7 @@ class SpawnBait(
|
||||
val TYPING = cobblemonResource("typing")
|
||||
val EGG_GROUP = cobblemonResource("egg_group")
|
||||
val SHINY_REROLL = cobblemonResource("shiny_reroll")
|
||||
val DROPS_REROLL = cobblemonResource("drops_reroll")
|
||||
val HIDDEN_ABILITY_CHANCE = cobblemonResource("ha_chance")
|
||||
val POKEMON_CHANCE = cobblemonResource("pokemon_chance")
|
||||
val FRIENDSHIP = cobblemonResource("friendship")
|
||||
@@ -85,6 +86,7 @@ class SpawnBait(
|
||||
registerEffect(NATURE) { entity, effect -> FishingSpawnCause.alterNatureAttempt(entity, effect) }
|
||||
registerEffect(IV) { entity, effect -> FishingSpawnCause.alterIVAttempt(entity, effect) }
|
||||
registerEffect(SHINY_REROLL) { entity, effect -> FishingSpawnCause.shinyReroll(entity, effect) }
|
||||
registerEffect(DROPS_REROLL) { entity, effect -> FishingSpawnCause.saveDropsReroll(entity, effect) }
|
||||
registerEffect(GENDER_CHANCE) { entity, effect -> FishingSpawnCause.alterGenderAttempt(entity, effect) }
|
||||
registerEffect(LEVEL_RAISE) { entity, effect -> FishingSpawnCause.alterLevelAttempt(entity, effect) }
|
||||
registerEffect(HIDDEN_ABILITY_CHANCE) { entity, _ -> FishingSpawnCause.alterHAAttempt(entity) }
|
||||
|
||||
@@ -53,20 +53,24 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getEffectsFromRodItemStack(stack: ItemStack): List<SpawnBait.Effect> {
|
||||
return getEffectsFromItemStack(stack.components.get(CobblemonItemComponents.BAIT)?.stack ?: ItemStack.EMPTY)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getEffectsFromItemStack(stack: ItemStack): List<SpawnBait.Effect> {
|
||||
val componentEffects = stack.get(CobblemonItemComponents.BAIT_EFFECTS)?.effects ?: emptyList()
|
||||
return componentEffects.mapNotNull(::getFromIdentifier).flatMap { it.effects } +
|
||||
getEffectsFromItem(stack.itemHolder)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getBaitIdentifiersFromItem(holder: Holder<Item>): List<ResourceLocation> {
|
||||
return effectsMap.entries.filter { it.value.item.fits(holder) }.map { it.key }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getBaitFromItemStack(holder: Holder<Item>): List<SpawnBait> {
|
||||
return effectsMap.values.filter { it.item.fits(holder) }
|
||||
}
|
||||
@@ -75,6 +79,7 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
|
||||
return getBaitFromItemStack(holder).flatMap { it.effects }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getFromIdentifier(identifier: ResourceLocation): SpawnBait? {
|
||||
// Check normal spawn bait registry
|
||||
effectsMap[identifier]?.let { return it }
|
||||
@@ -98,6 +103,7 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
|
||||
}
|
||||
|
||||
// if it has bait effects and is not listed as a seasoning then it is a bait
|
||||
@JvmStatic
|
||||
fun isFishingBait(stack: ItemStack): Boolean {
|
||||
val holder = stack.itemHolder
|
||||
return effectsMap.values.any { it.item.fits(holder) }
|
||||
|
||||
@@ -11,24 +11,18 @@ package com.cobblemon.mod.common.api.fishing
|
||||
import kotlin.math.ceil
|
||||
|
||||
object SpawnBaitUtils {
|
||||
@JvmStatic
|
||||
fun mergeEffects(effects: List<SpawnBait.Effect>): List<SpawnBait.Effect> {
|
||||
val grouped = effects.groupBy { Pair(it.type, it.subcategory) }
|
||||
|
||||
return grouped.map { (key, groupEffects) ->
|
||||
val (type, subcategory) = key
|
||||
|
||||
val count = groupEffects.size
|
||||
val totalChance = groupEffects.sumOf { it.chance }
|
||||
val totalValue = groupEffects.sumOf { it.value }
|
||||
|
||||
val multiplier = when (count) {
|
||||
2 -> 0.8
|
||||
3 -> 0.6
|
||||
else -> 1.0
|
||||
}
|
||||
|
||||
val adjustedChance = (totalChance * multiplier).coerceAtMost(1.0)
|
||||
val adjustedValue = ceil(totalValue * multiplier)
|
||||
val adjustedChance = totalChance.coerceAtMost(1.0)
|
||||
val adjustedValue = ceil(totalValue)
|
||||
|
||||
SpawnBait.Effect(type, subcategory, adjustedChance, adjustedValue)
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ object Fossils: JsonDataRegistry<Fossil> {
|
||||
/**
|
||||
* Gets all loaded [Fossil]s.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun all() = this.fossils.values.toList()
|
||||
|
||||
/**
|
||||
@@ -76,6 +77,7 @@ object Fossils: JsonDataRegistry<Fossil> {
|
||||
* @param identifier The identifier of the fossil.
|
||||
* @return The [Fossil] if loaded, otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByIdentifier(identifier: ResourceLocation): Fossil? = this.fossils[identifier]
|
||||
|
||||
/**
|
||||
@@ -83,6 +85,7 @@ object Fossils: JsonDataRegistry<Fossil> {
|
||||
* @param fossilStacks The fossil [ItemStack]'s.
|
||||
* @return The [Fossil] if found, otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getFossilByItemStacks(fossilStacks: List<ItemStack>): Fossil? {
|
||||
return this.all().firstOrNull { it.matchesIngredients(fossilStacks) }
|
||||
}
|
||||
@@ -92,6 +95,7 @@ object Fossils: JsonDataRegistry<Fossil> {
|
||||
* @param fossilStacks The fossil [ItemStack]'s.
|
||||
* @return The [Fossil] if found to be a superset, otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getSubFossilByItemStacks(fossilStacks: List<ItemStack>): Fossil? {
|
||||
return this.all().firstOrNull { it.matchesIngredientsSubSet(fossilStacks) }
|
||||
}
|
||||
@@ -100,6 +104,7 @@ object Fossils: JsonDataRegistry<Fossil> {
|
||||
* @param itemStack The ingredient [ItemStack].
|
||||
* @return true if it's a fossil ingredient, otherwise false.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isFossilIngredient(itemStack: ItemStack): Boolean {
|
||||
return this.all().any { it.isIngredient(itemStack) }
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isNaturalMaterial(item: ItemStack): Boolean {
|
||||
val itemId = BuiltInRegistries.ITEM.getKey(item.item)
|
||||
return itemId in itemMap.keys || tagMap.keys.any {
|
||||
@@ -64,6 +65,7 @@ object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getContent(item: ItemStack): Int? {
|
||||
val itemId = BuiltInRegistries.ITEM.getKey(item.item)
|
||||
if (itemId in itemMap.keys) {
|
||||
@@ -76,6 +78,7 @@ object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getReturnItem(item: ItemStack): ResourceLocation? {
|
||||
val itemId = BuiltInRegistries.ITEM.getKey(item.item)
|
||||
if (itemId in itemMap.keys) {
|
||||
@@ -87,4 +90,4 @@ object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,9 @@ object Marks: JsonDataRegistry<Mark> {
|
||||
/**
|
||||
* Gets all loaded [Mark]s.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun all() = this.marks.values.toList()
|
||||
@JvmStatic
|
||||
fun identifiers(): Collection<String> = marks.keys.toSet().map { it.toString() }
|
||||
|
||||
/**
|
||||
@@ -64,5 +66,6 @@ object Marks: JsonDataRegistry<Mark> {
|
||||
* @param identifier The identifier of the mark.
|
||||
* @return The [Mark] if loaded, otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByIdentifier(identifier: ResourceLocation): Mark? = this.marks[identifier]
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import com.bedrockk.molang.runtime.MoLangEnvironment
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.MoParams
|
||||
import com.bedrockk.molang.runtime.struct.ArrayStruct
|
||||
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.bedrockk.molang.runtime.struct.ContextStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
@@ -40,7 +40,6 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.NPCProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
|
||||
import com.cobblemon.mod.common.api.npc.NPCClass
|
||||
import com.cobblemon.mod.common.api.npc.NPCClasses
|
||||
import com.cobblemon.mod.common.api.npc.configuration.interaction.DialogueNPCInteractionConfiguration
|
||||
import com.cobblemon.mod.common.api.npc.configuration.interaction.ScriptNPCInteractionConfiguration
|
||||
@@ -57,7 +56,6 @@ import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.SidemodExperienceSource
|
||||
import com.cobblemon.mod.common.api.pokemon.moves.LearnsetQuery
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.riding.Rideable
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.Schedulable
|
||||
@@ -137,7 +135,6 @@ import net.minecraft.world.entity.LightningBolt
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.Mob
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.PlayerRideable
|
||||
import net.minecraft.world.entity.TamableAnimal
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
@@ -145,7 +142,6 @@ import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.animal.Animal
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.monster.Enemy
|
||||
import net.minecraft.world.entity.monster.Monster
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
@@ -160,9 +156,6 @@ import net.minecraft.world.level.levelgen.Heightmap
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.text.get
|
||||
import kotlin.text.toInt
|
||||
import kotlin.toString
|
||||
|
||||
/**
|
||||
* Holds a bunch of useful MoLang trickery that can be used or extended in API
|
||||
@@ -187,6 +180,18 @@ object MoLangFunctions {
|
||||
struct.map.clear()
|
||||
DoubleValue.ONE
|
||||
},
|
||||
"get_variable" to java.util.function.Function { params ->
|
||||
val struct = params.get<VariableStruct>(0)
|
||||
val variable = params.getString(1)
|
||||
return@Function struct.map[variable] ?: DoubleValue.ZERO
|
||||
},
|
||||
"set_variable" to java.util.function.Function { params ->
|
||||
val struct = params.get<VariableStruct>(0)
|
||||
val variable = params.getString(1)
|
||||
val value = params.get<MoValue>(2)
|
||||
struct.map[variable] = value
|
||||
return@Function value
|
||||
},
|
||||
"set_query" to java.util.function.Function { params ->
|
||||
val variable = params.getString(0)
|
||||
val value = params.get<MoValue>(1)
|
||||
@@ -304,8 +309,12 @@ object MoLangFunctions {
|
||||
val runtime = MoLangRuntime()
|
||||
runtime.environment.query = params.environment.query
|
||||
runtime.environment.variable = params.environment.variable
|
||||
runtime.environment.context = params.environment.context
|
||||
val args = params.params.subList(1, params.params.size)
|
||||
runtime.environment.context = ContextStruct(
|
||||
params.environment.context.map + args.mapIndexed { index, value -> "arg_${index + 1}" to value }.toMap()
|
||||
)
|
||||
val script = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
// store the args in the
|
||||
CobblemonScripts.run(script, runtime) ?: DoubleValue.ZERO
|
||||
},
|
||||
"run_molang" to java.util.function.Function { params ->
|
||||
@@ -357,7 +366,8 @@ object MoLangFunctions {
|
||||
val pickupPriority = params.getIntOrNull(1) ?: 0
|
||||
val pickupItem = ObtainableItem(item = item, pickupPriority = pickupPriority)
|
||||
return@Function pickupItem.struct
|
||||
}
|
||||
},
|
||||
"file" to java.util.function.Function { MoLangLoadedFilesCache.struct }
|
||||
)
|
||||
val biomeFunctions = mutableListOf<(Holder<Biome>) -> HashMap<String, java.util.function.Function<MoParams, Any>>>()
|
||||
val worldFunctions = mutableListOf<(Holder<Level>) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
@@ -598,10 +608,10 @@ object MoLangFunctions {
|
||||
}
|
||||
if (player is ServerPlayer) {
|
||||
map.put("seen_credits") { _ ->
|
||||
DoubleValue( DoubleValue(player.seenCredits) )
|
||||
DoubleValue(player.seenCredits)
|
||||
}
|
||||
map.put("is_in_dialogue") { _ ->
|
||||
DoubleValue( DoubleValue(player.isInDialogue) )
|
||||
DoubleValue(player.isInDialogue)
|
||||
}
|
||||
map.put("active_dialogue") { _ ->
|
||||
if (player.isInDialogue) {
|
||||
@@ -1185,16 +1195,28 @@ object MoLangFunctions {
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("has_memory_value") { params ->
|
||||
val memoryTypes = params.params.map {
|
||||
it.asString().asIdentifierDefaultingNamespace()
|
||||
}.map(BuiltInRegistries.MEMORY_MODULE_TYPE::get)
|
||||
return@put DoubleValue(memoryTypes.all { entity.brain.checkMemory(it, MemoryStatus.VALUE_PRESENT) })
|
||||
for (param in params.params) {
|
||||
if (!entity.hasMemoryFromString(param.asString())) {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("lacks_memory_value") { params ->
|
||||
val memoryTypes = params.params.map {
|
||||
it.asString().asIdentifierDefaultingNamespace()
|
||||
}.map(BuiltInRegistries.MEMORY_MODULE_TYPE::get)
|
||||
return@put DoubleValue(memoryTypes.none { entity.brain.checkMemory(it, MemoryStatus.VALUE_PRESENT) })
|
||||
for (param in params.params) {
|
||||
if (entity.hasMemoryFromString(param.asString())) {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("is_doing_activity") { params ->
|
||||
for (param in params.params) {
|
||||
if (entity.isDoingActivityFromString(param.asString())) {
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
}
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
map.put("can_see") { params ->
|
||||
val target = params.get<MoValue>(0)
|
||||
@@ -1252,15 +1274,6 @@ object MoLangFunctions {
|
||||
map.put("in_battle") { DoubleValue(npc.isInBattle()) }
|
||||
map.put("battles") { ArrayStruct(npc.battleIds.mapNotNull { BattleRegistry.getBattle(it)?.struct }.mapIndexed { index, value -> "$index" to value }.toMap()) }
|
||||
map.put("stop_battles") { _ -> npc.battleIds.forEach { BattleRegistry.getBattle(it)?.stop() } }
|
||||
map.put("is_doing_activity") { params ->
|
||||
val identifiers = params.params.map { it.asString().asIdentifierDefaultingNamespace(namespace = "minecraft") }
|
||||
val activities = identifiers.mapNotNull { identifier -> BuiltInRegistries.ACTIVITY.get(identifier) }
|
||||
if (activities.isNotEmpty()) {
|
||||
return@put DoubleValue(activities.any { activity -> npc.brain.isActive(activity) })
|
||||
} else {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("run_script_on_client") { params ->
|
||||
val world = npc.level()
|
||||
if (world is ServerLevel) {
|
||||
@@ -1891,12 +1904,43 @@ object MoLangFunctions {
|
||||
map.put("in_battle") { DoubleValue(pokemonEntity.isBattling) }
|
||||
map.put("is_moving") { DoubleValue((pokemonEntity.moveControl as? PokemonMoveControl)?.hasWanted() == true) }
|
||||
map.put("is_flying") { DoubleValue(pokemonEntity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) }
|
||||
map.put("get_alt_pose") { StringValue(pokemonEntity.getAltPose()) }
|
||||
map.put("is_gliding") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("gliding"))) }
|
||||
map.put("is_sprinting") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("sprinting"))) }
|
||||
map.put("is_drifting") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("drifting"))) }
|
||||
map.put("is_powered_drifting") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("powered_drifting"))) }
|
||||
map.put("in_air") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("in_air"))) }
|
||||
map.put("get_riding_state") { params ->
|
||||
val name = params.getStringOrNull(0)
|
||||
pokemonEntity.ifRidingAvailableSupply(DoubleValue.ZERO) { behaviour, settings, state ->
|
||||
val moValue = behaviour.asMoLangValue(settings, state, pokemonEntity)
|
||||
return@ifRidingAvailableSupply moValue.functions[name]?.apply(MoParams.EMPTY) as? MoValue ?: moValue
|
||||
}
|
||||
}
|
||||
map.put("is_gliding") {
|
||||
pokemonEntity.ifRidingAvailableSupply(DoubleValue.ZERO) { behaviour, settings, state ->
|
||||
val moValue = behaviour.asMoLangValue(settings, state, pokemonEntity)
|
||||
return@ifRidingAvailableSupply moValue.functions.get("gliding")?.apply(MoParams.EMPTY) as? MoValue ?: DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("is_sprinting") {
|
||||
pokemonEntity.ifRidingAvailableSupply(DoubleValue.ZERO) { behaviour, settings, state ->
|
||||
val moValue = behaviour.asMoLangValue(settings, state, pokemonEntity)
|
||||
return@ifRidingAvailableSupply moValue.functions.get("sprinting")?.apply(MoParams.EMPTY) as? MoValue ?: DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("is_drifting") {
|
||||
pokemonEntity.ifRidingAvailableSupply(DoubleValue.ZERO) { behaviour, settings, state ->
|
||||
val moValue = behaviour.asMoLangValue(settings, state, pokemonEntity)
|
||||
return@ifRidingAvailableSupply moValue.functions.get("drifting")?.apply(MoParams.EMPTY) as? MoValue ?: DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("is_powered_drifting") {
|
||||
pokemonEntity.ifRidingAvailableSupply(DoubleValue.ZERO) { behaviour, settings, state ->
|
||||
val moValue = behaviour.asMoLangValue(settings, state, pokemonEntity)
|
||||
return@ifRidingAvailableSupply moValue.functions.get("powered_drifting")?.apply(MoParams.EMPTY) as? MoValue ?: DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("in_air") {
|
||||
pokemonEntity.ifRidingAvailableSupply(DoubleValue.ZERO) { behaviour, settings, state ->
|
||||
val moValue = behaviour.asMoLangValue(settings, state, pokemonEntity)
|
||||
return@ifRidingAvailableSupply moValue.functions.get("in_air")?.apply(MoParams.EMPTY) as? MoValue ?: DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("is_wild") { DoubleValue(pokemonEntity.ownerUUID == null) }
|
||||
map.put("is_in_party") { DoubleValue(pokemonEntity.pokemon.storeCoordinates.get()?.store is PartyStore) }
|
||||
map.put("is_ridden") { DoubleValue(pokemonEntity.hasControllingPassenger()) }
|
||||
@@ -1905,6 +1949,9 @@ object MoLangFunctions {
|
||||
map.put("is_holding_item") { DoubleValue(!pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).let {
|
||||
it.isEmpty || it.`is`(CobblemonItemTags.WEARABLE_HAT_ITEMS) || it.`is`(CobblemonItemTags.WEARABLE_FACE_ITEMS)
|
||||
}) }
|
||||
map.put("riding_style") {
|
||||
StringValue(pokemonEntity.ifRidingAvailableSupply("") { behaviour, settings, state -> behaviour.getRidingStyle(settings, state).name })
|
||||
}
|
||||
map.put("is_wearing_hat") { DoubleValue(pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).`is`(CobblemonItemTags.WEARABLE_HAT_ITEMS)) }
|
||||
map.put("is_wearing_face") { DoubleValue(pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).`is`(CobblemonItemTags.WEARABLE_FACE_ITEMS)) }
|
||||
map.put("is_pastured") {
|
||||
@@ -2471,6 +2518,17 @@ object MoLangFunctions {
|
||||
return value
|
||||
}
|
||||
|
||||
fun Vec3.asMoLangValue(): ObjectValue<Vec3> {
|
||||
val value = ObjectValue(
|
||||
obj = this
|
||||
)
|
||||
value.addFunction("x") { this.x }
|
||||
value.addFunction("y") { this.y }
|
||||
value.addFunction("z") { this.z }
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Different functions exist depending on the entity type, this tries to make the struct that's most specific to the type.
|
||||
*/
|
||||
@@ -2657,5 +2715,4 @@ object MoLangFunctions {
|
||||
}
|
||||
}
|
||||
|
||||
fun Either<ResourceLocation, ExpressionLike>.runScript(runtime: MoLangRuntime) = map({ CobblemonScripts.run(it, runtime) }, { it.resolve(runtime) })
|
||||
|
||||
fun Either<ResourceLocation, ExpressionLike>.runScript(runtime: MoLangRuntime) = map({ CobblemonScripts.run(it, runtime) }, { it.resolve(runtime) })
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.molang
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonElement
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.world.level.storage.LevelResource
|
||||
|
||||
/**
|
||||
* A cache for loaded MoLang files to avoid redundant file I/O operations.
|
||||
* Provides functions to load, save, check existence, and clear cached files.
|
||||
*
|
||||
* Only files with /molang/ in their path and a .json extension within the config
|
||||
* or data folders can be accessed.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since November 1st, 2025
|
||||
*/
|
||||
object MoLangLoadedFilesCache {
|
||||
private val gson = GsonBuilder().setPrettyPrinting().create()
|
||||
val loadedFiles = ConcurrentHashMap<String, VariableStruct>()
|
||||
|
||||
/** Essentially the server root or world root for singleplayer. */
|
||||
lateinit var baseFolder: Path
|
||||
private lateinit var configFolder: Path
|
||||
private lateinit var dataFolder: Path
|
||||
|
||||
fun initialize(server: MinecraftServer) {
|
||||
baseFolder = server.getWorldPath(LevelResource.ROOT)
|
||||
configFolder = baseFolder.resolve("config").normalize().toAbsolutePath()
|
||||
dataFolder = baseFolder.resolve("data").normalize().toAbsolutePath()
|
||||
}
|
||||
|
||||
val struct = QueryStruct(hashMapOf())
|
||||
.addFunction("load") { params ->
|
||||
val fileName = params.params[0].asString()
|
||||
return@addFunction load(fileName)
|
||||
}
|
||||
.addFunction("save") { params ->
|
||||
val fileName = params.params[0].asString()
|
||||
val data = params.params[1] as VariableStruct
|
||||
save(fileName, data)
|
||||
return@addFunction DoubleValue.ONE
|
||||
}
|
||||
.addFunction("exists") { params ->
|
||||
val fileName = params.params[0].asString()
|
||||
val exists = exists(fileName)
|
||||
return@addFunction if (exists) DoubleValue.ONE else DoubleValue.ZERO
|
||||
}
|
||||
.addFunction("clear") { params ->
|
||||
val fileName = params.params[0].asString()
|
||||
clear(fileName)
|
||||
return@addFunction DoubleValue.ONE
|
||||
}
|
||||
|
||||
private fun validatePath(fileName: String): Path? {
|
||||
val filePath = baseFolder.resolve(fileName).normalize().toAbsolutePath()
|
||||
if (!filePath.startsWith(configFolder) && !filePath.startsWith(dataFolder)) {
|
||||
Cobblemon.LOGGER.error("MoLang attempted to access file outside of config or data folder: $fileName")
|
||||
return null
|
||||
} else if ("/molang/" !in fileName) {
|
||||
Cobblemon.LOGGER.error("MoLang attempted to access file outside of a 'molang' subfolder: $fileName")
|
||||
return null
|
||||
} else if (!fileName.endsWith(".json")) {
|
||||
Cobblemon.LOGGER.error("MoLang attempted to access file without a .json extension: $fileName")
|
||||
return null
|
||||
}
|
||||
return filePath
|
||||
}
|
||||
|
||||
fun exists(fileName: String): Boolean {
|
||||
val filePath = validatePath(fileName) ?: return false
|
||||
return filePath.toFile().exists()
|
||||
}
|
||||
|
||||
fun clear(fileName: String) {
|
||||
loadedFiles.remove(fileName)
|
||||
}
|
||||
|
||||
fun load(fileName: String): VariableStruct {
|
||||
return loadedFiles.getOrPut(fileName) {
|
||||
val filePath = validatePath(fileName) ?: return VariableStruct()
|
||||
val file = filePath.toFile()
|
||||
if (!file.exists()) {
|
||||
return VariableStruct()
|
||||
}
|
||||
val jsonElement = gson.fromJson(file.readText(), JsonElement::class.java)
|
||||
MoValue.of(jsonElement) as VariableStruct
|
||||
}
|
||||
}
|
||||
|
||||
fun save(fileName: String, data: VariableStruct) {
|
||||
loadedFiles[fileName] = data
|
||||
val filePath = validatePath(fileName) ?: return
|
||||
val file = filePath.toFile()
|
||||
file.parentFile?.mkdirs()
|
||||
val jsonElement = MoValue.writeToJson(data)
|
||||
file.writeText(gson.toJson(jsonElement))
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@
|
||||
package com.cobblemon.mod.common.api.molang
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
@@ -23,11 +23,11 @@ import net.minecraft.resources.ResourceLocation
|
||||
*/
|
||||
class ReferenceExpression(val identifier: ResourceLocation) : ExpressionLike {
|
||||
override fun resolve(runtime: MoLangRuntime, context: Map<String, MoValue>): MoValue {
|
||||
return getScript()?.resolve(runtime, context) ?: DoubleValue.ZERO
|
||||
return getScript()?.resolve(runtime, context) ?: StringValue(identifier.toString())
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return getScript()?.getString() ?: "0"
|
||||
return getScript()?.getString() ?: identifier.toString()
|
||||
}
|
||||
|
||||
fun getScript() = CobblemonScripts.scripts[identifier]
|
||||
|
||||
@@ -33,6 +33,7 @@ object HiddenPowerUtil {
|
||||
ElementalTypes.DARK
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun getHiddenPowerType(pokemon: Pokemon?): ElementalType {
|
||||
if (pokemon == null) {
|
||||
return ElementalTypes.NORMAL
|
||||
|
||||
@@ -53,8 +53,7 @@ open class MoveTemplate(
|
||||
val pp: Int,
|
||||
val priority: Int,
|
||||
val critRatio: Double,
|
||||
val effectChances: Array<Double>,
|
||||
val actionEffect: ActionEffectTimeline?
|
||||
val effectChances: Array<Double>
|
||||
) {
|
||||
val struct: MoStruct by lazy {
|
||||
QueryStruct(hashMapOf())
|
||||
@@ -87,8 +86,7 @@ open class MoveTemplate(
|
||||
pp = 5,
|
||||
priority = 0,
|
||||
critRatio = 0.0,
|
||||
effectChances = emptyArray(),
|
||||
actionEffect = null
|
||||
effectChances = emptyArray()
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -92,18 +92,7 @@ object Moves : DataRegistry {
|
||||
effectChances += secondaryMember.get("chance").asDouble
|
||||
}
|
||||
}
|
||||
val actionEffect = ActionEffects.actionEffects[id.asIdentifierDefaultingNamespace()]
|
||||
?: run {
|
||||
ActionEffects.actionEffects["generic_move".asIdentifierDefaultingNamespace()]
|
||||
// if (damageCategory == DamageCategories.STATUS) {
|
||||
// ActionEffects.actionEffects[cobblemonResource("status")]
|
||||
// } else {
|
||||
// val type = elementalType.name.lowercase()
|
||||
// val category = damageCategory.name.lowercase()
|
||||
// ActionEffects.actionEffects["${category}_$type".asIdentifierDefaultingNamespace()]
|
||||
// }
|
||||
}
|
||||
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray(), actionEffect)
|
||||
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray())
|
||||
this.register(move)
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Caught exception trying to resolve the move '{}'", id, e)
|
||||
@@ -117,12 +106,19 @@ object Moves : DataRegistry {
|
||||
MovesRegistrySyncPacket(all()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getByName(name: String) = allMoves[name.lowercase()]
|
||||
@JvmStatic
|
||||
fun getByNumericalId(id: Int) = idMapping[id]
|
||||
@JvmStatic
|
||||
fun getByNameOrDummy(name: String) = allMoves[name.lowercase()] ?: MoveTemplate.dummy(name.lowercase())
|
||||
@JvmStatic
|
||||
fun getExceptional() = getByName("tackle") ?: allMoves.values.random()
|
||||
@JvmStatic
|
||||
fun count() = allMoves.size
|
||||
@JvmStatic
|
||||
fun names(): Collection<String> = this.allMoves.keys.toSet()
|
||||
@JvmStatic
|
||||
fun all() = this.allMoves.values.toList()
|
||||
|
||||
internal fun receiveSyncPacket(moves: Collection<MoveTemplate>) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.keyframes.*
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.pokemon.adapters.CobblemonStatTypeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -91,5 +92,11 @@ object ActionEffects : JsonDataRegistry<ActionEffectTimeline> {
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
fun getEffectWithBattleContext(id: ResourceLocation, pokemon: BattlePokemon): ActionEffectTimeline? {
|
||||
val species = pokemon.entity?.exposedSpecies ?: pokemon.effectedPokemon.species
|
||||
val contextedEffect = actionEffects[ResourceLocation.fromNamespaceAndPath(id.namespace, id.path + "_" + species)]
|
||||
return contextedEffect ?: actionEffects[id]
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayer) {}
|
||||
}
|
||||
@@ -97,6 +97,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
|
||||
override val observable = SimpleObservable<NPCClasses>()
|
||||
private val npcClassesByIdentifier = hashMapOf<ResourceLocation, NPCClass>()
|
||||
|
||||
@JvmStatic
|
||||
val classes: Collection<NPCClass>
|
||||
get() = this.npcClassesByIdentifier.values
|
||||
|
||||
@@ -116,6 +117,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
|
||||
* @param identifier The unique [NPCClass.id] of the [NPCClass].
|
||||
* @return The [NPCClass] if existing.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByIdentifier(identifier: ResourceLocation) = this.npcClassesByIdentifier[identifier]
|
||||
|
||||
/**
|
||||
@@ -123,6 +125,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
|
||||
*
|
||||
* @return The loaded NPC class amount.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun count() = this.npcClassesByIdentifier.size
|
||||
|
||||
/**
|
||||
@@ -132,6 +135,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
|
||||
*
|
||||
* @return A randomly selected [Species].
|
||||
*/
|
||||
@JvmStatic
|
||||
fun random(): NPCClass = this.npcClassesByIdentifier.values.random()
|
||||
|
||||
fun dummy(): NPCClass {
|
||||
|
||||
@@ -102,6 +102,7 @@ object NPCPresets : JsonDataRegistry<NPCPreset> {
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getPreset(identifier: ResourceLocation): NPCPreset? {
|
||||
return npcPresetsByIdentifier[identifier]
|
||||
}
|
||||
|
||||
+8
-2
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.orientation
|
||||
|
||||
import com.cobblemon.mod.common.util.math.geometry.toDegrees
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import org.joml.Matrix3f
|
||||
@@ -63,7 +64,12 @@ open class OrientationController(val entity: LivingEntity) {
|
||||
}
|
||||
|
||||
fun getRenderOrientation(delta: Float): Quaternionf {
|
||||
val old = renderOrientationO ?: renderOrientation ?: orientation
|
||||
// Return direct orientation if this is the player that drives this entities orientation.
|
||||
//TODO: Why does this break the render orientation.
|
||||
// if(entity.level().isClientSide && entity.controllingPassenger == Minecraft.getInstance().player) {
|
||||
// return Quaternionf().setFromUnnormalized(orientation)
|
||||
// }
|
||||
val old = renderOrientationO ?: renderOrientation ?: orientation ?: Matrix3f()
|
||||
val new = renderOrientation ?: old
|
||||
val oldQuat = Quaternionf().setFromUnnormalized(old)
|
||||
val newQuat = Quaternionf().setFromUnnormalized(new)
|
||||
@@ -78,7 +84,7 @@ open class OrientationController(val entity: LivingEntity) {
|
||||
val renderMatrix = this.renderOrientation ?: current
|
||||
val renderQuat = Quaternionf().setFromUnnormalized(renderMatrix)
|
||||
val targetQuat = Quaternionf().setFromUnnormalized(current)
|
||||
val dampingFactor = 0.66f // We can change this factor for faster transitions
|
||||
val dampingFactor = 0.66f // Smooth interpolation to reduce jitter of orientations recieved from the server.
|
||||
renderQuat.slerp(targetQuat, dampingFactor)
|
||||
|
||||
val newRenderOrientation = Matrix3f()
|
||||
|
||||
@@ -23,11 +23,14 @@ object PastureLinkManager {
|
||||
// Maps player UUID
|
||||
val links = mutableMapOf<UUID, PastureLink>()
|
||||
|
||||
@JvmStatic
|
||||
fun getLinkByPlayerId(playerId: UUID) = links[playerId]
|
||||
@JvmStatic
|
||||
fun createLink(playerId: UUID, link: PastureLink) {
|
||||
links[playerId] = link
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getLinkByPlayer(player: ServerPlayer): PastureLink? {
|
||||
val link = getLinkByPlayerId(player.uuid)
|
||||
if (link != null) {
|
||||
@@ -40,6 +43,7 @@ object PastureLinkManager {
|
||||
return link
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun removeAt(world: ServerLevel, pos: BlockPos) {
|
||||
links.removeIf { (uuid, pastureLink) ->
|
||||
val shouldRemove = world.dimensionTypeRegistration().`is`(pastureLink.dimension) && pastureLink.pos == pos
|
||||
|
||||
+1
@@ -28,6 +28,7 @@ import net.minecraft.server.level.ServerPlayer
|
||||
object PasturePermissionControllers {
|
||||
val controllers = PrioritizedList<PasturePermissionController>()
|
||||
|
||||
@JvmStatic
|
||||
fun permit(player: ServerPlayer, pastureBlockEntity: PokemonPastureBlockEntity): PasturePermissions {
|
||||
return controllers.firstNotNullOfOrNull { it.permit(player, pastureBlockEntity) }
|
||||
?: PasturePermissions(
|
||||
|
||||
@@ -147,6 +147,10 @@ object CobblemonPermissions {
|
||||
@JvmStatic
|
||||
val SEE_HIDDEN_NPCS = this.create("seehiddennpcs", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
@JvmStatic
|
||||
val USE_RIDING_STATS_DEBUG = this.create("useridingstatsdebug", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
@JvmStatic
|
||||
fun all(): Iterable<Permission> = this.permissions
|
||||
|
||||
private fun create(node: String, level: PermissionLevel): Permission {
|
||||
|
||||
@@ -53,100 +53,196 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
// ToDo datapack pokeball type here instead
|
||||
private val custom = hashMapOf<ResourceLocation, PokeBall>()
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("getPokeBall")
|
||||
val POKE_BALL
|
||||
get() = this.byName("poke_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getSlateBall")
|
||||
val SLATE_BALL
|
||||
get() = this.byName("slate_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAzureBall")
|
||||
val AZURE_BALL
|
||||
get() = this.byName("azure_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getVerdantBall")
|
||||
val VERDANT_BALL
|
||||
get() = this.byName("verdant_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getRoseateBall")
|
||||
val ROSEATE_BALL
|
||||
get() = this.byName("roseate_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getCitrineBall")
|
||||
val CITRINE_BALL
|
||||
get() = this.byName("citrine_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getGreatBall")
|
||||
val GREAT_BALL
|
||||
get() = this.byName("great_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getUltraBall")
|
||||
val ULTRA_BALL
|
||||
get() = this.byName("ultra_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getMasterBall")
|
||||
val MASTER_BALL
|
||||
get() = this.byName("master_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getSafariBall")
|
||||
val SAFARI_BALL
|
||||
get() = this.byName("safari_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getFastBall")
|
||||
val FAST_BALL
|
||||
get() = this.byName("fast_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getLevelBall")
|
||||
val LEVEL_BALL
|
||||
get() = this.byName("level_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getLureBall")
|
||||
val LURE_BALL
|
||||
get() = this.byName("lure_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getHeavyBall")
|
||||
val HEAVY_BALL
|
||||
get() = this.byName("heavy_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getLoveBall")
|
||||
val LOVE_BALL
|
||||
get() = this.byName("love_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getFriendBall")
|
||||
val FRIEND_BALL
|
||||
get() = this.byName("friend_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getMoonBall")
|
||||
val MOON_BALL
|
||||
get() = this.byName("moon_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getSportBall")
|
||||
val SPORT_BALL
|
||||
get() = this.byName("sport_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getNetBall")
|
||||
val NET_BALL
|
||||
get() = this.byName("net_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getDiveBall")
|
||||
val DIVE_BALL
|
||||
get() = this.byName("dive_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getNestBall")
|
||||
val NEST_BALL
|
||||
get() = this.byName("nest_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getRepeatBall")
|
||||
val REPEAT_BALL
|
||||
get() = this.byName("repeat_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getTimerBall")
|
||||
val TIMER_BALL
|
||||
get() = this.byName("timer_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getLuxuryBall")
|
||||
val LUXURY_BALL
|
||||
get() = this.byName("luxury_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getPremierBall")
|
||||
val PREMIER_BALL
|
||||
get() = this.byName("premier_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getDuskBall")
|
||||
val DUSK_BALL
|
||||
get() = this.byName("dusk_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getHealBall")
|
||||
val HEAL_BALL
|
||||
get() = this.byName("heal_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getQuickBall")
|
||||
val QUICK_BALL
|
||||
get() = this.byName("quick_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getCherishBall")
|
||||
val CHERISH_BALL
|
||||
get() = this.byName("cherish_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getParkBall")
|
||||
val PARK_BALL
|
||||
get() = this.byName("park_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getDreamBall")
|
||||
val DREAM_BALL
|
||||
get() = this.byName("dream_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getBeastBall")
|
||||
val BEAST_BALL
|
||||
get() = this.byName("beast_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientPokeBall")
|
||||
val ANCIENT_POKE_BALL
|
||||
get() = this.byName("ancient_poke_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientCitrineBall")
|
||||
val ANCIENT_CITRINE_BALL
|
||||
get() = this.byName("ancient_citrine_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientVerdantBall")
|
||||
val ANCIENT_VERDANT_BALL
|
||||
get() = this.byName("ancient_verdant_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientAzureBall")
|
||||
val ANCIENT_AZURE_BALL
|
||||
get() = this.byName("ancient_azure_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientRoseateBall")
|
||||
val ANCIENT_ROSEATE_BALL
|
||||
get() = this.byName("ancient_roseate_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientSlateBall")
|
||||
val ANCIENT_SLATE_BALL
|
||||
get() = this.byName("ancient_slate_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientIvoryBall")
|
||||
val ANCIENT_IVORY_BALL
|
||||
get() = this.byName("ancient_ivory_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientGreatBall")
|
||||
val ANCIENT_GREAT_BALL
|
||||
get() = this.byName("ancient_great_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientUltraBall")
|
||||
val ANCIENT_ULTRA_BALL
|
||||
get() = this.byName("ancient_ultra_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientHeavyBall")
|
||||
val ANCIENT_HEAVY_BALL
|
||||
get() = this.byName("ancient_heavy_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientLeadenBall")
|
||||
val ANCIENT_LEADEN_BALL
|
||||
get() = this.byName("ancient_leaden_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientGigatonBall")
|
||||
val ANCIENT_GIGATON_BALL
|
||||
get() = this.byName("ancient_gigaton_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientFeatherBall")
|
||||
val ANCIENT_FEATHER_BALL
|
||||
get() = this.byName("ancient_feather_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientWingBall")
|
||||
val ANCIENT_WING_BALL
|
||||
get() = this.byName("ancient_wing_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientJetBall")
|
||||
val ANCIENT_JET_BALL
|
||||
get() = this.byName("ancient_jet_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientOriginBall")
|
||||
val ANCIENT_ORIGIN_BALL
|
||||
get() = this.byName("ancient_origin_ball")
|
||||
|
||||
@@ -225,8 +321,10 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
* Gets a Pokeball from registry name.
|
||||
* @return the pokeball object if found otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getPokeBall(name : ResourceLocation): PokeBall? = this.custom[name] ?: this.defaults[name]
|
||||
|
||||
@JvmStatic
|
||||
fun all() = this.defaults.filterKeys { !this.custom.containsKey(it) }.values + this.custom.values
|
||||
|
||||
private fun createDefault(
|
||||
@@ -250,4 +348,196 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
val identifier = cobblemonResource(name)
|
||||
return this.custom[identifier] ?: this.defaults[identifier]!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Backwards compatibility getters
|
||||
*/
|
||||
@JvmName("getPOKE_BALL")
|
||||
@Deprecated("Use PokeBalls.getPokeBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getPOKE_BALL() = POKE_BALL
|
||||
|
||||
@JvmName("getSLATE_BALL")
|
||||
@Deprecated("Use PokeBalls.getSlateBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getSLATE_BALL() = SLATE_BALL
|
||||
|
||||
@JvmName("getAZURE_BALL")
|
||||
@Deprecated("Use PokeBalls.getAzureBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getAZURE_BALL() = AZURE_BALL
|
||||
|
||||
@JvmName("getVERDANT_BALL")
|
||||
@Deprecated("Use PokeBalls.getVerdantBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getVERDANT_BALL() = VERDANT_BALL
|
||||
|
||||
@JvmName("getROSEATE_BALL")
|
||||
@Deprecated("Use PokeBalls.getRoseateBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getROSEATE_BALL() = ROSEATE_BALL
|
||||
|
||||
@JvmName("getCITRINE_BALL")
|
||||
@Deprecated("Use PokeBalls.getCitrineBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getCITRINE_BALL() = CITRINE_BALL
|
||||
|
||||
@JvmName("getGREAT_BALL")
|
||||
@Deprecated("Use PokeBalls.getGreatBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getGREAT_BALL() = GREAT_BALL
|
||||
|
||||
@JvmName("getULTRA_BALL")
|
||||
@Deprecated("Use PokeBalls.getUltraBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getULTRA_BALL() = ULTRA_BALL
|
||||
|
||||
@JvmName("getMASTER_BALL")
|
||||
@Deprecated("Use PokeBalls.getMasterBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getMASTER_BALL() = MASTER_BALL
|
||||
|
||||
@JvmName("getSAFARI_BALL")
|
||||
@Deprecated("Use PokeBalls.getSafariBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getSAFARI_BALL() = SAFARI_BALL
|
||||
|
||||
@JvmName("getFAST_BALL")
|
||||
@Deprecated("Use PokeBalls.getFastBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getFAST_BALL() = FAST_BALL
|
||||
|
||||
@JvmName("getLEVEL_BALL")
|
||||
@Deprecated("Use PokeBalls.getLevelBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getLEVEL_BALL() = LEVEL_BALL
|
||||
|
||||
@JvmName("getLURE_BALL")
|
||||
@Deprecated("Use PokeBalls.getLureBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getLURE_BALL() = LURE_BALL
|
||||
|
||||
@JvmName("getHEAVY_BALL")
|
||||
@Deprecated("Use PokeBalls.getHeavyBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getHEAVY_BALL() = HEAVY_BALL
|
||||
|
||||
@JvmName("getLOVE_BALL")
|
||||
@Deprecated("Use PokeBalls.getLoveBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getLOVE_BALL() = LOVE_BALL
|
||||
|
||||
@JvmName("getFRIEND_BALL")
|
||||
@Deprecated("Use PokeBalls.getFriendBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getFRIEND_BALL() = FRIEND_BALL
|
||||
|
||||
@JvmName("getMOON_BALL")
|
||||
@Deprecated("Use PokeBalls.getMoonBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getMOON_BALL() = MOON_BALL
|
||||
|
||||
@JvmName("getSPORT_BALL")
|
||||
@Deprecated("Use PokeBalls.getSportBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getSPORT_BALL() = SPORT_BALL
|
||||
|
||||
@JvmName("getNET_BALL")
|
||||
@Deprecated("Use PokeBalls.getNetBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getNET_BALL() = NET_BALL
|
||||
|
||||
@JvmName("getNEST_BALL")
|
||||
@Deprecated("Use PokeBalls.getNestBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getNEST_BALL() = NEST_BALL
|
||||
|
||||
@JvmName("getREPEAT_BALL")
|
||||
@Deprecated("Use PokeBalls.getRepeatBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getREPEAT_BALL() = REPEAT_BALL
|
||||
|
||||
@JvmName("getTIMER_BALL")
|
||||
@Deprecated("Use PokeBalls.getTimerBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getTIMER_BALL() = TIMER_BALL
|
||||
|
||||
@JvmName("getLUXURY_BALL")
|
||||
@Deprecated("Use PokeBalls.getLuxuryBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getLUXURY_BALL() = LUXURY_BALL
|
||||
|
||||
@JvmName("getPREMIER_BALL")
|
||||
@Deprecated("Use PokeBalls.getPremierBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getPREMIER_BALL() = PREMIER_BALL
|
||||
|
||||
@JvmName("getDUSK_BALL")
|
||||
@Deprecated("Use PokeBalls.getDuskBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getDUSK_BALL() = DUSK_BALL
|
||||
|
||||
@JvmName("getHEAL_BALL")
|
||||
@Deprecated("Use PokeBalls.getHealBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getHEAL_BALL() = HEAL_BALL
|
||||
|
||||
@JvmName("getQUICK_BALL")
|
||||
@Deprecated("Use PokeBalls.getQuickBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getQUICK_BALL() = QUICK_BALL
|
||||
|
||||
@JvmName("getCHERISH_BALL")
|
||||
@Deprecated("Use PokeBalls.getCherishBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getCHERISH_BALL() = CHERISH_BALL
|
||||
|
||||
@JvmName("getPARK_BALL")
|
||||
@Deprecated("Use PokeBalls.getParkBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getPARK_BALL() = PARK_BALL
|
||||
|
||||
@JvmName("getDREAM_BALL")
|
||||
@Deprecated("Use PokeBalls.getDreamBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getDREAM_BALL() = DREAM_BALL
|
||||
|
||||
@JvmName("getBEAST_BALL")
|
||||
@Deprecated("Use PokeBalls.getBeastBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getBEAST_BALL() = BEAST_BALL
|
||||
|
||||
@JvmName("getANCIENT_POKE_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientPokeBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_POKE_BALL() = ANCIENT_POKE_BALL
|
||||
|
||||
@JvmName("getANCIENT_CITRINE_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientCitrineBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_CITRINE_BALL() = ANCIENT_CITRINE_BALL
|
||||
|
||||
@JvmName("getANCIENT_VERDANT_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientVerdantBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_VERDANT_BALL() = ANCIENT_VERDANT_BALL
|
||||
|
||||
@JvmName("getANCIENT_AZURE_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientAzureBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_AZURE_BALL() = ANCIENT_AZURE_BALL
|
||||
|
||||
@JvmName("getANCIENT_ROSEATE_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientRoseateBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_ROSEATE_BALL() = ANCIENT_ROSEATE_BALL
|
||||
|
||||
@JvmName("getANCIENT_SLATE_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientSlateBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_SLATE_BALL() = ANCIENT_SLATE_BALL
|
||||
|
||||
@JvmName("getANCIENT_IVORY_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientIvoryBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_IVORY_BALL() = ANCIENT_IVORY_BALL
|
||||
|
||||
@JvmName("getANCIENT_GREAT_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientGreatBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_GREAT_BALL() = ANCIENT_GREAT_BALL
|
||||
|
||||
@JvmName("getANCIENT_ULTRA_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientUltraBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_ULTRA_BALL() = ANCIENT_ULTRA_BALL
|
||||
|
||||
@JvmName("getANCIENT_HEAVY_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientHeavyBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_HEAVY_BALL() = ANCIENT_HEAVY_BALL
|
||||
|
||||
@JvmName("getANCIENT_LEADEN_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientLeadenBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_LEADEN_BALL() = ANCIENT_LEADEN_BALL
|
||||
|
||||
@JvmName("getANCIENT_GIGATON_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientGigatonBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_GIGATON_BALL() = ANCIENT_GIGATON_BALL
|
||||
|
||||
@JvmName("getANCIENT_FEATHER_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientFeatherBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_FEATHER_BALL() = ANCIENT_FEATHER_BALL
|
||||
|
||||
@JvmName("getANCIENT_WING_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientWingBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_WING_BALL() = ANCIENT_WING_BALL
|
||||
|
||||
@JvmName("getANCIENT_JET_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientJetBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_JET_BALL() = ANCIENT_JET_BALL
|
||||
|
||||
@JvmName("getANCIENT_ORIGIN_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientOriginBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_ORIGIN_BALL() = ANCIENT_ORIGIN_BALL
|
||||
|
||||
}
|
||||
@@ -24,126 +24,151 @@ import net.minecraft.resources.ResourceLocation
|
||||
object Natures {
|
||||
private val allNatures = mutableListOf<Nature>()
|
||||
|
||||
@JvmField
|
||||
val HARDY = registerNature(
|
||||
Nature(cobblemonResource("hardy"), "cobblemon.nature.hardy",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val LONELY = registerNature(
|
||||
Nature(cobblemonResource("lonely"), "cobblemon.nature.lonely",
|
||||
Stats.ATTACK, Stats.DEFENCE, Flavour.SPICY, Flavour.SOUR)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BRAVE = registerNature(
|
||||
Nature(cobblemonResource("brave"), "cobblemon.nature.brave",
|
||||
Stats.ATTACK, Stats.SPEED, Flavour.SPICY, Flavour.SWEET)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val ADAMANT = registerNature(
|
||||
Nature(cobblemonResource("adamant"), "cobblemon.nature.adamant",
|
||||
Stats.ATTACK, Stats.SPECIAL_ATTACK, Flavour.SPICY, Flavour.DRY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val NAUGHTY = registerNature(
|
||||
Nature(cobblemonResource("naughty"), "cobblemon.nature.naughty",
|
||||
Stats.ATTACK, Stats.SPECIAL_DEFENCE, Flavour.SPICY, Flavour.BITTER)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BOLD = registerNature(
|
||||
Nature(cobblemonResource("bold"), "cobblemon.nature.bold",
|
||||
Stats.DEFENCE, Stats.ATTACK, Flavour.SOUR, Flavour.SPICY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val DOCILE = registerNature(
|
||||
Nature(cobblemonResource("docile"), "cobblemon.nature.docile",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val RELAXED = registerNature(
|
||||
Nature(cobblemonResource("relaxed"), "cobblemon.nature.relaxed",
|
||||
Stats.DEFENCE, Stats.SPEED, Flavour.SOUR, Flavour.SWEET)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val IMPISH = registerNature(
|
||||
Nature(cobblemonResource("impish"), "cobblemon.nature.impish",
|
||||
Stats.DEFENCE, Stats.SPECIAL_ATTACK, Flavour.SOUR, Flavour.DRY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val LAX = registerNature(
|
||||
Nature(cobblemonResource("lax"), "cobblemon.nature.lax",
|
||||
Stats.DEFENCE, Stats.SPECIAL_DEFENCE, Flavour.SOUR, Flavour.BITTER)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val TIMID = registerNature(
|
||||
Nature(cobblemonResource("timid"), "cobblemon.nature.timid",
|
||||
Stats.SPEED, Stats.ATTACK, Flavour.SWEET, Flavour.SPICY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val HASTY = registerNature(
|
||||
Nature(cobblemonResource("hasty"), "cobblemon.nature.hasty",
|
||||
Stats.SPEED, Stats.DEFENCE, Flavour.SWEET, Flavour.SOUR)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val SERIOUS = registerNature(
|
||||
Nature(cobblemonResource("serious"), "cobblemon.nature.serious",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val JOLLY = registerNature(
|
||||
Nature(cobblemonResource("jolly"), "cobblemon.nature.jolly",
|
||||
Stats.SPEED, Stats.SPECIAL_ATTACK, Flavour.SWEET, Flavour.DRY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val NAIVE = registerNature(
|
||||
Nature(cobblemonResource("naive"), "cobblemon.nature.naive",
|
||||
Stats.SPEED, Stats.SPECIAL_DEFENCE, Flavour.SWEET, Flavour.BITTER)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MODEST = registerNature(
|
||||
Nature(cobblemonResource("modest"), "cobblemon.nature.modest",
|
||||
Stats.SPECIAL_ATTACK, Stats.ATTACK, null, null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MILD = registerNature(
|
||||
Nature(cobblemonResource("mild"), "cobblemon.nature.mild",
|
||||
Stats.SPECIAL_ATTACK, Stats.DEFENCE, Flavour.DRY, Flavour.SOUR)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val QUIET = registerNature(
|
||||
Nature(cobblemonResource("quiet"), "cobblemon.nature.quiet",
|
||||
Stats.SPECIAL_ATTACK, Stats.SPEED, Flavour.DRY, Flavour.SWEET)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BASHFUL = registerNature(
|
||||
Nature(cobblemonResource("bashful"), "cobblemon.nature.bashful",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val RASH = registerNature(
|
||||
Nature(cobblemonResource("rash"), "cobblemon.nature.rash",
|
||||
Stats.SPECIAL_ATTACK, Stats.SPECIAL_DEFENCE, Flavour.DRY, Flavour.BITTER)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val CALM = registerNature(
|
||||
Nature(cobblemonResource("calm"), "cobblemon.nature.calm",
|
||||
Stats.SPECIAL_DEFENCE, Stats.ATTACK, Flavour.BITTER, Flavour.SPICY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GENTLE = registerNature(
|
||||
Nature(cobblemonResource("gentle"), "cobblemon.nature.gentle",
|
||||
Stats.SPECIAL_DEFENCE, Stats.DEFENCE, Flavour.BITTER, Flavour.SOUR)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val SASSY = registerNature(
|
||||
Nature(cobblemonResource("sassy"), "cobblemon.nature.sassy",
|
||||
Stats.SPECIAL_DEFENCE, Stats.SPEED, Flavour.BITTER, Flavour.SWEET)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val CAREFUL = registerNature(
|
||||
Nature(cobblemonResource("careful"), "cobblemon.nature.careful",
|
||||
Stats.SPECIAL_DEFENCE, Stats.SPECIAL_ATTACK, Flavour.BITTER, Flavour.DRY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val QUIRKY = registerNature(
|
||||
Nature(cobblemonResource("quirky"), "cobblemon.nature.quirky",
|
||||
null, null, null, null)
|
||||
@@ -153,6 +178,7 @@ object Natures {
|
||||
/**
|
||||
* Registers a new nature type
|
||||
*/
|
||||
@JvmStatic
|
||||
fun registerNature(nature: Nature): Nature {
|
||||
allNatures.add(nature)
|
||||
return nature
|
||||
@@ -162,6 +188,7 @@ object Natures {
|
||||
* Gets a nature by registry name
|
||||
* @return a nature type or null
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getNature(name: ResourceLocation): Nature? {
|
||||
return allNatures.find { nature -> nature.name == name }
|
||||
}
|
||||
@@ -170,20 +197,122 @@ object Natures {
|
||||
* Utility method to get a nature by string
|
||||
* @return a nature type or null
|
||||
*/
|
||||
fun getNature(identifier: String): Nature? {
|
||||
val nature = getNature(cobblemonResource(identifier))
|
||||
if(nature != null) return nature
|
||||
return getNature(ResourceLocation.parse(identifier))
|
||||
}
|
||||
@JvmStatic
|
||||
fun getNature(identifier: String) = getNature(cobblemonResource(identifier))
|
||||
?: getNature(ResourceLocation.parse(identifier))
|
||||
|
||||
/**
|
||||
* Helper function for a random Nature
|
||||
* @return a random nature type
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getRandomNature(): Nature {
|
||||
return allNatures.random()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun all(): Collection<Nature> = this.allNatures.toList()
|
||||
|
||||
/**
|
||||
* Backwards compatibility getters
|
||||
*/
|
||||
@JvmName("getHARDY")
|
||||
@Deprecated("Use Natures.HARDY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getHARDY() = HARDY
|
||||
|
||||
@JvmName("getLONELY")
|
||||
@Deprecated("Use Natures.LONELY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getLONELY() = LONELY
|
||||
|
||||
@JvmName("getBRAVE")
|
||||
@Deprecated("Use Natures.BRAVE, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getBRAVE() = BRAVE
|
||||
|
||||
@JvmName("getADAMANT")
|
||||
@Deprecated("Use Natures.ADAMANT, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getADAMANT() = ADAMANT
|
||||
|
||||
@JvmName("getNAUGHTY")
|
||||
@Deprecated("Use Natures.NAUGHTY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getNAUGHTY() = NAUGHTY
|
||||
|
||||
@JvmName("getBOLD")
|
||||
@Deprecated("Use Natures.BOLD, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getBOLD() = BOLD
|
||||
|
||||
@JvmName("getDOCILE")
|
||||
@Deprecated("Use Natures.DOCILE, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getDOCILE() = DOCILE
|
||||
|
||||
@JvmName("getRELAXED")
|
||||
@Deprecated("Use Natures.RELAXED, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getRELAXED() = RELAXED
|
||||
|
||||
@JvmName("getIMPISH")
|
||||
@Deprecated("Use Natures.IMPISH, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getIMPISH() = IMPISH
|
||||
|
||||
@JvmName("getLAX")
|
||||
@Deprecated("Use Natures.LAX, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getLAX() = LAX
|
||||
|
||||
@JvmName("getTIMID")
|
||||
@Deprecated("Use Natures.TIMID, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getTIMID() = TIMID
|
||||
|
||||
@JvmName("getHASTY")
|
||||
@Deprecated("Use Natures.HASTY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getHASTY() = HASTY
|
||||
|
||||
@JvmName("getSERIOUS")
|
||||
@Deprecated("Use Natures.SERIOUS, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getSERIOUS() = SERIOUS
|
||||
|
||||
@JvmName("getJOLLY")
|
||||
@Deprecated("Use Natures.JOLLY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getJOLLY() = JOLLY
|
||||
|
||||
@JvmName("getNAIVE")
|
||||
@Deprecated("Use Natures.NAIVE, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getNAIVE() = NAIVE
|
||||
|
||||
@JvmName("getMODEST")
|
||||
@Deprecated("Use Natures.MODEST, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getMODEST() = MODEST
|
||||
|
||||
@JvmName("getMILD")
|
||||
@Deprecated("Use Natures.MILD, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getMILD() = MILD
|
||||
|
||||
@JvmName("getQUIET")
|
||||
@Deprecated("Use Natures.QUIET, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getQUIET() = QUIET
|
||||
|
||||
@JvmName("getBASHFUL")
|
||||
@Deprecated("Use Natures.BASHFUL, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getBASHFUL() = BASHFUL
|
||||
|
||||
@JvmName("getRASH")
|
||||
@Deprecated("Use Natures.RASH, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getRASH() = RASH
|
||||
|
||||
@JvmName("getCALM")
|
||||
@Deprecated("Use Natures.CALM, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getCALM() = CALM
|
||||
|
||||
@JvmName("getGENTLE")
|
||||
@Deprecated("Use Natures.GENTLE, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getGENTLE() = GENTLE
|
||||
|
||||
@JvmName("getSASSY")
|
||||
@Deprecated("Use Natures.SASSY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getSASSY() = SASSY
|
||||
|
||||
@JvmName("getCAREFUL")
|
||||
@Deprecated("Use Natures.CAREFUL, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getCAREFUL() = CAREFUL
|
||||
|
||||
@JvmName("getQUIRKY")
|
||||
@Deprecated("Use Natures.QUIRKY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getQUIRKY() = QUIRKY
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.events.pokemon.ShinyChanceCalculationEvent
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
@@ -31,10 +32,12 @@ import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.OriginalTrainerType
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.RenderablePokemon
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.isDouble
|
||||
import com.cobblemon.mod.common.util.isFloat
|
||||
import com.cobblemon.mod.common.util.isUuid
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.util.simplify
|
||||
@@ -146,6 +149,8 @@ open class PokemonProperties {
|
||||
props.originalTrainer = parsePlayerProperty(keyPairs, listOf("originaltrainer", "ot"))
|
||||
props.moves = parseString(keyPairs, listOf("moves"))?.split(",")
|
||||
props.heldItem = parseString(keyPairs, listOf("helditem", "held_item"))
|
||||
props.minPerfectIVs = parseIntProperty(keyPairs, listOf("min_perfect_ivs"))?.coerceIn(0, Stats.PERMANENT.size)
|
||||
props.scaleModifier = parseFloatProperty(keyPairs, listOf("scale_modifier"))
|
||||
|
||||
val maybeIVs = IVs()
|
||||
val maybeEVs = EVs()
|
||||
@@ -195,6 +200,16 @@ open class PokemonProperties {
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseFloatProperty(keyPairs: MutableList<Pair<String, String?>>, labels: Iterable<String>): Float? {
|
||||
val matchingKeyPair = getMatchedKeyPair(keyPairs, labels) ?: return null
|
||||
val value = matchingKeyPair.second
|
||||
return if (value == null || !value.isFloat()) {
|
||||
null
|
||||
} else {
|
||||
value.toFloat()
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseIdentifierOfRegistry(keyPairs: MutableList<Pair<String, String?>>, validKeys: List<String>, valueFetcher: (ResourceLocation) -> String?): String? {
|
||||
val matched = getMatchedKeyPair(keyPairs, validKeys) ?: return null
|
||||
val value = matched.second?.lowercase() ?: return null
|
||||
@@ -343,7 +358,9 @@ open class PokemonProperties {
|
||||
var moves: List<String>? = null
|
||||
var heldItem: String? = null
|
||||
var cosmeticItem: String? = null
|
||||
var scaleModifier: Float? = null
|
||||
|
||||
var minPerfectIVs: Int? = null
|
||||
var ivs: IVs? = null
|
||||
var evs: EVs? = null
|
||||
var customProperties = mutableListOf<CustomPokemonProperty>()
|
||||
@@ -413,6 +430,11 @@ open class PokemonProperties {
|
||||
pokemon.hyperTrainIV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
minPerfectIVs?.let {
|
||||
CobblemonStatProvider.ofType(Stat.Type.PERMANENT).shuffled().take(it).forEach { stat ->
|
||||
pokemon.setIV(stat, IVs.MAX_VALUE)
|
||||
}
|
||||
}
|
||||
evs?.let { evs ->
|
||||
evs.forEach { stat ->
|
||||
pokemon.setEV(stat.key, stat.value)
|
||||
@@ -469,6 +491,7 @@ open class PokemonProperties {
|
||||
if (stack.isEmpty) return@let
|
||||
pokemon.swapHeldItem(stack, decrement = true, aiCanDrop = false)
|
||||
}
|
||||
scaleModifier?.let { pokemon.scaleModifier = it }
|
||||
pokemon.updateAspects()
|
||||
}
|
||||
|
||||
@@ -512,6 +535,7 @@ open class PokemonProperties {
|
||||
nature?.takeIf { it != pokemon.nature.name.toString() }?.let { return false }
|
||||
ability?.takeIf { it != pokemon.ability.name }?.let { return false }
|
||||
status?.takeIf { it != pokemon.status?.status?.showdownName }?.let { return false }
|
||||
minPerfectIVs?.takeIf { pokemon.ivs.count { stat -> stat.value == IVs.MAX_VALUE } < it }?.let { return false }
|
||||
ivs?.forEach{ stat ->
|
||||
if (stat.value != pokemon.ivs[stat.key]) { return false }
|
||||
}
|
||||
@@ -542,6 +566,7 @@ open class PokemonProperties {
|
||||
|
||||
return@takeIf false
|
||||
}?.let { return false }
|
||||
scaleModifier?.takeIf { it != pokemon.scaleModifier }?.let { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -570,6 +595,7 @@ open class PokemonProperties {
|
||||
nature?.takeIf { it != properties.nature }?.let { return false }
|
||||
ability?.takeIf { it != properties.ability }?.let { return false }
|
||||
status?.takeIf { it != properties.status }?.let { return false }
|
||||
minPerfectIVs?.takeIf { it != properties.minPerfectIVs }?.let { return false }
|
||||
ivs?.let{ ivs ->
|
||||
ivs.forEach{ stat ->
|
||||
//If the potential subset has IV and the main set does not then it cant be a subset
|
||||
@@ -593,6 +619,7 @@ open class PokemonProperties {
|
||||
originalTrainerType?.takeIf { it != properties.originalTrainerType }?.let{ return false }
|
||||
moves?.takeIf { it.any { move -> properties.moves?.none { it == move } == true } }?.let { return false }
|
||||
fullness?.takeIf { it != properties.fullness }?.let { return false }
|
||||
scaleModifier?.takeIf { it != properties.scaleModifier }?.let { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -646,6 +673,7 @@ open class PokemonProperties {
|
||||
nature?.let { nbt.putString(DataKeys.POKEMON_NATURE, it) }
|
||||
ability?.let { nbt.putString(DataKeys.POKEMON_ABILITY, it) }
|
||||
status?.let { nbt.putString(DataKeys.POKEMON_STATUS_NAME, it) }
|
||||
minPerfectIVs?.let { nbt.putInt(DataKeys.POKEMON_MIN_PERFECT_IVS, it) }
|
||||
ivs?.let { nbt.put(DataKeys.POKEMON_IVS, IVs.CODEC.encodeStart(NbtOps.INSTANCE, it).result().get()) }
|
||||
evs?.let { nbt.put(DataKeys.POKEMON_EVS, EVs.CODEC.encodeStart(NbtOps.INSTANCE, it).result().get()) }
|
||||
type?.let { nbt.putString(DataKeys.ELEMENTAL_TYPE, it) }
|
||||
@@ -657,6 +685,7 @@ open class PokemonProperties {
|
||||
originalTrainer?.let { nbt.putString(DataKeys.POKEMON_ORIGINAL_TRAINER, it) }
|
||||
moves?.let { nbt.putString(DataKeys.POKEMON_PROPERTIES_MOVES, it.joinToString(separator = ",")) }
|
||||
heldItem?.let {nbt.putString(DataKeys.POKEMON_PROPERTIES_HELDITEM, it)}
|
||||
scaleModifier?.let { nbt.putFloat(DataKeys.POKEMON_SCALE_MODIFIER, it) }
|
||||
val custom = ListTag()
|
||||
customProperties.map { StringTag.valueOf(it.asString()) }.forEach { custom.add(it) }
|
||||
nbt.put(DataKeys.POKEMON_PROPERTIES_CUSTOM, custom)
|
||||
@@ -678,6 +707,7 @@ open class PokemonProperties {
|
||||
nature = if (tag.contains(DataKeys.POKEMON_NATURE)) tag.getString(DataKeys.POKEMON_NATURE) else null
|
||||
ability = if (tag.contains(DataKeys.POKEMON_ABILITY)) tag.getString(DataKeys.POKEMON_ABILITY) else null
|
||||
status = if (tag.contains(DataKeys.POKEMON_STATUS_NAME)) tag.getString(DataKeys.POKEMON_STATUS_NAME) else null
|
||||
minPerfectIVs = if (tag.contains(DataKeys.POKEMON_MIN_PERFECT_IVS)) tag.getInt(DataKeys.POKEMON_MIN_PERFECT_IVS) else null
|
||||
ivs = if (tag.contains(DataKeys.POKEMON_IVS)) IVs.CODEC.decode(NbtOps.INSTANCE, tag.getCompound(DataKeys.POKEMON_IVS)).result().getOrNull()?.first else null
|
||||
evs = if (tag.contains(DataKeys.POKEMON_EVS)) EVs.CODEC.decode(NbtOps.INSTANCE, tag.getCompound(DataKeys.POKEMON_EVS)).result().getOrNull()?.first else null
|
||||
type = if (tag.contains(DataKeys.ELEMENTAL_TYPE)) tag.getString(DataKeys.ELEMENTAL_TYPE) else null
|
||||
@@ -689,6 +719,7 @@ open class PokemonProperties {
|
||||
originalTrainer = if (tag.contains(DataKeys.POKEMON_ORIGINAL_TRAINER)) tag.getString(DataKeys.POKEMON_ORIGINAL_TRAINER) else null
|
||||
moves = if (tag.contains(DataKeys.POKEMON_PROPERTIES_MOVES)) tag.getString(DataKeys.POKEMON_PROPERTIES_MOVES).split(",") else null
|
||||
heldItem = if (tag.contains(DataKeys.POKEMON_PROPERTIES_HELDITEM)) tag.getString(DataKeys.POKEMON_PROPERTIES_HELDITEM) else null
|
||||
scaleModifier = if (tag.contains(DataKeys.POKEMON_SCALE_MODIFIER)) tag.getFloat(DataKeys.POKEMON_SCALE_MODIFIER) else null
|
||||
val custom = tag.getList(DataKeys.POKEMON_PROPERTIES_CUSTOM, Tag.TAG_STRING.toInt())
|
||||
// This is kinda gross
|
||||
custom.forEach { customProperties.addAll(parse(it.asString).customProperties) }
|
||||
@@ -704,14 +735,14 @@ open class PokemonProperties {
|
||||
shiny?.let { json.addProperty(DataKeys.POKEMON_SHINY, it) }
|
||||
gender?.let { json.addProperty(DataKeys.POKEMON_GENDER, it.name) }
|
||||
species?.let { json.addProperty(DataKeys.POKEMON_SPECIES_TEXT, it) }
|
||||
//nickname?.let { json.addProperty(DataKeys.POKEMON_NICKNAME, Text.Serialization.toJsonString(it)) }
|
||||
form?.let { json.addProperty(DataKeys.POKEMON_FORM_ID, it) }
|
||||
friendship?.let { json.addProperty(DataKeys.POKEMON_FRIENDSHIP, it) }
|
||||
fullness?.let {json.addProperty(DataKeys.POKEMON_FULLNESS, it)}
|
||||
fullness?.let { json.addProperty(DataKeys.POKEMON_FULLNESS, it) }
|
||||
pokeball?.let { json.addProperty(DataKeys.POKEMON_CAUGHT_BALL, it) }
|
||||
nature?.let { json.addProperty(DataKeys.POKEMON_NATURE, it) }
|
||||
ability?.let { json.addProperty(DataKeys.POKEMON_ABILITY, it) }
|
||||
status?.let { json.addProperty(DataKeys.POKEMON_STATUS_NAME, it) }
|
||||
minPerfectIVs?.let { json.addProperty(DataKeys.POKEMON_MIN_PERFECT_IVS, it) }
|
||||
ivs?.let { json.add(DataKeys.POKEMON_IVS, IVs.CODEC.encodeStart(JsonOps.INSTANCE, it).result().get()) }
|
||||
evs?.let { json.add(DataKeys.POKEMON_EVS, EVs.CODEC.encodeStart(JsonOps.INSTANCE, it).result().get()) }
|
||||
type?.let { json.addProperty(DataKeys.ELEMENTAL_TYPE, it) }
|
||||
@@ -723,6 +754,7 @@ open class PokemonProperties {
|
||||
originalTrainer?.let { json.addProperty(DataKeys.POKEMON_ORIGINAL_TRAINER, it) }
|
||||
moves?.let { json.addProperty(DataKeys.POKEMON_PROPERTIES_MOVES, it.joinToString(separator = ",")) }
|
||||
heldItem?.let {json.addProperty(DataKeys.POKEMON_PROPERTIES_HELDITEM, it)}
|
||||
scaleModifier?.let { json.addProperty(DataKeys.POKEMON_SCALE_MODIFIER, it) }
|
||||
val custom = JsonArray()
|
||||
customProperties.map { it.asString() }.forEach { custom.add(it) }
|
||||
json.add(DataKeys.POKEMON_PROPERTIES_CUSTOM, custom)
|
||||
@@ -737,7 +769,6 @@ open class PokemonProperties {
|
||||
shiny = json.get(DataKeys.POKEMON_SHINY)?.asBoolean
|
||||
gender = json.get(DataKeys.POKEMON_GENDER)?.asString?.let { Gender.valueOf(it) }
|
||||
species = json.get(DataKeys.POKEMON_SPECIES_TEXT)?.asString
|
||||
//nickname = json.get(DataKeys.POKEMON_NICKNAME)?.asString?.let { Text.Serialization.fromJson(it) }
|
||||
form = json.get(DataKeys.POKEMON_FORM_ID)?.asString
|
||||
friendship = json.get(DataKeys.POKEMON_FRIENDSHIP)?.asInt
|
||||
fullness = json.get(DataKeys.POKEMON_FULLNESS)?.asInt
|
||||
@@ -745,6 +776,7 @@ open class PokemonProperties {
|
||||
nature = json.get(DataKeys.POKEMON_NATURE)?.asString
|
||||
ability = json.get(DataKeys.POKEMON_ABILITY)?.asString
|
||||
status = json.get(DataKeys.POKEMON_STATUS_NAME)?.asString
|
||||
minPerfectIVs = json.get(DataKeys.POKEMON_MIN_PERFECT_IVS)?.asInt
|
||||
ivs = json.getAsJsonObject(DataKeys.POKEMON_IVS)?.let { IVs.CODEC.decode(JsonOps.INSTANCE, it).result().getOrNull()?.first }
|
||||
evs = json.getAsJsonObject(DataKeys.POKEMON_EVS)?.let { EVs.CODEC.decode(JsonOps.INSTANCE, it).result().getOrNull()?.first }
|
||||
type = json.get(DataKeys.ELEMENTAL_TYPE)?.asString
|
||||
@@ -756,6 +788,7 @@ open class PokemonProperties {
|
||||
originalTrainer = json.get(DataKeys.POKEMON_ORIGINAL_TRAINER)?.asString
|
||||
moves = json.get(DataKeys.POKEMON_PROPERTIES_MOVES)?.asString?.split(",")
|
||||
heldItem = json.get(DataKeys.POKEMON_PROPERTIES_HELDITEM)?.asString
|
||||
scaleModifier = json.get(DataKeys.POKEMON_SCALE_MODIFIER)?.asFloat
|
||||
val custom = json.get(DataKeys.POKEMON_PROPERTIES_CUSTOM)?.asJsonArray
|
||||
// This is still kinda gross
|
||||
custom?.forEach { customProperties.addAll(parse(it.asString).customProperties) }
|
||||
@@ -772,11 +805,12 @@ open class PokemonProperties {
|
||||
shiny?.let { pieces.add("shiny=$it") }
|
||||
gender?.let { pieces.add("gender=$it")}
|
||||
friendship?.let { pieces.add("friendship=$it") }
|
||||
fullness?.let {pieces.add("fullness=$it")}
|
||||
fullness?.let { pieces.add("fullness=$it") }
|
||||
pokeball?.let { pieces.add("pokeball=$it") }
|
||||
nature?.let { pieces.add("nature=$it") }
|
||||
ability?.let { pieces.add("ability=$it") }
|
||||
status?.let { pieces.add("status=$it") }
|
||||
minPerfectIVs?.let { pieces.add("min_perfect_ivs=$it") }
|
||||
ivs?.forEach{ stat ->
|
||||
pieces.add("${stat.key}_iv=${stat.value}")
|
||||
}
|
||||
@@ -793,6 +827,7 @@ open class PokemonProperties {
|
||||
customProperties.forEach { pieces.add(it.asString()) }
|
||||
moves?.let { pieces.add("moves=${it.joinToString(separator = ",")}") }
|
||||
heldItem?.let {pieces.add("helditem=$it")}
|
||||
scaleModifier?.let { pieces.add("scale_modifier=$it") }
|
||||
return pieces.joinToString(separator)
|
||||
}
|
||||
|
||||
@@ -806,8 +841,8 @@ open class PokemonProperties {
|
||||
return PokemonProperties().loadFromJSON(this.saveToJSON())
|
||||
}
|
||||
|
||||
// If the config value is at least 1, then do 1/x and use that as the property chance
|
||||
private fun Float.checkRate(): Boolean = if (this >= 1) (Random.Default.nextFloat() < 1 / this) else Random.Default.nextFloat() < this
|
||||
// If the config value is at least 0, then do 1/x and use that as the property chance
|
||||
private fun Float.checkRate(): Boolean = this > 0 && (Random.nextFloat() < 1 / this)
|
||||
|
||||
/**
|
||||
* Attempts to find an ability by ID and resolve if it should be forced or if it's legal for the given form.
|
||||
|
||||
@@ -39,7 +39,6 @@ import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStatDefinition
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.adapters.ElementalTypeAdapter
|
||||
@@ -129,7 +128,6 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
.registerTypeAdapter(MobEffect::class.java, RegistryElementAdapter<MobEffect>(BuiltInRegistries::MOB_EFFECT))
|
||||
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
|
||||
.registerTypeAdapter(RidingBehaviourSettings::class.java, RidingBehaviourSettingsAdapter)
|
||||
.registerTypeAdapter(RidingStatDefinition::class.java, RidingStatDefinitionAdapter)
|
||||
.registerTypeAdapter(RideSoundSettingsList::class.java, RideSoundSettingsListAdapter)
|
||||
.registerTypeAdapter(ObtainableItemCondition::class.java, ObtainableItemConditionAdapter)
|
||||
.disableHtmlEscaping()
|
||||
@@ -144,8 +142,10 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
private val speciesByIdentifier = hashMapOf<ResourceLocation, Species>()
|
||||
private val speciesByDex = HashBasedTable.create<String, Int, Species>()
|
||||
|
||||
@JvmStatic
|
||||
val species: Collection<Species>
|
||||
get() = this.speciesByIdentifier.values
|
||||
@JvmStatic
|
||||
val implemented: List<Species>
|
||||
get() = this.species.filter { it.implemented }
|
||||
|
||||
@@ -171,6 +171,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
* @param name The path of the species asset.
|
||||
* @return The [Species] if existing.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByName(name: String) = this.getByIdentifier(cobblemonResource(name))
|
||||
|
||||
/**
|
||||
@@ -179,6 +180,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
* @param ndex The [Species.nationalPokedexNumber].
|
||||
* @return The [Species] if existing.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByPokedexNumber(ndex: Int, namespace: String = Cobblemon.MODID) = this.speciesByDex.get(namespace, ndex)
|
||||
|
||||
/**
|
||||
@@ -187,6 +189,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
* @param identifier The unique [Species.resourceIdentifier] of the [Species].
|
||||
* @return The [Species] if existing.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByIdentifier(identifier: ResourceLocation) = this.speciesByIdentifier[identifier]
|
||||
|
||||
/**
|
||||
@@ -194,6 +197,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
*
|
||||
* @return The loaded species amount.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun count() = this.speciesByIdentifier.size
|
||||
|
||||
/**
|
||||
@@ -201,6 +205,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
*
|
||||
* @return The dex numbers map to species.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getSpeciesInNamespace(namespace: String = Cobblemon.MODID): MutableMap<Int, Species> = speciesByDex.row(namespace)
|
||||
|
||||
/**
|
||||
@@ -208,6 +213,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
*
|
||||
* @return The list of loaded namespaces.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getNamespaces() = speciesByDex.rowKeySet().toList()
|
||||
|
||||
/**
|
||||
@@ -217,6 +223,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
*
|
||||
* @return A randomly selected [Species].
|
||||
*/
|
||||
@JvmStatic
|
||||
fun random(): Species = this.implemented.random()
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, Species>) {
|
||||
@@ -316,4 +323,4 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -9,8 +9,9 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.aspect
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.api.ai.config.task.PollinateFlowerTaskConfig
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SaccharineLogSlatheredInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.prospecting.LurePokeSnackDetector
|
||||
import com.cobblemon.mod.common.block.entity.PokeSnackBlockEntity
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import net.minecraft.core.particles.BlockParticleOption
|
||||
import net.minecraft.core.particles.ParticleOptions
|
||||
@@ -22,11 +23,12 @@ import net.minecraft.resources.ResourceLocation
|
||||
*/
|
||||
val aspectParticleMap: Map<String, ParticleData> = mapOf(
|
||||
SaccharineLogSlatheredInfluence.HONEY_DRENCHED_ASPECT to ParticleData.MinecraftParticle(ParticleTypes.FALLING_HONEY, 0.075, 1),
|
||||
LurePokeSnackDetector.POKE_SNACK_CRUMBED_ASPECT to ParticleData.MinecraftParticle(
|
||||
PokeSnackBlockEntity.POKE_SNACK_CRUMBED_ASPECT to ParticleData.MinecraftParticle(
|
||||
BlockParticleOption(
|
||||
ParticleTypes.BLOCK,
|
||||
CobblemonBlocks.POKE_SNACK.defaultBlockState()
|
||||
), 0.05, 3),
|
||||
PollinateFlowerTaskConfig.HAS_NECTAR_ASPECT to ParticleData.MinecraftParticle(ParticleTypes.FALLING_NECTAR, 0.075, 1)
|
||||
)
|
||||
|
||||
sealed class ParticleData {
|
||||
|
||||
+4
@@ -36,12 +36,16 @@ object ShoulderEffectRegistry {
|
||||
PlatformEvents.SERVER_PLAYER_LOGIN.subscribe { this.refreshEffects(it.player) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun register(name: String, effect: Class<out ShoulderEffect>) = effect.also { effects[name] = it }
|
||||
|
||||
@JvmStatic
|
||||
fun unregister(name: String) = effects.remove(name)
|
||||
|
||||
@JvmStatic
|
||||
fun getName(clazz: Class<out ShoulderEffect>) = effects.firstNotNullOf { if (it.value == clazz) it.key else null }
|
||||
|
||||
@JvmStatic
|
||||
fun get(name: String): Class<out ShoulderEffect>? = effects[name]
|
||||
|
||||
// It was removed by a source such as milk, reapply
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user