mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-11-01 05:48:53 -05:00
Compare commits
652
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c49a60a23a | ||
|
|
f287dde994 | ||
|
|
f33c35ea43 | ||
|
|
e5acbe86c6 | ||
|
|
271ae37e5b | ||
|
|
004f0a50e8 | ||
|
|
348ecd0be2 | ||
|
|
8691bb4a05 | ||
|
|
e4ad12ddcf | ||
|
|
8b11fb7150 | ||
|
|
0223702f9d | ||
|
|
eaad6c18ab | ||
|
|
627f3e3023 | ||
|
|
c408247bd4 | ||
|
|
ee7eafab72 | ||
|
|
4d22a54507 | ||
|
|
5012181fcd | ||
|
|
edd96ca426 | ||
|
|
9cefbb81a7 | ||
|
|
a0eb40d796 | ||
|
|
2f9f00c8e3 | ||
|
|
0c927854fd | ||
|
|
d023fb8139 | ||
|
|
620deaa40b | ||
|
|
541346095c | ||
|
|
d63c60e311 | ||
|
|
54d854f009 | ||
|
|
2fb8f798f1 | ||
|
|
02e1e0157b | ||
|
|
ccbd7ea6e3 | ||
|
|
6b24bf5cae | ||
|
|
0f65a986ed | ||
|
|
2ef169e43d | ||
|
|
65fc9e63dd | ||
|
|
7e4252c699 | ||
|
|
1ac83162ea | ||
|
|
f9dd1448e5 | ||
|
|
ecf5d57ad2 | ||
|
|
8663888abc | ||
|
|
f452cd9a05 | ||
|
|
4fe9cd7fd6 | ||
|
|
2c1d11ed11 | ||
|
|
b88adf0479 | ||
|
|
b1066671f5 | ||
|
|
387e85d4ad | ||
|
|
77ab58d823 | ||
|
|
1a9e736d8b | ||
|
|
aa39c1906e | ||
|
|
2e460e2ca2 | ||
|
|
a07ff7f442 | ||
|
|
5374569ea1 | ||
|
|
af9c1196bf | ||
|
|
09d5543469 | ||
|
|
49e4dd0298 | ||
|
|
c8e408c50a | ||
|
|
e8a0467643 | ||
|
|
2dd0b66b83 | ||
|
|
68374017e1 | ||
|
|
120520f51d | ||
|
|
e8dea9773a | ||
|
|
7b31e6bcc4 | ||
|
|
c6ffca639f | ||
|
|
c491a1f7ca | ||
|
|
0b333b743d | ||
|
|
95e79865e5 | ||
|
|
0e2860cd90 | ||
|
|
3259bf032c | ||
|
|
116205cdf1 | ||
|
|
43277d18dc | ||
|
|
86153419ee | ||
|
|
2b4d9c451c | ||
|
|
7f0e2fa9d8 | ||
|
|
e165095bd5 | ||
|
|
b8708d6e10 | ||
|
|
ef536390ca | ||
|
|
28befab173 | ||
|
|
c142439d5b | ||
|
|
1ca7335654 | ||
|
|
9197d9cdcd | ||
|
|
f75813e64d | ||
|
|
1f617c76a4 | ||
|
|
ebf573aa7a | ||
|
|
75363da470 | ||
|
|
cce4b932cc | ||
|
|
0973e1ced0 | ||
|
|
e7b5c84024 | ||
|
|
4001cc2a89 | ||
|
|
6e57d77d10 | ||
|
|
2206d96a6e | ||
|
|
33f05858f1 | ||
|
|
a4f204a5a3 | ||
|
|
31b6be2164 | ||
|
|
0dbf73067b | ||
|
|
775703e1f5 | ||
|
|
bcdfef4886 | ||
|
|
a19adb463b | ||
|
|
5004edbbb6 | ||
|
|
d8bdd6329a | ||
|
|
82d56637a0 | ||
|
|
7232a43816 | ||
|
|
098eb7d14b | ||
|
|
835b70ed48 | ||
|
|
9d828a86fb | ||
|
|
910551ee70 | ||
|
|
9beee548d4 | ||
|
|
6f3894f27b | ||
|
|
bbc9a5e62e | ||
|
|
94765da04a | ||
|
|
8caa82f123 | ||
|
|
2f87d53af6 | ||
|
|
131ef31492 | ||
|
|
b6b067b1d3 | ||
|
|
546f10eca7 | ||
|
|
542839ba69 | ||
|
|
efab1bba08 | ||
|
|
8f986bc326 | ||
|
|
e155d32aaf | ||
|
|
743e0b7d66 | ||
|
|
1518d703f9 | ||
|
|
af9d851d67 | ||
|
|
20ca91f1c9 | ||
|
|
6fb3c0e49a | ||
|
|
5cb4ff5f5f | ||
|
|
d035c08a5c | ||
|
|
fda7b13f50 | ||
|
|
fb4aaed220 | ||
|
|
c5e1b37ead | ||
|
|
2be9d303ea | ||
|
|
99ac6d213a | ||
|
|
f595724971 | ||
|
|
0511ba147b | ||
|
|
760f48d850 | ||
|
|
bf296b4921 | ||
|
|
6f4aae8b7d | ||
|
|
01e5e74e64 | ||
|
|
b6565a5dee | ||
|
|
49886389cf | ||
|
|
643bf9068b | ||
|
|
53f3258246 | ||
|
|
1e9895ec84 | ||
|
|
52dacb03ae | ||
|
|
85b0f3f393 | ||
|
|
a04a91bf24 | ||
|
|
5e814f7ab5 | ||
|
|
2780f491d6 | ||
|
|
2d3ec7aff1 | ||
|
|
cb7baf2696 | ||
|
|
5cc069df78 | ||
|
|
9222476c1f | ||
|
|
f220755f99 | ||
|
|
d55bbf237c | ||
|
|
83a9d44c3a | ||
|
|
c5a802eaf6 | ||
|
|
2e27875460 | ||
|
|
cd66887faa | ||
|
|
d665c87c21 | ||
|
|
044d3102b6 | ||
|
|
c421a93b06 | ||
|
|
2865aa2272 | ||
|
|
7c4aae3e9d | ||
|
|
d9f671f2a8 | ||
|
|
69733b530b | ||
|
|
d4471c30bc | ||
|
|
185f7e03f5 | ||
|
|
a45eb0eb21 | ||
|
|
ed67142379 | ||
|
|
13169c6848 | ||
|
|
8be134ee2f | ||
|
|
8c3206a413 | ||
|
|
4d4c071b95 | ||
|
|
b82c27754f | ||
|
|
63afec184e | ||
|
|
65699f045e | ||
|
|
d02441a273 | ||
|
|
f76ab784b5 | ||
|
|
a566e36754 | ||
|
|
ef1479fde6 | ||
|
|
d6c7b271e4 | ||
|
|
df9acfa0d1 | ||
|
|
9d7fc8435e | ||
|
|
ab4492ac5c | ||
|
|
cb78dc8d88 | ||
|
|
020adabe26 | ||
|
|
08aca7a274 | ||
|
|
2a9ef2b9fe | ||
|
|
90dc489547 | ||
|
|
5ec5cfbc4a | ||
|
|
1ef65449a8 | ||
|
|
c6ff1ea72e | ||
|
|
cbfa8d3e78 | ||
|
|
5098ff3cfd | ||
|
|
7c32b07d3f | ||
|
|
b2142fed1d | ||
|
|
fef21516e9 | ||
|
|
6fba0f55c1 | ||
|
|
95d43de79f | ||
|
|
0be617b8ab | ||
|
|
c02d22f449 | ||
|
|
846b645856 | ||
|
|
25d93a771c | ||
|
|
f16c782336 | ||
|
|
ed0f315e41 | ||
|
|
d20b03f4c5 | ||
|
|
a3920413ac | ||
|
|
92bccf620f | ||
|
|
15f8a9ee71 | ||
|
|
dfb9ee755e | ||
|
|
68f4117e29 | ||
|
|
f74a24a056 | ||
|
|
e5750cbba0 | ||
|
|
c6482c82cd | ||
|
|
b4c23a9132 | ||
|
|
c470894bd3 | ||
|
|
a940e32f8d | ||
|
|
b6b59eccad | ||
|
|
b520b94fae | ||
|
|
9af99d16f7 | ||
|
|
2cc17d3280 | ||
|
|
20b2bcaa5a | ||
|
|
d1ada605fd | ||
|
|
d37f73626d | ||
|
|
73a94cb02e | ||
|
|
5a48945e50 | ||
|
|
476448a2ce | ||
|
|
bcba4f7fb7 | ||
|
|
20e9608ff3 | ||
|
|
3e5733ceaf | ||
|
|
af29c99b03 | ||
|
|
60d596a24f | ||
|
|
3f993e0466 | ||
|
|
9e3d22ee54 | ||
|
|
e86cb1981f | ||
|
|
e94f265adb | ||
|
|
b3fc35240a | ||
|
|
d74618bddb | ||
|
|
8b54a8d459 | ||
|
|
c17104a0fd | ||
|
|
88ca3ebbf3 | ||
|
|
4003456e5c | ||
|
|
1d21a52d28 | ||
|
|
2d49c62f85 | ||
|
|
20fac724f6 | ||
|
|
0807d73646 | ||
|
|
3013302f35 | ||
|
|
879e7bef21 | ||
|
|
557623dfe2 | ||
|
|
a28d1e176d | ||
|
|
f3c52db70d | ||
|
|
525575b0ba | ||
|
|
a55efeb378 | ||
|
|
da18b082a6 | ||
|
|
7511facebc | ||
|
|
1486f5cfc2 | ||
|
|
f8a16e5081 | ||
|
|
558e2d89ff | ||
|
|
ea7b688655 | ||
|
|
fdafa3435c | ||
|
|
f17c90f6ea | ||
|
|
1dc45669bb | ||
|
|
f3658614a4 | ||
|
|
cad39d8802 | ||
|
|
422f60f587 | ||
|
|
8190ddf0e9 | ||
|
|
af281d0bde | ||
|
|
00905b8c32 | ||
|
|
79b3cb8611 | ||
|
|
797e908621 | ||
|
|
3df3c395de | ||
|
|
b2f682ebb1 | ||
|
|
754e9bc158 | ||
|
|
2df8504139 | ||
|
|
2838f97c56 | ||
|
|
68c75deeeb | ||
|
|
3bc2659740 | ||
|
|
89bba8a67a | ||
|
|
cbd5cdaf92 | ||
|
|
5b9d5cbb55 | ||
|
|
6d6e13be83 | ||
|
|
899bec77b6 | ||
|
|
6dd8325772 | ||
|
|
e9bffd3ad7 | ||
|
|
ff890307c2 | ||
|
|
dda9d3e790 | ||
|
|
1acc02a2ec | ||
|
|
460c472c55 | ||
|
|
69c3b6142d | ||
|
|
9a036a4c01 | ||
|
|
0fbe206893 | ||
|
|
3cea6dd175 | ||
|
|
2fa053f833 | ||
|
|
ea4f858919 | ||
|
|
2aa4ab4b52 | ||
|
|
113977990e | ||
|
|
d86021e2a1 | ||
|
|
79faadef59 | ||
|
|
9b6629db7f | ||
|
|
d151a1ce65 | ||
|
|
d9ca7b483d | ||
|
|
708f7fc1b8 | ||
|
|
621db85845 | ||
|
|
b09066c580 | ||
|
|
7c45f28827 | ||
|
|
9c1b2cae22 | ||
|
|
16b2f81bd4 | ||
|
|
1969af65b9 | ||
|
|
3bd3ce5688 | ||
|
|
108f0e3d88 | ||
|
|
4344c127eb | ||
|
|
881a87216b | ||
|
|
1d473b82af | ||
|
|
6e0c005587 | ||
|
|
5955547c6f | ||
|
|
7a3a1cb8de | ||
|
|
1674cb0913 | ||
|
|
152ce4e923 | ||
|
|
3a6d024217 | ||
|
|
3b722068b0 | ||
|
|
f2fcc5ba79 | ||
|
|
db0fb8e287 | ||
|
|
dae36a67d1 | ||
|
|
6f99862288 | ||
|
|
0377747e1e | ||
|
|
6bc974f90f | ||
|
|
aca53de259 | ||
|
|
41bde38727 | ||
|
|
a4b7ee3b38 | ||
|
|
154b653c57 | ||
|
|
04489bc969 | ||
|
|
25499b3e7a | ||
|
|
bb6bda54dc | ||
|
|
9f3dbdc2d8 | ||
|
|
932148338c | ||
|
|
e0d0c38232 | ||
|
|
a0e732dc6e | ||
|
|
309f674853 | ||
|
|
ea20c2aa4c | ||
|
|
da5272c473 | ||
|
|
dc705c7720 | ||
|
|
a785e574e0 | ||
|
|
4b236b0268 | ||
|
|
1cd86ae5d6 | ||
|
|
b7489a0b14 | ||
|
|
f7554425dc | ||
|
|
9bfc577444 | ||
|
|
217d4cda42 | ||
|
|
08daa43aae | ||
|
|
184d889831 | ||
|
|
c6e0f431ae | ||
|
|
93daeab840 | ||
|
|
f132b297c6 | ||
|
|
858d2e908a | ||
|
|
b61e0b0c82 | ||
|
|
4d9a6e71c9 | ||
|
|
a0010de504 | ||
|
|
cb73a30e23 | ||
|
|
905d63e098 | ||
|
|
1ea8ab7dcc | ||
|
|
a45d21b279 | ||
|
|
3ca6d350fe | ||
|
|
2997ce8457 | ||
|
|
ff279d8310 | ||
|
|
9a7536b068 | ||
|
|
bd973e702e | ||
|
|
ede1851d34 | ||
|
|
cdb8ee0d8e | ||
|
|
e7d86a382c | ||
|
|
eb911df830 | ||
|
|
1c30acc53c | ||
|
|
32b0699235 | ||
|
|
e9c6580230 | ||
|
|
f893eb48fd | ||
|
|
232e2f18bf | ||
|
|
c266c99710 | ||
|
|
2a0e8f6d47 | ||
|
|
e6bd8ec529 | ||
|
|
911a95e873 | ||
|
|
447cfc2ae5 | ||
|
|
8dfeb0d260 | ||
|
|
caa7b19833 | ||
|
|
91d6fb62ba | ||
|
|
8f4a5b2015 | ||
|
|
07604c9a3b | ||
|
|
64dd8ae193 | ||
|
|
156ee6f290 | ||
|
|
c0a524a718 | ||
|
|
fe433d1417 | ||
|
|
efe8f34413 | ||
|
|
0dc662d295 | ||
|
|
081e370bfd | ||
|
|
3ef0567287 | ||
|
|
3cad9e5481 | ||
|
|
dc8b7908be | ||
|
|
85085a1eca | ||
|
|
bff59dee6e | ||
|
|
bb5828531a | ||
|
|
cd08e98c28 | ||
|
|
6bb23582c4 | ||
|
|
56ccb43997 | ||
|
|
bf7d40c9b5 | ||
|
|
5abb3d7f97 | ||
|
|
975ad8186a | ||
|
|
26b6419f04 | ||
|
|
331f7ca425 | ||
|
|
f445c05333 | ||
|
|
71c9ac0ff0 | ||
|
|
1404cc0ab5 | ||
|
|
a62485fc1f | ||
|
|
044f3080ff | ||
|
|
28b0cab906 | ||
|
|
82f34d651c | ||
|
|
6ca908a91d | ||
|
|
0948b8da9a | ||
|
|
22e04a53b3 | ||
|
|
df3217b41b | ||
|
|
9ff15a1913 | ||
|
|
89e43945a3 | ||
|
|
bd8dcddf35 | ||
|
|
dd372f3160 | ||
|
|
c56aab28d4 | ||
|
|
ca58801794 | ||
|
|
38fa5e2628 | ||
|
|
fae1ae7124 | ||
|
|
3ec5f76c73 | ||
|
|
5fbbcb5707 | ||
|
|
5bb8aaba55 | ||
|
|
23ba41e981 | ||
|
|
29b049452b | ||
|
|
0b0f665804 | ||
|
|
3cdf28ffdd | ||
|
|
5d53fba2ce | ||
|
|
c6fb18ea51 | ||
|
|
2d851cb134 | ||
|
|
92b0ef84e9 | ||
|
|
dc8d18384c | ||
|
|
f685be0aab | ||
|
|
44c056ecd5 | ||
|
|
dcc707c20d | ||
|
|
14cc851562 | ||
|
|
7223d1fd68 | ||
|
|
6ab5ad52ec | ||
|
|
079b2ae766 | ||
|
|
34eea827e7 | ||
|
|
06c6ee5a9c | ||
|
|
54748c20ea | ||
|
|
75f52e4cf4 | ||
|
|
55446dd4b1 | ||
|
|
02e63b6fc8 | ||
|
|
3aebcf66ec | ||
|
|
580a24eac3 | ||
|
|
07b1b22c2c | ||
|
|
49a5f716b7 | ||
|
|
23078eccba | ||
|
|
8b825d558f | ||
|
|
8a82f35edf | ||
|
|
bec664c073 | ||
|
|
9a7f97f11f | ||
|
|
95b8d62e4a | ||
|
|
3e61424d8f | ||
|
|
0bd7b4dab3 | ||
|
|
8cbada0cf5 | ||
|
|
f0784fec2d | ||
|
|
c1606c6fc9 | ||
|
|
cfe0c5e0a5 | ||
|
|
e0108cc99f | ||
|
|
0bc5bb5caa | ||
|
|
3330941a2c | ||
|
|
79ea082d7e | ||
|
|
3d78929ff0 | ||
|
|
5d94b03f7a | ||
|
|
587305eb52 | ||
|
|
e363ce5e0e | ||
|
|
e49b704200 | ||
|
|
ec8b35860c | ||
|
|
c0de8a2591 | ||
|
|
b8733eed52 | ||
|
|
4aa30efec7 | ||
|
|
74c49bf2da | ||
|
|
4354c3fb03 | ||
|
|
c03e7d9ed3 | ||
|
|
f25a676bd5 | ||
|
|
a9906762a0 | ||
|
|
7b5b88eca2 | ||
|
|
291682ba52 | ||
|
|
546d403b45 | ||
|
|
2652e53e0c | ||
|
|
b423fb1c46 | ||
|
|
8ae26a268a | ||
|
|
39b522abcc | ||
|
|
9bcfcef4fd | ||
|
|
60ac2d8058 | ||
|
|
9366d28141 | ||
|
|
75b48196b7 | ||
|
|
c9f40e32a1 | ||
|
|
d642b8dd07 | ||
|
|
549a11116e | ||
|
|
b5468a4a4f | ||
|
|
c5d278ccb7 | ||
|
|
bf5e15de45 | ||
|
|
f4af417267 | ||
|
|
69c04acaeb | ||
|
|
83a6bb188f | ||
|
|
494a8b5e91 | ||
|
|
c8021f2f08 | ||
|
|
8cdf3af047 | ||
|
|
c90a24e1ab | ||
|
|
83e3cfc34e | ||
|
|
133dd4e5b7 | ||
|
|
a8cca14b86 | ||
|
|
9b0f356fa4 | ||
|
|
f2b0a102b6 | ||
|
|
a7d01b230a | ||
|
|
2a7db4b9b8 | ||
|
|
77e5f2501d | ||
|
|
e6513717bd | ||
|
|
0e0c98f693 | ||
|
|
528bfa4e22 | ||
|
|
83c87779d7 | ||
|
|
dc33235144 | ||
|
|
935c658c5f | ||
|
|
0426f4fbf9 | ||
|
|
7930ec52fa | ||
|
|
75bc03fdcb | ||
|
|
f65cb9538c | ||
|
|
57eb306e4f | ||
|
|
bd0511a9fb | ||
|
|
c14f3292aa | ||
|
|
46e771a062 | ||
|
|
4c0095844b | ||
|
|
10a2ef27d6 | ||
|
|
309ff3da13 | ||
|
|
3af91e2a74 | ||
|
|
2e027e3db7 | ||
|
|
fc40fb02c0 | ||
|
|
2c1c0299f9 | ||
|
|
3c7637515c | ||
|
|
08cbbaf68c | ||
|
|
6e911acf01 | ||
|
|
f6d82a1b28 | ||
|
|
702126aeab | ||
|
|
df566e8fcb | ||
|
|
c83e0f33b5 | ||
|
|
f279f936b6 | ||
|
|
f8e20bafd9 | ||
|
|
a5211ca7ff | ||
|
|
0a5abdb331 | ||
|
|
4ed7413dd2 | ||
|
|
40b66c24fc | ||
|
|
2f7bedf001 | ||
|
|
44c31a9ddb | ||
|
|
20a35de3d8 | ||
|
|
cfc8a15db1 | ||
|
|
d5ba22a86c | ||
|
|
a38505f1c5 | ||
|
|
3cf1ba1fb3 | ||
|
|
9f5d595827 | ||
|
|
75673f0204 | ||
|
|
b43a7571ff | ||
|
|
b071dc04d3 | ||
|
|
12f9ff1647 | ||
|
|
3256a302df | ||
|
|
edbe447477 | ||
|
|
2f43910368 | ||
|
|
c2e87e4cfa | ||
|
|
e40d2ee806 | ||
|
|
ba74e7603b | ||
|
|
19c3fe6dc4 | ||
|
|
d0778dd124 | ||
|
|
8fb2b1cf3d | ||
|
|
5c7d1cbe10 | ||
|
|
3348bfc362 | ||
|
|
8db9252434 | ||
|
|
d9d4fe15cc | ||
|
|
8453e2d514 | ||
|
|
4d3070c0c2 | ||
|
|
15f273a9ef | ||
|
|
007c079cd6 | ||
|
|
9851b1e8ad | ||
|
|
584983e616 | ||
|
|
e86559b5d4 | ||
|
|
f83bc8c58f | ||
|
|
c65c2610cd | ||
|
|
2be08a3fcc | ||
|
|
4cdf440eee | ||
|
|
1545ee8fc2 | ||
|
|
a009fabfe4 | ||
|
|
46e4bfdd13 | ||
|
|
e24c82860d | ||
|
|
1291dee1e1 | ||
|
|
69732be09b | ||
|
|
8ce4ed7dee | ||
|
|
33d3cc0104 | ||
|
|
33b6b519ed | ||
|
|
5ec849f4e3 | ||
|
|
6f4a2d2cd5 | ||
|
|
0bca89e77d | ||
|
|
8f9f162011 | ||
|
|
ac3bea3d5e | ||
|
|
178d4f199b | ||
|
|
933819380d | ||
|
|
d68131e1b9 | ||
|
|
ffbc379c0b | ||
|
|
7053d12508 | ||
|
|
d41442200f | ||
|
|
d2564c343e | ||
|
|
d1c19e8837 | ||
|
|
0ec3bfabad | ||
|
|
43ffb04621 | ||
|
|
eeaedf76a9 | ||
|
|
120fb4829a | ||
|
|
12b93e53a7 | ||
|
|
00b17b9764 | ||
|
|
06192f809d | ||
|
|
278e9afb1a | ||
|
|
d09eb0d3ff | ||
|
|
416321679c | ||
|
|
bb2f8793f4 | ||
|
|
31697b3c73 | ||
|
|
45943a884a | ||
|
|
3f6b8b6de8 | ||
|
|
72c4e6e54f | ||
|
|
696df0e0e5 | ||
|
|
d57e6d058f | ||
|
|
a87929019d | ||
|
|
84e6931b88 | ||
|
|
84c29fdf62 | ||
|
|
881ad52f36 | ||
|
|
377dc44d7e | ||
|
|
d3738e3424 | ||
|
|
2e183db903 | ||
|
|
fa174b88dd | ||
|
|
0b4abe6d16 | ||
|
|
759fb0ecd8 | ||
|
|
429e927c3f | ||
|
|
643aed9133 | ||
|
|
e701642de2 | ||
|
|
a3a03e3da6 | ||
|
|
5dd3d5b552 | ||
|
|
1bae246e6c | ||
|
|
c94ef10189 | ||
|
|
dfacf1f9df | ||
|
|
06c5e34f48 | ||
|
|
1ab8b35e98 | ||
|
|
261b61ee6c | ||
|
|
5abf8e1bab | ||
|
|
7c0b463637 | ||
|
|
e156ab2432 | ||
|
|
0b46a7163b | ||
|
|
21b76c008a | ||
|
|
b7e9f8248d | ||
|
|
8b21e76a36 | ||
|
|
515471185f | ||
|
|
628e8f4e5e |
No files matched your search
+6
-3
@@ -1,4 +1,4 @@
|
||||
image: amazoncorretto:21
|
||||
image: amazoncorretto:25
|
||||
|
||||
before_script:
|
||||
- export GRADLE_USER_HOME=`pwd`/.gradle
|
||||
@@ -157,6 +157,9 @@ build:
|
||||
paths:
|
||||
- neoforge/build/libs
|
||||
- fabric/build/libs
|
||||
exclude:
|
||||
- neoforge/build/libs/*-dev-shadow.jar
|
||||
- fabric/build/libs/*-dev-shadow.jar
|
||||
|
||||
publish:
|
||||
stage: deploy
|
||||
@@ -181,8 +184,8 @@ deploy_artifacts:
|
||||
script:
|
||||
- yum install -y findutils
|
||||
- echo "Collecting artifacts..."
|
||||
- find neoforge/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
|
||||
- find fabric/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
|
||||
- find neoforge/build/libs/ -type f -name "*.jar" | grep -vE "dev-slim|sources|javadoc" | xargs -I {} mv {} ./
|
||||
- find fabric/build/libs/ -type f -name "*.jar" | grep -vE "dev-slim|sources|javadoc" | xargs -I {} mv {} ./
|
||||
- for f in *.jar; do mv "$f" "$(echo "$f" | sed s/+/b$CI_PIPELINE_IID+/)"; done
|
||||
artifacts:
|
||||
paths:
|
||||
|
||||
+70
-42
@@ -1,60 +1,88 @@
|
||||
# Changelog
|
||||
## [1.8.1 (MONTH Xth, 2026)](#1-8-1)
|
||||
## [1.8.3 (MONTH xth, 2026)](#1-8-3)
|
||||
|
||||
### Additions
|
||||
|
||||
### New rideable Pokémon
|
||||
|
||||
### Pokémon Added
|
||||
### Cries added/updated for the following Pokémon
|
||||
- Hoppip
|
||||
- Skiploom
|
||||
- Jumpluff
|
||||
- Houndour
|
||||
- Houndoom
|
||||
- Wurmple
|
||||
- Silcoon
|
||||
- Beautifly
|
||||
- Cascoon
|
||||
- Dustox
|
||||
- Surskit
|
||||
- Masquerain
|
||||
- Torkoal
|
||||
- Starly
|
||||
- Staravia
|
||||
- Staraptor
|
||||
- Combee
|
||||
- Vespiquen
|
||||
- Dusknoir
|
||||
- Helioptile
|
||||
- Heliolisk
|
||||
- Grubbin
|
||||
- Charjabug
|
||||
- Vikavolt
|
||||
- Applin (updated)
|
||||
- Flapple (updated)
|
||||
- Appletun
|
||||
- Runerigus
|
||||
- Dipplin
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Vikavolt
|
||||
|
||||
### Changes
|
||||
- Changed the Misc icon in the Campfire Pot Recipe Book to Health Candy
|
||||
- Moved EXP Candies from the Medicine recipe book category to the Misc category
|
||||
- Removed Dynamic Lights data from the Magmarizer item for consistency with the block
|
||||
- Added `doPokemonPredation` gamerule, which controls aggressiveness of Pokémon with `hate_entity` brain task defined
|
||||
- Added `predation_chance` server config value, which controls the possibility of attacking the hated entity found by `hate_entity` brain task
|
||||
- Prehistoric Eroded Pillar generates slightly more frequently
|
||||
|
||||
### Fixes
|
||||
- Fixed the `stat_compare` and `stat_equal` evolution requirements crashing the game when given `special_attack` or `special_defence`, and made them treat any non-permanent stat as a failed requirement instead of crashing.
|
||||
- Fixed the Beast Ball not applying its 0.1× penalty to Pokémon that are not Ultra Beasts.
|
||||
- Fixed the Moon Ball reading the world's total elapsed time instead of the time of day, so its bonus applied during the day instead.
|
||||
- Fixed the Love Ball never awarding its 2.5× opposite gender bonus, and matching species by display name instead of identifier.
|
||||
- Fixed the Timer Ball being weaker than a regular Poké Ball on early turns and only reaching 4× on turn 14 instead of turn 10.
|
||||
- Fixed the Luxury Ball only doubling Friendship gains of 1, leaving level up and berry gains unaffected.
|
||||
- Fixed NPCs getting their own TM progress file.
|
||||
- Fixed the TM Machine refusing move selections that the `unlockAllMoveDexMovesByDefault` config had made visible, leaving the move slot blank and the craft button unresponsive.
|
||||
- Fixed Rufflet, Braviary, and Hisuian Braviary flooding logs with errors about missing sound events.
|
||||
- Fixed Pokémon property typos in Pangoro and Dedenne herd spawn files.
|
||||
- Fixed form typo in Rockruff dusk spawn entry.
|
||||
- Fixed a potential world gen stall with the Type Gem clusters.
|
||||
- Fixed Rowap and Jacoba berries not correctly altering Pokémon sizes when used as bait
|
||||
- Fixed Ampharos' eyes not emitting particles
|
||||
- Fixed Alolan Raticate's cry not playing
|
||||
- Fixed unintentional watermelon cosmetic for Hisuian Electrode.
|
||||
- Fixed Blastoise having an unintentional passenger seat
|
||||
- Fixed odd NeoForge crash due to a dependency being outdated. It will now flag the dependency for being outdated correctly.
|
||||
- Fixed form typo in Rockruff-Dusk spawn, preventing it from being able to spawn.
|
||||
- Fixed a potential world gen stall caused by Type Gem clusters.
|
||||
- Fixed Rowap and Jacoba berries not correctly altering Pokémon sizes when used as bait.
|
||||
- Fixed Ampharos' eyes not emitting particles.
|
||||
- Fixed Alolan Raticate's cry not playing.
|
||||
- Fixed odd NeoForge crash due to a dependency being outdated. It will now correctly flag the dependency for being outdated.
|
||||
- Fixed several incorrect light-based spawning conditions for ghosts and bugs.
|
||||
- Removed unused, placeholder habitat pools.
|
||||
- Fixed Mantyke, Mantine, and Quaxly getting stuck in a recoil 'expression' during battles due to a having an expression mistakenly assigned as a recoil animation.
|
||||
- Fixed Pokémon on shoulders not animating if they are visibly holding a held item.
|
||||
- Fixed Mantyke, Mantine, and Quaxly getting stuck in a recoil 'expression' during battles due to a having an expression mistakenly assigned as a recoil animation.
|
||||
- Fixed Lycanroc's head movement
|
||||
- Added head movement to Archaludon
|
||||
- Fixed Duraludon line not having their sleep animations
|
||||
- Fixed Diglett line not having their faint animations
|
||||
- Fixed Kingambit moving its legs while walking
|
||||
|
||||
- Fixed datapacks with item interaction evolutions that don't specify an item crashing the world on load.
|
||||
- Fixed the Pokédex evolution tree crashing when a datapack's dex entry is missing an evolution's form.
|
||||
- Fixed the Pokédex evolution tree crashing with a stack overflow on evolutions that loop back on themselves.
|
||||
- Fixed the Pokédex evolution tree crashing when looking at a dex that is not part of the "National Dex" aggregate.
|
||||
- Fixed evolution trees not building properly when a Pokémon has several Pokédex entries for different regions.
|
||||
- Fixed form-changing evolutions sometimes resolving to the source form in the Pokédex evolution tree.
|
||||
- Broken datapack evolutions are now logged and skipped in the Pokédex evolution tree instead of crashing.
|
||||
- Fixed the `alpha` property having no tab completion in commands such as `/pokespawn`, `/pokegive` and `/pokeedit`, and added the missing `dmax_level`, `gmax_factor` and `tradable` aliases to tab completion
|
||||
- Fixed friendship booster items not being recognised as such
|
||||
- Fixed conflicts with other mods that would make use of recipe books in certain ways (Farmer's Delight Cooking Pot)
|
||||
- Fixed Pokémon battles stalling when a sidemod cancels the `THROWN_POKEBALL_HIT` hit event
|
||||
- Fixed choice feature tab completion in `spawnpokemon/pokegive/pokeedit` commands
|
||||
- Fixed MoLang that's targeting players intermittedly failing when they have died, needing them to relog
|
||||
- Fixed a NeoForge bug where none of the Cobblemon plants/berries could be placed into pots
|
||||
- Fixed party overlay not hiding when the player opens the Pokédex scanner
|
||||
- Added compat for AppleSkin
|
||||
- Fixed some display names having unintended font colours
|
||||
- Fixed `hate_entity` task focusing on its own entity
|
||||
- Thus enabled deadly warfare between Zangoose and Seviper
|
||||
- Prehistoric Frozen Pond, Prehistoric Frozen Spike, and Prehistoric Lush Den now generate
|
||||
- Fixed Frogadier floating in its battle_idle animation
|
||||
- Fixed absence or incorrect mergers in spawning conditions, making max height/depth of conditions to use the min value instead
|
||||
- Added stricter riding checks on server side to prevent possible packet forgery when player tries to ride pokemon
|
||||
- Fixed Pokémon cries and animation sounds played from GUIs, such as the starter selection screen and the Pokédex, being tied to the Master volume slider instead of Friendly Creatures
|
||||
|
||||
### Developer
|
||||
- Bumped NeoForge to `21.1.195` to get access to MixinExtras `0.5` and the expressions annotation
|
||||
- New Platform Event `PLAYER_RESPAWN` which is fired when a player respawns (either through death or returning from the end)
|
||||
- Platform Events `SERVER_PLAYER_TICK_PRE` and `SERVER_PLAYER_TICK_POST` no longer fire when the player is dead
|
||||
- it is now tied much closer to the actual entity rather than the player (or their connection)
|
||||
|
||||
### Molang & Datapacks
|
||||
|
||||
### Particles
|
||||
- Fixed `q.pokemon.nature` returning class instance instead of proper string value (`cobblemon:adamant`)
|
||||
- Fixed `q.entity.is_looking_at` result being always `1` for whatever entity passed as target
|
||||
- Added hate chance optional parameter to `hate_entity` task. `1.0` will make an entity always attack the target
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Updated translations for:
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
- Nodemaker bug, it thinks jumps are possible from water up an entire block - they aint
|
||||
https://gyazo.com/759b8285e7c07046ff2e54adf0d7a7ac
|
||||
|
||||
- Why is magikarp trying to path through ice
|
||||
https://gyazo.com/ae230758c529f885eeb0dd91e60530d2
|
||||
|
||||
- We should use mixins to put the path node filtering from OmniPathNodeMaker in the base classes otherwise
|
||||
NPC wandering will be jank too.
|
||||
@@ -1,9 +0,0 @@
|
||||
- Some kind of particle effect for them? they're meant to have glowing eyes, so maybe some red particles on the eye locator
|
||||
--- global posers? stacked posers?
|
||||
--- red texture seems to be what some people wanted.
|
||||
|
||||
/- shoulder mounts part of it
|
||||
- omni boost
|
||||
- roar when player comes within reach, adjust levels
|
||||
|
||||
- Riding settings to control what the min scale is for a pokemon to be ridable.
|
||||
+5
-2
@@ -1,3 +1,6 @@
|
||||
import utilities.gitBranch
|
||||
import utilities.gitShortCommit
|
||||
|
||||
plugins {
|
||||
id("cobblemon.root-conventions")
|
||||
}
|
||||
@@ -6,6 +9,6 @@ version = "${project.property("mod_version")}+${project.property("mc_version")}"
|
||||
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") == true
|
||||
if (isSnapshot) {
|
||||
val fixedBranchName = versioning.info.branch.substringAfter("/")
|
||||
version = "$version-${fixedBranchName}-${versioning.info.build}"
|
||||
val fixedBranchName = gitBranch().substringAfter("/")
|
||||
version = "$version-${fixedBranchName}-${gitShortCommit()}"
|
||||
}
|
||||
@@ -36,6 +36,7 @@
|
||||
- Added `cobblemon:catch_alpha_pokemon` advancement trigger and `totalAlphaCaptureCount` stat for captured Alpha Pokémon.
|
||||
|
||||
### New rideable Pokémon
|
||||
- Pidgeot
|
||||
- Crobat
|
||||
- Skarmory
|
||||
- Milotic
|
||||
@@ -106,7 +107,9 @@
|
||||
- Avalugg (Hisuian Form)
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
|
||||
- Pidgey
|
||||
- Pidgeotto
|
||||
- Pidgeot
|
||||
- Sandshrew
|
||||
- Sandslash
|
||||
- Nidoking
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# Changelog
|
||||
## [1.8.1 (September 13th, 2026)](#1-8-1)
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Flapple, Appletun, Dipplin, Hydrapple (placeholder animations only).
|
||||
|
||||
### Fixes
|
||||
- Fixed a potential world generation stall caused by Type Gem clusters.
|
||||
- Fixed Pokémon on shoulders not animating if they are visibly holding a held item.
|
||||
- Fixed NPCs getting their own TM progress file.
|
||||
- Fixed odd NeoForge crash due to a dependency being outdated. It will now correctly flag the dependency for being outdated.
|
||||
- Fixed the TM Machine refusing move selections that the `unlockAllMoveDexMovesByDefault` config had made visible, leaving the move slot blank and the craft button unresponsive.
|
||||
- Fixed the Beast Ball not applying its 0.1× penalty to Pokémon that are not Ultra Beasts.
|
||||
- Fixed the Moon Ball reading the world's total elapsed time instead of the time of day, so its bonus applied during the day instead.
|
||||
- Fixed the Love Ball never awarding its 2.5× opposite gender bonus, and matching species by display name instead of identifier.
|
||||
- Fixed the Timer Ball being weaker than a regular Poké Ball on early turns and only reaching 4× on turn 14 instead of turn 10.
|
||||
- Fixed the Luxury Ball only doubling Friendship gains of 1, leaving level up and berry gains unaffected.
|
||||
- Fixed Rufflet, Braviary, and Hisuian Braviary flooding logs with errors about missing sound events.
|
||||
- Fixed Pokémon property typos in Pangoro and Dedenne herd spawn files.
|
||||
- Fixed unintentional watermelon cosmetic for Hisuian Electrode.
|
||||
- Fixed Blastoise having an unintentional passenger seat.
|
||||
- Fixed form typo in Rockruff-Dusk spawn, preventing it from being able to spawn.
|
||||
- Fixed the `stat_compare` and `stat_equal` evolution requirements crashing the game when given `special_attack` or `special_defence`, and made them treat any non-permanent stat as a failed requirement instead of crashing.
|
||||
- Fixed Rowap and Jacoba berries not correctly altering Pokémon sizes when used as bait.
|
||||
- Fixed Ampharos' eyes not emitting particles.
|
||||
- Fixed Alolan Raticate's cry not playing.
|
||||
- Fixed several incorrect light-based spawning conditions for ghosts and bugs.
|
||||
- Removed unused, placeholder habitat pools.
|
||||
- Fixed Mantyke, Mantine, and Quaxly getting stuck in a recoil 'expression' during battles due to having an expression assigned as a recoil animation.
|
||||
- Fixed Lucario's aura particles not emitting.
|
||||
- Fixed Lycanroc's head movement.
|
||||
- Added head movement to Archaludon.
|
||||
- Fixed Duraludon line not having their sleep animations.
|
||||
- Fixed Diglett line not having their faint animations.
|
||||
- Fixed Kingambit moving its legs while walking.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Brazilian Portuguese
|
||||
- Simplified Chinese
|
||||
- Japanese
|
||||
@@ -0,0 +1,211 @@
|
||||
# Changelog
|
||||
## [1.8.2 (October 11th, 2026)](#1-8-2)
|
||||
|
||||
### Additions
|
||||
- The following items can now be placed on the ground as blocks:
|
||||
- King's Rock, Galarica Cuff, Unremarkable Teacup, Masterpiece Teacup, Chipped Pot, Cracked Pot, Sachet, Metal Powder, Quick Powder, Bright Powder, Soft Sand, Electirizer, Magmarizer, Icy Rock, Heat Rock, Smooth Rock, Damp Rock, Destiny Knot, Luminous Moss, Never-Melt Ice, Wide Lens, Scope Lens, and Zoom Lens.
|
||||
- I wasn't finished. Iron Ball, Metal Coat, Throat Spray, Terrain Extender, Medicinal Brew, Moomoo Milk, HP Up, Protein, Iron, Carbos, Calcium, Zinc, PP Up, PP Max, Upgrade, Dubious Disc, and Loaded Dice.
|
||||
- The following items can now be placed on various surfaces:
|
||||
- Galarica Wreath, Magnet, Flame Orb, Life Orb, Toxic Orb, Light Ball, and Smoke Ball.
|
||||
- The following items can now be placed as blocks and have additional functionality:
|
||||
- Ring Target, Metronome, and Eject Button.
|
||||
- The following items can now be worn by Players and Pokémon:
|
||||
- Galarica Wreath, Cleanse Tag, Spell Tag, Sharp Beak, Covert Cloak, Shell Helmet, and Never-Melt Ice.
|
||||
- Wearable items can now be equipped by a player by holding it and right-clicking (or whatever you've rebound use/interact to).
|
||||
- Wearable items that can be placed down are exempt from this behaviour.
|
||||
- Mint Leaves can now be placed on the ground as Leaf Litter, or in Flower Pots.
|
||||
- The recall animation now renders the ball in hand with the player's arm raised.
|
||||
- Added Oricorio Flowers.
|
||||
- Added Terrain Plants, four plants grown from Electric, Grassy, Misty, and Psychic Seeds, which glow under specific environmental conditions and can be farmed for more of their seeds.
|
||||
- Berries can now be placed in Flower Pots.
|
||||
- The evolution tree for a Pokémon can now be viewed in the Pokédex, showing the Pokémon's full family line and what's needed to evolve into each stage.
|
||||
- Added custom sounds to a bunch of items that can be placed as blocks: liquid bottles, pill bottles, powders, and dice.
|
||||
- Added paper as a new cosmetic item for Pikachu.
|
||||
- Burmy changes its cloak after a battle it took part in, based on the biome.
|
||||
- Trash Cloak in the Deep Dark, Nether and End.
|
||||
- Plant Cloak in lush biomes such as forests, jungles, plains and swamps.
|
||||
- Sandy Cloak in sandy biomes, beaches and caves.
|
||||
|
||||
### Pokémon Added
|
||||
#### Generation 4
|
||||
- Snover
|
||||
- Abomasnow
|
||||
- Burmy
|
||||
- Wormadam
|
||||
- Mothim
|
||||
|
||||
#### Generation 5
|
||||
- Tympole
|
||||
- Palpitoad
|
||||
- Seismitoad
|
||||
|
||||
#### Generation 6
|
||||
- Helioptile
|
||||
- Heliolisk
|
||||
|
||||
#### Generation 7
|
||||
- Grubbin
|
||||
- Charjabug
|
||||
- Vikavolt
|
||||
- Minior
|
||||
|
||||
#### Generation 8
|
||||
- Eternatus
|
||||
|
||||
#### Generation 9
|
||||
- Greavard
|
||||
- Houndstone
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Sudowoodo
|
||||
- Spheal
|
||||
- Cacnea
|
||||
- Cacturne
|
||||
- Binacle
|
||||
- Barbaracle
|
||||
- Glimmet
|
||||
- Glimmora
|
||||
- Deerling
|
||||
- Sawsbuck (All forms)
|
||||
- Absol
|
||||
- Poliwag
|
||||
- Politoed
|
||||
- Ekans
|
||||
- Oddish
|
||||
- Gloom
|
||||
- Vileplume
|
||||
- Bellossom
|
||||
- Shroomish
|
||||
- Chespin
|
||||
- Quilladin
|
||||
- Chesnaught
|
||||
- Fennekin
|
||||
- Braixen
|
||||
- Delphox
|
||||
- Froakie
|
||||
- Frogadier
|
||||
- Greninja
|
||||
- Shinx
|
||||
- Luxio
|
||||
- Luxray
|
||||
- Slakoth
|
||||
- Riolu
|
||||
- Lucario
|
||||
- Corsola
|
||||
- Mime Jr.
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Treecko (New Shoulder Mount!)
|
||||
- Bonsly (New Shoulder Mount!)
|
||||
- Sudowoodo
|
||||
- Cacnea
|
||||
- Cacturne
|
||||
- Ekans
|
||||
- Arbok
|
||||
- Oddish
|
||||
- Gloom
|
||||
- Vileplume
|
||||
- Bellossom
|
||||
- Pichu
|
||||
- Pikachu
|
||||
- Raichu (+ Alolan)
|
||||
- Greninja
|
||||
- Slakoth
|
||||
|
||||
### Changes
|
||||
- Slowed the speed of Type Gem growth, and revamped their generation to grow in a more crystal-like shape.
|
||||
- Terrain Seeds can now be planted.
|
||||
- Terrain Seeds are now consumed during PvP and NPC battles.
|
||||
- Glow Item Frames can be crafted using Bright Powder as an alternative to Glow Ink Sacs.
|
||||
- Bright Powder can be used on Signs and Hanging Signs to make text glow, as an alternative to Glow Ink Sacs.
|
||||
- Updated various recipes to display in Recipe Groups within the Recipe Book.
|
||||
- Updated most recipes to display more logically and consistently within the Recipe Book's categories.
|
||||
- Updated the following recipes
|
||||
- Never-Melt Ice, Focus Sash, Blunder Policy, Weakness Policy, Blank TM.
|
||||
- Made ride rotations less jittery in multiplayer.
|
||||
- Changes Disc Shelf TMs to use textures instead of tinting and overlays to line up with item display.
|
||||
- Blank TM can now be inserted into the Disc Shelf.
|
||||
- Added a TM creative tab.
|
||||
- Made regional and Vivillon split-evo locations mutually exclusive.
|
||||
- Vivillon's patterns are now viewable as forms with form names and unique Pokédex entries displayed.
|
||||
- Item evolutions now unlock **all** locked evolutions whose requirements are met instead of stopping after the first.
|
||||
- Exceptions being "forced" evolutions which stop after the first one.
|
||||
- Removed Mega Drain as a TM.
|
||||
- PokeSnacks (and other area spawns) will now start the vertical offset checking from the center rather than base coordinate
|
||||
- This will help PokeSnacks to work inside caves or tighter spaces better.
|
||||
|
||||
### Fixes
|
||||
- Type Gem blocks now properly generate clusters off of the block.
|
||||
- Correctly grant "They're Minerals!" advancement when planting a Type Gem.
|
||||
- Shoulder mounted Pokémon now follow player body animations, improving their positioning with custom player animations and default actions.
|
||||
- Shoulder mounted Pokémon now sit slightly higher with chest armor equipped for better alignment, with a configurable blacklist.
|
||||
- Type Gem Blocks now have advancements to give you the recipe in the recipe book (the data for the advancements were inside the recipes somehow??).
|
||||
- Some other recipes without advancements have also been corrected.
|
||||
- Corrected the TM Recipes for Charge Beam and Payday.
|
||||
- Starter Screen Categories will no longer stop rendering if they are bigger than the viewport and you are not viewing the top or bottom edges.
|
||||
- The Random Starter option no longer runs off into other categories or becomes unaccessible due to scroll limits if it causes a new row.
|
||||
- Mochi and Feathers no longer drop glass bottles on use.
|
||||
- Fixed a rare set of concurrency bugs related to reloading packs on NeoForge; fixes a ModernFix compatibility issue.
|
||||
- Removed unnecessary conditions for Mimikyu's standing pose. Hopefully fixes the rare instance of it using its shoulder animations during battle in multiplayer scenarios.
|
||||
- Fixed Rockruff line not blinking.
|
||||
- Fixed Flygon sometimes using its running animation instead of walking.
|
||||
- Fixed Bramblin always sleeping outside of battle.
|
||||
- Fixed Dragonair using its battle idle as a normal idle.
|
||||
- Fixed Lycanroc's head movement.
|
||||
- Added head movement to Archaludon.
|
||||
- Fixed Duraludon line not having any sleep animations.
|
||||
- Fixed Diglett line not having their faint animations.
|
||||
- Fixed Kingambit moving its legs while walking.
|
||||
- Fixed Alolan Diglett's cry not playing.
|
||||
- Fixed shiny alpha Snorlax using the non-shiny texture.
|
||||
- Fixed Crabominable's head breaking when looking around.
|
||||
- Fixed Shiny Dipplin and Hydrapple's textures.
|
||||
- Various structure fixes.
|
||||
- Fixed shiny Pokémon under certain circumstances forgetting taught TMs.
|
||||
- Fixed certain Pokémon sounds sometimes being doubled when played at specific times in their animations.
|
||||
- Fixed ball capture beam origin coming from behind the ball.
|
||||
- Fixed Safari Ball catch rate outside of battle.
|
||||
- Fixed alpha eye (and other) particles not respecting the client particle density setting in video options.
|
||||
- Fixed the TM Machine UI not closing when player is moving away from it.
|
||||
- Moved the config category for alpha/shiny chance config fields for fossil machine and honey log slathering to Spawning.
|
||||
- Fixed crashes for addon species with non-Cobblemon namespaces in evolution, fishing bait, and Pokédex lookups.
|
||||
- Bees will now grow Apricorns and the Galarica Nut Bush, which were in the bee growables tag but never handled, and correctly spend their nectar when they do.
|
||||
- Saccharine Leaves can now be bone mealed.
|
||||
- Fixed equipping a stack of wearable items instead of one item of a stack.
|
||||
- Fixed TM stack consumption in TM Machine screen when a player teaches a move to a Pokémon.
|
||||
- Fixed every Miltank giving mushroom stew, not only mushroom variants.
|
||||
- Medicinal Leeks can now be eaten when they aren't being planted, matching their food properties.
|
||||
- Sweeping attacks no longer set owned Pokémon on fire (e.g. with Fire Aspect) or knock them back. Friendly Fire is now off.
|
||||
- Fixed Pokémon not losing their previous form's signature moves when changing forms (e.g. Rotom keeping Overheat after leaving its Heat form).
|
||||
- Form-specific moves gained from a form change are now only granted if the Pokémon is high enough level to learn them, and no longer create duplicates in benched moves.
|
||||
- Spinda now learns Teeter Dance at level 32 instead of via TM.
|
||||
- Fixed Oricorio Pa'u form description in the Pokédex.
|
||||
- Fixed PC playing sound on close when opened via command.
|
||||
|
||||
### Developer
|
||||
- Evolution requirements can now set `pokedexIcon` and `pokedexTooltip` directly in their JSON to control how they're shown on the Pokédex's evolution tree, for example:
|
||||
```json
|
||||
{
|
||||
"variant": "attack_defence_ratio",
|
||||
"pokedexIcon": "minecraft:diamond_sword",
|
||||
"pokedexTooltip": "cobblemon.ui.pokedex.requirement.attack_defence_ratio.tooltip"
|
||||
}
|
||||
```
|
||||
- Fixed the wrong order of operations in the code flow prior to the `FOSSIL_REVIVED` event causing Pokémon to appear without the entity link.
|
||||
- Fixed TestPartySlot command not correctly comparing the provided spec with the target Pokémon.
|
||||
|
||||
### Molang & Datapacks
|
||||
- A new `negate` variant for evolution requirements has been added, which will negate (invert) the provided inner condition.
|
||||
- Added Molang functions for individual Pokédex ids, wherein a subdex is passed in as a string to `dex_caught_count` etc.
|
||||
- Added a `battle_ended` callback, backed by the new `BATTLE_ENDED` event, which fires whenever a battle ends for any reason, alongside a multitude of flags not previously covered by `BATTLE_VICTORY`.
|
||||
- Added `battle_pokemon` to battle actor structs and `has_faced_opponents` to battle Pokémon structs.
|
||||
- Added the `cobblemon:form_change/bagworm_cloak/plant_cloak`, `sandy_cloak` and `trash_cloak` biome tags, which control Burmy's cloak after battle.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Brazilian Portuguese
|
||||
- Canadian French
|
||||
- Japanese
|
||||
- Korean
|
||||
- Russian
|
||||
- Ukrainian
|
||||
+43
-29
@@ -1,9 +1,7 @@
|
||||
|
||||
import utilities.isSnapshot
|
||||
import utilities.version
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
import utilities.gitBranch
|
||||
import utilities.gitCommit
|
||||
|
||||
/*
|
||||
*
|
||||
@@ -18,13 +16,9 @@ import java.time.format.DateTimeFormatter
|
||||
plugins {
|
||||
id("cobblemon.base-conventions")
|
||||
id("cobblemon.publish-conventions")
|
||||
|
||||
id("net.kyori.blossom")
|
||||
id("org.jetbrains.gradle.plugin.idea-ext")
|
||||
}
|
||||
|
||||
architectury {
|
||||
common("neoforge", "fabric")
|
||||
kotlin("kapt")
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -32,53 +26,71 @@ repositories {
|
||||
maven(url = "https://api.modrinth.com/maven")
|
||||
maven(url = "https://maven.neoforged.net/releases")
|
||||
maven(url = "https://maven.gegy.dev")
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
val mappingsAttribute = Attribute.of("net.minecraft.mappings", String::class.java)
|
||||
dependencies {
|
||||
implementation(libs.bundles.kotlin)
|
||||
modImplementation(libs.fabric.loader)
|
||||
modApi(libs.molang)
|
||||
compileOnly(libs.bundles.common.mixin.compileOnly)
|
||||
annotationProcessor(libs.mixinExtras.common)
|
||||
|
||||
api(libs.molang)
|
||||
|
||||
// Integrations
|
||||
compileOnlyApi(libs.jei.api)
|
||||
modCompileOnly(libs.bundles.common.integrations.compileOnly) {
|
||||
compileOnly(libs.bundles.common.integrations.compileOnly) {
|
||||
isTransitive = false
|
||||
}
|
||||
// LambDynamicLights is handled differently because we need the Mojang-mappings version of it.
|
||||
modCompileOnly(libs.lambDynamicLights) {
|
||||
capabilities {
|
||||
requireCapability("dev.lambdaurora.lambdynamiclights:api-mojmap")
|
||||
compileOnly(libs.lambDynamicLights) {
|
||||
attributes {
|
||||
attribute(mappingsAttribute, "mojmap")
|
||||
}
|
||||
}
|
||||
// Flywheel has no common dep so just pick one and don't use any platform specific code in common
|
||||
// modCompileOnly(libs.flywheelFabric)
|
||||
|
||||
// Showdown
|
||||
modCompileOnly(libs.graal.core)
|
||||
compileOnly(libs.graal.core)
|
||||
compileOnly(libs.graal.polyglot)
|
||||
|
||||
// Data Storage
|
||||
modCompileOnly(libs.bundles.mongo)
|
||||
compileOnly(libs.bundles.mongo)
|
||||
|
||||
// Unit Testing
|
||||
testImplementation(libs.bundles.unitTesting)
|
||||
testImplementation(libs.graal.sdk)
|
||||
testRuntimeOnly(libs.bundles.graal)
|
||||
testRuntimeOnly(libs.junit.platform)
|
||||
testImplementation(kotlin("test"))
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
// Static GL mocks must not load a graphics driver on headless CI.
|
||||
systemProperty("org.lwjgl.opengl.explicitInit", "true")
|
||||
testLogging {
|
||||
setEvents(listOf("failed"))
|
||||
setExceptionFormat("full")
|
||||
}
|
||||
System.getProperty("camera.benchmark")?.let { systemProperty("camera.benchmark", it) }
|
||||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.addAll(
|
||||
"-Xno-param-assertions",
|
||||
"-Xno-call-assertions",
|
||||
"-Xno-receiver-assertions"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Git info lives in its own output dir (not processResources) so a new commit only rewrites this one file.
|
||||
val writeGitInfo by tasks.registering(WriteProperties::class) {
|
||||
destinationFile = layout.buildDirectory.file("generated/gitInfo/cobblemon-git.properties")
|
||||
property("commit", gitCommit())
|
||||
property("branch", gitBranch())
|
||||
}
|
||||
sourceSets.main { output.dir(mapOf("builtBy" to writeGitInfo), layout.buildDirectory.dir("generated/gitInfo")) }
|
||||
|
||||
tasks.processResources {
|
||||
exclude("data/**/README.md")
|
||||
}
|
||||
@@ -87,11 +99,11 @@ sourceSets {
|
||||
main {
|
||||
blossom {
|
||||
kotlinSources {
|
||||
fun generateLicenseHeader() : String {
|
||||
fun generateLicenseHeader(): String {
|
||||
val builder = StringBuilder()
|
||||
builder.append("/*\n")
|
||||
rootProject.file("HEADER").forEachLine {
|
||||
if(it.isEmpty()) {
|
||||
if (it.isEmpty()) {
|
||||
builder.append(" *").append("\n")
|
||||
} else {
|
||||
builder.append(" * ").append(it).append("\n")
|
||||
@@ -104,12 +116,14 @@ sourceSets {
|
||||
property("license", generateLicenseHeader())
|
||||
property("modid", "cobblemon")
|
||||
property("version", project.version())
|
||||
property("isSnapshot", if(rootProject.isSnapshot()) "true" else "false")
|
||||
property("gitCommit", versioning.info.commit)
|
||||
property("branch", versioning.info.branch)
|
||||
property("isSnapshot", if (rootProject.isSnapshot()) "true" else "false")
|
||||
System.getProperty("buildNumber")?.let { property("buildNumber", it) }
|
||||
property("timestamp", OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss")) + " UTC")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The platform jars are built from :common:jar, so the remapped common jars are only needed by `publish`
|
||||
tasks.assemble {
|
||||
setDependsOn(dependsOn.filterNot { (it as? TaskProvider<*>)?.name in setOf("remapJar", "remapSourcesJar") })
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
maven.artifactId = mod
|
||||
maven.artifactId = mod
|
||||
fabric.loom.disableObfuscation=true
|
||||
-153
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.camera;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.camera.CameraFeedHandler;
|
||||
import com.cobblemon.mod.common.client.util.compat.SodiumCompat;
|
||||
import com.cobblemon.mod.common.platform.events.ClientChunkEvent;
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class CameraClientChunkCacheExtension {
|
||||
private static final Long2ObjectOpenHashMap<LevelChunk> CHUNKS = new Long2ObjectOpenHashMap<>();
|
||||
|
||||
private CameraClientChunkCacheExtension() {}
|
||||
|
||||
public static boolean shouldKeepChunk(ChunkPos chunkPos) {
|
||||
int renderDistance = Minecraft.getInstance().options.renderDistance().get();
|
||||
return CameraChunkVisibilityManager.shouldKeepChunk(chunkPos, renderDistance)
|
||||
|| CameraFeedHandler.shouldAddChunk(chunkPos, renderDistance);
|
||||
}
|
||||
|
||||
public static void retain(LevelChunk chunk) {
|
||||
synchronized (CHUNKS) {
|
||||
CHUNKS.put(chunk.getPos().toLong(), chunk);
|
||||
}
|
||||
}
|
||||
|
||||
public static LevelChunk take(ClientLevel level, int x, int z) {
|
||||
synchronized (CHUNKS) {
|
||||
long position = ChunkPos.asLong(x, z);
|
||||
LevelChunk chunk = CHUNKS.get(position);
|
||||
return chunk != null && chunk.getLevel() == level ? CHUNKS.remove(position) : null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void drop(ClientLevel level, ChunkPos chunkPos) {
|
||||
LevelChunk chunk = take(level, chunkPos.x, chunkPos.z);
|
||||
if (chunk != null) {
|
||||
unload(level, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
public static LevelChunk getChunk(int x, int z) {
|
||||
synchronized (CHUNKS) {
|
||||
return CHUNKS.get(ChunkPos.asLong(x, z));
|
||||
}
|
||||
}
|
||||
|
||||
public static LevelChunk replaceWithPacketData(ClientLevel level, int x, int z, FriendlyByteBuf packetData, CompoundTag chunkTag, Consumer<ClientboundLevelChunkPacketData.BlockEntityTagOutput> tagOutput) {
|
||||
if (!Minecraft.getInstance().isSameThread()) {
|
||||
throw new IllegalStateException("Camera chunk packet applied off the client thread");
|
||||
}
|
||||
ChunkPos chunkPos = new ChunkPos(x, z);
|
||||
LevelChunk chunk = getChunk(x, z);
|
||||
if (chunk == null || chunk.getLevel() != level) {
|
||||
chunk = new LevelChunk(level, chunkPos);
|
||||
}
|
||||
chunk.replaceWithPacketData(packetData, chunkTag, tagOutput);
|
||||
retain(chunk);
|
||||
level.onChunkLoaded(chunkPos);
|
||||
SodiumCompat.getInstance().notifyChunkAdded(level, x, z);
|
||||
PlatformEvents.CLIENT_CHUNK_LOAD.postEvents(new ClientChunkEvent.Load(chunk, level));
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public static void prune(ClientLevel level) {
|
||||
for (LevelChunk chunk : snapshot()) {
|
||||
if (chunk.getLevel() == level && !shouldKeepChunk(chunk.getPos())) {
|
||||
try {
|
||||
drop(level, chunk.getPos());
|
||||
} finally {
|
||||
queueLightRemoval(level, chunk.getPos());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
ArrayList<LevelChunk> removed;
|
||||
synchronized (CHUNKS) {
|
||||
removed = new ArrayList<>(CHUNKS.values());
|
||||
CHUNKS.clear();
|
||||
}
|
||||
RuntimeException failure = null;
|
||||
for (LevelChunk chunk : removed) {
|
||||
ClientLevel level = (ClientLevel) chunk.getLevel();
|
||||
try {
|
||||
try {
|
||||
unload(level, chunk);
|
||||
} finally {
|
||||
queueLightRemoval(level, chunk.getPos());
|
||||
}
|
||||
} catch (RuntimeException exception) {
|
||||
if (failure == null) failure = exception;
|
||||
else if (failure != exception) failure.addSuppressed(exception);
|
||||
}
|
||||
}
|
||||
if (failure != null) throw failure;
|
||||
}
|
||||
|
||||
public static ArrayList<LevelChunk> snapshot() {
|
||||
synchronized (CHUNKS) {
|
||||
return new ArrayList<>(CHUNKS.values());
|
||||
}
|
||||
}
|
||||
|
||||
private static void queueLightRemoval(ClientLevel level, ChunkPos position) {
|
||||
level.queueLightUpdate(() -> {
|
||||
LevelLightEngine lightEngine = level.getLightEngine();
|
||||
lightEngine.setLightEnabled(position, false);
|
||||
for (int y = lightEngine.getMinLightSection(); y < lightEngine.getMaxLightSection(); y++) {
|
||||
SectionPos section = SectionPos.of(position, y);
|
||||
lightEngine.queueSectionData(LightLayer.BLOCK, section, null);
|
||||
lightEngine.queueSectionData(LightLayer.SKY, section, null);
|
||||
}
|
||||
for (int y = level.getMinSection(); y < level.getMaxSection(); y++) {
|
||||
lightEngine.updateSectionStatus(SectionPos.of(position, y), true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void unload(ClientLevel level, LevelChunk chunk) {
|
||||
ChunkPos position = chunk.getPos();
|
||||
try {
|
||||
SodiumCompat.getInstance().notifyChunkRemoved(level, position.x, position.z);
|
||||
} finally {
|
||||
try {
|
||||
PlatformEvents.CLIENT_CHUNK_UNLOAD.postEvents(new ClientChunkEvent.Unload(chunk, level));
|
||||
} finally {
|
||||
level.unload(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-155
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.camera;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class CameraViewAreaExtension {
|
||||
private static final Long2ObjectOpenHashMap<SectionRenderDispatcher.RenderSection> SECTIONS = new Long2ObjectOpenHashMap<>();
|
||||
private static final Map<UUID, LongSet> OWNERS = new HashMap<>();
|
||||
private static SectionRenderDispatcher sectionRenderDispatcher;
|
||||
private static final AtomicLong REVISION = new AtomicLong();
|
||||
private static final AtomicLong GRAPH_REVISION = new AtomicLong();
|
||||
private static final Set<SectionRenderDispatcher.RenderSection> CAMERA_SECTIONS = Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>()));
|
||||
private static int minSectionY;
|
||||
private static int maxSectionY;
|
||||
|
||||
private CameraViewAreaExtension() {
|
||||
}
|
||||
|
||||
public static void allChanged(SectionRenderDispatcher dispatcher, Level level) {
|
||||
clear();
|
||||
sectionRenderDispatcher = dispatcher;
|
||||
minSectionY = level.getMinSection();
|
||||
maxSectionY = level.getMaxSection();
|
||||
}
|
||||
|
||||
public static SectionRenderDispatcher.RenderSection rawFetch(int cx, int cy, int cz, boolean generateNew) {
|
||||
if (sectionRenderDispatcher == null || cy < minSectionY || cy >= maxSectionY) {
|
||||
return null;
|
||||
}
|
||||
|
||||
long sectionPos = SectionPos.asLong(cx, cy, cz);
|
||||
return generateNew ? provideSection(sectionPos) : SECTIONS.get(sectionPos);
|
||||
}
|
||||
|
||||
public static void setDirty(int cx, int cy, int cz, boolean playerChanged) {
|
||||
SectionRenderDispatcher.RenderSection section = rawFetch(cx, cy, cz, false);
|
||||
if (section != null) {
|
||||
section.setDirty(playerChanged);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onChunkUnload(int sectionX, int sectionZ) {
|
||||
REVISION.incrementAndGet();
|
||||
Collection<SectionRenderDispatcher.RenderSection> removed = new ArrayList<>();
|
||||
for (int sectionY = minSectionY; sectionY < maxSectionY; sectionY++) {
|
||||
long sectionPos = SectionPos.asLong(sectionX, sectionY, sectionZ);
|
||||
SectionRenderDispatcher.RenderSection section = SECTIONS.remove(sectionPos);
|
||||
|
||||
if (section != null) {
|
||||
removed.add(section);
|
||||
}
|
||||
}
|
||||
releaseBuffers(removed);
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
REVISION.incrementAndGet();
|
||||
sectionRenderDispatcher = null;
|
||||
minSectionY = 0;
|
||||
maxSectionY = 0;
|
||||
OWNERS.clear();
|
||||
Collection<SectionRenderDispatcher.RenderSection> removed = new ArrayList<>(SECTIONS.values());
|
||||
SECTIONS.clear();
|
||||
releaseBuffers(removed);
|
||||
}
|
||||
|
||||
public static long revision() {
|
||||
return REVISION.get();
|
||||
}
|
||||
|
||||
public static long graphRevision() {
|
||||
return GRAPH_REVISION.get();
|
||||
}
|
||||
|
||||
public static boolean onSectionCompiled(SectionRenderDispatcher.RenderSection section) {
|
||||
// Late camera uploads must not enter the player's graph after their buffers have been released.
|
||||
if (!CAMERA_SECTIONS.contains(section)) return false;
|
||||
GRAPH_REVISION.incrementAndGet();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void retainSections(UUID cameraId, Collection<SectionRenderDispatcher.RenderSection> sections) {
|
||||
LongSet positions = new LongOpenHashSet();
|
||||
for (SectionRenderDispatcher.RenderSection section : sections) {
|
||||
positions.add(SectionPos.asLong(section.getOrigin()));
|
||||
}
|
||||
LongSet previous = OWNERS.put(cameraId, positions);
|
||||
releaseUnownedSections(previous);
|
||||
}
|
||||
|
||||
public static void releaseSections(UUID cameraId) {
|
||||
releaseUnownedSections(OWNERS.remove(cameraId));
|
||||
}
|
||||
|
||||
private static void releaseUnownedSections(LongSet positions) {
|
||||
if (positions == null) return;
|
||||
Collection<SectionRenderDispatcher.RenderSection> removed = new ArrayList<>();
|
||||
for (long position : positions) {
|
||||
if (OWNERS.values().stream().anyMatch(owner -> owner.contains(position))) continue;
|
||||
SectionRenderDispatcher.RenderSection section = SECTIONS.remove(position);
|
||||
if (section != null) removed.add(section);
|
||||
}
|
||||
releaseBuffers(removed);
|
||||
}
|
||||
|
||||
private static void releaseBuffers(Collection<SectionRenderDispatcher.RenderSection> sections) {
|
||||
RuntimeException failure = null;
|
||||
for (SectionRenderDispatcher.RenderSection section : sections) {
|
||||
try {
|
||||
section.releaseBuffers();
|
||||
} catch (RuntimeException exception) {
|
||||
if (failure == null) failure = exception;
|
||||
else if (failure != exception) failure.addSuppressed(exception);
|
||||
}
|
||||
}
|
||||
if (failure != null) throw failure;
|
||||
}
|
||||
|
||||
private static SectionRenderDispatcher.RenderSection provideSection(long sectionPos) {
|
||||
return SECTIONS.computeIfAbsent(sectionPos, CameraViewAreaExtension::createSection);
|
||||
}
|
||||
|
||||
private static SectionRenderDispatcher.RenderSection createSection(long sectionPos) {
|
||||
if (sectionRenderDispatcher == null) {
|
||||
throw new IllegalStateException("SectionRenderDispatcher not initialised");
|
||||
}
|
||||
BlockPos origin = SectionPos.of(sectionPos).origin();
|
||||
SectionRenderDispatcher.RenderSection section = sectionRenderDispatcher.new RenderSection(0, origin.getX(), origin.getY(), origin.getZ());
|
||||
CAMERA_SECTIONS.add(section);
|
||||
return section;
|
||||
}
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.camera.accessor;
|
||||
|
||||
public interface CameraFeedRenderState {
|
||||
boolean cobblemonRenderHand();
|
||||
boolean cobblemonRenderBlockOutline();
|
||||
}
|
||||
+1
-1
@@ -36,7 +36,7 @@ public interface Bone {
|
||||
/**
|
||||
* Renders a particular bone in relation to a particular entity.
|
||||
*
|
||||
* @param context The render context this bone is being drawn for.
|
||||
* @param context The extractRenderState context this bone is being drawn for.
|
||||
* @param stack The current [MatrixStack] for the renderer
|
||||
* @param buffer The vertex consumer deployed by the renderer
|
||||
* @param packedLight The light level to be applied to the bone
|
||||
|
||||
+7
-8
@@ -9,20 +9,22 @@
|
||||
package com.cobblemon.mod.common.compat.lambdynamiclights;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.CobblemonEntities;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightsContext;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightsInitializer;
|
||||
import dev.lambdaurora.lambdynlights.api.entity.luminance.EntityLuminance;
|
||||
import dev.lambdaurora.lambdynlights.api.item.ItemLightSourceManager;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.EntityTypes;
|
||||
|
||||
public class LambDynamicLightsInitializer implements DynamicLightsInitializer {
|
||||
public static final EntityLuminance.Type POKEMON_LUMINANCE = EntityLuminance.Type.registerSimple(
|
||||
ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "pokemon"),
|
||||
Identifier.fromNamespaceAndPath(Cobblemon.MODID, "pokemon"),
|
||||
PokemonLuminance.INSTANCE
|
||||
);
|
||||
public static final EntityLuminance.Type PLAYER_LUMINANCE = EntityLuminance.Type.registerSimple(
|
||||
ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "shoulder"),
|
||||
Identifier.fromNamespaceAndPath(Cobblemon.MODID, "shoulder"),
|
||||
PlayerLuminance.INSTANCE
|
||||
);
|
||||
|
||||
@@ -31,12 +33,9 @@ public class LambDynamicLightsInitializer implements DynamicLightsInitializer {
|
||||
Cobblemon.LOGGER.info("Lamb Dynamic Lights compatibility enabled");
|
||||
|
||||
context.entityLightSourceManager().onRegisterEvent().register(ctx -> {
|
||||
ctx.register(EntityType.PLAYER, PlayerLuminance.INSTANCE);
|
||||
ctx.register(EntityTypes.PLAYER, PlayerLuminance.INSTANCE);
|
||||
ctx.register(CobblemonEntities.POKEMON, PokemonLuminance.INSTANCE);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings({"removal", "UnstableApiUsage"})
|
||||
@Override
|
||||
public void onInitializeDynamicLights(ItemLightSourceManager itemLightSourceManager) {}
|
||||
}
|
||||
|
||||
+5
-4
@@ -10,10 +10,11 @@ package com.cobblemon.mod.common.compat.lambdynamiclights;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
|
||||
import com.cobblemon.mod.common.duck.PlayerDuck;
|
||||
import dev.lambdaurora.lambdynlights.api.entity.luminance.EntityLuminance;
|
||||
import dev.lambdaurora.lambdynlights.api.item.ItemLightSourceManager;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
@@ -25,7 +26,7 @@ import org.jetbrains.annotations.Range;
|
||||
|
||||
public final class PlayerLuminance extends CustomLuminance implements EntityLuminance {
|
||||
public static final PlayerLuminance INSTANCE = new PlayerLuminance();
|
||||
private static final TagKey<Item> POKEDEX = TagKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "pokedex"));
|
||||
private static final TagKey<Item> POKEDEX = TagKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(Cobblemon.MODID, "pokedex"));
|
||||
|
||||
@Override
|
||||
public @NotNull Type type() {
|
||||
@@ -46,8 +47,8 @@ public final class PlayerLuminance extends CustomLuminance implements EntityLumi
|
||||
}
|
||||
|
||||
private @Range(from = 0L, to = 15L) static int shoulderLuminance(@NotNull ItemLightSourceManager itemLightSourceManager, @NotNull Player player) {
|
||||
final var leftShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityLeft());
|
||||
final var rightShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityRight());
|
||||
final var leftShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(((PlayerDuck)player).getShoulderEntityLeft());
|
||||
final var rightShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(((PlayerDuck)player).getShoulderEntityRight());
|
||||
|
||||
if (leftShoulder == null && rightShoulder == null) {
|
||||
return 0;
|
||||
|
||||
@@ -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.duck;
|
||||
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface AvatarRenderStateDuck {
|
||||
@Nullable AbstractClientPlayer cobblemon$getMountedPlayer();
|
||||
void cobblemon$setMountedPlayer(@Nullable AbstractClientPlayer player);
|
||||
|
||||
@Nullable PokemonEntity cobblemon$getMountedPokemon();
|
||||
void cobblemon$setMountedPokemon(@Nullable PokemonEntity pokemonEntity);
|
||||
}
|
||||
@@ -30,4 +30,6 @@ public interface CameraDuck {
|
||||
|
||||
float cobblemon$getYRot();
|
||||
void cobblemon$setYRot(float yRot);
|
||||
|
||||
void cobblemon$markDirty();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.client.gui.GuiGraphicsExtractor;
|
||||
import net.minecraft.client.renderer.entity.state.EntityRenderState;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public interface GuiGraphicsExtractorDuck {
|
||||
GuiGraphicsExtractor.ScissorStack getScissorStack();
|
||||
void entityWithCustomLight(final EntityRenderState renderState, final float scale,
|
||||
final Vector3f translation, final Quaternionf rotation,
|
||||
final @Nullable Quaternionf overrideCameraAngle,
|
||||
final int x0, final int y0, final int x1, final int y1);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.cobblemon.mod.common.entity.PoseType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface LivingEntityRenderStateDuck {
|
||||
@Nullable LivingEntity cobblemon$getMountedEntity();
|
||||
void cobblemon$setMountedEntity(@Nullable LivingEntity entity);
|
||||
|
||||
float cobblemon$getMountedPartialTick();
|
||||
void cobblemon$setMountedPartialTick(float partialTick);
|
||||
|
||||
int cobblemon$getMountedSeatIndex();
|
||||
void cobblemon$setMountedSeatIndex(int seatIndex);
|
||||
|
||||
@Nullable String cobblemon$getMountedSeatLocator();
|
||||
void cobblemon$setMountedSeatLocator(@Nullable String seatLocator);
|
||||
|
||||
@Nullable PoseType cobblemon$getMountedPoseType();
|
||||
void cobblemon$setMountedPoseType(@Nullable PoseType poseType);
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Duck that facilitates getting a level key for a given level.
|
||||
*
|
||||
* @author dualspiral
|
||||
* @since August 30th, 2026
|
||||
*/
|
||||
public interface MinecraftServerDuck {
|
||||
Optional<ResourceKey<Level>> cobblemon$getLevelKey(Level level);
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public interface PlayerDuck {
|
||||
@@ -15,4 +16,8 @@ public interface PlayerDuck {
|
||||
Vector3f getDriverInput();
|
||||
void setLastSentDriverInput(Vector3f driverInput);
|
||||
Vector3f getLastSentDriverInput();
|
||||
CompoundTag getShoulderEntityLeft();
|
||||
CompoundTag getShoulderEntityRight();
|
||||
void setShoulderEntityLeft(CompoundTag entityNbt);
|
||||
void setShoulderEntityRight(CompoundTag entityNbt);
|
||||
}
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.item.crafting.RecipeAccess;
|
||||
|
||||
public interface RecipeAwareSlot {
|
||||
void setRecipeManager(RecipeManager recipeManager);
|
||||
void setRecipeManager(RecipeAccess recipeManager);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Duck that facilitates getting a level key that we store on the level.
|
||||
*
|
||||
* @author dualspiral
|
||||
* @since August 30th, 2026
|
||||
*/
|
||||
public interface ServerLevelDuck {
|
||||
ResourceLocation cobblemon$getLevelResourceLocation();
|
||||
}
|
||||
@@ -10,12 +10,12 @@ package com.cobblemon.mod.common.duck;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
|
||||
public interface SoundEngineDuck {
|
||||
|
||||
void pauseSounds(@Nullable ResourceLocation id, @Nullable SoundSource category);
|
||||
void pauseSounds(@Nullable Identifier id, @Nullable SoundSource category);
|
||||
|
||||
void resumeSounds(@Nullable ResourceLocation id, @Nullable SoundSource category);
|
||||
void resumeSounds(@Nullable Identifier id, @Nullable SoundSource category);
|
||||
}
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface SoundManagerDuck {
|
||||
|
||||
void pauseSounds(@Nullable ResourceLocation id, @Nullable SoundSource category);
|
||||
void pauseSounds(@Nullable Identifier id, @Nullable SoundSource category);
|
||||
|
||||
void resumeSounds(@Nullable ResourceLocation id, @Nullable SoundSource category);
|
||||
void resumeSounds(@Nullable Identifier id, @Nullable SoundSource category);
|
||||
}
|
||||
@@ -13,7 +13,7 @@ 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.entity.projectile.arrow.AbstractArrow;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -8,54 +8,43 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.block.SaccharineLeafBlock;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.animal.bee.Bee;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.BonemealSource;
|
||||
import net.minecraft.world.level.block.BonemealableBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
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.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
|
||||
@Mixin(targets = "net.minecraft.world.entity.animal.Bee$BeeGrowCropGoal")
|
||||
@Mixin(targets = "net.minecraft.world.entity.animal.bee.Bee$BeeGrowCropGoal")
|
||||
public abstract class BeeEntityMixin {
|
||||
|
||||
@Unique
|
||||
private BlockState cobblemon$result = null;
|
||||
@Shadow(aliases = {"this$0", "field_20373"}) @Final private Bee bee;
|
||||
|
||||
@Inject(method = "tick()V", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/block/BonemealableBlock;performBonemeal(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/util/RandomSource;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V",
|
||||
shift = At.Shift.BY,
|
||||
by = 2
|
||||
),
|
||||
locals = LocalCapture.CAPTURE_FAILHARD
|
||||
)
|
||||
private void injectCustomGrowth(CallbackInfo ci, int i, BlockPos blockPos, BlockState blockState, Block block) {
|
||||
if (block instanceof SaccharineLeafBlock) {
|
||||
|
||||
int age = blockState.getValue(SaccharineLeafBlock.Companion.getAGE());
|
||||
boolean waterlogged = blockState.getValue(BlockStateProperties.WATERLOGGED);
|
||||
|
||||
if (age < 2 && !waterlogged) {
|
||||
this.cobblemon$result = blockState.setValue(SaccharineLeafBlock.Companion.getAGE(), age + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "tick", at = @At(value = "LOAD", ordinal = 0), index = 5)
|
||||
private BlockState applyCustomBlockState(BlockState before) {
|
||||
if(this.cobblemon$result != null && before == null) {
|
||||
BlockState result = this.cobblemon$result;
|
||||
this.cobblemon$result = null;
|
||||
return result;
|
||||
// Grows bonemealable blocks vanilla's hardcoded checks miss, returning the state so it handles the rest.
|
||||
@ModifyVariable(method = "tick", at = @At(value = "LOAD", ordinal = 0), name = "growState")
|
||||
private BlockState cobblemon$growBonemealableBlocks(BlockState grownState, @Local(name = "belowState") BlockState blockState, @Local(name = "belowPos") BlockPos pos) {
|
||||
if (grownState != null || blockState.is(Blocks.CAVE_VINES) || blockState.is(Blocks.CAVE_VINES_PLANT)) {
|
||||
return grownState;
|
||||
}
|
||||
|
||||
return before;
|
||||
if (!(blockState.getBlock() instanceof BonemealableBlock bonemealable)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ServerLevel level = (ServerLevel) this.bee.level();
|
||||
if (!bonemealable.isValidBonemealTarget(level, pos, blockState, BonemealSource.MOB)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
bonemealable.performBonemeal(level, this.bee.getRandom(), pos, blockState, BonemealSource.MOB);
|
||||
return level.getBlockState(pos);
|
||||
}
|
||||
}
|
||||
@@ -14,19 +14,26 @@ import com.cobblemon.mod.common.api.ai.config.task.PathToBeeHiveTaskConfig;
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.world.feature.SaccharineTreeFeature;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.util.ProblemReporter;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntitySpawnReason;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus;
|
||||
import net.minecraft.world.item.component.CustomData;
|
||||
import net.minecraft.world.item.component.TypedEntityData;
|
||||
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.level.storage.TagValueOutput;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.slf4j.Logger;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
@@ -38,25 +45,28 @@ import java.util.Objects;
|
||||
@Mixin(BeehiveBlockEntity.Occupant.class)
|
||||
public abstract class BeeOccupantMixin {
|
||||
|
||||
@Unique
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
@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();
|
||||
String id = compoundTag.getString("id");
|
||||
CompoundTag compoundTag = occupant.entityData().copyTagWithoutId();
|
||||
String id = compoundTag.getStringOr("id", "");
|
||||
Entity entity = null;
|
||||
if (id.equals(SaccharineTreeFeature.Companion.getPOKEMON_PLACEHOLD_ID())) {
|
||||
// Special case for Pokemon stuffed into a beenest upon world gen.
|
||||
// For technical reasons we cannot create them as full entities during world gen.
|
||||
// So we look for this special id tag and complete the entity when it attempts to exit a hive.
|
||||
if (compoundTag.contains("pokemonProperties")) {
|
||||
String properties = compoundTag.getString("pokemonProperties");
|
||||
String properties = compoundTag.getString("pokemonProperties").get();
|
||||
PokemonProperties pokemon = PokemonProperties.Companion.parse(properties);
|
||||
entity = pokemon.createEntity(level);
|
||||
}
|
||||
} else {
|
||||
entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
|
||||
entity = EntityType.loadEntityRecursive(compoundTag, level, EntitySpawnReason.LOAD, (entityx) -> entityx);
|
||||
}
|
||||
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
@@ -76,11 +86,11 @@ public abstract class BeeOccupantMixin {
|
||||
// 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
|
||||
center.x + level.getRandom().nextFloat() * 0.6 - 0.3,
|
||||
center.y + level.getRandom().nextFloat() * 0.6 - 0.3,
|
||||
center.z + level.getRandom().nextFloat() * 0.6 - 0.3
|
||||
);
|
||||
newYaw = level.random.nextFloat() * 360F;
|
||||
newYaw = level.getRandom().nextFloat() * 360F;
|
||||
if (brain.checkMemory(CobblemonMemories.HIVE_LOCATION, MemoryStatus.REGISTERED)) {
|
||||
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION);
|
||||
}
|
||||
@@ -100,7 +110,7 @@ public abstract class BeeOccupantMixin {
|
||||
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;
|
||||
int j = level.getRandom().nextInt(100) == 0 ? 2 : 1;
|
||||
if (i + j > 5) {
|
||||
--j;
|
||||
}
|
||||
@@ -117,16 +127,19 @@ public abstract class BeeOccupantMixin {
|
||||
@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", "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().checkMemory(CobblemonMemories.HAS_NECTAR, MemoryStatus.REGISTERED)
|
||||
&& pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
|
||||
cir.setReturnValue(new BeehiveBlockEntity.Occupant(CustomData.of(compoundTag), 0, hasNectar ? 2400 : 600));
|
||||
cir.cancel();
|
||||
try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(pokemonEntity.problemPath(), LOGGER)) {
|
||||
List<String> IGNORED_BEE_TAGS = BeehiveBlockEntity.IGNORED_BEE_TAGS;
|
||||
TagValueOutput output = TagValueOutput.createWithContext(reporter, pokemonEntity.registryAccess());
|
||||
pokemonEntity.save(output);
|
||||
Objects.requireNonNull(output);
|
||||
IGNORED_BEE_TAGS.forEach(output::discard);
|
||||
CompoundTag entityTag = output.buildResult();
|
||||
boolean hasNectar = pokemonEntity.getBrain().checkMemory(CobblemonMemories.HAS_NECTAR, MemoryStatus.REGISTERED)
|
||||
&& pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
|
||||
cir.setReturnValue(new BeehiveBlockEntity.Occupant(TypedEntityData.of(pokemonEntity.getType(), entityTag), 0, hasNectar ? 2400 : 600));
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ 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;
|
||||
@@ -21,6 +20,7 @@ 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 net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
@@ -43,7 +43,7 @@ public abstract class BeehiveBlockEntityMixin {
|
||||
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)
|
||||
if (blockEntity.isSedated() || player.position().distanceToSqr(Vec3.atCenterOf(blockEntity.getBlockPos())) > 16.0)
|
||||
return;
|
||||
// from this point need to access private members of the block entity
|
||||
final BeehiveBlockEntityAccessor blockEntityAccessor = (BeehiveBlockEntityAccessor) this;
|
||||
@@ -59,8 +59,8 @@ public abstract class BeehiveBlockEntityMixin {
|
||||
}
|
||||
if (isPokemon) {
|
||||
return BeehiveBlockEntityAccessor.releaseOccupant(
|
||||
((BlockEntityAccessor) blockEntityAccessor).getLevel(),
|
||||
((BlockEntityAccessor) blockEntityAccessor).getWorldPosition(),
|
||||
blockEntity.getLevel(),
|
||||
blockEntity.getBlockPos(),
|
||||
state,
|
||||
occupant,
|
||||
list,
|
||||
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRenderer;
|
||||
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
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(BlockEntityWithoutLevelRenderer.class)
|
||||
public class BuiltinModelItemRendererMixin {
|
||||
|
||||
@Inject(method = "renderByItem", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$useDynamicItemRenderer(ItemStack stack, ItemDisplayContext mode, PoseStack matrices, MultiBufferSource vertexConsumers, int light, int overlay, CallbackInfo ci) {
|
||||
CobblemonBuiltinItemRenderer renderer = CobblemonBuiltinItemRendererRegistry.INSTANCE.rendererOf(stack.getItem());
|
||||
if (renderer != null) {
|
||||
renderer.render(stack, mode, matrices, vertexConsumers, light, overlay);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import static com.cobblemon.mod.common.datafixer.CobblemonSchemas.VERSION_KEY;
|
||||
|
||||
import com.cobblemon.mod.common.datafixer.CobblemonSchemas;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.util.datafix.DataFixTypes;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.chunk.storage.ChunkStorage;
|
||||
import net.minecraft.world.level.storage.DimensionDataStorage;
|
||||
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.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(ChunkStorage.class)
|
||||
public class ChunkStorageMixin {
|
||||
//Modifies the NBT returned by the vanilla upgradeChunkTag to also incorporate cobblemon fixup stuff
|
||||
@ModifyExpressionValue(
|
||||
method = "upgradeChunkTag(Lnet/minecraft/resources/ResourceKey;Ljava/util/function/Supplier;Lnet/minecraft/nbt/CompoundTag;Ljava/util/Optional;)Lnet/minecraft/nbt/CompoundTag;",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/util/datafix/DataFixTypes;updateToCurrentVersion(Lcom/mojang/datafixers/DataFixer;Lnet/minecraft/nbt/CompoundTag;I)Lnet/minecraft/nbt/CompoundTag;"
|
||||
)
|
||||
)
|
||||
public CompoundTag cobblemon$doChunkFix(
|
||||
CompoundTag vanillaFixed
|
||||
) {
|
||||
int curVersion = vanillaFixed.contains(VERSION_KEY) ? vanillaFixed.getInt(VERSION_KEY) : 0;
|
||||
return DataFixTypes.CHUNK.update(CobblemonSchemas.getDATA_FIXER(), vanillaFixed, curVersion, CobblemonSchemas.DATA_VERSION);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.block.dispenser.DispenserBehaviorRegistry;
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior;
|
||||
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(DispenseItemBehavior.class)
|
||||
public interface DispenseItemBehaviourMixin {
|
||||
@Inject(method = "bootStrap", at = @At("TAIL"))
|
||||
private static void addCobblemonDispenserBehaviors(CallbackInfo ci) {
|
||||
DispenserBehaviorRegistry.INSTANCE.registerDispenserBehaviors();
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResultHolder;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.EnderpearlItem;
|
||||
@@ -28,7 +28,7 @@ import java.util.Comparator;
|
||||
@Mixin(EnderpearlItem.class)
|
||||
public abstract class EnderPearlItemMixin {
|
||||
@Inject(method = "use", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void cobblemon$use(Level level, Player player, InteractionHand usedHand, CallbackInfoReturnable<InteractionResultHolder<ItemStack>> cir) {
|
||||
private void cobblemon$use(Level level, Player player, InteractionHand usedHand, CallbackInfoReturnable<InteractionResult> cir) {
|
||||
double range = player.entityInteractionRange();
|
||||
Entity closestEntity = level.getEntities(player, AABB.ofSize(player.position(), range, range, range)).stream()
|
||||
.filter(entity -> isLookingAt(player, entity))
|
||||
@@ -36,7 +36,7 @@ public abstract class EnderPearlItemMixin {
|
||||
.orElse(null);
|
||||
|
||||
if (closestEntity instanceof PokemonEntity pokemonEntity) {
|
||||
if (player.isCrouching() && pokemonEntity.getOwnerUUID() == player.getUUID()) {
|
||||
if (player.isCrouching() && pokemonEntity.isOwnedBy(player)) {
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.cobblemon.mod.common.pokemon.ai.EntityBehaviour;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
|
||||
import net.minecraft.world.entity.animal.Fox;
|
||||
import net.minecraft.world.entity.animal.fox.Fox;
|
||||
import net.minecraft.world.entity.monster.Creeper;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
+5
-64
@@ -9,19 +9,11 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState;
|
||||
import com.cobblemon.mod.common.entity.PosableEntity;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
|
||||
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||
import net.minecraft.client.resources.PlayerSkin;
|
||||
import net.minecraft.client.renderer.entity.player.AvatarRenderer;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.entity.player.PlayerModelType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -33,7 +25,7 @@ import java.util.Map;
|
||||
@Mixin(EntityRenderDispatcher.class)
|
||||
public class EntityRenderDispatcherMixin {
|
||||
|
||||
@Shadow private Map<PlayerSkin.Model, EntityRenderer<? extends Player>> playerRenderers;
|
||||
@Shadow private Map<PlayerModelType, AvatarRenderer<AbstractClientPlayer>> playerRenderers;
|
||||
|
||||
@Inject(
|
||||
method = "onResourceManagerReload",
|
||||
@@ -43,55 +35,4 @@ public class EntityRenderDispatcherMixin {
|
||||
CobblemonClient.INSTANCE.onAddLayer(this.playerRenderers);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "renderHitbox(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraft/world/entity/Entity;FFFF)V",
|
||||
at = @At(value = "TAIL")
|
||||
)
|
||||
private static void renderLocators(
|
||||
PoseStack poseStack,
|
||||
VertexConsumer buffer,
|
||||
Entity entity,
|
||||
float red,
|
||||
float green,
|
||||
float blue,
|
||||
float alpha,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
if (entity instanceof PosableEntity posableEntity) {
|
||||
if (posableEntity.getDelegate() instanceof PosableState state) {
|
||||
state.getLocatorStates().forEach((locator, matrix) -> {
|
||||
poseStack.pushPose();
|
||||
Vec3 pos = matrix.getOrigin().subtract(entity.position());
|
||||
LevelRenderer.renderLineBox(
|
||||
poseStack,
|
||||
buffer,
|
||||
AABB.ofSize(pos, 0.25, 0.25, 0.25),
|
||||
0F,
|
||||
1F,
|
||||
0F,
|
||||
1F
|
||||
);
|
||||
|
||||
/*if (locator.contains("middle")){
|
||||
PoseStack.Pose pose = poseStack.last();
|
||||
Vector3f vec = matrix.getMatrix().getRotation(new AxisAngle4f()).transform(new Vector3f(0, 0, -1));
|
||||
buffer.addVertex(pose, pos.toVector3f()).setColor(0xffff00ff).setNormal(pose, vec.x, vec.y, vec.z); //Forward, pink
|
||||
buffer.addVertex(pose, (float)(pos.x() + vec.x), (float)(pos.y() + vec.y), (float)(pos.z() + vec.z)).setColor(0xffff00ff).setNormal(pose, vec.x, vec.y, vec.z);
|
||||
|
||||
vec = matrix.getMatrix().getRotation(new AxisAngle4f()).transform(new Vector3f(0, 1, 0));
|
||||
buffer.addVertex(pose, pos.toVector3f()).setColor(0xffffff00).setNormal(pose, vec.x, vec.y, vec.z); //Up, yellow
|
||||
buffer.addVertex(pose, (float)(pos.x() + vec.x), (float)(pos.y() + vec.y), (float)(pos.z() + vec.z)).setColor(0xffffff00).setNormal(pose, vec.x, vec.y, vec.z);
|
||||
|
||||
vec = matrix.getMatrix().getRotation(new AxisAngle4f()).transform(new Vector3f(-1, 0, 0));
|
||||
buffer.addVertex(pose, pos.toVector3f()).setColor(0xff00ffff).setNormal(pose, vec.x, vec.y, vec.z); //Left, cyan
|
||||
buffer.addVertex(pose, (float)(pos.x() + vec.x), (float)(pos.y() + vec.y), (float)(pos.z() + vec.z)).setColor(0xff00ffff).setNormal(pose, vec.x, vec.y, vec.z);
|
||||
}*/
|
||||
|
||||
|
||||
poseStack.popPose();
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
|
||||
import net.minecraft.world.entity.monster.AbstractSkeleton;
|
||||
import net.minecraft.world.entity.monster.skeleton.AbstractSkeleton;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
public class EntityStorageMixin {
|
||||
//Modifies the NBT returned by the vanilla upgradeChunkTag to also incorporate cobblemon fixup stuff
|
||||
@ModifyExpressionValue(
|
||||
method = "method_31731(Lnet/minecraft/world/level/ChunkPos;Ljava/util/Optional;)Lnet/minecraft/world/level/entity/ChunkEntities;",
|
||||
method = "lambda$loadEntities$0",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/chunk/storage/SimpleRegionStorage;upgradeChunkTag(Lnet/minecraft/nbt/CompoundTag;I)Lnet/minecraft/nbt/CompoundTag;"
|
||||
@@ -32,7 +32,7 @@ public class EntityStorageMixin {
|
||||
public CompoundTag cobblemon$doEntityFix(
|
||||
CompoundTag vanillaFixed
|
||||
) {
|
||||
int curVersion = vanillaFixed.contains(VERSION_KEY) ? vanillaFixed.getInt(VERSION_KEY) : 0;
|
||||
int curVersion = vanillaFixed.getIntOr(VERSION_KEY, 0);
|
||||
CompoundTag newTag = DataFixTypes.ENTITY_CHUNK.update(CobblemonSchemas.getDATA_FIXER(), vanillaFixed, curVersion, CobblemonSchemas.DATA_VERSION);
|
||||
newTag.put(VERSION_KEY, IntTag.valueOf(CobblemonSchemas.DATA_VERSION));
|
||||
return newTag;
|
||||
|
||||
@@ -15,17 +15,18 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import com.cobblemon.mod.common.villager.VillagerGatherableItems;
|
||||
|
||||
import java.util.Objects;
|
||||
import net.minecraft.world.entity.npc.Villager;
|
||||
import net.minecraft.world.entity.npc.VillagerProfession;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.npc.villager.Villager;
|
||||
import net.minecraft.world.entity.npc.villager.VillagerProfession;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
@Mixin(Villager.class)
|
||||
public abstract class EntityVillagerMixin {
|
||||
|
||||
@Inject(method = "wantsToPickUp", at = @At(value = "RETURN"), cancellable = true)
|
||||
private void cobblemon$canGather(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
private void cobblemon$canGather(ServerLevel serverLevel, ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
final Villager villager = (Villager) (Object) this;
|
||||
if (ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canAddItem(stack)) {
|
||||
if (!ci.getReturnValue() && Objects.equals(villager.getVillagerData().profession().value(), VillagerProfession.FARMER) && villager.getInventory().canAddItem(stack)) {
|
||||
if(VillagerGatherableItems.INSTANCE.getVillagerGatherableItems().contains(stack.getItem()))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents;
|
||||
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
import kotlin.Unit;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.component.Consumable;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(FoodProperties.class)
|
||||
public class FoodPropertiesMixin {
|
||||
@Inject(method = "onConsume", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/food/FoodData;eat(Lnet/minecraft/world/food/FoodProperties;)V"))
|
||||
public void dropLeftOvers(Level level, LivingEntity user, ItemStack stack, Consumable consumable, CallbackInfo ci) {
|
||||
if (!level.isClientSide()) {
|
||||
if (stack.is(CobblemonItemTags.LEAVES_LEFTOVERS) && level.getRandom().nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
|
||||
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS);
|
||||
CobblemonEvents.LEFTOVERS_CREATED.postThen(
|
||||
new LeftoversCreatedEvent(user, leftovers),
|
||||
_ -> Unit.INSTANCE,
|
||||
leftoversCreatedEvent -> {
|
||||
user.handleExtraItemsCreatedOnUse(leftoversCreatedEvent.getLeftovers());
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.item.ItemProperties;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
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(ItemProperties.class)
|
||||
public class ItemPropertiesMixin {
|
||||
|
||||
// Mixins into the fishing rod's register() lambda expression
|
||||
// Without this, the fishing rod item model appears cast when using a PokeRod in the other hand
|
||||
@Inject(method = "method_27883", at = @At(value = "RETURN", ordinal = 1), cancellable = true)
|
||||
private static void cobblemon$preventRodMixup(ItemStack itemStack, ClientLevel clientLevel, LivingEntity livingEntity, int i, CallbackInfoReturnable<Float> cir) {
|
||||
if (!(livingEntity instanceof Player) || ((Player) livingEntity).fishing instanceof PokeRodFishingBobberEntity) {
|
||||
cir.setReturnValue(0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.ItemInteractionResult;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
@@ -35,8 +35,8 @@ import static net.minecraft.world.level.block.LecternBlock.HAS_BOOK;
|
||||
@Mixin(LecternBlock.class)
|
||||
public abstract class LecternBlockMixin {
|
||||
@Inject(method = "useItemOn", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void cobblemon$useItemOn(ItemStack itemStack, BlockState blockState, Level world, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult, CallbackInfoReturnable<ItemInteractionResult> cir) {
|
||||
if (!world.isClientSide && itemStack.getItem() instanceof PokedexItem) {
|
||||
private void cobblemon$useItemOn(ItemStack itemStack, BlockState blockState, Level world, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult, CallbackInfoReturnable<InteractionResult> cir) {
|
||||
if (!world.isClientSide() && itemStack.getItem() instanceof PokedexItem) {
|
||||
BlockEntity blockEntity = world.getBlockEntity(blockPos);
|
||||
if (!blockState.getValue(HAS_BOOK)
|
||||
&& blockEntity instanceof net.minecraft.world.level.block.entity.LecternBlockEntity
|
||||
@@ -53,9 +53,9 @@ public abstract class LecternBlockMixin {
|
||||
if (lecternEntity instanceof LecternBlockEntity) {
|
||||
((LecternBlockEntity) lecternEntity).setItemStack((pokedexItemStack));
|
||||
world.playSound(null, blockPos, CobblemonSounds.POKEDEX_CLOSE, SoundSource.BLOCKS, 0.5F, 1.25F);
|
||||
cir.setReturnValue(ItemInteractionResult.SUCCESS);
|
||||
cir.setReturnValue(InteractionResult.SUCCESS);
|
||||
} else {
|
||||
cir.setReturnValue(itemStack.isEmpty() && interactionHand == InteractionHand.MAIN_HAND ? ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION : ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION);
|
||||
cir.setReturnValue(itemStack.isEmpty() && interactionHand == InteractionHand.MAIN_HAND ? InteractionResult.PASS : InteractionResult.TRY_WITH_EMPTY_HAND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.util.List;
|
||||
@Mixin(LightningBolt.class)
|
||||
public abstract class LightningBoltMixin {
|
||||
|
||||
@Inject(method = "spawnFire", at = @At(value = "Head"), cancellable = true)
|
||||
@Inject(method = "spawnFire", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void cobblemon$spawnFire(int extraIgnitions, CallbackInfo ci) {
|
||||
// This prevents fire from spawning around Pokemon who otherwise should be immune to lightning and effectively absorb the hit
|
||||
final LightningBolt lightningBolt = (LightningBolt) (Object) this;
|
||||
@@ -41,4 +41,4 @@ public abstract class LightningBoltMixin {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.api.cinematic.runtime.CinematicManager;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
@@ -17,18 +15,23 @@ 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.api.tags.CobblemonItemTags;
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
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.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
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.item.ItemStack;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
@@ -57,8 +60,8 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
return cobblemon$orientationController;
|
||||
}
|
||||
|
||||
@Inject(method = "onEffectRemoved", at = @At(value = "TAIL"))
|
||||
private void cobblemon$onEffectRemoved(MobEffectInstance effect, CallbackInfo ci) {
|
||||
@Inject(method = "removeEffect", at = @At(value = "TAIL"))
|
||||
private void cobblemon$onEffectRemoved(Holder<MobEffect> effect, CallbackInfoReturnable<Boolean> cir) {
|
||||
final LivingEntity entity = (LivingEntity) (Object) this;
|
||||
if (entity instanceof ServerPlayer) {
|
||||
ShoulderEffectRegistry.INSTANCE.onEffectEnd((ServerPlayer) entity);
|
||||
@@ -78,27 +81,40 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity && pokemonEntity.getDelegate() instanceof PokemonClientDelegate delegate) {
|
||||
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
|
||||
if (seatIndex >= 0 && seatIndex < pokemonEntity.getSeats().size()) {
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
|
||||
if (locator != null) {
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
Vec3 eyePosition = cobblemon$getEyePosition(partialTicks, pokemonEntity, locatorOffset);
|
||||
return cobblemon$pickFromEyePosition(hitDistance, partialTicks, hitFluids, eyePosition);
|
||||
}
|
||||
}
|
||||
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
|
||||
Vec3 eyePosition = cobblemon$getEyePosition(partialTicks, pokemonEntity, locatorOffset);
|
||||
|
||||
Vec3 viewVector = this.getViewVector(partialTicks);
|
||||
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
|
||||
|
||||
return this.level()
|
||||
.clip(
|
||||
new ClipContext(
|
||||
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
|
||||
)
|
||||
);
|
||||
if ((Object) this instanceof RidePassenger ridePassenger) {
|
||||
Vec3 rideEyePosition = ridePassenger.cobblemon$getRideEyePos();
|
||||
if (!rideEyePosition.equals(Vec3.ZERO)) {
|
||||
return cobblemon$pickFromEyePosition(hitDistance, partialTicks, hitFluids, rideEyePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private @NotNull HitResult cobblemon$pickFromEyePosition(double hitDistance, float partialTicks, boolean hitFluids, Vec3 eyePosition) {
|
||||
Vec3 viewVector = this.getViewVector(partialTicks);
|
||||
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
|
||||
|
||||
return this.level()
|
||||
.clip(
|
||||
new ClipContext(
|
||||
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Vec3 cobblemon$getEyePosition(float partialTicks, PokemonEntity pokemonEntity, Vec3 locatorOffset) {
|
||||
OrientationController controller = this.getOrientationController();
|
||||
@@ -120,30 +136,6 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
this.cobblemon$orientationController.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void absMoveTo(double x, double y, double z, float yaw, float pitch) {
|
||||
if (cobblemon$orientationController.getActive()) {
|
||||
this.absMoveTo(x, y, z);
|
||||
this.setYRot(yaw % 360.0f);
|
||||
this.setXRot(pitch % 360.0f);
|
||||
this.yRotO = this.getYRot();
|
||||
this.xRotO = this.getXRot();
|
||||
} else {
|
||||
this.absMoveTo(x, y, z);
|
||||
this.absRotateTo(yaw, pitch);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "hurt(Lnet/minecraft/world/damagesource/DamageSource;F)Z", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$cancelDamageDuringCinematicTakeover(DamageSource source, float amount, CallbackInfoReturnable<Boolean> cir) {
|
||||
final LivingEntity self = (LivingEntity) (Object) this;
|
||||
if (self instanceof ServerPlayer serverPlayer) {
|
||||
if (CinematicManager.INSTANCE.isPlayerUnderImmuneTakeover(serverPlayer.getUUID())) {
|
||||
cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "decreaseAirSupply", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$conditionalWaterBreathing(
|
||||
int currentAir,
|
||||
@@ -171,4 +163,10 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "stopRiding", at = @At("HEAD"))
|
||||
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
|
||||
LivingEntity player = (LivingEntity)(Object)this;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
controllableVehicle.getOrientationController().setActive(false);
|
||||
}
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.server.ServerInterface;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
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(ServerLevel.class)
|
||||
public abstract class MinecraftDedicatedServerMixin implements ServerInterface {
|
||||
|
||||
@Inject(method = "shouldDiscardEntity", at = @At(value = "HEAD"), cancellable = true)
|
||||
public void cobblemon$allowPokemonSpawns(Entity entity, CallbackInfoReturnable<Boolean> callback) {
|
||||
if (entity instanceof PokemonEntity) {
|
||||
callback.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.duck.MinecraftServerDuck;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public class MinecraftServerMixin implements MinecraftServerDuck {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private Map<ResourceKey<Level>, ServerLevel> levels;
|
||||
|
||||
@Override
|
||||
public Optional<ResourceKey<Level>> cobblemon$getLevelKey(final Level level) {
|
||||
return this.levels.entrySet()
|
||||
.stream()
|
||||
// Reference equality is intended here, the level we're handed is the same one as in the
|
||||
// map so we don't need to check value semantics.
|
||||
.filter(entry -> entry.getValue() == level)
|
||||
.map(Map.Entry::getKey)
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public abstract class NoteBlockMixin {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!level.isClientSide) {
|
||||
if (!level.isClientSide()) {
|
||||
final BlockPos instrumentPos = shelfPos.below();
|
||||
final SoundEvent soundEvent;
|
||||
if (level.getBlockState(instrumentPos).isAir()) {
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.api.snowstorm.ParticleMaterials;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.cobblemon.mod.common.client.particle.SnowstormParticleGroup;
|
||||
import java.util.ArrayList;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
@@ -17,8 +18,10 @@ 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.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import net.minecraft.client.particle.ParticleGroup;
|
||||
import net.minecraft.client.particle.ParticleEngine;
|
||||
import net.minecraft.client.particle.ParticleRenderType;
|
||||
|
||||
@@ -31,7 +34,21 @@ final class ParticleManagerMixin {
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "<clinit>")
|
||||
private static void lodestone$addTypes(CallbackInfo ci) {
|
||||
RENDER_ORDER = ImmutableList.<ParticleRenderType>builder().addAll(RENDER_ORDER)
|
||||
.add(ParticleMaterials.INSTANCE.getADD(), ParticleMaterials.INSTANCE.getALPHA(), ParticleMaterials.INSTANCE.getBLEND(), ParticleMaterials.INSTANCE.getOPAQUE()).build();
|
||||
ArrayList<ParticleRenderType> types = new ArrayList<>(RENDER_ORDER);
|
||||
types.add(ParticleMaterials.INSTANCE.getADD());
|
||||
types.add(ParticleMaterials.INSTANCE.getALPHA());
|
||||
types.add(ParticleMaterials.INSTANCE.getBLEND());
|
||||
types.add(ParticleMaterials.INSTANCE.getOPAQUE());
|
||||
RENDER_ORDER = types;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "createParticleGroup", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$createSnowstormParticleGroup(ParticleRenderType renderType, CallbackInfoReturnable<ParticleGroup<?>> cir) {
|
||||
if (renderType == ParticleMaterials.INSTANCE.getADD()
|
||||
|| renderType == ParticleMaterials.INSTANCE.getALPHA()
|
||||
|| renderType == ParticleMaterials.INSTANCE.getBLEND()
|
||||
|| renderType == ParticleMaterials.INSTANCE.getOPAQUE()) {
|
||||
cir.setReturnValue(new SnowstormParticleGroup((ParticleEngine) (Object) this, renderType));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,17 +9,12 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents;
|
||||
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.HoverBehaviour;
|
||||
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;
|
||||
@@ -32,30 +27,31 @@ import com.cobblemon.mod.common.pokemon.Species;
|
||||
import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
|
||||
import com.cobblemon.mod.common.util.CompoundTagUtilities;
|
||||
import com.cobblemon.mod.common.util.DataKeys;
|
||||
import com.cobblemon.mod.common.util.ShoulderEntitySynchronizer;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityDimensions;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.Pose;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.storage.ValueInput;
|
||||
import net.minecraft.world.level.storage.ValueOutput;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Vector3f;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
@@ -66,34 +62,23 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger {
|
||||
@Unique
|
||||
private CompoundTag cobblemon$shoulderEntityLeft = new CompoundTag();
|
||||
@Unique
|
||||
private CompoundTag cobblemon$shoulderEntityRight = new CompoundTag();
|
||||
|
||||
@Unique
|
||||
private Vector3f cobblemon$driverInput;
|
||||
@Unique
|
||||
private Vector3f cobblemon$lastSentDriverInput;
|
||||
|
||||
@Shadow public abstract CompoundTag getShoulderEntityLeft();
|
||||
|
||||
@Shadow public abstract CompoundTag getShoulderEntityRight();
|
||||
|
||||
@Shadow public abstract void respawnEntityOnShoulder(CompoundTag entityNbt);
|
||||
|
||||
@Shadow public abstract void setShoulderEntityRight(CompoundTag entityNbt);
|
||||
|
||||
@Shadow public abstract void setShoulderEntityLeft(CompoundTag entityNbt);
|
||||
|
||||
@Shadow public abstract boolean isSpectator();
|
||||
|
||||
@Shadow public abstract boolean addItem(ItemStack stack);
|
||||
|
||||
@Shadow public abstract void displayClientMessage(Component message, boolean overlay);
|
||||
|
||||
@Shadow @Final private static Map<Pose, EntityDimensions> POSES;
|
||||
@Shadow @Final public static EntityDimensions STANDING_DIMENSIONS;
|
||||
@Shadow protected int jumpTriggerTime;
|
||||
@Unique private final OrientationController cobblemon$orientationController = new OrientationController(this);
|
||||
|
||||
@@ -107,71 +92,70 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
super(p_20966_, p_20967_);
|
||||
}
|
||||
|
||||
@Inject(method = "respawnEntityOnShoulder", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/EntityType;create(Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/level/Level;)Ljava/util/Optional;"), cancellable = true)
|
||||
private void cobblemon$removePokemon(CompoundTag nbt, CallbackInfo ci) {
|
||||
if (CompoundTagExtensionsKt.isPokemonEntity(nbt)) {
|
||||
final UUID uuid = CompoundTagUtilities.getPokemonID(nbt);
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())) {
|
||||
final UUID uuidRight = CompoundTagUtilities.getPokemonID(this.getShoulderEntityRight());
|
||||
if (uuid.equals(uuidRight)) {
|
||||
this.recallPokemon(uuidRight);
|
||||
this.setShoulderEntityRight(new CompoundTag());
|
||||
}
|
||||
}
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())) {
|
||||
final UUID uuidLeft = CompoundTagUtilities.getPokemonID(this.getShoulderEntityLeft());
|
||||
if (uuid.equals(uuidLeft)) {
|
||||
this.recallPokemon(uuidLeft);
|
||||
this.setShoulderEntityLeft(new CompoundTag());
|
||||
}
|
||||
}
|
||||
ci.cancel();
|
||||
@Inject(method = "readAdditionalSaveData", at = @At("TAIL"))
|
||||
private void cobblemon$readShoulderData(ValueInput input, CallbackInfo ci) {
|
||||
input.read("ShoulderEntityLeft", CompoundTag.CODEC)
|
||||
.ifPresent(entityNbt -> this.cobblemon$setShoulderEntity(true, entityNbt, false));
|
||||
input.read("ShoulderEntityRight", CompoundTag.CODEC)
|
||||
.ifPresent(entityNbt -> this.cobblemon$setShoulderEntity(false, entityNbt, false));
|
||||
}
|
||||
|
||||
@Inject(method = "addAdditionalSaveData", at = @At("TAIL"))
|
||||
private void cobblemon$writeShoulderData(ValueOutput output, CallbackInfo ci) {
|
||||
CompoundTag leftShoulder = this.getShoulderEntityLeft();
|
||||
if (!leftShoulder.isEmpty()) {
|
||||
output.store("ShoulderEntityLeft", CompoundTag.CODEC, leftShoulder);
|
||||
}
|
||||
|
||||
CompoundTag rightShoulder = this.getShoulderEntityRight();
|
||||
if (!rightShoulder.isEmpty()) {
|
||||
output.store("ShoulderEntityRight", CompoundTag.CODEC, rightShoulder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDimensions getDefaultDimensions(Pose pose) {
|
||||
if (this.getVehicle() instanceof PokemonEntity) {
|
||||
return STANDING_DIMENSIONS;
|
||||
return super.getDefaultDimensions(Pose.STANDING);
|
||||
}
|
||||
return POSES.getOrDefault(pose, STANDING_DIMENSIONS);
|
||||
return super.getDefaultDimensions(pose);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "removeEntitiesOnShoulder",
|
||||
at = @At(
|
||||
value = "JUMP",
|
||||
opcode = Opcodes.IFGE,
|
||||
ordinal = 0,
|
||||
shift = At.Shift.AFTER
|
||||
),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$preventPokemonDropping(CallbackInfo ci) {
|
||||
// We want to allow both of these to forcefully remove the entities
|
||||
if (this.isSpectator() || this.isDeadOrDying())
|
||||
return;
|
||||
if (!CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())) {
|
||||
this.respawnEntityOnShoulder(this.getShoulderEntityLeft());
|
||||
this.setShoulderEntityLeft(new CompoundTag());
|
||||
}
|
||||
if (!CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())) {
|
||||
this.respawnEntityOnShoulder(this.getShoulderEntityRight());
|
||||
this.setShoulderEntityRight(new CompoundTag());
|
||||
}
|
||||
ci.cancel();
|
||||
@Override
|
||||
public CompoundTag getShoulderEntityLeft() {
|
||||
return this.cobblemon$shoulderEntityLeft;
|
||||
}
|
||||
|
||||
private void recallPokemon(UUID uuid) {
|
||||
// We need to do this cause the Entity doesn't store a reference to its storage
|
||||
final PartyStore party = Cobblemon.INSTANCE.getStorage().getParty(this.getUUID(), this.registryAccess());
|
||||
for (Pokemon pokemon : party) {
|
||||
if (pokemon.getUuid().equals(uuid)) {
|
||||
pokemon.recall();
|
||||
}
|
||||
@Override
|
||||
public CompoundTag getShoulderEntityRight() {
|
||||
return this.cobblemon$shoulderEntityRight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShoulderEntityLeft(CompoundTag entityNbt) {
|
||||
this.cobblemon$setShoulderEntity(true, entityNbt, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShoulderEntityRight(CompoundTag entityNbt) {
|
||||
this.cobblemon$setShoulderEntity(false, entityNbt, true);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$setShoulderEntity(boolean isLeftShoulder, CompoundTag entityNbt, boolean shouldSync) {
|
||||
CompoundTag copied = entityNbt == null ? new CompoundTag() : entityNbt.copy();
|
||||
if (isLeftShoulder) {
|
||||
this.cobblemon$shoulderEntityLeft = copied;
|
||||
} else {
|
||||
this.cobblemon$shoulderEntityRight = copied;
|
||||
}
|
||||
|
||||
if (shouldSync && !this.level().isClientSide() && (Object)this instanceof ServerPlayer player) {
|
||||
ShoulderEntitySynchronizer.sync(player);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Redirect(
|
||||
method = "getDestroySpeed",
|
||||
at = @At(
|
||||
@@ -198,39 +182,11 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
return player.onGround();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "eat",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/player/Player;getFoodData()Lnet/minecraft/world/food/FoodData;",
|
||||
shift = At.Shift.AFTER
|
||||
)
|
||||
)
|
||||
public void onEatFood(Level world, ItemStack stack, FoodProperties foodComponent, CallbackInfoReturnable<ItemStack> cir) {
|
||||
if (!level().isClientSide) {
|
||||
if (stack.is(CobblemonItemTags.LEAVES_LEFTOVERS) && level().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
|
||||
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS);
|
||||
ServerPlayer player = Objects.requireNonNull(getServer()).getPlayerList().getPlayer(uuid);
|
||||
assert player != null;
|
||||
CobblemonEvents.LEFTOVERS_CREATED.postThen(
|
||||
new LeftoversCreatedEvent(player, leftovers),
|
||||
leftoversCreatedEvent -> null,
|
||||
leftoversCreatedEvent -> {
|
||||
if(!player.addItem(leftoversCreatedEvent.getLeftovers())) {
|
||||
var itemPos = player.getLookAngle().scale(0.5f).add(position());
|
||||
level().addFreshEntity(new ItemEntity(level(), itemPos.x(), itemPos.y(), itemPos.z(), leftoversCreatedEvent.getLeftovers()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "isInvulnerableTo", at = @At("HEAD"), cancellable = true)
|
||||
public void isInvulnerableTo(DamageSource source, CallbackInfoReturnable<Boolean> ci) {
|
||||
if (!level().isClientSide && (Object) this instanceof ServerPlayer player) {
|
||||
boolean invulnerableInBattle = this.level().getGameRules().getBoolean(CobblemonGameRules.BATTLE_INVULNERABILITY);
|
||||
public void isInvulnerableTo(net.minecraft.server.level.ServerLevel serverLevel, DamageSource source, CallbackInfoReturnable<Boolean> ci) {
|
||||
if ((Object) this instanceof ServerPlayer player) {
|
||||
boolean invulnerableInBattle = serverLevel.getGameRules().get(CobblemonGameRules.BATTLE_INVULNERABILITY);
|
||||
boolean inBattle = Cobblemon.INSTANCE.getBattleRegistry().getBattleByParticipatingPlayer(player) != null;
|
||||
if (invulnerableInBattle && inBattle) {
|
||||
ci.setReturnValue(true);
|
||||
@@ -240,34 +196,40 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
|
||||
@Override @Nullable
|
||||
public PokedexEntityData resolvePokemonScan() {
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())){
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())) {
|
||||
return getDataFromShoulderPokemon(this.getShoulderEntityRight());
|
||||
}
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())){
|
||||
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())) {
|
||||
return getDataFromShoulderPokemon(this.getShoulderEntityLeft());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable @Unique
|
||||
@Nullable
|
||||
@Unique
|
||||
private PokedexEntityData getDataFromShoulderPokemon(CompoundTag shoulderTag) {
|
||||
Pokemon pokemon;
|
||||
if (level().isClientSide) {
|
||||
CompoundTag pokemonTag = shoulderTag.getCompound(DataKeys.POKEMON);
|
||||
if (level().isClientSide()) {
|
||||
CompoundTag pokemonTag = shoulderTag.getCompound(DataKeys.POKEMON).orElse(new CompoundTag());
|
||||
if (pokemonTag.isEmpty()) return null;
|
||||
Species species = PokemonSpecies.getByIdentifier(ResourceLocation.parse(pokemonTag.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER)));
|
||||
String speciesId = pokemonTag.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER).orElse("");
|
||||
if (speciesId.isEmpty()) return null;
|
||||
Species species = PokemonSpecies.getByIdentifier(Identifier.parse(speciesId));
|
||||
if (species == null) return null;
|
||||
String formId = pokemonTag.getString(DataKeys.POKEMON_FORM_ID);
|
||||
String formId = pokemonTag.getString(DataKeys.POKEMON_FORM_ID).orElse("");
|
||||
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);
|
||||
String genderString = pokemonTag.getString(DataKeys.POKEMON_GENDER).orElse("");
|
||||
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());
|
||||
boolean shiny = pokemonTag.getBoolean(DataKeys.POKEMON_SHINY).orElse(false);
|
||||
int level = pokemonTag.getInt(DataKeys.POKEMON_LEVEL).orElse(0);
|
||||
Set<String> aspects = new HashSet<>();
|
||||
for (var tag : shoulderTag.getList(DataKeys.SHOULDER_ASPECTS).orElse(new ListTag())) {
|
||||
tag.asString().ifPresent(aspects::add);
|
||||
}
|
||||
|
||||
pokemon = new Pokemon();
|
||||
pokemon.setSpecies(species);
|
||||
@@ -277,8 +239,8 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
pokemon.setLevel(level);
|
||||
pokemon.setForcedAspects(aspects);
|
||||
} else {
|
||||
PlayerPartyStore party = Cobblemon.INSTANCE.getStorage().getParty(this.getUUID(), this.registryAccess());
|
||||
pokemon = party.get(shoulderTag.getUUID(DataKeys.SHOULDER_UUID));
|
||||
PartyStore party = Cobblemon.INSTANCE.getStorage().getParty(this.getUUID(), this.registryAccess());
|
||||
pokemon = party.get(CompoundTagExtensionsKt.getUUID(shoulderTag, DataKeys.SHOULDER_UUID));
|
||||
}
|
||||
return (pokemon == null) ? null : new PokedexEntityData(pokemon, null);
|
||||
}
|
||||
@@ -288,21 +250,6 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void absMoveTo(double x, double y, double z, float yaw, float pitch) {
|
||||
if (cobblemon$orientationController.getActive()) {
|
||||
this.absMoveTo(x, y, z);
|
||||
this.setYRot(yaw % 360.0f);
|
||||
this.setXRot(pitch % 360.0f);
|
||||
this.yRotO = this.getYRot();
|
||||
this.xRotO = this.getXRot();
|
||||
}
|
||||
else {
|
||||
this.absMoveTo(x, y, z);
|
||||
this.absRotateTo(yaw, pitch);
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(
|
||||
method = "rideTick()V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;wantsToStopRiding()Z")
|
||||
@@ -371,4 +318,37 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
this.cobblemon$rideEyePos = rideEyePos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sweeping attacks apply post-attack enchantment effects (e.g. Fire Aspect) to every entity caught
|
||||
* in the sweep, even if the damage itself was blocked. Skip them for Pokémon immune to the attack.
|
||||
*/
|
||||
@WrapOperation(
|
||||
method = "attack",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;itemAttackInteraction(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/damagesource/DamageSource;Z)V")
|
||||
)
|
||||
private void cobblemon$skipPostAttackEffectsOnImmunePokemon(Player instance, Entity target, ItemStack attackingItemStack, DamageSource damageSource, boolean applyToTarget, Operation<Void> original, @Local DamageSource source) {
|
||||
if (this.level() instanceof ServerLevel serverLevel) {
|
||||
if (target instanceof PokemonEntity pokemonEntity && pokemonEntity.isInvulnerableTo(serverLevel, source)) {
|
||||
return;
|
||||
}
|
||||
original.call(instance, target, attackingItemStack, damageSource, applyToTarget);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sweeping attacks also knock back every entity caught in the sweep regardless of whether it took damage.
|
||||
*/
|
||||
@WrapOperation(
|
||||
method = "attack",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;causeExtraKnockback(Lnet/minecraft/world/entity/Entity;FLnet/minecraft/world/phys/Vec3;)V")
|
||||
)
|
||||
private void cobblemon$skipKnockbackOnImmunePokemon(Player instance, Entity target, float knockbackAmount, Vec3 oldMovement, Operation<Void> original, @Local DamageSource source) {
|
||||
if (this.level() instanceof ServerLevel serverLevel) {
|
||||
if (target instanceof PokemonEntity pokemonEntity && pokemonEntity.isInvulnerableTo(serverLevel, source)) {
|
||||
return;
|
||||
}
|
||||
original.call(instance, target, knockbackAmount, oldMovement);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,23 +9,20 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonBlockTags;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.PointedDripstoneBlock;
|
||||
import net.minecraft.world.level.block.SpeleothemBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.Slice;
|
||||
|
||||
@Mixin(PointedDripstoneBlock.class)
|
||||
@Mixin(SpeleothemBlock.class)
|
||||
public abstract class PointedDripstoneBlockMixin {
|
||||
|
||||
@Redirect(
|
||||
method = "canGrow(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)Z",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/block/Block;)Z", ordinal = 0),
|
||||
slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/level/block/Blocks;DRIPSTONE_BLOCK:Lnet/minecraft/world/level/block/Block;"))
|
||||
method = "canGrow",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Ljava/lang/Object;)Z", ordinal = 0)
|
||||
)
|
||||
private static boolean cobblemon$validateMoonStoneDripstone(BlockState instance, Block block) {
|
||||
private static boolean cobblemon$validateMoonStoneDripstone(BlockState instance, Object o) {
|
||||
return instance.is(CobblemonBlockTags.DRIPSTONE_GROWABLE);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRecipeBookTypes;
|
||||
import net.minecraft.stats.RecipeBookSettings;
|
||||
import net.minecraft.world.inventory.RecipeBookType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
@Mixin(RecipeBookSettings.class)
|
||||
public class RecipeBookSettingsMixin {
|
||||
@Unique
|
||||
private RecipeBookSettings.TypeSettings cobblemon$cookingPot = new RecipeBookSettings.TypeSettings(false, false);
|
||||
|
||||
@Inject(method = "getSettings", at = @At("HEAD"), cancellable = true)
|
||||
public void getSettings(RecipeBookType type, CallbackInfoReturnable<RecipeBookSettings.TypeSettings> cir) {
|
||||
if (type == CobblemonRecipeBookTypes.INSTANCE.getCOOKING_POT()) {
|
||||
cir.setReturnValue(cobblemon$cookingPot);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "updateSettings", at = @At("HEAD"), cancellable = true)
|
||||
private void updateSetting(RecipeBookType recipeBookType, UnaryOperator<RecipeBookSettings.TypeSettings> operator, CallbackInfo ci) {
|
||||
if (recipeBookType == CobblemonRecipeBookTypes.INSTANCE.getCOOKING_POT()) {
|
||||
cobblemon$cookingPot = operator.apply(cobblemon$cookingPot);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.fabric.mixin;
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRecipeBookTypes;
|
||||
import net.minecraft.world.inventory.RecipeBookType;
|
||||
@@ -41,8 +41,6 @@ public class RecipeBookTypeMixin {
|
||||
)
|
||||
private static void cobblemon$addRecipeBookType(CallbackInfo ci) {
|
||||
ArrayList<RecipeBookType> types = new ArrayList<>(List.of($VALUES));
|
||||
// if you change or add any of these, neoforge uses a separate mechanism
|
||||
// check enumextensions.json and `CobblemonEnumExtensions`
|
||||
types.add(cobblemon$createBookType(CobblemonRecipeBookTypes.COOKING_POT_NAME, $VALUES.length));
|
||||
$VALUES = types.toArray(RecipeBookType[]::new);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.CobblemonRecipePropertySets;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.item.crafting.Ingredient;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.item.crafting.RecipePropertySet;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
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.callback.CallbackInfo;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(RecipeManager.class)
|
||||
public abstract class RecipeManagerMixin {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private static Map<ResourceKey<RecipePropertySet>, RecipeManager.IngredientExtractor> RECIPE_PROPERTY_SETS;
|
||||
|
||||
@WrapOperation(method = "<clinit>", at = @At(value = "INVOKE", target = "Ljava/util/Map;of(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/Map;"))
|
||||
private static Map poggers(Object k1, Object v1,
|
||||
Object k2, Object v2,
|
||||
Object k3, Object v3,
|
||||
Object k4, Object v4,
|
||||
Object k5, Object v5,
|
||||
Object k6, Object v6,
|
||||
Object k7, Object v7,
|
||||
Object k8, Object v8,
|
||||
Object k9, Object v9,
|
||||
Operation<Map> original) {
|
||||
return new HashMap(original.call(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7, k8, v8, k9, v9));
|
||||
}
|
||||
|
||||
@Inject(method = "<clinit>", at = @At("TAIL"))
|
||||
private static void cobblemon$addPropertySets(CallbackInfo ci) {
|
||||
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getBREWING_BOTTLE(), recipe -> {
|
||||
if (recipe instanceof BrewingStandRecipe brew) {
|
||||
return Optional.of(brew.getBottle());
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
|
||||
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getBREWING_INPUT(), recipe -> {
|
||||
if (recipe instanceof BrewingStandRecipe brew) {
|
||||
return Optional.of(brew.getInput());
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
|
||||
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getCOOKING_POT_FLAVOUR_PROCESSOR(), recipe -> {
|
||||
if (recipe instanceof CookingPotRecipeBase cooking && cooking.getSeasoningProcessors().stream().anyMatch(x -> x.getType().equals("flavour"))) {
|
||||
return Optional.of(Ingredient.of(cooking.getResult().item().value()));
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
|
||||
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getCOOKING_POT_FOOD_PROCESSOR(), recipe -> {
|
||||
if (recipe instanceof CookingPotRecipeBase cooking && cooking.getSeasoningProcessors().stream().anyMatch(x -> x.getType().equals("food"))) {
|
||||
return Optional.of(Ingredient.of(cooking.getResult().item().value()));
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
|
||||
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getCOOKING_POT_MOB_EFFECTS_PROCESSOR(), recipe -> {
|
||||
if (recipe instanceof CookingPotRecipeBase cooking && cooking.getSeasoningProcessors().stream().anyMatch(x -> x.getType().equals("mob_effects"))) {
|
||||
return Optional.of(Ingredient.of(cooking.getResult().item().value()));
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
|
||||
RECIPE_PROPERTY_SETS.put(CobblemonRecipePropertySets.INSTANCE.getCOOKING_POT_SPAWN_BAIT_PROCESSOR(), recipe -> {
|
||||
if (recipe instanceof CookingPotRecipeBase cooking && cooking.getSeasoningProcessors().stream().anyMatch(x -> x.getType().equals("spawn_bait"))) {
|
||||
return Optional.of(Ingredient.of(cooking.getResult().item().value()));
|
||||
}
|
||||
return Optional.empty();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.mixin.accessor.TrackedEntityAccessor;
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateDriverInputPacket;
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.ClientboundUpdateRidingStatePacket;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClientboundSeatAssignmentPacket;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
@@ -29,6 +30,8 @@ import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
@@ -47,9 +50,6 @@ import java.util.function.Consumer;
|
||||
@Mixin(ServerEntity.class)
|
||||
public abstract class ServerEntityMixin {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private Consumer<Packet<?>> broadcast;
|
||||
@Shadow
|
||||
@Final
|
||||
private Entity entity;
|
||||
|
||||
@@ -8,35 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.duck.MinecraftServerDuck;
|
||||
import com.cobblemon.mod.common.duck.ServerLevelDuck;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.storage.WritableLevelData;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
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.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
@Mixin(ServerLevel.class)
|
||||
public abstract class ServerLevelMixin extends Level implements ServerLevelDuck {
|
||||
public abstract class ServerLevelMixin extends Level {
|
||||
|
||||
// Ignored by Mixin, fulfils Java contract
|
||||
protected ServerLevelMixin(
|
||||
@@ -44,32 +37,12 @@ public abstract class ServerLevelMixin extends Level implements ServerLevelDuck
|
||||
ResourceKey<Level> dimension,
|
||||
RegistryAccess registryAccess,
|
||||
Holder<DimensionType> dimensionTypeRegistration,
|
||||
Supplier<ProfilerFiller> profiler,
|
||||
boolean isClientSide,
|
||||
boolean isDebug,
|
||||
long biomeZoomSeed,
|
||||
int maxChainedNeighborUpdates
|
||||
) {
|
||||
super(levelData, dimension, registryAccess, dimensionTypeRegistration, profiler, isClientSide, isDebug, biomeZoomSeed, maxChainedNeighborUpdates);
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public abstract MinecraftServer shadow$getServer();
|
||||
|
||||
/**
|
||||
* Cached to speed up level world key checks every tick.
|
||||
*/
|
||||
private ResourceLocation cobblemon$levelResourceLocation;
|
||||
|
||||
@Override
|
||||
public ResourceLocation cobblemon$getLevelResourceLocation() {
|
||||
if (this.cobblemon$levelResourceLocation == null) {
|
||||
this.cobblemon$levelResourceLocation = ((MinecraftServerDuck) this.shadow$getServer())
|
||||
.cobblemon$getLevelKey(this)
|
||||
.map(ResourceKey::location)
|
||||
.orElse(null);
|
||||
}
|
||||
return this.cobblemon$levelResourceLocation;
|
||||
super(levelData, dimension, registryAccess, dimensionTypeRegistration, isClientSide, isDebug, biomeZoomSeed, maxChainedNeighborUpdates);
|
||||
}
|
||||
|
||||
@Inject(method = "findLightningRod", at = @At(value = "RETURN"), cancellable = true)
|
||||
@@ -77,14 +50,14 @@ public abstract class ServerLevelMixin extends Level implements ServerLevelDuck
|
||||
final ServerLevel serverLevel = (ServerLevel) (Object) this;
|
||||
if (ci.getReturnValue().isEmpty()) {
|
||||
// Search for Pokemon with the ability Lightning Rod and redirect to them
|
||||
AABB aABB = AABB.encapsulatingFullBlocks(blockPos, new BlockPos(blockPos.atY(serverLevel.getMaxBuildHeight()))).inflate(64.0);
|
||||
AABB aABB = AABB.encapsulatingFullBlocks(blockPos, blockPos.atY(serverLevel.getMaxY() + 1)).inflate(64.0);
|
||||
List<LivingEntity> list = serverLevel.getEntitiesOfClass(LivingEntity.class, aABB, (livingEntity) -> livingEntity != null
|
||||
&& livingEntity.isAlive()
|
||||
&& livingEntity instanceof PokemonEntity
|
||||
&& ((PokemonEntity) livingEntity).getBeamMode() == 0
|
||||
&& ((PokemonEntity) livingEntity).getPokemon().getAbility().getName().equals("lightningrod"));
|
||||
if (!list.isEmpty()) {
|
||||
ci.setReturnValue(Optional.of((list.get(serverLevel.random.nextInt(list.size()))).blockPosition()));
|
||||
ci.setReturnValue(Optional.of((list.get(serverLevel.getRandom().nextInt(list.size()))).blockPosition()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,21 +15,23 @@ import com.cobblemon.mod.common.api.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
|
||||
import com.cobblemon.mod.common.api.stats.CobblemonStats;
|
||||
import com.cobblemon.mod.common.duck.ServerLevelDuck;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.util.CompoundTagUtilities;
|
||||
import com.cobblemon.mod.common.util.ShoulderEntitySynchronizer;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
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.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@@ -37,15 +39,29 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
|
||||
@Shadow
|
||||
public abstract ServerLevel serverLevel();
|
||||
@Shadow public abstract CompoundTag getShoulderEntityLeft();
|
||||
|
||||
@Shadow public abstract CompoundTag getShoulderEntityRight();
|
||||
|
||||
@Shadow public abstract void respawnEntityOnShoulder(CompoundTag entityNbt);
|
||||
|
||||
@Shadow public abstract void setShoulderEntityRight(CompoundTag entityNbt);
|
||||
|
||||
@Shadow public abstract void setShoulderEntityLeft(CompoundTag entityNbt);
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
public MinecraftServer server;
|
||||
|
||||
@Unique
|
||||
public PlayerSpawner cobblemon$spawner;
|
||||
|
||||
@Shadow
|
||||
private long timeEntitySatOnShoulder;
|
||||
|
||||
@Shadow
|
||||
public abstract Level level();
|
||||
|
||||
@Override
|
||||
public PlayerSpawner getPlayerSpawner() {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
@@ -67,13 +83,51 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "removeEntitiesOnShoulder", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$preventPokemonDropping(CallbackInfo ci) {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
if (player.isSpectator() || player.isDeadOrDying()) {
|
||||
return;
|
||||
}
|
||||
|
||||
long gameTime = player.level().getGameTime();
|
||||
if (this.timeEntitySatOnShoulder + 20L >= gameTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean changed = false;
|
||||
CompoundTag leftShoulder = player.getShoulderEntityLeft();
|
||||
if (!leftShoulder.isEmpty() && !CompoundTagUtilities.isShoulderPokemon(leftShoulder)) {
|
||||
respawnEntityOnShoulder(leftShoulder);
|
||||
setShoulderEntityLeft(new CompoundTag());
|
||||
changed = true;
|
||||
}
|
||||
|
||||
CompoundTag rightShoulder = player.getShoulderEntityRight();
|
||||
if (!rightShoulder.isEmpty() && !CompoundTagUtilities.isShoulderPokemon(rightShoulder)) {
|
||||
respawnEntityOnShoulder(rightShoulder);
|
||||
setShoulderEntityRight(new CompoundTag());
|
||||
changed = true;
|
||||
}
|
||||
|
||||
this.timeEntitySatOnShoulder = gameTime;
|
||||
if (changed) {
|
||||
ShoulderEntitySynchronizer.sync(player);
|
||||
}
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
Entity vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation(vehicle);
|
||||
controllableVehicle.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
var controller = controllableVehicle.getOrientationController();
|
||||
controller.setActive(shouldUseCustomOrientation);
|
||||
if (shouldUseCustomOrientation && controller.getOrientation() == null) {
|
||||
controller.updateOrientation(matrix -> matrix);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
@@ -85,16 +139,9 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(method = "stopRiding", at = @At("HEAD"))
|
||||
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
|
||||
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
|
||||
@ModifyExpressionValue(method = "addAdditionalSaveData", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hasExactlyOnePlayerPassenger()Z"))
|
||||
private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(ordinal=0) Entity entity) {
|
||||
@ModifyExpressionValue(method = "saveParentVehicle", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;hasExactlyOnePlayerPassenger()Z"))
|
||||
private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(name = "rootVehicle") Entity entity) {
|
||||
return original && !(entity instanceof PokemonEntity);
|
||||
}
|
||||
|
||||
@@ -136,10 +183,8 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
@Unique
|
||||
private boolean cobblemon$canSpawn() {
|
||||
return Cobblemon.config.getEnableSpawning() &&
|
||||
this.serverLevel().getGameRules().getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) &&
|
||||
this.server.getGameRules().get(CobblemonGameRules.DO_POKEMON_SPAWNING) &&
|
||||
// intentionally last as this is a more expensive check, even with all the caching
|
||||
!Cobblemon.config.getWorldSpawningBlocklist().contains(
|
||||
((ServerLevelDuck) this.serverLevel()).cobblemon$getLevelResourceLocation()
|
||||
);
|
||||
!Cobblemon.config.getWorldSpawningBlocklist().contains(this.level().dimension().identifier());
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -13,6 +13,7 @@ import kotlin.Unit;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.dispenser.ShearsDispenseItemBehavior;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -24,10 +25,10 @@ public abstract class ShearsDispenserBehaviorMixin {
|
||||
|
||||
// This exists, so we can execute our custom interaction only if no one redirected shears interactions to overwrite the vanilla ones.
|
||||
@Inject(method = "tryShearBeehive", at = @At("HEAD"), cancellable = true)
|
||||
private static void cobblemon$tryApricornHarvest(ServerLevel world, BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
|
||||
final BlockState state = world.getBlockState(pos);
|
||||
private static void cobblemon$tryApricornHarvest(ServerLevel serverLevel, ItemStack itemStack, BlockPos blockPos, CallbackInfoReturnable<Boolean> cir) {
|
||||
final BlockState state = serverLevel.getBlockState(blockPos);
|
||||
if (state.getBlock() instanceof ShearableBlock shearableBlock) {
|
||||
cir.setReturnValue(shearableBlock.attemptShear(world, state, pos, () -> Unit.INSTANCE));
|
||||
cir.setReturnValue(shearableBlock.attemptShear(serverLevel, state, blockPos, () -> Unit.INSTANCE));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,13 +11,13 @@ package com.cobblemon.mod.common.mixin;
|
||||
import com.cobblemon.mod.common.block.HeartyGrainsBlock;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.DoublePlantBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.feature.SimpleBlockFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.SimpleBlockConfiguration;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
@@ -28,7 +28,7 @@ public class SimpleBlockFeatureMixin {
|
||||
//this mixin inserts the logic needed to ensure that when hearty grains are of a certain age, they place with the upper block too
|
||||
//similarly to what the doubleblock logic is here
|
||||
@Inject(method = "place", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;canSurvive(Lnet/minecraft/world/level/LevelReader;Lnet/minecraft/core/BlockPos;)Z", shift = At.Shift.AFTER), cancellable = true)
|
||||
public void place(FeaturePlaceContext<SimpleBlockConfiguration> context, CallbackInfoReturnable<Boolean> cir,
|
||||
public void place(WorldGenLevel level, ChunkGenerator chunkGenerator, RandomSource random, BlockPos origin, CallbackInfoReturnable<Boolean> cir,
|
||||
@Local BlockState blockState, @Local BlockPos blockPos, @Local WorldGenLevel worldGenLevel) {
|
||||
if (!(blockState.getBlock() instanceof HeartyGrainsBlock)) {
|
||||
return;
|
||||
|
||||
@@ -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;
|
||||
|
||||
import static com.cobblemon.mod.common.datafixer.CobblemonSchemas.VERSION_KEY;
|
||||
|
||||
import com.cobblemon.mod.common.datafixer.CobblemonSchemas;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.datafix.DataFixTypes;
|
||||
import net.minecraft.world.level.chunk.storage.SimpleRegionStorage;
|
||||
import org.spongepowered.asm.mixin.Debug;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(SimpleRegionStorage.class)
|
||||
public class SimpleRegionStorageMixin {
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private DataFixTypes dataFixType;
|
||||
//Modifies the NBT returned by the vanilla upgradeChunkTag to also incorporate cobblemon fixup stuff
|
||||
@ModifyExpressionValue(
|
||||
method = "upgradeChunkTag(Lnet/minecraft/nbt/CompoundTag;ILnet/minecraft/nbt/CompoundTag;I)Lnet/minecraft/nbt/CompoundTag;",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/util/datafix/DataFixTypes;update(Lcom/mojang/datafixers/DataFixer;Lnet/minecraft/nbt/CompoundTag;II)Lnet/minecraft/nbt/CompoundTag;"
|
||||
)
|
||||
)
|
||||
public CompoundTag cobblemon$doChunkFix(
|
||||
CompoundTag vanillaFixed
|
||||
) {
|
||||
int curVersion = vanillaFixed.getIntOr(VERSION_KEY, 0);
|
||||
return vanillaFixed; //TODO FIGURE OUT WHAT THE HECK IS GOING ON HERE
|
||||
//return this.dataFixType.update(CobblemonSchemas.getDATA_FIXER(), vanillaFixed, curVersion, CobblemonSchemas.DATA_VERSION);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.client.resources.sounds.TickableSoundInstance;
|
||||
import net.minecraft.client.sounds.ChannelAccess;
|
||||
import net.minecraft.client.sounds.SoundEngine;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
@@ -71,39 +71,39 @@ public abstract class SoundEngineMixin implements SoundEngineDuck {
|
||||
|
||||
/** Resumes the SoundInstance(s) queried by id and/or category. */
|
||||
@Override
|
||||
public void resumeSounds(@Nullable ResourceLocation id, @Nullable SoundSource category) {
|
||||
public void resumeSounds(@Nullable Identifier id, @Nullable SoundSource category) {
|
||||
if (category != null) {
|
||||
this.instanceBySource.get(category).forEach((sound) -> {
|
||||
if (id == null || sound.getLocation().equals(id)) resume(sound);
|
||||
if (id == null || sound.getIdentifier().equals(id)) resume(sound);
|
||||
});
|
||||
} else if (id == null) {
|
||||
this.instanceToChannel.keySet().forEach(this::resume);
|
||||
} else {
|
||||
this.instanceToChannel.keySet().forEach(sound -> {
|
||||
if (sound.getLocation().equals(id)) resume(sound);
|
||||
if (sound.getIdentifier().equals(id)) resume(sound);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Pauses the SoundInstances queried by id and/or category. */
|
||||
@Override
|
||||
public void pauseSounds(@Nullable ResourceLocation id, @Nullable SoundSource category) {
|
||||
public void pauseSounds(@Nullable Identifier id, @Nullable SoundSource category) {
|
||||
if (category != null) {
|
||||
this.instanceBySource.get(category).forEach((sound) -> {
|
||||
if (id == null || sound.getLocation().equals(id)) pause(sound);
|
||||
if (id == null || sound.getIdentifier().equals(id)) pause(sound);
|
||||
});
|
||||
} else if (id == null) {
|
||||
this.instanceToChannel.keySet().forEach(this::pause);
|
||||
} else {
|
||||
this.instanceToChannel.keySet().forEach(sound -> {
|
||||
if (sound.getLocation().equals(id)) pause(sound);
|
||||
if (sound.getIdentifier().equals(id)) pause(sound);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Allows stopping all SoundInstances that belong to a queried category. */
|
||||
@Inject(method = "stop(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/sounds/SoundSource;)V", at = @At("HEAD"), cancellable = true)
|
||||
public void stopSounds(@Nullable ResourceLocation id, @Nullable SoundSource category, CallbackInfo cb) {
|
||||
@Inject(method = "stop(Lnet/minecraft/resources/Identifier;Lnet/minecraft/sounds/SoundSource;)V", at = @At("HEAD"), cancellable = true)
|
||||
public void stopSounds(@Nullable Identifier id, @Nullable SoundSource category, CallbackInfo cb) {
|
||||
if (id == null && category != null) {
|
||||
this.instanceBySource.get(category).forEach(this::stop);
|
||||
cb.cancel();
|
||||
@@ -116,7 +116,7 @@ public abstract class SoundEngineMixin implements SoundEngineDuck {
|
||||
*/
|
||||
@Inject(method = "calculatePitch", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$allowExtendedNoteblockPitch(SoundInstance sound, CallbackInfoReturnable<Float> cir) {
|
||||
if (sound.getLocation().getPath().startsWith("block.note_block.")) {
|
||||
if (sound.getIdentifier().getPath().startsWith("block.note_block.")) {
|
||||
cir.setReturnValue(Mth.clamp(sound.getPitch(), 0.5F, 4.0F));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ import com.cobblemon.mod.common.duck.SoundEngineDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundManagerDuck;
|
||||
import net.minecraft.client.resources.sounds.BiomeAmbientSoundsHandler;
|
||||
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.client.resources.sounds.UnderwaterAmbientSoundInstances;
|
||||
import net.minecraft.client.resources.sounds.UnderLiquidSubSound;
|
||||
import net.minecraft.client.sounds.SoundEngine;
|
||||
import net.minecraft.client.sounds.SoundManager;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
@@ -26,6 +26,7 @@ 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.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(SoundManager.class)
|
||||
public abstract class SoundManagerMixin implements SoundManagerDuck {
|
||||
@@ -38,7 +39,7 @@ public abstract class SoundManagerMixin implements SoundManagerDuck {
|
||||
|
||||
// Never-ending ambient loops are a special exception (they are only initiated once) and should always be paused if filtered.
|
||||
private boolean isAmbientLoop(SoundInstance sound) {
|
||||
return sound instanceof BiomeAmbientSoundsHandler.LoopSoundInstance || sound instanceof UnderwaterAmbientSoundInstances.UnderwaterAmbientSoundInstance;
|
||||
return sound instanceof BiomeAmbientSoundsHandler.LoopSoundInstance || sound instanceof UnderLiquidSubSound;
|
||||
}
|
||||
|
||||
private boolean filterCondition(SoundInstance sound) {
|
||||
@@ -55,20 +56,20 @@ public abstract class SoundManagerMixin implements SoundManagerDuck {
|
||||
|
||||
/** Pauses the queried SoundInstance(s). If id is null, will pause all sounds belonging to the SoundCategory. */
|
||||
@Override
|
||||
public void pauseSounds(@Nullable ResourceLocation id, @Nullable SoundSource category) {
|
||||
public void pauseSounds(@Nullable Identifier id, @Nullable SoundSource category) {
|
||||
((SoundEngineDuck)soundEngine).pauseSounds(id, category);
|
||||
}
|
||||
|
||||
/** Resumes the queried SoundInstance(s). If id is null, will resume all sounds belonging to the SoundCategory. */
|
||||
@Override
|
||||
public void resumeSounds(@Nullable ResourceLocation id, @Nullable SoundSource category) {
|
||||
public void resumeSounds(@Nullable Identifier id, @Nullable SoundSource category) {
|
||||
((SoundEngineDuck)soundEngine).resumeSounds(id, category);
|
||||
}
|
||||
|
||||
/** Blocks filtered sounds from being played while a BattleMusicInstance is in progress. */
|
||||
@Inject(method = "play(Lnet/minecraft/client/resources/sounds/SoundInstance;)V", at = @At("HEAD"), cancellable = true)
|
||||
public void playStart(SoundInstance sound, CallbackInfo cb) {
|
||||
if (filterCondition(sound)) cb.cancel();
|
||||
@Inject(method = "play", at = @At("HEAD"), cancellable = true)
|
||||
public void playStart(SoundInstance soundInstance, CallbackInfoReturnable<SoundEngine.PlayResult> cir) {
|
||||
if (filterCondition(soundInstance)) cir.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "playDelayed(Lnet/minecraft/client/resources/sounds/SoundInstance;I)V", at = @At("HEAD"), cancellable = true)
|
||||
@@ -77,14 +78,14 @@ public abstract class SoundManagerMixin implements SoundManagerDuck {
|
||||
}
|
||||
|
||||
/** Pauses ambient loops while a BattleMusicInstance is in progress. */
|
||||
@Inject(method = "play(Lnet/minecraft/client/resources/sounds/SoundInstance;)V", at = @At("TAIL"))
|
||||
public void playEnd(SoundInstance sound, CallbackInfo cb) {
|
||||
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getLocation(), SoundSource.AMBIENT);
|
||||
@Inject(method = "play", at = @At("TAIL"))
|
||||
public void playEnd(SoundInstance soundInstance, CallbackInfoReturnable<SoundEngine.PlayResult> cir) {
|
||||
if (ambientLoopCondition(soundInstance)) this.pauseSounds(soundInstance.getIdentifier(), SoundSource.AMBIENT);
|
||||
}
|
||||
|
||||
@Inject(method = "playDelayed(Lnet/minecraft/client/resources/sounds/SoundInstance;I)V", at = @At("TAIL"))
|
||||
public void playEnd(SoundInstance sound, int delay, CallbackInfo cb) {
|
||||
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getLocation(), SoundSource.AMBIENT);
|
||||
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getIdentifier(), SoundSource.AMBIENT);
|
||||
}
|
||||
|
||||
/** Clears tracked sounds on the client when disconnected. */
|
||||
|
||||
@@ -13,10 +13,13 @@ import com.cobblemon.mod.common.world.structureprocessors.HeightRangeStructurePr
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.BiomeSource;
|
||||
import net.minecraft.world.level.biome.Climate;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.RandomState;
|
||||
import net.minecraft.world.level.levelgen.structure.PoolElementStructurePiece;
|
||||
@@ -54,11 +57,11 @@ public abstract class StructureMixin {
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$rejectStartsOutsideHeightRange(
|
||||
RegistryAccess registryAccess, ChunkGenerator chunkGenerator, BiomeSource biomeSource,
|
||||
Holder<Structure> selected, ResourceKey<Level> dimension, RegistryAccess registryAccess,
|
||||
ChunkGenerator chunkGenerator, BiomeSource biomeSource, Climate.Sampler climateSampler,
|
||||
RandomState randomState, StructureTemplateManager structureTemplateManager, long seed,
|
||||
ChunkPos chunkPos, int references, LevelHeightAccessor heightAccessor,
|
||||
Predicate<Holder<Biome>> validBiome,
|
||||
CallbackInfoReturnable<StructureStart> cir,
|
||||
ChunkPos sourceChunkPos, int references, LevelHeightAccessor heightAccessor,
|
||||
Predicate<Holder<Biome>> validBiome, CallbackInfoReturnable<StructureStart> cir,
|
||||
@Local StructureStart structureStart
|
||||
) {
|
||||
for (StructurePiece piece : structureStart.getPieces()) {
|
||||
@@ -100,4 +103,4 @@ public abstract class StructureMixin {
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,4 +29,4 @@ public interface StructurePoolAccessor {
|
||||
|
||||
@Accessor("templates")
|
||||
ObjectArrayList<StructurePoolElement> getElements();
|
||||
}
|
||||
}
|
||||
+11
-11
@@ -11,7 +11,7 @@ package com.cobblemon.mod.common.mixin;
|
||||
import com.cobblemon.mod.common.world.CobblemonStructureIDs;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
@@ -38,7 +38,7 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
Map<String, Integer> generatedStructureGroupCounts;
|
||||
|
||||
private static final Map<String, Integer> structureMaxes;
|
||||
private static final Map<ResourceLocation, Set<String>> structureGroups = new HashMap<>();
|
||||
private static final Map<Identifier, Set<String>> structureGroups = new HashMap<>();
|
||||
static {
|
||||
String pokecenter = "pokecenter";
|
||||
String berry = "berry_farm";
|
||||
@@ -73,11 +73,11 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
structureMaxes = Collections.unmodifiableMap(aMap);
|
||||
}
|
||||
|
||||
public Set<String> getGroups(ResourceLocation structureIdentifier) {
|
||||
public Set<String> getGroups(Identifier structureIdentifier) {
|
||||
return structureGroups.getOrDefault(structureIdentifier, Set.of());
|
||||
}
|
||||
|
||||
public boolean hasReachedMaximum(ResourceLocation structureIdentifier) {
|
||||
public boolean hasReachedMaximum(Identifier structureIdentifier) {
|
||||
Set<String> groups = getGroups(structureIdentifier);
|
||||
for (String group : groups) {
|
||||
int count = generatedStructureGroupCounts.getOrDefault(group, 0);
|
||||
@@ -89,7 +89,7 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void incrementStructureCount(ResourceLocation structureIdentifier) {
|
||||
public void incrementStructureCount(Identifier structureIdentifier) {
|
||||
Set<String> groups = getGroups(structureIdentifier);
|
||||
for (String group : groups) {
|
||||
generatedStructureGroupCounts.put(group, generatedStructureGroupCounts.getOrDefault(group, 0) + 1);
|
||||
@@ -107,7 +107,7 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
StructurePoolElement structure = iterator.next();
|
||||
ResourceLocation structurePieceLocationKey = getCobblemonOnlyLocation(structure);
|
||||
Identifier structurePieceLocationKey = getCobblemonOnlyLocation(structure);
|
||||
if (structurePieceLocationKey == null) {
|
||||
reducedList.add(structure);
|
||||
continue;
|
||||
@@ -134,14 +134,14 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
CallbackInfo ci,
|
||||
@Local(ordinal = 1) StructurePoolElement structurePoolElement
|
||||
) {
|
||||
ResourceLocation structureLocationKey = getCobblemonOnlyLocation(structurePoolElement);
|
||||
Identifier structureLocationKey = getCobblemonOnlyLocation(structurePoolElement);
|
||||
if (structureLocationKey != null) {
|
||||
incrementStructureCount(structureLocationKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static ResourceLocation getCobblemonOnlyLocation(StructurePoolElement structurePoolElement) {
|
||||
ResourceLocation location = getLocationIfAvailable(structurePoolElement);
|
||||
private static Identifier getCobblemonOnlyLocation(StructurePoolElement structurePoolElement) {
|
||||
Identifier location = getLocationIfAvailable(structurePoolElement);
|
||||
if (location == null) return null;
|
||||
|
||||
if (!location.getNamespace().equals("cobblemon")) return null;
|
||||
@@ -149,7 +149,7 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
return location;
|
||||
}
|
||||
|
||||
private static ResourceLocation getLocationIfAvailable(StructurePoolElement structurePoolElement) {
|
||||
private static Identifier getLocationIfAvailable(StructurePoolElement structurePoolElement) {
|
||||
if (structurePoolElement instanceof LegacySinglePoolElement legacySinglePoolElement) {
|
||||
if (legacySinglePoolElement.template.left().isEmpty()) return null;
|
||||
|
||||
@@ -162,4 +162,4 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import com.bedrockk.molang.runtime.value.DoubleValue;
|
||||
import com.cobblemon.mod.common.entity.MoLangScriptingEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.InsideBlockEffectApplier;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.SweetBerryBushBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
@@ -25,7 +26,15 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
public abstract class SweetBerryBushBlockMixin {
|
||||
|
||||
@Inject(method = "entityInside", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void cobblemon$entityInside(BlockState state, Level level, BlockPos pos, Entity entity, CallbackInfo callbackInfo) {
|
||||
private void cobblemon$entityInside(
|
||||
BlockState state,
|
||||
Level level,
|
||||
BlockPos pos,
|
||||
Entity entity,
|
||||
InsideBlockEffectApplier effectApplier,
|
||||
boolean moved,
|
||||
CallbackInfo callbackInfo
|
||||
) {
|
||||
if (entity instanceof MoLangScriptingEntity) {
|
||||
if (((MoLangScriptingEntity) entity).getConfig().getMap().getOrDefault("immune_to_sweet_berry_bush_block", DoubleValue.ZERO).asDouble() == 1.0) {
|
||||
callbackInfo.cancel();
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
|
||||
@@ -23,11 +24,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
public class TargetingConditionsMixin {
|
||||
|
||||
@Inject(method = "test", at = @At("HEAD"), cancellable = true)
|
||||
public void test(@Nullable LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> ci) {
|
||||
public void test(ServerLevel serverLevel, LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (targetEntity instanceof ServerPlayer player) {
|
||||
if (player.level().getGameRules().getBoolean(CobblemonGameRules.MOB_TARGET_IN_BATTLE)) return;
|
||||
if (serverLevel.getGameRules().get(CobblemonGameRules.MOB_TARGET_IN_BATTLE)) return;
|
||||
boolean targetInBattle = Cobblemon.INSTANCE.getBattleRegistry().getBattleByParticipatingPlayer(player) != null;
|
||||
if (targetInBattle) ci.setReturnValue(false);
|
||||
if (targetInBattle) cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.CobblemonVillagerProfessions;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import kotlin.Pair;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.model.EntityModel;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.layers.RenderLayer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.monster.ZombieVillager;
|
||||
import net.minecraft.world.entity.npc.Villager;
|
||||
import net.minecraft.world.entity.npc.VillagerProfession;
|
||||
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(RenderLayer.class)
|
||||
public abstract class VillagerProfessionLayerMixin {
|
||||
@Inject(method = "renderColoredCutoutModel", at = @At(value = "HEAD"), cancellable = true)
|
||||
private static <T extends LivingEntity> void cobblemon$renderVillagerProfessionLayer(EntityModel<T> entityModel, ResourceLocation resourceLocation, PoseStack poseStack, MultiBufferSource multiBufferSource, int i, T livingEntity, int j, CallbackInfo ci) {
|
||||
if (resourceLocation.getNamespace().equals(Cobblemon.MODID)) {
|
||||
VillagerProfession profession = null;
|
||||
boolean isZombie = false;
|
||||
|
||||
if (livingEntity instanceof Villager) profession = ((Villager) livingEntity).getVillagerData().getProfession();
|
||||
if (livingEntity instanceof ZombieVillager) {
|
||||
profession = ((ZombieVillager) livingEntity).getVillagerData().getProfession();
|
||||
isZombie = true;
|
||||
}
|
||||
|
||||
Pair<String, String[]> override = CobblemonVillagerProfessions.INSTANCE.getNameTagOverride(profession);
|
||||
if (profession != null && override != null) {
|
||||
String entityName = ChatFormatting.stripFormatting(livingEntity.getName().getString());
|
||||
boolean nameMatches = false;
|
||||
for (String name: override.getSecond())
|
||||
if (entityName.endsWith(name)) {
|
||||
nameMatches = true;
|
||||
break;
|
||||
}
|
||||
if (nameMatches && resourceLocation.equals(getProfessionResourceLocation(resourceLocation.getNamespace(), ResourceLocation.parse(profession.name()).getPath(), isZombie))) {
|
||||
ResourceLocation textureLocation = getProfessionResourceLocation(resourceLocation.getNamespace(), override.getFirst(), isZombie);
|
||||
VertexConsumer vertexConsumer = multiBufferSource.getBuffer(RenderType.entityCutoutNoCull(textureLocation));
|
||||
entityModel.renderToBuffer(poseStack, vertexConsumer, i, LivingEntityRenderer.getOverlayCoords(livingEntity, 0.0F), j);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ResourceLocation getProfessionResourceLocation(String namespace, String profession, Boolean isZombie) {
|
||||
return ResourceLocation.fromNamespaceAndPath(namespace, "textures/entity/" + (isZombie ? "zombie_villager" : "villager") + "/profession/" + profession + ".png");
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,9 @@ package com.cobblemon.mod.common.mixin.accessor;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(Entity.class)
|
||||
public interface AccessorEntity {
|
||||
@Invoker("updateFluidOnEyes")
|
||||
void cobblemonUpdateFluidOnEyes();
|
||||
|
||||
@Accessor("eyeHeight")
|
||||
void standingEyeHeight(float standingEyeHeight);
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
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(BlockEntity.class)
|
||||
public interface BlockEntityAccessor {
|
||||
@Accessor("level") Level getLevel();
|
||||
@Accessor("worldPosition") BlockPos getWorldPosition();
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.world.entity.vehicle.Boat;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(Boat.class)
|
||||
public interface BoatEntityAccessor {
|
||||
|
||||
@Accessor("lastYd")
|
||||
void setFallVelocity(double fallVelocity);
|
||||
|
||||
@Accessor("status")
|
||||
Boat.Status getLocation();
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public interface CameraAccessor {
|
||||
@Accessor("detached")
|
||||
void setDetached(boolean detached);
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientChunkCache;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
@Mixin(ClientChunkCache.Storage.class)
|
||||
public interface CameraChunkStorageAccessor {
|
||||
@Accessor("chunks")
|
||||
AtomicReferenceArray<LevelChunk> cobblemon$getChunks();
|
||||
|
||||
@Accessor("chunkRadius")
|
||||
int cobblemon$getChunkRadius();
|
||||
|
||||
@Accessor("chunkCount")
|
||||
int cobblemon$getChunkCount();
|
||||
|
||||
@Accessor("chunkCount")
|
||||
void cobblemon$setChunkCount(int count);
|
||||
|
||||
@Accessor("viewCenterX")
|
||||
int cobblemon$getViewCenterX();
|
||||
|
||||
@Accessor("viewCenterZ")
|
||||
int cobblemon$getViewCenterZ();
|
||||
|
||||
@Invoker("getIndex")
|
||||
int cobblemon$getIndex(int x, int z);
|
||||
}
|
||||
@@ -17,4 +17,4 @@ import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
public interface ChunkMapAccessor {
|
||||
@Accessor("entityMap")
|
||||
Int2ObjectMap<?> getEntityMap();
|
||||
}
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior;
|
||||
import net.minecraft.world.level.block.DispenserBlock;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(DispenserBlock.class)
|
||||
public interface DispenserBlockAccessor {
|
||||
@Accessor("DISPENSER_REGISTRY")
|
||||
static Map<Item, DispenseItemBehavior> getItemBehaviors() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.client.gui.components.AbstractSelectionList;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(AbstractSelectionList.class)
|
||||
public interface EntryListWidgetAccessor {
|
||||
@Accessor("renderHeader")
|
||||
boolean getRenderHeader();
|
||||
}
|
||||
+2
-2
@@ -8,7 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.client.gui.components.StateSwitchingButton;
|
||||
import net.minecraft.client.gui.components.CycleButton;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -18,5 +18,5 @@ import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
@Mixin(RecipeBookComponent.class)
|
||||
public interface RecipeBookComponentAccessor {
|
||||
@Accessor("filterButton")
|
||||
StateSwitchingButton getFilterButton();
|
||||
CycleButton<Boolean> getFilterButton();
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(ServerEntity.class)
|
||||
public interface ServerEntityEntityAccessor {
|
||||
@Accessor("entity")
|
||||
Entity getEntity();
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public interface ServerPlayerAccessor {
|
||||
@Invoker("setShoulderEntityLeft")
|
||||
public void cobblemon$setShoulderEntityLeft(CompoundTag nbt);
|
||||
@Invoker("setShoulderEntityRight")
|
||||
public void cobblemon$setShoulderEntityRight(CompoundTag nbt);
|
||||
@Invoker("respawnEntityOnShoulder")
|
||||
public void cobblemon$respawnEntityOnShoulder(CompoundTag nbt);
|
||||
}
|
||||
-9
@@ -9,23 +9,14 @@
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(targets = "net.minecraft.server.level.ChunkMap$TrackedEntity")
|
||||
public interface TrackedEntityAccessor {
|
||||
@Accessor("seenBy")
|
||||
Set<ServerPlayerConnection> getSeenBy();
|
||||
|
||||
@Accessor("serverEntity")
|
||||
ServerEntity getServerEntity();
|
||||
|
||||
@Invoker("updatePlayers")
|
||||
void cobblemon$updatePlayers(List<ServerPlayer> players);
|
||||
}
|
||||
+17
-15
@@ -15,11 +15,11 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.Containers;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.ItemStackTemplate;
|
||||
import net.minecraft.world.item.alchemy.PotionBrewing;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
@@ -37,8 +37,8 @@ import java.util.Optional;
|
||||
@Mixin(BrewingStandBlockEntity.class)
|
||||
public class BrewingStandBlockEntityMixin {
|
||||
|
||||
@WrapOperation(method = "serverTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;doBrew(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/NonNullList;)V"))
|
||||
private static void cobblemon$doBrew(Level level, BlockPos pos, NonNullList<ItemStack> slots, Operation<Void> original) {
|
||||
@WrapOperation(method = "serverTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;doBrew(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;)V"))
|
||||
private static void cobblemon$doBrew(ServerLevel level, BlockPos pos, BrewingStandBlockEntity entity, Operation<Void> original) {
|
||||
var recipe = cobblemon$fetchBrewingRecipe(slots, level);
|
||||
if(recipe == null) {
|
||||
original.call(level, pos, slots);
|
||||
@@ -48,17 +48,17 @@ public class BrewingStandBlockEntityMixin {
|
||||
ItemStack itemStack = slots.get(3);
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
if (!slots.get(i).isEmpty()){
|
||||
slots.set(i, recipe.getResult().copy());
|
||||
slots.set(i, recipe.getResult().create());
|
||||
}
|
||||
}
|
||||
|
||||
itemStack.shrink(1);
|
||||
if (itemStack.getItem().hasCraftingRemainingItem()) {
|
||||
ItemStack itemStack2 = new ItemStack(itemStack.getItem().getCraftingRemainingItem());
|
||||
ItemStackTemplate itemStack2 = itemStack.getItem().getCraftingRemainder();
|
||||
if (itemStack2 != null) {
|
||||
if (itemStack.isEmpty()) {
|
||||
itemStack = itemStack2;
|
||||
itemStack = itemStack2.create();
|
||||
} else {
|
||||
Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), itemStack2);
|
||||
Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), itemStack2.create());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,9 +66,8 @@ public class BrewingStandBlockEntityMixin {
|
||||
level.levelEvent(LevelEvent.SOUND_BREWING_STAND_BREW, pos, 0);
|
||||
}
|
||||
|
||||
@WrapOperation(method = "serverTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;isBrewable(Lnet/minecraft/world/item/alchemy/PotionBrewing;Lnet/minecraft/core/NonNullList;)Z"))
|
||||
private static boolean cobblemon$isBrewable(PotionBrewing potionBrewing, NonNullList<ItemStack> items, Operation<Boolean> original,
|
||||
@Local(argsOnly = true) Level level) {
|
||||
@WrapOperation(method = "serverTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;isBrewable(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;)Z"))
|
||||
private static boolean cobblemon$isBrewable(ServerLevel serverLevel, BrewingStandBlockEntity entity, Operation<Boolean> original) {
|
||||
return cobblemon$fetchBrewingRecipe(items, level) != null || original.call(potionBrewing, items);
|
||||
}
|
||||
|
||||
@@ -90,7 +89,10 @@ public class BrewingStandBlockEntityMixin {
|
||||
}
|
||||
|
||||
BrewingStandInput input = new BrewingStandInput(ingredient, bottles);
|
||||
RecipeManager recipeManager = level.getRecipeManager();
|
||||
if (level.getServer() == null) {
|
||||
return null;
|
||||
}
|
||||
RecipeManager recipeManager = level.getServer().getRecipeManager();
|
||||
|
||||
Optional<RecipeHolder<BrewingStandRecipe>> recipeHolder =
|
||||
recipeManager.getRecipeFor(CobblemonRecipeTypes.INSTANCE.getBREWING_STAND(), input, level);
|
||||
@@ -107,7 +109,7 @@ public class BrewingStandBlockEntityMixin {
|
||||
|
||||
if (level != null) {
|
||||
|
||||
var rm = level.getRecipeManager();
|
||||
var rm = level.recipeAccess();
|
||||
|
||||
//Input slot
|
||||
if (slot == 3) {
|
||||
@@ -128,4 +130,4 @@ public class BrewingStandBlockEntityMixin {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -29,7 +29,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
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();
|
||||
var recipeManager = playerInventory.player.level().recipeAccess();
|
||||
for (Slot slot : ((BrewingStandMenu) (Object) this).slots) {
|
||||
if (slot instanceof RecipeAwareSlot awareSlot) {
|
||||
awareSlot.setRecipeManager(recipeManager);
|
||||
|
||||
+3
-4
@@ -12,8 +12,7 @@ import com.cobblemon.mod.common.duck.RecipeAwareSlot;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
|
||||
import net.minecraft.world.inventory.BrewingStandMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.item.crafting.RecipeAccess;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -24,10 +23,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
public class IngredientSlotMixin implements RecipeAwareSlot {
|
||||
|
||||
@Unique
|
||||
private RecipeManager cobblemon$recipeManager;
|
||||
private RecipeAccess cobblemon$recipeManager;
|
||||
|
||||
@Override
|
||||
public void setRecipeManager(RecipeManager recipeManager) {
|
||||
public void setRecipeManager(RecipeAccess recipeManager) {
|
||||
this.cobblemon$recipeManager = recipeManager;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ import com.cobblemon.mod.common.duck.RecipeAwareSlot;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
|
||||
import net.minecraft.world.inventory.BrewingStandMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.item.crafting.RecipeAccess;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -24,10 +23,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
public class PotionSlotMixin implements RecipeAwareSlot {
|
||||
|
||||
@Unique
|
||||
private RecipeManager cobblemon$recipeManager;
|
||||
private RecipeAccess cobblemon$recipeManager;
|
||||
|
||||
@Override
|
||||
public void setRecipeManager(RecipeManager recipeManager) {
|
||||
public void setRecipeManager(RecipeAccess recipeManager) {
|
||||
this.cobblemon$recipeManager = recipeManager;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.cinematic;
|
||||
|
||||
import com.cobblemon.mod.common.api.cinematic.runtime.CinematicViewerScopedEntity;
|
||||
import com.cobblemon.mod.common.mixin.accessor.ServerEntityEntityAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.TrackedEntityAccessor;
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
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;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@Mixin(targets = "net.minecraft.server.level.ChunkMap$TrackedEntity")
|
||||
public abstract class TrackedEntityMixin {
|
||||
|
||||
// Cancellation must also unpair existing viewers, or they keep receiving updates after the scope narrows.
|
||||
@Inject(method = "updatePlayer", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$filterViewerScopedEntity(ServerPlayer player, CallbackInfo ci) {
|
||||
final TrackedEntityAccessor self = (TrackedEntityAccessor) this;
|
||||
final ServerEntity serverEntity = self.getServerEntity();
|
||||
if (serverEntity == null) return;
|
||||
final Entity entity = ((ServerEntityEntityAccessor) serverEntity).getEntity();
|
||||
if (entity == null) return;
|
||||
|
||||
if (entity instanceof CinematicViewerScopedEntity scoped) {
|
||||
final Set<UUID> allowed = scoped.getCobblemonSceneViewers();
|
||||
if (allowed != null && !allowed.contains(player.getUUID())) {
|
||||
if (self.getSeenBy().remove(player.connection)) {
|
||||
serverEntity.removePairing(player);
|
||||
}
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -21,7 +21,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
@Mixin(AbstractClientPlayer.class)
|
||||
public class AbstractClientPlayerMixin {
|
||||
@Inject(
|
||||
method = "getFieldOfViewModifier()F",
|
||||
method = "getFieldOfViewModifier",
|
||||
at = @At(
|
||||
value = "HEAD"
|
||||
),
|
||||
@@ -35,8 +35,7 @@ public class AbstractClientPlayerMixin {
|
||||
// Only modify fov through riding if the pokedex is not open
|
||||
AbstractClientPlayer player = (AbstractClientPlayer) (Object) this;
|
||||
// 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();
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity ride && player.getVehicle().getControllingPassenger() == player) {
|
||||
|
||||
// Return custom fov mult for riding
|
||||
cir.setReturnValue(ride.rideFovMult());
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.minecraft.client.model.AgeableListModel;
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.model.Model;
|
||||
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;
|
||||
|
||||
/**
|
||||
* This mixin adds to the head of the renderToBuffer function and allows us to detect if it is a HumanoidModel and
|
||||
* is being rendered as part of a player in the world who is riding a PokemonEntity. If so we need to obey any
|
||||
* root animations that have been applied earlier.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since May 16, 2025
|
||||
*/
|
||||
@Mixin(AgeableListModel.class)
|
||||
public class AgeableListModelMixin {
|
||||
@Inject(method = "renderToBuffer", at = @At("HEAD"))
|
||||
private void cobblemon$renderToBuffer(
|
||||
PoseStack poseStack,
|
||||
VertexConsumer vertexConsumer,
|
||||
int packedLight,
|
||||
int packedOverlay,
|
||||
int colour,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
Model model = (Model) (Object) this;
|
||||
if (model instanceof HumanoidModel<?> && MountedPlayerRenderer.shouldApplyRootAnimation) {
|
||||
MountedPlayerRenderer.INSTANCE.animateRoot(poseStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.duck.AvatarRenderStateDuck;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
@Mixin(AvatarRenderState.class)
|
||||
public class AvatarRenderStateMixin implements AvatarRenderStateDuck {
|
||||
@Unique
|
||||
private @Nullable AbstractClientPlayer cobblemon$mountedPlayer;
|
||||
|
||||
@Unique
|
||||
private @Nullable PokemonEntity cobblemon$mountedPokemon;
|
||||
|
||||
@Override
|
||||
public @Nullable AbstractClientPlayer cobblemon$getMountedPlayer() {
|
||||
return this.cobblemon$mountedPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setMountedPlayer(@Nullable AbstractClientPlayer player) {
|
||||
this.cobblemon$mountedPlayer = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PokemonEntity cobblemon$getMountedPokemon() {
|
||||
return this.cobblemon$mountedPokemon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setMountedPokemon(@Nullable PokemonEntity pokemonEntity) {
|
||||
this.cobblemon$mountedPokemon = pokemonEntity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.duck.AvatarRenderStateDuck;
|
||||
import com.cobblemon.mod.common.duck.LivingEntityRenderStateDuck;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.entity.player.AvatarRenderer;
|
||||
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
|
||||
import net.minecraft.world.entity.Avatar;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
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;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(AvatarRenderer.class)
|
||||
public abstract class AvatarRendererMixin {
|
||||
@Inject(method = "extractRenderState", at = @At("TAIL"))
|
||||
private void cobblemon$captureMountedPlayer(Avatar avatar, AvatarRenderState state, float partialTick, CallbackInfo ci) {
|
||||
AvatarRenderStateDuck duck = (AvatarRenderStateDuck) state;
|
||||
LivingEntityRenderStateDuck livingDuck = (LivingEntityRenderStateDuck) state;
|
||||
if (avatar instanceof AbstractClientPlayer player && player.getVehicle() instanceof PokemonEntity pokemonEntity) {
|
||||
duck.cobblemon$setMountedPlayer(player);
|
||||
duck.cobblemon$setMountedPokemon(pokemonEntity);
|
||||
state.isCrouching = false;
|
||||
} else {
|
||||
duck.cobblemon$setMountedPlayer(null);
|
||||
duck.cobblemon$setMountedPokemon(null);
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyExpressionValue(
|
||||
method = "getRenderOffset(Lnet/minecraft/client/renderer/entity/state/AvatarRenderState;)Lnet/minecraft/world/phys/Vec3;",
|
||||
at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/entity/state/AvatarRenderState;isCrouching:Z", opcode = Opcodes.GETFIELD)
|
||||
)
|
||||
private boolean cobblemon$disableMountedCrouchOffset(boolean isCrouching, AvatarRenderState state) {
|
||||
AvatarRenderStateDuck duck = (AvatarRenderStateDuck) state;
|
||||
if (duck.cobblemon$getMountedPlayer() != null && duck.cobblemon$getMountedPokemon() != null) {
|
||||
return false;
|
||||
}
|
||||
return isCrouching;
|
||||
}
|
||||
|
||||
}
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.camera.CameraClientChunkCacheExtension;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
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.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ClientPacketListener.class)
|
||||
public abstract class CameraClientPacketListenerMixin {
|
||||
@Shadow
|
||||
private ClientLevel level;
|
||||
|
||||
@Inject(method = "queueLightRemoval", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$keepCameraLight(ClientboundForgetLevelChunkPacket packet, CallbackInfo ci) {
|
||||
ChunkPos position = packet.pos();
|
||||
LevelChunk retained = CameraClientChunkCacheExtension.getChunk(position.x, position.z);
|
||||
if (retained != null && retained.getLevel() == level) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
-127
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.camera.CameraClientChunkCacheExtension;
|
||||
import com.cobblemon.mod.common.client.render.camera.CameraFeedHandler;
|
||||
import com.cobblemon.mod.common.client.render.camera.CameraViewAreaExtension;
|
||||
import com.cobblemon.mod.common.client.util.compat.SodiumCompat;
|
||||
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import net.minecraft.client.renderer.ViewArea;
|
||||
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
|
||||
import net.minecraft.client.renderer.culling.Frustum;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.SectionPos;
|
||||
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.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(value = LevelRenderer.class, priority = 1100)
|
||||
public abstract class CameraLevelRendererMixin {
|
||||
private static final int CINEMATIC_RENDER_DISTANCE_CHUNKS = 32;
|
||||
private static final float CINEMATIC_FOG_DISTANCE = CINEMATIC_RENDER_DISTANCE_CHUNKS * 16;
|
||||
|
||||
@Shadow
|
||||
private SectionRenderDispatcher sectionRenderDispatcher;
|
||||
@Shadow
|
||||
private ClientLevel level;
|
||||
|
||||
@WrapWithCondition(method = "setupRender", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ViewArea;repositionCamera(DD)V"))
|
||||
private boolean cobblemon$shouldRepositionCamera(ViewArea viewArea, double x, double z) {
|
||||
return !CameraFeedHandler.isCapturing();
|
||||
}
|
||||
|
||||
// Sodium owns its setup pipeline even while vanilla feed sections are substituted.
|
||||
@Inject(method = "setupRender", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$onSetupRender(Camera camera, Frustum frustum, boolean hasCapturedFrustum, boolean isSpectator, CallbackInfo ci) {
|
||||
if (CameraFeedHandler.isCapturing() && !SodiumCompat.getInstance().isActive()) {
|
||||
CameraFeedHandler.prepareVisibleSections(frustum);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "setLevel", at = @At("HEAD"))
|
||||
private void cobblemon$onSetLevel(ClientLevel level, CallbackInfo ci) {
|
||||
try {
|
||||
if (this.level != level) {
|
||||
CameraClientChunkCacheExtension.clear();
|
||||
}
|
||||
} finally {
|
||||
CameraViewAreaExtension.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "allChanged", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/SectionOcclusionGraph;waitAndReset(Lnet/minecraft/client/renderer/ViewArea;)V"))
|
||||
private void cobblemon$onAllChanged(CallbackInfo ci) {
|
||||
CameraViewAreaExtension.allChanged(sectionRenderDispatcher, level);
|
||||
}
|
||||
|
||||
@Inject(method = "addRecentlyCompiledSection", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$onSectionCompiled(SectionRenderDispatcher.RenderSection section, CallbackInfo ci) {
|
||||
if (CameraViewAreaExtension.onSectionCompiled(section)) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "isSectionCompiled", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$onIsSectionCompiled(BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (CameraFeedHandler.isCapturing()) {
|
||||
SectionPos sectionPos = SectionPos.of(pos);
|
||||
SectionRenderDispatcher.RenderSection section = CameraViewAreaExtension.rawFetch(sectionPos.x(), sectionPos.y(), sectionPos.z(), false);
|
||||
|
||||
if (section != null && section.getCompiled() != SectionRenderDispatcher.CompiledSection.UNCOMPILED) {
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/FogRenderer;setupColor(Lnet/minecraft/client/Camera;FLnet/minecraft/client/multiplayer/ClientLevel;IF)V"), ordinal = 1)
|
||||
private float cobblemon$modifyFogRenderDistance(float original) {
|
||||
if (CameraFeedHandler.isCapturing())
|
||||
return CINEMATIC_FOG_DISTANCE;
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
// A Marker camera otherwise excludes the local player from vanilla entity rendering.
|
||||
@WrapOperation(
|
||||
method = "renderLevel",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;getEntity()Lnet/minecraft/world/entity/Entity;")
|
||||
)
|
||||
private Entity cobblemon$getCameraEntityDuringCapture(Camera camera, Operation<Entity> original) {
|
||||
if (CameraFeedHandler.isCapturing()) {
|
||||
Entity player = Minecraft.getInstance().player;
|
||||
if (player != null) return player;
|
||||
}
|
||||
return original.call(camera);
|
||||
}
|
||||
|
||||
@WrapOperation(
|
||||
method = "renderLevel",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;isDetached()Z")
|
||||
)
|
||||
private boolean cobblemon$isCameraDetachedDuringCapture(Camera camera, Operation<Boolean> original) {
|
||||
if (CameraFeedHandler.isCapturing()) {
|
||||
return true;
|
||||
}
|
||||
return original.call(camera);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,27 +8,22 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.api.camera.CameraRotation;
|
||||
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.camera.ClientCameraController;
|
||||
import com.cobblemon.mod.common.client.render.camera.CameraFeedHandler;
|
||||
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
|
||||
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.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import java.util.UUID;
|
||||
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;
|
||||
@@ -37,21 +32,20 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
public abstract class CameraMixin implements CameraDuck {
|
||||
@Shadow private float eyeHeight;
|
||||
@Shadow private float eyeHeightOld;
|
||||
@Shadow private BlockGetter level;
|
||||
@Shadow private Level level;
|
||||
@Shadow private Entity entity;
|
||||
@Final @Shadow private Quaternionf rotation;
|
||||
@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);
|
||||
@Shadow private Vec3 position;
|
||||
@Shadow @Final private BlockPos.MutableBlockPos blockPosition;
|
||||
@Shadow private int matrixPropertiesDirty;
|
||||
|
||||
@Override public BlockGetter cobblemon$getLevel() {
|
||||
return level;
|
||||
}
|
||||
@Shadow protected abstract void setRotation(float yRot, float xRot);
|
||||
|
||||
@Override public Entity cobblemon$getEntity() {
|
||||
return entity;
|
||||
@@ -69,15 +63,19 @@ public abstract class CameraMixin implements CameraDuck {
|
||||
@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();
|
||||
@Override public void cobblemon$markDirty() { this.matrixPropertiesDirty |= 3; }
|
||||
|
||||
@Inject(method = "setPosition(DDD)V", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$positionCamera(double x, double y, double z, CallbackInfo ci) {
|
||||
if (this.entity == null) return;
|
||||
Entity entity = this.entity;
|
||||
Entity vehicle = entity.getVehicle();
|
||||
boolean thirdPersonReverse = Minecraft.getInstance().options.getCameraType().isMirrored();
|
||||
MountedPokemonAnimationRenderController.INSTANCE.reset();
|
||||
|
||||
if(vehicle instanceof Rideable){
|
||||
Vec3 position = MountedCameraRenderer.INSTANCE.getCameraPosition(
|
||||
instance,
|
||||
if (vehicle instanceof Rideable) {
|
||||
Vec3 ridePos = MountedCameraRenderer.INSTANCE.getCameraPosition(
|
||||
(Camera) (Object) this,
|
||||
entity,
|
||||
vehicle,
|
||||
thirdPersonReverse,
|
||||
@@ -85,39 +83,17 @@ public abstract class CameraMixin implements CameraDuck {
|
||||
eyeHeightOld
|
||||
);
|
||||
|
||||
if(position != null) {
|
||||
setPosition(position);
|
||||
if (ridePos != null) {
|
||||
// Directly set the position field instead of calling setPosition(Vec3)
|
||||
this.position = ridePos;
|
||||
this.blockPosition.set(ridePos.x, ridePos.y, ridePos.z);
|
||||
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// reset the rotation values if it is now not being ridden.
|
||||
MountedCameraRenderer.INSTANCE.setSmoothRotation(null);
|
||||
original.call(instance, x, y, z);
|
||||
}
|
||||
|
||||
// Apply after vanilla third-person and sleeping offsets so authored transforms remain exact.
|
||||
@Inject(method = "setup", at = @At("RETURN"))
|
||||
private void cobblemon$applyCinematicTransform(BlockGetter level, Entity entity, boolean detached, boolean thirdPersonReverse, float partialTick, CallbackInfo ci) {
|
||||
UUID capturedId = CameraFeedHandler.getCurrentlyCapturedCamera();
|
||||
CameraFeedHandler.FeedContext context = capturedId != null ? CameraFeedHandler.getFeedContext(capturedId) : null;
|
||||
float roll;
|
||||
if (context != null) {
|
||||
setPosition(context.getPosition());
|
||||
setRotation(context.getYaw(), context.getPitch());
|
||||
roll = context.getRoll();
|
||||
} else {
|
||||
if (!ClientCameraController.shouldUseCinematicCamera()) return;
|
||||
ClientCameraController.ActiveTransform transform = ClientCameraController.getCameraTransform();
|
||||
if (transform == null) return;
|
||||
CameraRotation rotation = transform.getRotation();
|
||||
setPosition(transform.getPosition());
|
||||
setRotation(rotation.getYaw(), rotation.getPitch());
|
||||
roll = transform.getRoll();
|
||||
}
|
||||
this.rotation.rotateZ((float) Math.toRadians(roll));
|
||||
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
|
||||
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
|
||||
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,14 @@ import com.mojang.blaze3d.audio.Channel;
|
||||
import org.lwjgl.openal.AL10;
|
||||
import org.lwjgl.openal.AL11;
|
||||
import org.lwjgl.openal.EXTEfx;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(Channel.class)
|
||||
public abstract class ChannelMixin implements ChannelDuck {
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private int source;
|
||||
|
||||
|
||||
-178
@@ -1,178 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.camera.CameraClientChunkCacheExtension;
|
||||
import com.cobblemon.mod.common.mixin.accessor.CameraChunkStorageAccessor;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.client.multiplayer.ClientChunkCache;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(value = ClientChunkCache.class, priority = 1100)
|
||||
public abstract class ClientChunkCacheMixin {
|
||||
@Shadow
|
||||
volatile ClientChunkCache.Storage storage;
|
||||
@Shadow
|
||||
@Final
|
||||
ClientLevel level;
|
||||
@Shadow
|
||||
@Final
|
||||
private LevelChunk emptyChunk;
|
||||
|
||||
@Inject(method = "drop", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$onDrop(ChunkPos chunkPos, CallbackInfo ci) {
|
||||
if (CameraClientChunkCacheExtension.shouldKeepChunk(chunkPos)) {
|
||||
CameraChunkStorageAccessor access = (CameraChunkStorageAccessor) (Object) storage;
|
||||
int index = access.cobblemon$getIndex(chunkPos.x, chunkPos.z);
|
||||
LevelChunk chunk = access.cobblemon$getChunks().get(index);
|
||||
if (chunk != null && chunk.getPos().equals(chunkPos)) {
|
||||
cobblemon$retain(access, index, chunk);
|
||||
}
|
||||
ci.cancel();
|
||||
} else {
|
||||
CameraClientChunkCacheExtension.drop(level, chunkPos);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "updateViewCenter", at = @At("HEAD"))
|
||||
private void cobblemon$onViewCenter(int x, int z, CallbackInfo ci) {
|
||||
CameraChunkStorageAccessor access = (CameraChunkStorageAccessor) (Object) storage;
|
||||
cobblemon$retainOutsideRange(access, x, z, access.cobblemon$getChunkRadius());
|
||||
}
|
||||
|
||||
@Inject(method = "updateViewRadius", at = @At("HEAD"))
|
||||
private void cobblemon$onViewRadius(int radius, CallbackInfo ci) {
|
||||
CameraChunkStorageAccessor access = (CameraChunkStorageAccessor) (Object) storage;
|
||||
cobblemon$retainOutsideRange(access, access.cobblemon$getViewCenterX(), access.cobblemon$getViewCenterZ(), Math.max(2, radius) + 3);
|
||||
}
|
||||
|
||||
@Inject(method = "updateViewCenter", at = @At("TAIL"))
|
||||
private void cobblemon$afterViewCenter(int x, int z, CallbackInfo ci) {
|
||||
cobblemon$promoteCameraChunks((CameraChunkStorageAccessor) (Object) storage);
|
||||
}
|
||||
|
||||
@Inject(method = "updateViewRadius", at = @At("TAIL"))
|
||||
private void cobblemon$afterViewRadius(int radius, CallbackInfo ci) {
|
||||
cobblemon$promoteCameraChunks((CameraChunkStorageAccessor) (Object) storage);
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void cobblemon$onTick(BooleanSupplier hasTimeLeft, boolean tickChunks, CallbackInfo ci) {
|
||||
CameraClientChunkCacheExtension.prune(level);
|
||||
}
|
||||
|
||||
@Inject(method = "replaceWithPacketData", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$onReplaceWithPacketData(int x, int z, FriendlyByteBuf buffer, CompoundTag chunkTag, Consumer<ClientboundLevelChunkPacketData.BlockEntityTagOutput> tagOutputConsumer, CallbackInfoReturnable<LevelChunk> cir) {
|
||||
if (!storage.inRange(x, z)) {
|
||||
if (CameraClientChunkCacheExtension.shouldKeepChunk(new ChunkPos(x, z))) {
|
||||
cir.setReturnValue(CameraClientChunkCacheExtension.replaceWithPacketData(level, x, z, buffer, chunkTag, tagOutputConsumer));
|
||||
}
|
||||
return;
|
||||
}
|
||||
CameraChunkStorageAccessor access = (CameraChunkStorageAccessor) (Object) storage;
|
||||
int index = access.cobblemon$getIndex(x, z);
|
||||
LevelChunk previous = access.cobblemon$getChunks().get(index);
|
||||
if (previous != null && (previous.getPos().x != x || previous.getPos().z != z)
|
||||
&& CameraClientChunkCacheExtension.shouldKeepChunk(previous.getPos())) {
|
||||
cobblemon$retain(access, index, previous);
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "replaceWithPacketData", at = @At(value = "NEW", target = "(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/level/ChunkPos;)Lnet/minecraft/world/level/chunk/LevelChunk;"))
|
||||
private LevelChunk cobblemon$reuseCameraChunk(Level level, ChunkPos position, Operation<LevelChunk> original) {
|
||||
LevelChunk retained = CameraClientChunkCacheExtension.take(this.level, position.x, position.z);
|
||||
return retained != null ? retained : original.call(level, position);
|
||||
}
|
||||
|
||||
@Inject(method = "replaceBiomes", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$onReplaceBiomes(int x, int z, FriendlyByteBuf buffer, CallbackInfo ci) {
|
||||
LevelChunk chunk = CameraClientChunkCacheExtension.getChunk(x, z);
|
||||
if (chunk != null && chunk.getLevel() == level) {
|
||||
chunk.replaceBiomes(buffer);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "getChunk(IILnet/minecraft/world/level/chunk/status/ChunkStatus;Z)Lnet/minecraft/world/level/chunk/LevelChunk;", at = @At("RETURN"), cancellable = true)
|
||||
private void cobblemon$onGetChunk(int x, int z, ChunkStatus chunkStatus, boolean requireChunk, CallbackInfoReturnable<LevelChunk> cir) {
|
||||
if (cir.getReturnValue() == null || cir.getReturnValue() == emptyChunk) {
|
||||
LevelChunk chunk = CameraClientChunkCacheExtension.getChunk(x, z);
|
||||
if (chunk != null && chunk.getLevel() == level) {
|
||||
cir.setReturnValue(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$promoteCameraChunks(CameraChunkStorageAccessor access) {
|
||||
AtomicReferenceArray<LevelChunk> chunks = access.cobblemon$getChunks();
|
||||
for (LevelChunk chunk : CameraClientChunkCacheExtension.snapshot()) {
|
||||
ChunkPos position = chunk.getPos();
|
||||
if (chunk.getLevel() != level
|
||||
|| Math.abs(position.x - access.cobblemon$getViewCenterX()) > access.cobblemon$getChunkRadius()
|
||||
|| Math.abs(position.z - access.cobblemon$getViewCenterZ()) > access.cobblemon$getChunkRadius()) continue;
|
||||
int index = access.cobblemon$getIndex(position.x, position.z);
|
||||
LevelChunk previous = chunks.get(index);
|
||||
if (previous != null && CameraClientChunkCacheExtension.shouldKeepChunk(previous.getPos())) {
|
||||
cobblemon$retain(access, index, previous);
|
||||
previous = null;
|
||||
}
|
||||
CameraClientChunkCacheExtension.take(level, position.x, position.z);
|
||||
chunks.set(index, chunk);
|
||||
if (previous == null) {
|
||||
access.cobblemon$setChunkCount(access.cobblemon$getChunkCount() + 1);
|
||||
} else {
|
||||
CameraClientChunkCacheExtension.unload(level, previous);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$retainOutsideRange(CameraChunkStorageAccessor access, int centerX, int centerZ, int radius) {
|
||||
AtomicReferenceArray<LevelChunk> chunks = access.cobblemon$getChunks();
|
||||
for (int index = 0; index < chunks.length(); index++) {
|
||||
LevelChunk chunk = chunks.get(index);
|
||||
if (chunk == null) continue;
|
||||
ChunkPos position = chunk.getPos();
|
||||
if ((Math.abs(position.x - centerX) > radius || Math.abs(position.z - centerZ) > radius)
|
||||
&& CameraClientChunkCacheExtension.shouldKeepChunk(position)) {
|
||||
cobblemon$retain(access, index, chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$retain(CameraChunkStorageAccessor access, int index, LevelChunk chunk) {
|
||||
// Detach before loader unload callbacks: lighting and block entities belong to this same LevelChunk.
|
||||
if (access.cobblemon$getChunks().compareAndSet(index, chunk, null)) {
|
||||
access.cobblemon$setChunkCount(access.cobblemon$getChunkCount() - 1);
|
||||
CameraClientChunkCacheExtension.retain(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRecipeCategories;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotBookCategory;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import net.minecraft.client.ClientRecipeBook;
|
||||
import net.minecraft.client.RecipeBookCategories;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
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.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(ClientRecipeBook.class)
|
||||
public abstract class ClientRecipeBookMixin {
|
||||
|
||||
@Shadow
|
||||
protected static Map<RecipeBookCategories, List<List<RecipeHolder<?>>>> categorizeAndGroupRecipes(Iterable<RecipeHolder<?>> recipes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private Map<RecipeBookCategories, List<RecipeCollection>> collectionsByTab;
|
||||
|
||||
@Shadow
|
||||
private List<RecipeCollection> allCollections;
|
||||
|
||||
@Inject(method = "getCategory", at = @At(value = "HEAD"), cancellable = true)
|
||||
private static void addCustomCategory(RecipeHolder<?> recipe, CallbackInfoReturnable<RecipeBookCategories> cir) {
|
||||
Recipe<?> recipe2 = recipe.value();
|
||||
if (recipe2 instanceof CookingPotRecipeBase) {
|
||||
CookingPotBookCategory category = ((CookingPotRecipeBase) recipe2).getCategory();
|
||||
RecipeBookCategories var7;
|
||||
switch (category) {
|
||||
case MISC -> var7 = CobblemonRecipeCategories.COOKING_POT_MISC.toVanillaCategory();
|
||||
case FOODS -> var7 = CobblemonRecipeCategories.COOKING_POT_FOODS.toVanillaCategory();
|
||||
case MEDICINES -> var7 = CobblemonRecipeCategories.COOKING_POT_MEDICINES.toVanillaCategory();
|
||||
case COMPLEX_DISHES -> var7 = CobblemonRecipeCategories.COOKING_POT_COMPLEX_DISHES.toVanillaCategory();
|
||||
default -> throw new MatchException(null, null);
|
||||
}
|
||||
cir.setReturnValue(var7);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "setupCollections", at = @At("RETURN"))
|
||||
private void addCustomAggregateCategories(Iterable<RecipeHolder<?>> recipes, RegistryAccess registryAccess, CallbackInfo ci) {
|
||||
Map<RecipeBookCategories, List<List<RecipeHolder<?>>>> map = categorizeAndGroupRecipes(recipes);
|
||||
Map<RecipeBookCategories, List<RecipeCollection>> map2 = Maps.newHashMap();
|
||||
ImmutableList.Builder<RecipeCollection> builder = ImmutableList.builder();
|
||||
|
||||
map.forEach((recipeBookCategories, list) -> {
|
||||
List<RecipeCollection> collections = list.stream()
|
||||
.map(listx -> new RecipeCollection(registryAccess, listx))
|
||||
.peek(builder::add)
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
map2.put(recipeBookCategories, collections);
|
||||
});
|
||||
RecipeBookCategories.AGGREGATE_CATEGORIES.forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List) list.stream().flatMap((recipeBookCategoriesx) -> ((List) map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
|
||||
CobblemonRecipeCategories.Companion.getCustomAggregateCategories().forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List) list.stream().flatMap((recipeBookCategoriesx) -> ((List) map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
|
||||
|
||||
this.collectionsByTab = ImmutableMap.copyOf(map2);
|
||||
this.allCollections = builder.build();
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.mojang.blaze3d.platform.cursor.CursorType;
|
||||
import net.minecraft.client.gui.GuiGraphicsExtractor;
|
||||
import net.minecraft.client.gui.screens.inventory.CreativeModeInventoryScreen;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(CreativeModeInventoryScreen.class)
|
||||
public abstract class CreativeModeInventoryScreenMixin {
|
||||
|
||||
@Redirect(
|
||||
method = "renderTabButton",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/gui/GuiGraphicsExtractor;requestCursor(Lcom/mojang/blaze3d/platform/cursor/CursorType;)V"
|
||||
)
|
||||
)
|
||||
private void cobblemon$skipCreativeTabCursor(GuiGraphicsExtractor guiGraphics, CursorType cursorType, GuiGraphicsExtractor context, int mouseX, int mouseY, CreativeModeTab tab) {
|
||||
// 1.21.1 had no special cursor on creative tab hover; keep the arrow cursor for tab icons.
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.gui.ScrollingWidget;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import net.minecraft.client.gui.components.AbstractSelectionList;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(AbstractSelectionList.class)
|
||||
public abstract class EntryListWidgetMixin {
|
||||
|
||||
@SuppressWarnings("ConstantValue")
|
||||
@ModifyExpressionValue(method = "getEntryAtPosition", at = @At(value = "CONSTANT", args = {"intValue=4"}))
|
||||
public int cobblemon$adjustOnlyIfNecessary(int original) {
|
||||
if(ScrollingWidget.class.isInstance(this)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
}
|
||||
+15
-123
@@ -9,162 +9,54 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
|
||||
import com.cobblemon.mod.common.client.camera.GameCamera;
|
||||
import com.cobblemon.mod.common.client.camera.ClientCameraController;
|
||||
import com.cobblemon.mod.common.client.cinematic.ClientSceneSessionManager;
|
||||
import com.cobblemon.mod.common.client.render.camera.accessor.CameraFeedRenderState;
|
||||
import com.cobblemon.mod.common.client.render.camera.CameraFeedHandler;
|
||||
import com.cobblemon.mod.common.client.render.camera.compositor.CompositorManager;
|
||||
import net.minecraft.client.Camera;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
import java.util.UUID;
|
||||
|
||||
@Mixin(GameRenderer.class)
|
||||
public abstract class GameRendererMixin implements CameraFeedRenderState {
|
||||
|
||||
@Shadow private boolean renderHand;
|
||||
@Shadow private boolean renderBlockOutline;
|
||||
|
||||
@Override public boolean cobblemonRenderHand() { return renderHand; }
|
||||
@Override public boolean cobblemonRenderBlockOutline() { return renderBlockOutline; }
|
||||
|
||||
@Shadow @Final @Mutable
|
||||
private Camera mainCamera;
|
||||
|
||||
public class GameRendererMixin {
|
||||
@Unique
|
||||
private Camera cobblemon$playerCamera;
|
||||
long lastTime = -1;
|
||||
|
||||
@Unique
|
||||
private final GameCamera cobblemon$gameCamera = new GameCamera();
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$usingCinematic;
|
||||
|
||||
@Unique
|
||||
private long cobblemon$lastTime = -1;
|
||||
|
||||
@Inject(method = "render", at = @At("HEAD"))
|
||||
private void cobblemon$swapCamera(DeltaTracker counter, boolean tick, CallbackInfo ci) {
|
||||
@Inject(
|
||||
method = "render",
|
||||
at = @At(value = "TAIL")
|
||||
)
|
||||
public void render(CallbackInfo ci) {
|
||||
Minecraft client = Minecraft.getInstance();
|
||||
if (client.level == null) {
|
||||
cobblemon$restoreCamera();
|
||||
return;
|
||||
}
|
||||
|
||||
ClientCameraController.advanceFrame(client.isPaused() ? 0f : counter.getRealtimeDeltaTicks() / 20f);
|
||||
|
||||
ClientSceneSessionManager.INSTANCE.getAllSessions().forEach(session -> session.refreshCompositor());
|
||||
|
||||
if (ClientCameraController.shouldUseCinematicCamera()) {
|
||||
if (!cobblemon$usingCinematic) {
|
||||
cobblemon$playerCamera = mainCamera;
|
||||
mainCamera = cobblemon$gameCamera;
|
||||
cobblemon$usingCinematic = true;
|
||||
}
|
||||
cobblemon$gameCamera.prepare(client, counter.getGameTimeDeltaPartialTick(tick));
|
||||
} else if (cobblemon$usingCinematic) {
|
||||
cobblemon$restoreCamera();
|
||||
}
|
||||
}
|
||||
|
||||
// WrapOperation allows Iris/Sodium to share this call site; Redirect claims it exclusively.
|
||||
@WrapOperation(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;renderLevel(Lnet/minecraft/client/DeltaTracker;)V"))
|
||||
private void cobblemon$skipVanillaRenderLevel(GameRenderer instance, DeltaTracker deltaTracker, Operation<Void> original) {
|
||||
if (!CompositorManager.isFullscreenActive()) {
|
||||
original.call(instance, deltaTracker);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GameRenderer;tryTakeScreenshotIfNeeded()V"))
|
||||
private void cobblemon$afterLevelRendering(DeltaTracker deltaTracker, boolean renderLevel, CallbackInfo ci) {
|
||||
boolean compositorNeedsFeeds = CompositorManager.isFullscreenActive()
|
||||
|| !CompositorManager.INSTANCE.getRequiredFeeds().isEmpty();
|
||||
if (compositorNeedsFeeds && CameraFeedHandler.hasFeeds()) {
|
||||
CameraFeedHandler.captureFeeds(deltaTracker);
|
||||
}
|
||||
if (CompositorManager.isFullscreenActive()) {
|
||||
CompositorManager.INSTANCE.compositeAll();
|
||||
CompositorManager.renderFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "pick", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$preventFramePick(float partialTicks, CallbackInfo ci) {
|
||||
if (CameraFeedHandler.isCapturing())
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "getFov", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$overrideCinematicFov(Camera camera, float partialTicks, boolean useFovSetting, CallbackInfoReturnable<Double> cir) {
|
||||
UUID capturedId = CameraFeedHandler.getCurrentlyCapturedCamera();
|
||||
Float fov;
|
||||
if (capturedId != null) {
|
||||
CameraFeedHandler.FeedContext context = CameraFeedHandler.getFeedContext(capturedId);
|
||||
fov = context != null ? context.getFov() : null;
|
||||
} else {
|
||||
if (camera != cobblemon$gameCamera || !ClientCameraController.shouldUseCinematicCamera()) return;
|
||||
fov = ClientCameraController.getPrimaryFovOverride();
|
||||
}
|
||||
if (fov != null) {
|
||||
cir.setReturnValue(fov.doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At(value = "TAIL"))
|
||||
private void cobblemon$afterRender(DeltaTracker counter, boolean tick, CallbackInfo ci) {
|
||||
Minecraft client = Minecraft.getInstance();
|
||||
|
||||
long newTime = System.currentTimeMillis();
|
||||
|
||||
// Don't play scheduled animations when the game is paused
|
||||
if (client.isPaused()) {
|
||||
cobblemon$lastTime = newTime;
|
||||
lastTime = newTime;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cobblemon$lastTime != -1) {
|
||||
float delta = (newTime - cobblemon$lastTime) / 1000F;
|
||||
ClientTaskTracker.INSTANCE.update(delta);
|
||||
if (lastTime != -1) {
|
||||
ClientTaskTracker.INSTANCE.update((newTime - lastTime) / 1000F);
|
||||
}
|
||||
cobblemon$lastTime = newTime;
|
||||
lastTime = newTime;
|
||||
}
|
||||
|
||||
@ModifyArg(
|
||||
method = "pick(Lnet/minecraft/world/entity/Entity;DDF)Lnet/minecraft/world/phys/HitResult;",
|
||||
method = "pick",
|
||||
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;"
|
||||
target = "Lnet/minecraft/world/phys/EntityHitResult;getEntity()Lnet/minecraft/world/entity/Entity;"
|
||||
),
|
||||
index = 4
|
||||
)
|
||||
private Predicate<Entity> filterPokemonVehicle(Predicate<Entity> original, @Local(ordinal = 0, argsOnly = true) Entity entity) {
|
||||
private Predicate<Entity> filterPokemonVehicle(Predicate<Entity> original, @Local Entity entity) {
|
||||
return (entityX) -> !(entity.getVehicle() == entityX && entityX instanceof PokemonEntity) && original.test(entityX);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$restoreCamera() {
|
||||
if (cobblemon$usingCinematic) {
|
||||
mainCamera = cobblemon$playerCamera;
|
||||
cobblemon$playerCamera = null;
|
||||
cobblemon$usingCinematic = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.duck.GuiGraphicsExtractorDuck;
|
||||
import com.mojang.blaze3d.platform.cursor.CursorType;
|
||||
import net.minecraft.client.gui.GuiGraphicsExtractor;
|
||||
import net.minecraft.client.renderer.entity.state.EntityRenderState;
|
||||
import net.minecraft.client.renderer.state.gui.GuiRenderState;
|
||||
import net.minecraft.client.renderer.state.gui.pip.GuiEntityRenderState;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(GuiGraphicsExtractor.class)
|
||||
public class GuiGraphicsExtractorAccessor implements GuiGraphicsExtractorDuck {
|
||||
@Final
|
||||
@Shadow
|
||||
private GuiRenderState guiRenderState;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private GuiGraphicsExtractor.ScissorStack scissorStack;
|
||||
|
||||
@Override
|
||||
public GuiGraphicsExtractor.ScissorStack getScissorStack() {
|
||||
return this.scissorStack;
|
||||
}
|
||||
|
||||
@Override // copy of .entity() without overwriting the lightcoords
|
||||
public void entityWithCustomLight(final EntityRenderState renderState, final float scale,
|
||||
final Vector3f translation, final Quaternionf rotation,
|
||||
final @Nullable Quaternionf overrideCameraAngle,
|
||||
final int x0, final int y0, final int x1, final int y1) {
|
||||
this.guiRenderState.addPicturesInPictureState(new GuiEntityRenderState(renderState, translation, rotation,
|
||||
overrideCameraAngle, x0, y0, x1, y1, scale, this.scissorStack.peek()));
|
||||
}
|
||||
}
|
||||
+83
-53
@@ -8,19 +8,23 @@
|
||||
|
||||
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.duck.AvatarRenderStateDuck;
|
||||
import com.cobblemon.mod.common.duck.LivingEntityRenderStateDuck;
|
||||
import com.cobblemon.mod.common.entity.PoseType;
|
||||
import com.cobblemon.mod.common.client.render.player.RecallArmAnimationTracker;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.model.geom.ModelPart;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.entity.state.AvatarRenderState;
|
||||
import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
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.Coerce;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@@ -41,59 +45,85 @@ public class HumanoidModelMixin {
|
||||
@Shadow @Final
|
||||
public ModelPart body;
|
||||
|
||||
@Inject(method = "setupAnim*", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/geom/ModelPart;copyFrom(Lnet/minecraft/client/model/geom/ModelPart;)V", shift = At.Shift.BEFORE))
|
||||
public void cobblemon$animateRiders(
|
||||
LivingEntity entity,
|
||||
float limbSwing,
|
||||
float limbSwingAmount,
|
||||
float ageInTicks,
|
||||
float netHeadYaw,
|
||||
float headPitch,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
@Inject(
|
||||
method = "setupAnim(Lnet/minecraft/client/renderer/entity/state/HumanoidRenderState;)V",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
public void cobblemon$animateRiders(HumanoidRenderState renderState, CallbackInfo ci) {
|
||||
MountedPlayerRenderer.shouldApplyRootAnimation = false;
|
||||
|
||||
if (MountedPlayerRenderer.relevantPartsByName.size() <= 1) {
|
||||
MountedPlayerRenderer.relevantPartsByName.put("arm_left", leftArm);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("arm_right", rightArm);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("leg_left", leftLeg);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("leg_right", rightLeg);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("head", head);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("hat", hat);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("torso", body);
|
||||
if (!(renderState instanceof AvatarRenderState avatarRenderState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entity vehicle = entity.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity && entity instanceof OrientationControllable) {
|
||||
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) ->
|
||||
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;
|
||||
if (this.head != null) {
|
||||
this.head.yRot = 0f;
|
||||
this.head.xRot = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(entity instanceof AbstractClientPlayer player)) return;
|
||||
|
||||
MountedPlayerRenderer.shouldApplyRootAnimation = true;
|
||||
MountedPlayerRenderer.INSTANCE.animate((HumanoidModel<AbstractClientPlayer>)(Object)this, pokemonEntity, player, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
|
||||
AvatarRenderStateDuck duck = (AvatarRenderStateDuck) avatarRenderState;
|
||||
LivingEntityRenderStateDuck livingDuck = (LivingEntityRenderStateDuck) avatarRenderState;
|
||||
AbstractClientPlayer player = duck.cobblemon$getMountedPlayer();
|
||||
PokemonEntity pokemonEntity = duck.cobblemon$getMountedPokemon();
|
||||
if (player == null || pokemonEntity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int seatIndex = livingDuck.cobblemon$getMountedSeatIndex();
|
||||
String seatLocator = livingDuck.cobblemon$getMountedSeatLocator();
|
||||
PoseType poseType = livingDuck.cobblemon$getMountedPoseType();
|
||||
|
||||
if (seatIndex < 0 || poseType == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MountedPlayerRenderer.relevantPartsByName.put("arm_left", leftArm);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("arm_right", rightArm);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("leg_left", leftLeg);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("leg_right", rightLeg);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("head", head);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("hat", hat);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("torso", body);
|
||||
|
||||
Entity vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof PokemonEntity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) ->
|
||||
behaviour.shouldRotateRiderHead(settings, state, pokemonEntity)
|
||||
);
|
||||
|
||||
float netHeadYaw = avatarRenderState.yRot;
|
||||
float headPitch = avatarRenderState.xRot;
|
||||
|
||||
if (!shouldRotatePlayerHead) {
|
||||
netHeadYaw = 0f;
|
||||
headPitch = 0f;
|
||||
this.head.yRot = 0f;
|
||||
this.head.xRot = 0f;
|
||||
}
|
||||
|
||||
MountedPlayerRenderer.INSTANCE.animate(
|
||||
(HumanoidModel<?>)(Object)this,
|
||||
pokemonEntity,
|
||||
player,
|
||||
avatarRenderState,
|
||||
seatIndex,
|
||||
seatLocator,
|
||||
poseType,
|
||||
netHeadYaw,
|
||||
headPitch,
|
||||
avatarRenderState.ageInTicks,
|
||||
avatarRenderState.walkAnimationPos,
|
||||
avatarRenderState.walkAnimationSpeed
|
||||
);
|
||||
MountedPlayerRenderer.shouldApplyRootAnimation = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//@Inject(method = "setupAnim*", at = @At("TAIL"))
|
||||
//public void cobblemon$poseRecallArm(LivingEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, CallbackInfo ci) {
|
||||
// if (!(entity instanceof AbstractClientPlayer) || entity.getVehicle() instanceof PokemonEntity) return;
|
||||
// float raise = RecallArmAnimationTracker.INSTANCE.raiseFactor(entity.getUUID());
|
||||
// if (raise <= 0f) return;
|
||||
// this.rightArm.xRot = Mth.lerp(raise, this.rightArm.xRot, (float) (-Math.PI / 2.0));
|
||||
// this.rightArm.yRot = Mth.lerp(raise, this.rightArm.yRot, 0f);
|
||||
// this.rightArm.zRot = Mth.lerp(raise, this.rightArm.zRot, 0f);
|
||||
//}
|
||||
}
|
||||
@@ -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.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.player.RecallArmAnimationTracker;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.entity.layers.ItemInHandLayer;
|
||||
import net.minecraft.client.renderer.entity.state.ArmedEntityRenderState;
|
||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||
import net.minecraft.world.entity.HumanoidArm;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
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(ItemInHandLayer.class)
|
||||
public class ItemInHandLayerMixin {
|
||||
//@Inject(method = "submitArmWithItem", at = @At("HEAD"), cancellable = true)
|
||||
//private void cobblemon$hideRecallHandItem(ArmedEntityRenderState state, ItemStackRenderState item, ItemStack itemStack,
|
||||
// HumanoidArm arm, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, int lightCoords, CallbackInfo ci) {
|
||||
// if (arm == HumanoidArm.RIGHT && RecallArmAnimationTracker.INSTANCE.isRecalling(state..getId())) {
|
||||
// ci.cancel();
|
||||
// }
|
||||
//}
|
||||
}
|
||||
Loaded 100 of 7097 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user