mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-21 22:56:23 -04:00
Compare commits
677
Commits
v1.4.1
...
mod_station
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4faae33d43 | ||
|
|
bd8f761ddb | ||
|
|
46798d694e | ||
|
|
056dd0fd4b | ||
|
|
3ac00d976b | ||
|
|
b30a76855b | ||
|
|
b6c964e03b | ||
|
|
3ed46cb7af | ||
|
|
cf9efe9b8c | ||
|
|
02b9431731 | ||
|
|
a30ae0ccef | ||
|
|
a2905f4d37 | ||
|
|
b3aba1532c | ||
|
|
6369bdb612 | ||
|
|
b5db5605ef | ||
|
|
0207459a0f | ||
|
|
0e2fdfbce8 | ||
|
|
8c9da885c7 | ||
|
|
a5b6529f3c | ||
|
|
b430b7db76 | ||
|
|
8015ff0e20 | ||
|
|
ee78657e3d | ||
|
|
6cc84cd38c | ||
|
|
31d6ff541e | ||
|
|
e1a4086f24 | ||
|
|
b1992a94d3 | ||
|
|
b41c4c21a8 | ||
|
|
e1893f50ae | ||
|
|
a458b31c9f | ||
|
|
03b5336eb8 | ||
|
|
a270371632 | ||
|
|
a9caf92d2f | ||
|
|
ff4d9ae208 | ||
|
|
a87d522f6d | ||
|
|
c24ab2049d | ||
|
|
b7b1850a4e | ||
|
|
8995c107f7 | ||
|
|
dca6b5273d | ||
|
|
2e8483cdc7 | ||
|
|
6b1c2e2074 | ||
|
|
8af5b5e07a | ||
|
|
7ae19ca774 | ||
|
|
830f00553e | ||
|
|
c87f56c83f | ||
|
|
4478532bcb | ||
|
|
184348d6fa | ||
|
|
04d288ed7e | ||
|
|
0d5cce730e | ||
|
|
3e01535203 | ||
|
|
f0d99a9d83 | ||
|
|
b4eb46d632 | ||
|
|
7e52336255 | ||
|
|
2b40b5b689 | ||
|
|
da889f220b | ||
|
|
ac65910380 | ||
|
|
ba6847be9a | ||
|
|
5ddbcd1830 | ||
|
|
47605646d0 | ||
|
|
d9fdf089c2 | ||
|
|
41db2a53ce | ||
|
|
85d8779818 | ||
|
|
e9a405694c | ||
|
|
d5af099120 | ||
|
|
d817ce1471 | ||
|
|
ce09b66db5 | ||
|
|
d0c666a20d | ||
|
|
04cef915e4 | ||
|
|
e50412443e | ||
|
|
3fe1f87f18 | ||
|
|
5a0fc199ff | ||
|
|
beb769c2a5 | ||
|
|
a7b6fae4ed | ||
|
|
af2ff7bbfa | ||
|
|
4f3575b2c6 | ||
|
|
98c248ef13 | ||
|
|
4a2c69d47c | ||
|
|
c23cb644d9 | ||
|
|
a8b12cfca3 | ||
|
|
825e1ee110 | ||
|
|
b489e747bb | ||
|
|
08f957e33b | ||
|
|
e17d38c53a | ||
|
|
ee0dc24207 | ||
|
|
e5d702bb5a | ||
|
|
0397e39735 | ||
|
|
6ca1d23f45 | ||
|
|
44def2be76 | ||
|
|
507f70c2d5 | ||
|
|
d91118d05f | ||
|
|
07d8e6ed09 | ||
|
|
fb34d4bd23 | ||
|
|
6ca1337ff9 | ||
|
|
0d344337dd | ||
|
|
c6e514216c | ||
|
|
64d160020b | ||
|
|
fb4c80f68c | ||
|
|
3d27681aaa | ||
|
|
2b5433f9da | ||
|
|
352202203a | ||
|
|
62cfbd7087 | ||
|
|
5a64e8ea1b | ||
|
|
8dc9863a5d | ||
|
|
9bad141c3f | ||
|
|
9280258413 | ||
|
|
51a11163dd | ||
|
|
fe8e4dcaff | ||
|
|
e0bd6766fc | ||
|
|
4da800d396 | ||
|
|
f3246ae14a | ||
|
|
d5ad84a495 | ||
|
|
47f87b1be3 | ||
|
|
b01086270a | ||
|
|
da6a09c942 | ||
|
|
8d5eb5883d | ||
|
|
0d12bf1190 | ||
|
|
4217938ada | ||
|
|
4c5f88db06 | ||
|
|
4f773f63cb | ||
|
|
cfd743c4c0 | ||
|
|
1bbfc6dce5 | ||
|
|
6f2235c751 | ||
|
|
50a0f2d858 | ||
|
|
27210512f6 | ||
|
|
53aa124de6 | ||
|
|
a18b54849f | ||
|
|
c868c63a5f | ||
|
|
31df7c92f4 | ||
|
|
3f3ae74535 | ||
|
|
7429fea802 | ||
|
|
3b65d1967e | ||
|
|
f30b15003f | ||
|
|
c4c1b7ac27 | ||
|
|
ea9287cfb5 | ||
|
|
02f845af5c | ||
|
|
ac5cd47715 | ||
|
|
3bb3a00cef | ||
|
|
f1ae4163c9 | ||
|
|
05957f2106 | ||
|
|
4b9ea1d4cd | ||
|
|
78dff75db9 | ||
|
|
dbab6404a1 | ||
|
|
e5c4240ae0 | ||
|
|
317112f9bb | ||
|
|
c635a1d331 | ||
|
|
58fda2e261 | ||
|
|
cf2173a281 | ||
|
|
3b442d387a | ||
|
|
710d37f453 | ||
|
|
2b575c888f | ||
|
|
6e5e572412 | ||
|
|
ce87d0dc48 | ||
|
|
d43c91129c | ||
|
|
d66b9c8d3b | ||
|
|
1fb3416211 | ||
|
|
dc37b381a0 | ||
|
|
1206aaaf13 | ||
|
|
95bcb9a7b8 | ||
|
|
c7d879ec57 | ||
|
|
f80a2850bb | ||
|
|
d5752982d7 | ||
|
|
64fe6cefde | ||
|
|
f1439ec724 | ||
|
|
0cac5714ac | ||
|
|
8529bb119f | ||
|
|
26f337c0fd | ||
|
|
ac1c7d8b78 | ||
|
|
b68b3ad55e | ||
|
|
70c6b74f0f | ||
|
|
5cb7a51163 | ||
|
|
a68b6928aa | ||
|
|
0c26cb026c | ||
|
|
6078e22b14 | ||
|
|
cb1226013d | ||
|
|
0c8318d317 | ||
|
|
8d80bcfd6b | ||
|
|
cfd4fa1785 | ||
|
|
86bd70177c | ||
|
|
92dd85643e | ||
|
|
8849de1bfd | ||
|
|
ce668b31ff | ||
|
|
943d6e0c55 | ||
|
|
7d82a2f7c8 | ||
|
|
782ba524df | ||
|
|
c571d79035 | ||
|
|
054c22b926 | ||
|
|
d2fce5edb5 | ||
|
|
cba32b7443 | ||
|
|
4a81c24a3d | ||
|
|
776e629850 | ||
|
|
9afb8b04c2 | ||
|
|
2a349697b4 | ||
|
|
9fc81c1b33 | ||
|
|
5c599dbb9a | ||
|
|
d5a94ff784 | ||
|
|
024f299486 | ||
|
|
9a2b588568 | ||
|
|
b6fb5e8776 | ||
|
|
987b9bb275 | ||
|
|
03bda4e27d | ||
|
|
b04ab8b95b | ||
|
|
5d8abbd4c7 | ||
|
|
6b167a7a17 | ||
|
|
dab0623d61 | ||
|
|
cb5b6ec68b | ||
|
|
90c74eddc8 | ||
|
|
3600178d3b | ||
|
|
ea57c9dc5d | ||
|
|
66d8a01917 | ||
|
|
68e32b21b5 | ||
|
|
670882bb4d | ||
|
|
d36c24075c | ||
|
|
d1a8122296 | ||
|
|
a8e6e684ab | ||
|
|
188fc2b5d9 | ||
|
|
9c0708651f | ||
|
|
1b3bb3b5bc | ||
|
|
cd03ef68c3 | ||
|
|
69716b5050 | ||
|
|
015deb4eeb | ||
|
|
96023077ad | ||
|
|
d96c68b5b4 | ||
|
|
dc27867502 | ||
|
|
bfbea377c1 | ||
|
|
f5954fcb33 | ||
|
|
eaa909a9f2 | ||
|
|
5ba4d460b1 | ||
|
|
09143b7ad6 | ||
|
|
aa1e14b4ac | ||
|
|
0f29cdeaf9 | ||
|
|
b976b9dd68 | ||
|
|
9abab091d9 | ||
|
|
e2e50d2f1b | ||
|
|
4ac88ba192 | ||
|
|
37eccce8b1 | ||
|
|
e44db7c380 | ||
|
|
d57bb42720 | ||
|
|
fa94ca8033 | ||
|
|
f206352b6e | ||
|
|
f0c44f040f | ||
|
|
2d6e2f87ed | ||
|
|
cdee981933 | ||
|
|
f2fc32b6a9 | ||
|
|
8b4193a5db | ||
|
|
667dfe32e3 | ||
|
|
218253765e | ||
|
|
f46b581327 | ||
|
|
ff1241304b | ||
|
|
7a15e6b004 | ||
|
|
6ee6beddeb | ||
|
|
b92960da77 | ||
|
|
ff082adf67 | ||
|
|
66959816ef | ||
|
|
0e85835a87 | ||
|
|
e165d4958d | ||
|
|
e0736e1988 | ||
|
|
724ff86a21 | ||
|
|
97427fa58b | ||
|
|
c9d47a3e21 | ||
|
|
c5c884ca2e | ||
|
|
f086c32b95 | ||
|
|
ecea176300 | ||
|
|
c00413bb32 | ||
|
|
be78012ce6 | ||
|
|
dd746e6775 | ||
|
|
44956ec6da | ||
|
|
83e7a1968a | ||
|
|
3b285cc8bd | ||
|
|
553ecc8509 | ||
|
|
7b0d488b7c | ||
|
|
4dead98e6b | ||
|
|
db36f8da2a | ||
|
|
3f7a5e1318 | ||
|
|
ce7485f557 | ||
|
|
b5ca5c29d4 | ||
|
|
43f60da22e | ||
|
|
0102c8b392 | ||
|
|
6bb5c5dadf | ||
|
|
dd21fe2ea3 | ||
|
|
656c46817a | ||
|
|
a373f437fa | ||
|
|
0fe3637034 | ||
|
|
7215860d74 | ||
|
|
dc899ffc1b | ||
|
|
88fe55bbb9 | ||
|
|
4b4be0e2cc | ||
|
|
3e673ae8f0 | ||
|
|
4b3b7443d3 | ||
|
|
70c1b42ede | ||
|
|
b2048bb66f | ||
|
|
9956f1c159 | ||
|
|
25857dafc5 | ||
|
|
80345b3810 | ||
|
|
d4dc24ec49 | ||
|
|
2209ee10b6 | ||
|
|
a91aa9835c | ||
|
|
0e980a846c | ||
|
|
3d3c421b5c | ||
|
|
f54bbe754f | ||
|
|
92fff27b4e | ||
|
|
255874cbe4 | ||
|
|
824bc1b080 | ||
|
|
3ee55f24d8 | ||
|
|
c3379ddf21 | ||
|
|
3844dd6314 | ||
|
|
5983b17e87 | ||
|
|
27986d28a7 | ||
|
|
8807f2134e | ||
|
|
d74b1228c1 | ||
|
|
a3dcfe8bfb | ||
|
|
8725ef2b54 | ||
|
|
080077189f | ||
|
|
3074b067dc | ||
|
|
8d0ee6dd6f | ||
|
|
a1c1c9bc90 | ||
|
|
5e52d350c1 | ||
|
|
e3ad34e023 | ||
|
|
f308918fd1 | ||
|
|
82a8257fa9 | ||
|
|
6c06c91cca | ||
|
|
c5e44031a6 | ||
|
|
6be2e14af4 | ||
|
|
5cae25c059 | ||
|
|
87e4f94af5 | ||
|
|
90ac9ae4df | ||
|
|
527518d0c2 | ||
|
|
bcb326cd87 | ||
|
|
89a4edb327 | ||
|
|
ab37580258 | ||
|
|
c116c01fd6 | ||
|
|
e3ad8f8079 | ||
|
|
a491d508b6 | ||
|
|
43075f1cb8 | ||
|
|
e1b1e3d5e9 | ||
|
|
c226b80430 | ||
|
|
935f7039cf | ||
|
|
02fb825328 | ||
|
|
a7095b30a3 | ||
|
|
ac5a03eebc | ||
|
|
8df6eea107 | ||
|
|
1376bb68f4 | ||
|
|
beb8f2ccf1 | ||
|
|
bd79b58571 | ||
|
|
7c164fc4c8 | ||
|
|
5e1c233493 | ||
|
|
95e95afef3 | ||
|
|
bf9c54e539 | ||
|
|
2ccda57c66 | ||
|
|
846acaef88 | ||
|
|
5fa12ff1c5 | ||
|
|
2b3db32243 | ||
|
|
4b54405017 | ||
|
|
b7addd0203 | ||
|
|
7e64938ec9 | ||
|
|
3824531735 | ||
|
|
618f66c775 | ||
|
|
9eb9c782ce | ||
|
|
49149c9c54 | ||
|
|
fd1d1075db | ||
|
|
1648926aa6 | ||
|
|
7784794689 | ||
|
|
07b41d7c0a | ||
|
|
f5287c7e83 | ||
|
|
4fa86c7742 | ||
|
|
b0d57dd875 | ||
|
|
6c09e2b553 | ||
|
|
593104fb0a | ||
|
|
e314664731 | ||
|
|
d0a38a9704 | ||
|
|
63a30dcfd0 | ||
|
|
9cc63b59e6 | ||
|
|
cb17c29be5 | ||
|
|
fd16d59ea2 | ||
|
|
3c9cff5027 | ||
|
|
6e155d7651 | ||
|
|
ae8f8a2fb8 | ||
|
|
5a6a83aac1 | ||
|
|
3ce22c0759 | ||
|
|
a1047e05d4 | ||
|
|
797eeb09cc | ||
|
|
e6df322556 | ||
|
|
744d1e1263 | ||
|
|
7987713179 | ||
|
|
f8efe0a7d1 | ||
|
|
be558ed0ab | ||
|
|
b7c1157c5c | ||
|
|
a786adee9e | ||
|
|
2d6c7f5148 | ||
|
|
cc8a51abcd | ||
|
|
f3f3bfead4 | ||
|
|
506ff8d1e4 | ||
|
|
4764264c9a | ||
|
|
7a761003c5 | ||
|
|
f9fa9dcf24 | ||
|
|
dfc4873ce3 | ||
|
|
38174155bf | ||
|
|
65bd00033c | ||
|
|
f82fa2b4e6 | ||
|
|
966acecf6d | ||
|
|
2cd09af4d0 | ||
|
|
1bc22f1afc | ||
|
|
2698006f93 | ||
|
|
aa38674fc8 | ||
|
|
3480085a29 | ||
|
|
9ca0742386 | ||
|
|
f5c0bfb40e | ||
|
|
9dc9740363 | ||
|
|
32d291890e | ||
|
|
be16d00dd5 | ||
|
|
777ece02cc | ||
|
|
188ae2ac85 | ||
|
|
381fd1d5e2 | ||
|
|
a2fbe16ede | ||
|
|
0b478ebd5a | ||
|
|
388e03e261 | ||
|
|
b0b07e8edd | ||
|
|
1829f7d48a | ||
|
|
bcc3c885d7 | ||
|
|
e2a6dbc709 | ||
|
|
b32ca4af5d | ||
|
|
a2e728905e | ||
|
|
ead232be6f | ||
|
|
feaba85ba0 | ||
|
|
6a8822ca76 | ||
|
|
8fc6d93be4 | ||
|
|
97f8dc562a | ||
|
|
6616cd1d4c | ||
|
|
f9635cf03f | ||
|
|
49db87737f | ||
|
|
a414213255 | ||
|
|
59a8c21429 | ||
|
|
b67fda7a37 | ||
|
|
4392a61ab5 | ||
|
|
a9d96818ec | ||
|
|
6b285e48e9 | ||
|
|
532ef09acd | ||
|
|
f0f7bb96ad | ||
|
|
ecfb6c60c3 | ||
|
|
5be436f25c | ||
|
|
2ddc265b0f | ||
|
|
52af8ceb99 | ||
|
|
14a5060100 | ||
|
|
9d33586b44 | ||
|
|
d4f328157e | ||
|
|
c4331043f7 | ||
|
|
9945d8a069 | ||
|
|
2595d6ee91 | ||
|
|
95a0f9603c | ||
|
|
f16e024bbe | ||
|
|
87a5522acc | ||
|
|
2c812cdc3c | ||
|
|
f6e910038e | ||
|
|
5c7d96897d | ||
|
|
862d892c84 | ||
|
|
9246e1e8ee | ||
|
|
0715cb465f | ||
|
|
2e251972aa | ||
|
|
de89c11f24 | ||
|
|
7a1f96e31e | ||
|
|
d405b099b3 | ||
|
|
a8e4f87c59 | ||
|
|
74322e2f48 | ||
|
|
f16d233693 | ||
|
|
54d2711583 | ||
|
|
e54f179ccf | ||
|
|
40a37fedd2 | ||
|
|
3bc6c50d79 | ||
|
|
1ef9f44a1b | ||
|
|
f1ed339d9d | ||
|
|
f07930ef16 | ||
|
|
c6d18cda44 | ||
|
|
263b86e833 | ||
|
|
953560051d | ||
|
|
bf3904a214 | ||
|
|
c426f4154b | ||
|
|
a326eb3832 | ||
|
|
1708eb9b3e | ||
|
|
0dee18dbfd | ||
|
|
7ee7aaab76 | ||
|
|
3dd4f515dd | ||
|
|
f24310d043 | ||
|
|
61bfe02322 | ||
|
|
7cbcb30aff | ||
|
|
6fc8fa5b60 | ||
|
|
7763a6d3e7 | ||
|
|
1288469172 | ||
|
|
86cf79bff9 | ||
|
|
22441e0b09 | ||
|
|
8c6f7335a5 | ||
|
|
8418bc87c8 | ||
|
|
c747d089ca | ||
|
|
8c881ab85a | ||
|
|
ec43a78ae4 | ||
|
|
762a53923c | ||
|
|
1cf03d4a0d | ||
|
|
48f7be485f | ||
|
|
89364a9fd0 | ||
|
|
43d965f2a1 | ||
|
|
e4a698b04b | ||
|
|
824773150a | ||
|
|
33cfbf7d1c | ||
|
|
3dc285cc70 | ||
|
|
d6fbb70db0 | ||
|
|
150a5c668a | ||
|
|
09da392c36 | ||
|
|
94ad2f1250 | ||
|
|
6ddf048984 | ||
|
|
f396b63a34 | ||
|
|
e12d0bea66 | ||
|
|
253cfd55d8 | ||
|
|
1bf01a2826 | ||
|
|
e75d0c564f | ||
|
|
1e97143a6a | ||
|
|
4d1bf677a1 | ||
|
|
069f56acfd | ||
|
|
7b4e63001b | ||
|
|
bd4df4485e | ||
|
|
19cdc8fbef | ||
|
|
1408b94f06 | ||
|
|
58fba24f01 | ||
|
|
f49265ae52 | ||
|
|
de081dc514 | ||
|
|
001864e20c | ||
|
|
0c9fe19da3 | ||
|
|
28ebd1dec1 | ||
|
|
94bbc0e574 | ||
|
|
5bc4994091 | ||
|
|
034e7d315c | ||
|
|
2b992dfd51 | ||
|
|
fb785b4204 | ||
|
|
ac807ce25b | ||
|
|
c065f0f8fd | ||
|
|
9c7d286dd8 | ||
|
|
69d8e4fab9 | ||
|
|
b788fe3984 | ||
|
|
cfd90fac04 | ||
|
|
1cf2359195 | ||
|
|
6868d7f26c | ||
|
|
3e58229a89 | ||
|
|
d76f1524bd | ||
|
|
58b5eb155d | ||
|
|
fd9caa537b | ||
|
|
5262972a8d | ||
|
|
011a095314 | ||
|
|
3520c50541 | ||
|
|
3eccac861f | ||
|
|
7a85b0b690 | ||
|
|
ff3aa5d782 | ||
|
|
9e6dec8605 | ||
|
|
1fe223c772 | ||
|
|
d89ccc110e | ||
|
|
72c337195a | ||
|
|
28a2ec3fc0 | ||
|
|
72bba7fdfd | ||
|
|
a258e48582 | ||
|
|
21a15686b2 | ||
|
|
5da7183ae3 | ||
|
|
d847972bb1 | ||
|
|
5e88e73e3f | ||
|
|
e9086ec2bd | ||
|
|
866db464c4 | ||
|
|
3dbcc2d28c | ||
|
|
1538f12934 | ||
|
|
857f67604c | ||
|
|
ae49e3f977 | ||
|
|
ec01a03820 | ||
|
|
96cc3671da | ||
|
|
ad7c9c560c | ||
|
|
ee15ff6b35 | ||
|
|
b8e95bd210 | ||
|
|
b14465f2a1 | ||
|
|
ca83103703 | ||
|
|
1aeb894b09 | ||
|
|
8e9ab26963 | ||
|
|
44b4fbcfe3 | ||
|
|
42cc1dd8a9 | ||
|
|
2a60048f7e | ||
|
|
d69310e52c | ||
|
|
a0f89274d1 | ||
|
|
eefc125f24 | ||
|
|
f95f17d0c6 | ||
|
|
ba7e98e95c | ||
|
|
02067929a2 | ||
|
|
0bc3e8465b | ||
|
|
0ebf5712b9 | ||
|
|
4020e28da9 | ||
|
|
dbc074bfde | ||
|
|
17cdedf65f | ||
|
|
f96766505b | ||
|
|
fe96642be4 | ||
|
|
701af6cd8f | ||
|
|
5515fbfeda | ||
|
|
41a0dce7fc | ||
|
|
3b122b7bcc | ||
|
|
2b3500dfc3 | ||
|
|
e921253a57 | ||
|
|
da45797022 | ||
|
|
fc1f68711d | ||
|
|
da9c1f440c | ||
|
|
ae10ca9541 | ||
|
|
80d2f76dfc | ||
|
|
ebf3c9b82f | ||
|
|
af57ac45a2 | ||
|
|
0ad45df8f5 | ||
|
|
7f464f2e3e | ||
|
|
d8e209e4a2 | ||
|
|
41a87d0c8a | ||
|
|
45faed038f | ||
|
|
30a78f978d | ||
|
|
d8c1d50aa5 | ||
|
|
03f377cf0a | ||
|
|
eb7bf65e02 | ||
|
|
373092f572 | ||
|
|
c7d3164ff4 | ||
|
|
e6da43be6d | ||
|
|
8bfc0fefaf | ||
|
|
4e44807523 | ||
|
|
36251fea75 | ||
|
|
06206a7447 | ||
|
|
66e901f88d | ||
|
|
05f089d390 | ||
|
|
f52345036d | ||
|
|
bd99ff2bfd | ||
|
|
19510ca8ba | ||
|
|
23df8f70cf | ||
|
|
bd25e8682a | ||
|
|
0ece90bcf1 | ||
|
|
906cd54c98 | ||
|
|
c2894b4bf1 | ||
|
|
8c3958cdf0 | ||
|
|
92cb847755 | ||
|
|
fc4fed42b5 | ||
|
|
ea332515c4 | ||
|
|
49965d6856 | ||
|
|
a1897f69ca | ||
|
|
a88700969d | ||
|
|
91eb9e597e | ||
|
|
e762542e49 | ||
|
|
6e7694d650 | ||
|
|
a301779a42 | ||
|
|
440a07d1de | ||
|
|
b3e5734f39 | ||
|
|
fc7951cbcd | ||
|
|
2d5296288f | ||
|
|
44b58ab9a0 | ||
|
|
cab3f2bf38 | ||
|
|
d24a6fa75c | ||
|
|
fca867a8b8 | ||
|
|
9514c48eaa | ||
|
|
31efdc4254 | ||
|
|
34aace8a1b | ||
|
|
a877ad5a69 | ||
|
|
5a8c090055 | ||
|
|
98ccf39728 | ||
|
|
d029b4380a | ||
|
|
4c29c9726b | ||
|
|
af9fff9793 | ||
|
|
a8d84c4a28 | ||
|
|
5215388e33 | ||
|
|
93c7685ef7 | ||
|
|
5c395a1987 | ||
|
|
755d367760 | ||
|
|
3b26d24958 | ||
|
|
27afe40892 | ||
|
|
fcd4dccdad | ||
|
|
35e206a5d6 | ||
|
|
b51d007341 | ||
|
|
a85fd79818 | ||
|
|
3222e2ebca | ||
|
|
ba89ed1574 | ||
|
|
68ab953644 | ||
|
|
4d3030e20e | ||
|
|
2e324e65a1 | ||
|
|
a34b7481f5 | ||
|
|
d2a3905b03 | ||
|
|
16b3d76504 | ||
|
|
363fe76dd1 | ||
|
|
040a29f66e |
@@ -33,3 +33,12 @@ common/src/main/resources/assets/cobblemon/showdown
|
||||
# Generated files
|
||||
*/generated/resources/*
|
||||
/fabric/src/generated/resources/cobblemon-common.accesswidener
|
||||
/.ignored/
|
||||
|
||||
# Logs
|
||||
common/logs
|
||||
fabric/logs
|
||||
forge/logs
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
+123
-1
@@ -1,4 +1,124 @@
|
||||
# Changelog
|
||||
## [1.5.0](#1-5-0)
|
||||
### Additions
|
||||
- Added over (number here) ruin structures, where you can find Pokémon-themed Armor Trims and Pottery Sherds, Tumblestones, and more.
|
||||
- Added (number here) fossil structures, where you can brush Suspicious Sand/Gravel for Fossils.
|
||||
- Added the Data Monitor, Fossil Compartment, and Restoration Tank. Placed in the correct formation, you can use these to create a Restoration Machine where you can bring fossils back to life.
|
||||
- Added 3 variants of Tumblestones, which can be planted near Lava or Magma to grow harvestable Tumblestone Clusters.
|
||||
- Added Tumblestone Blocks, a storage block crafted from 9 Tumblestones.
|
||||
- Added Ancient Poké Balls, which are aesthetic variants crafted from Tumblestones.
|
||||
- Added the Ancient Feather, Wing, and Jet Balls, which fly further than regular Poké Balls.
|
||||
- Added the Ancient Heavy, Leaden, and Gigaton Balls, which are heavier and don't fly as far as regular Poké Balls. These will receive more functionality in a future update.
|
||||
- Added Original Trainer functionality. To edit the OT through commands, you must specify originaltrainertype=<Player/NPC>, and originaltrainer=<Username or UUID/NPC Name>
|
||||
- Added support for planting Apricorn trees, berries, and mints in [Botany Pots](https://modrinth.com/mod/botany-pots)
|
||||
- Added the hidden "True Vivillionaire" advancement.
|
||||
- The "Poké Ball" Vivillon variant is now obtainable by evolving a Spewpa after obtaining the "Aspiring Vivillionaire" advancement.
|
||||
- Added dynamic lighting support for any Species or Forms when using [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) or [Dynamic Lights Reforged](https://www.curseforge.com/minecraft/mc-mods/dynamiclights-reforged), at this time we don't ship with any defaults for this feature but addon creators can make use of this feature.
|
||||
- Added a Display Case block! Use it to display your archaeological findings, or other items.
|
||||
- Added 6 Pokémon-themed Pottery Sherds, obtained from ruin structures.
|
||||
- Added a Pokémon-themed armor trim, obtained from ruin structures.
|
||||
- You can now find Nether Fire Stone Ore in, surprisingly, the Nether.
|
||||
- Added effects for many Poké Balls when sending out Pokémon or capturing.
|
||||
- Added a new send-out ball toss animation that showcases the ball used for the Pokémon.
|
||||
- Added simple move animations for Pokémon in battle with a proof of concept for more complicated animations.
|
||||
- Added the EV Boosting Feathers.
|
||||
- Added Type Gems.
|
||||
- Added various new tags for searchability and better compatibility.
|
||||
- Added the [Ability Capsule](https://bulbapedia.bulbagarden.net/wiki/Ability_Capsule) and [Patch](https://bulbapedia.bulbagarden.net/wiki/Ability_Patch), these have no acquisition method for now and only work as intended with the traditional ability format of 1 to 2 common abilities and 1 hidden ability.
|
||||
- Added Gilded Chests, available in all Apricorn colors.
|
||||
- Added Relic Coins, Relic Coin Pouches, and Relic Coin Sacks.
|
||||
- Added Gimmighoul.
|
||||
- Using Relic Coins, you can increase Gimmighoul's Coin Stash. Upon reaching 999, it can be evolved into Gholdengo.
|
||||
- Additionally, if you give Gimmighoul a Netherite Scrap, you can increase its Netherite Stash. Who knows what might happen if it fills up?
|
||||
- Completed the advancement for placing a Tumblestone near Lava or Magma to make it grow.
|
||||
|
||||
### Changes
|
||||
- Pokémon now transition more smoothly between different poses.
|
||||
- Added more held items to the held item tag, and Metal Coat to the held item tab.
|
||||
- Added all ores to the modloader ore tags, and added tags for each ore type to the mod (both blocks and items).
|
||||
- Changed the Destiny Knot to be crafted with a Ghast Tear, rather than a diamond.
|
||||
- You can now punch grown apricorns to harvest them.
|
||||
- Renamed the "Vivillionaire" advancement to "Aspiring Vivillionaire"
|
||||
- Removed the Inferno, Forsaken, Poké Ball, and Void patterns from the Aspiring Vivillionaire advancement.
|
||||
- Updated movesets to add Gen 9 DLC moves.
|
||||
- Apricorn Sprouts can now be planted directly on Apricorn leaves to create a new Apricorn of the same color.
|
||||
- Added tooltips to interaction GUIs to make it clearer what they do.
|
||||
- Poké Ball recipes now use tags for their center ingredient, rather than specificied Copper Ingot, Iron Ingot, Gold Ingot, and Diamond, allowing for further datapack customisation.
|
||||
|
||||
### Fixes
|
||||
- Re-added the recipe for the Iron Vitamin.
|
||||
- Cleaned up empty evolutions declaration in species files (no, I'm not listing all 169 by name).
|
||||
- Fixed Exeggcute not being able to evolve.
|
||||
- Fixed battle lang for Poison Touch Ability
|
||||
- Fixed Cubone not being able to evolve into Alolan Marowak.
|
||||
- Fixed Squawkabilly forms not being recognized.
|
||||
- Fixed the bounce animation for Poké Balls being delayed by like, a full second.
|
||||
- Note blocks now play the correct sound on the Apricorn Plank based blocks.
|
||||
- Fixed an issue with transformed parts in posers causing whacky positional issues.
|
||||
- Fixed Poké Balls freezing in an open state if you look away when it's meant to close.
|
||||
- Adds a translation string name to the Empty Pokeball entity.
|
||||
- Fixed very many issues with Bedrock particle effects.
|
||||
- Fixed Arbok patterns not being as specific in spawning as they were intended.
|
||||
- Fixed Pokémon not avoiding danger at all when pathfinding.
|
||||
- Fixed Sobble line not being able to swim or breathe underwater.
|
||||
- Fixed incompatibility with [Just Enough Resources](https://modrinth.com/mod/just-enough-resources-jer).
|
||||
- Fixed incompatibility with [Visual Overhaul](https://modrinth.com/mod/visual-overhaul).
|
||||
- Fixed an issue that allowed Pokemon to spawn on rails.
|
||||
- Fixed the data set on Pokémon when abilities are given via properties such as in ``/spawnpokemon``.
|
||||
- Fixed sometimes Pokémon losing hidden abilities when evolving, this fix will only take effect to newly created Pokémon.
|
||||
|
||||
### Developer
|
||||
- Significantly changed the way properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed).
|
||||
- Rebuilt the scheduling API to more clearly force side choices and temporal frames of reference for tasks.
|
||||
- Added dialogue API and data registry.
|
||||
- Opened up the ItemDropEntry class to allow for it to be extended.
|
||||
- Added a new "advancement" evolution variant that takes an advancement identifier and succeeds if the player has the advancement.
|
||||
- Made spawning API capable of non-entity spawning
|
||||
- Made PokemonProperties.parse more interoperable with Java.
|
||||
- Added the ``HeldItemEvent``, this comes with 2 implementation ``HeldItemEvent.Pre`` and ``HeldItemEvent.Post``.
|
||||
- API to support dynamic lighting in any mod that implements this feature has been added to all Species & Forms, see LightingData class for details.
|
||||
- Added a Mixin for the BrewingStandScreenHandler to fix the incorrect handling of quickMove in Fabric.
|
||||
- Corrections to the ability implementation have been made that make ``Ability.forced`` function as intended and never reroll an ability for a Pokémon, please check your implementations to ensure the corrected behavior is intended for your use case.
|
||||
- ``Pokemon.ability`` no longer has a public setter, please migrate to using ``Pokemon#updateAbility``, this handles the ability coordinate storage for you when necessary.
|
||||
- ``Ability.forced``, ``Ability.index`` and ``Ability.priority`` have all had their setters internalized, there is no longer any need to manually adjust these migrate to the method mentioned above to handle that process for you.
|
||||
- ``AbilityChanger`` has been added to API alongside some implementations, this is subject to change as the ability capsule and patch currently only expect the traditional behaviour in the Pokémon games of 1 to 2 regular abilities and 1 hidden.
|
||||
- ``Pokemon#rollAbility`` has been added, this rerolls a legal ability for the Pokémon.
|
||||
|
||||
### Datapack & Resourcepack Creators
|
||||
- The maximum amount of fossils that can fit in the Fossil Analyzer can be adjusted in the config.
|
||||
- Custom fossils can be defined using a list of items and the resulting Pokémon. An example of `aerodactyl.json`:
|
||||
```JSON
|
||||
{
|
||||
"result": "aerodactyl",
|
||||
"fossils": [
|
||||
"cobblemon:old_amber_fossil"
|
||||
]
|
||||
}
|
||||
```
|
||||
- Fetus models can be defined in `bedrock/fossils`.
|
||||
- Fetus textures can be defined in `textures/fossils`.
|
||||
- Fuel for the Restoration Machine is registered inside the `natural_materials` folder. To register more fuels, create a JSON file containing an array of objects. Each object supports the following fields:
|
||||
- `content`: Integer containing the amount of fuel to add.
|
||||
- `item` OR `tag`: Identifier of the item or item tag to be inserted.
|
||||
- `returnItem`: Identifier of an item to return to the player after consumption.
|
||||
- Added 3 new item tags: `ancient_poke_balls`, `fossils`, and `tumblestones`.
|
||||
- Added a spawn rules system to modify general spawning behaviour, see the [wiki](https://wiki.cobblemon.com/index.php/Spawn_Rules) for more information.
|
||||
- Added dialogue datapack folder and /opendialogue command.
|
||||
- Added the item tag ``cobblemon:held/leaves_leftovers`` this can be used to flag apple-like items that can create leftovers when eaten.
|
||||
- You can now add support for dynamic lighting implementations, Cobblemon ships with a default implementation for [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) and the [Dynamic Lights Reforged](https://www.curseforge.com/minecraft/mc-mods/dynamiclights-reforged), add the following to any species or form:
|
||||
```JSON
|
||||
{
|
||||
"lightingData": {
|
||||
"lightLevel": 14,
|
||||
"_lightLevelCommentRemoveMe": "Above supports 0 to 15",
|
||||
"liquidGlowMode": "LAND",
|
||||
"_liquidGlowModeCommentRemoveMe": "Above supports LAND, UNDERWATER or BOTH"
|
||||
}
|
||||
}
|
||||
```
|
||||
- Following up on this change ``light_source`` was removed as a possible shoulder effect due to becoming unnecessary and never having had a default implementation.
|
||||
- Added the item tag ``cobblemon:ability_changers``, contains the ``cobblemon:ability_capsule`` & ``cobblemon:ability_patch`` by default.
|
||||
|
||||
## [1.4.1 (December 23rd, 2023)](#1-4-1)
|
||||
|
||||
### Additions
|
||||
@@ -15,6 +135,7 @@
|
||||
- Added cries to Beldum, Metang and Metagross.
|
||||
- Added a /bedrockparticle command to run Snowstorm-format particle effects.
|
||||
- Added data for Dipplin, Fezandipiti, Munkidori, Ogerpon, Okidogi, Poltchageist and Sinistcha.
|
||||
- Added additional nickname trigger "Grumm" for Inkay's evolution.
|
||||
|
||||
### Changes
|
||||
- Using Potions, Status Heals, Ethers, and Antidotes will now return a glass bottle
|
||||
@@ -100,6 +221,7 @@
|
||||
### Developer
|
||||
- Fixed the `SpawnEvent` not respecting usage of `Cancelable#cancel`.
|
||||
- Added the `EvolutionTestedEvent`, this allows listening and overriding the final result of evolution requirement tests.
|
||||
- Rebuilt the scheduling API to more clearly force side choices and allow more local temporal frames of reference for tasks.
|
||||
- Added utility script that can be used to generate all Spawn JSONS for all pokemon from the spawning spreadsheet in 1 click ([cobblemon_spawn_csv_to_json.py](utilityscripts%2Fcobblemon_spawn_csv_to_json.py)).
|
||||
- The `HeldItemManager` has a new method `shouldConsumeItem`, this will return false by default to prevent breaking changes, see the documentation and update your implementations as needed.
|
||||
- Added and implemented minSkyLight and maxSkyLight as config options for SpawnConditions
|
||||
@@ -931,4 +1053,4 @@ Thank you so much to all of our community translators that bring the mod to the
|
||||
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
|
||||
|
||||
## [1.0.0 (November 12th, 2022)](#1-0-0)
|
||||
- Initial release.
|
||||
- Initial release.
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
base
|
||||
id("cobblemon.root-conventions")
|
||||
id ("net.nemerosa.versioning") version "2.8.2"
|
||||
}
|
||||
|
||||
group = "com.cobblemon.mod"
|
||||
@@ -8,5 +9,5 @@ version = "${project.property("mod_version")}+${project.property("mc_version")}"
|
||||
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
|
||||
if (isSnapshot) {
|
||||
version = "$version-SNAPSHOT"
|
||||
}
|
||||
version = "$version-${versioning.info.branch}-${versioning.info.build}-SNAPSHOT"
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ dependencies {
|
||||
modApi(libs.molang)
|
||||
compileOnlyApi(libs.jeiApi)
|
||||
modCompileOnly(libs.adornFabric)
|
||||
modCompileOnly(libs.lambDynamicLights) { isTransitive = false }
|
||||
|
||||
// For Showdown
|
||||
modCompileOnly(libs.graal)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
[19:57:25] [Test worker/INFO]: Booting LaxPermissionValidator, permissions will be checked using Minecrafts permission level system, see https://minecraft.fandom.com/wiki/Permission_level
|
||||
-3
@@ -8,12 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pose;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityModel;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@@ -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.compat;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonEntities;
|
||||
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokemon.FormData;
|
||||
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightHandler;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightHandlers;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
// Java class due to relying on entrypoint on Fabric side
|
||||
public class LambDynamicLightsCompat {
|
||||
|
||||
// This is all called on client side
|
||||
// These things are checked every tick so try to keep it as free as possible
|
||||
// That being said it's unlikely school Toshiba person is running dynamic lighting and shaders to enjoy this
|
||||
// Make sure not to call anything Fabric specific :)
|
||||
public static void hookCompat() {
|
||||
// Pokémon entities
|
||||
DynamicLightHandlers.registerDynamicLightHandler(
|
||||
CobblemonEntities.POKEMON,
|
||||
DynamicLightHandler.makeHandler(
|
||||
pokemon -> resolvedPokemonLightLevel(pokemon, false),
|
||||
pokemon -> true
|
||||
)
|
||||
);
|
||||
DynamicLightHandlers.registerDynamicLightHandler(
|
||||
CobblemonEntities.POKEMON,
|
||||
DynamicLightHandler.makeHandler(
|
||||
pokemon -> resolvedPokemonLightLevel(pokemon, true),
|
||||
pokemon -> false
|
||||
)
|
||||
);
|
||||
|
||||
// Shouldered Pokémon
|
||||
DynamicLightHandlers.registerDynamicLightHandler(
|
||||
EntityType.PLAYER,
|
||||
DynamicLightHandler.makeHandler(
|
||||
player -> resolvedShoulderLightLevel(player, false),
|
||||
player -> true
|
||||
)
|
||||
);
|
||||
DynamicLightHandlers.registerDynamicLightHandler(
|
||||
EntityType.PLAYER,
|
||||
DynamicLightHandler.makeHandler(
|
||||
player -> resolvedShoulderLightLevel(player, true),
|
||||
player -> false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static int resolvedPokemonLightLevel(PokemonEntity pokemon, boolean underwater) {
|
||||
return extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
|
||||
}
|
||||
|
||||
private static int resolvedShoulderLightLevel(PlayerEntity player, boolean underwater) {
|
||||
final Pair<PokemonOnShoulderRenderer.ShoulderData, PokemonOnShoulderRenderer.ShoulderData> shoulderDataPair = PokemonOnShoulderRenderer.shoulderDataOf(player);
|
||||
final Optional<Integer> leftLightLevel = extractShoulderLightLevel(shoulderDataPair.getLeft(), underwater);
|
||||
final Optional<Integer> rightLightLevel = extractShoulderLightLevel(shoulderDataPair.getRight(), underwater);
|
||||
return Math.max(leftLightLevel.orElse(0), rightLightLevel.orElse(0));
|
||||
}
|
||||
|
||||
private static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
|
||||
if (form.getLightingData() == null || !liquidGlowModeSupport(form.getLightingData().getLiquidGlowMode(), underwater)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(form.getLightingData().getLightLevel());
|
||||
}
|
||||
|
||||
private static Optional<Integer> extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
|
||||
if (shoulderData == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return extractFormLightLevel(shoulderData.getForm(), underwater);
|
||||
}
|
||||
|
||||
private static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
|
||||
return underwater ? liquidGlowMode.getGlowsUnderwater() : liquidGlowMode.getGlowsInLand();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.sherds.CobblemonSherds;
|
||||
import net.minecraft.block.DecoratedPotPatterns;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
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(DecoratedPotPatterns.class)
|
||||
public abstract class DecoratedPotPatternsMixin {
|
||||
@Inject(method = "fromSherd", at=@At("HEAD"), cancellable = true)
|
||||
private static void cobblemon$getCobblemonSherdTexture(Item sherd,
|
||||
CallbackInfoReturnable<RegistryKey<String>> cir) {
|
||||
if (CobblemonSherds.INSTANCE.getSherdToPattern().containsKey(sherd)) {
|
||||
cir.setReturnValue(CobblemonSherds.INSTANCE.getSherdToPattern().get(sherd));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,20 +8,37 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTaskTracker;
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(GameRenderer.class)
|
||||
public class GameRendererMixin {
|
||||
@Unique
|
||||
long lastTime = -1;
|
||||
|
||||
@Inject(
|
||||
method = "render",
|
||||
at = @At(value = "TAIL")
|
||||
)
|
||||
public void render(float tickDelta, long startTime, boolean tick, CallbackInfo ci) {
|
||||
ScheduledTaskTracker.INSTANCE.update();
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
long newTime = System.currentTimeMillis();
|
||||
// Don't play scheduled animations when the game is paused
|
||||
if (client.isPaused()) {
|
||||
lastTime = newTime;
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastTime != -1) {
|
||||
ClientTaskTracker.INSTANCE.update((newTime - lastTime) / 1000F);
|
||||
}
|
||||
lastTime = newTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.CobblemonBakingOverrides;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import net.minecraft.client.render.model.ModelLoader;
|
||||
import net.minecraft.client.render.model.UnbakedModel;
|
||||
import net.minecraft.client.render.model.json.JsonUnbakedModel;
|
||||
import net.minecraft.client.util.ModelIdentifier;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
import org.slf4j.Logger;
|
||||
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.InjectionPoint;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.points.BeforeStringInvoke;
|
||||
|
||||
@Mixin(ModelLoader.class)
|
||||
public abstract class ModelLoaderMixin {
|
||||
|
||||
@Shadow protected abstract void addModel(ModelIdentifier modelId);
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private Map<Identifier, UnbakedModel> unbakedModels;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private static Logger LOGGER;
|
||||
|
||||
@Inject(
|
||||
method = "<init>",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
public void init(BlockColors blockColors,
|
||||
Profiler profiler,
|
||||
Map jsonUnbakedModels,
|
||||
Map blockStates,
|
||||
CallbackInfo ci) {
|
||||
CobblemonBakingOverrides.INSTANCE.getModels().forEach(bakingOverride -> {
|
||||
try {
|
||||
this.unbakedModels.put(bakingOverride.getModelIdentifier(), this.loadModelFromJson(bakingOverride.getModelLocation()));
|
||||
this.addModel(bakingOverride.getModelIdentifier());
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Error loading a Cobblemon BakedModel:", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private JsonUnbakedModel loadModelFromJson(Identifier id) throws IOException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.api.snowstorm.ParticleMaterials;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.client.particle.ParticleManager;
|
||||
import net.minecraft.client.particle.ParticleTextureSheet;
|
||||
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.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(ParticleManager.class)
|
||||
final class ParticleManagerMixin {
|
||||
@Mutable
|
||||
@Final
|
||||
@Shadow
|
||||
private static List<ParticleTextureSheet> PARTICLE_TEXTURE_SHEETS;
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "<clinit>")
|
||||
private static void lodestone$addTypes(CallbackInfo ci) {
|
||||
PARTICLE_TEXTURE_SHEETS = ImmutableList.<ParticleTextureSheet>builder().addAll(PARTICLE_TEXTURE_SHEETS)
|
||||
.add(ParticleMaterials.INSTANCE.getADD(), ParticleMaterials.INSTANCE.getALPHA(), ParticleMaterials.INSTANCE.getBLEND(), ParticleMaterials.INSTANCE.getOPAQUE()).build();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import net.minecraft.entity.mob.PiglinBrain;
|
||||
import net.minecraft.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(PiglinBrain.class)
|
||||
public class PiglinBarterMixin {
|
||||
|
||||
@Inject(method = "acceptsForBarter", at = @At(value = "RETURN"), cancellable = true)
|
||||
private static void cobblemon$acceptsForBarter(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
if(!ci.getReturnValue()) {
|
||||
//TODO: Make a tag?
|
||||
if(stack.isOf(CobblemonItems.RELIC_COIN_POUCH))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.CobblemonItems;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.mob.PiglinEntity;
|
||||
import net.minecraft.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(PiglinEntity.class)
|
||||
public abstract class PiglinEntityMixin {
|
||||
@Inject(method = "equipToOffHand", at = @At(value = "HEAD"), cancellable = true)
|
||||
public void cobblemon$isValidBarteringItem(ItemStack stack, CallbackInfo ci) {
|
||||
PiglinEntity entity = (PiglinEntity)(Object) this;
|
||||
if (stack.isOf(CobblemonItems.RELIC_COIN_POUCH)) {
|
||||
entity.equipStack(EquipmentSlot.OFFHAND, stack);
|
||||
entity.updateDropChances(EquipmentSlot.OFFHAND);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents;
|
||||
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
||||
import com.cobblemon.mod.common.api.storage.NoPokemonStoreException;
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon;
|
||||
import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
|
||||
import com.cobblemon.mod.common.util.DataKeys;
|
||||
@@ -22,11 +23,8 @@ import net.minecraft.entity.ItemEntity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.world.World;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
@@ -40,8 +38,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.cobblemon.mod.common.util.LocalizationUtilsKt.lang;
|
||||
|
||||
@Mixin(PlayerEntity.class)
|
||||
public abstract class PlayerMixin extends LivingEntity {
|
||||
|
||||
@@ -144,7 +140,7 @@ public abstract class PlayerMixin extends LivingEntity {
|
||||
)
|
||||
public void onEatFood(World world, ItemStack stack, CallbackInfoReturnable<ItemStack> cir) {
|
||||
if (!getWorld().isClient) {
|
||||
if (stack.getItem() == Items.APPLE && getWorld().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
|
||||
if (stack.isIn(CobblemonItemTags.LEAVES_LEFTOVERS) && getWorld().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
|
||||
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS);
|
||||
ServerPlayerEntity player = Objects.requireNonNull(getServer()).getPlayerManager().getPlayer(uuid);
|
||||
assert player != null;
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.cobblemon.mod.common.mixin.invoker;
|
||||
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.BlockSetType;
|
||||
import net.minecraft.block.PressurePlateBlock;
|
||||
import net.minecraft.resource.featuretoggle.FeatureSet;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.screen.ScreenHandlerType.Factory;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(ScreenHandlerType.class)
|
||||
public interface ScreenHandlerTypeInvoker {
|
||||
@Invoker("<init>")
|
||||
static <T extends ScreenHandler> ScreenHandlerType<T> cobblemon$create(Factory<T> factory, FeatureSet requiredFeatures) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.render.model.BakedModel
|
||||
import net.minecraft.client.util.ModelIdentifier
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Contains information for forcing a model to be baked
|
||||
*
|
||||
* @param modelLocation The location of the model
|
||||
* @param modelIdentifier The identifier that the BakedModel will be registered to
|
||||
*/
|
||||
data class BakingOverride(
|
||||
val modelLocation: Identifier,
|
||||
val modelIdentifier: ModelIdentifier
|
||||
) {
|
||||
fun getModel(): BakedModel {
|
||||
return MinecraftClient.getInstance().bakedModelManager.getModel(modelIdentifier)
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,11 @@ import com.cobblemon.mod.common.api.drop.ItemDropEntry
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.BATTLE_VICTORY
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.EVOLUTION_COMPLETE
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.HELD_ITEM_UPDATED
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.LEVEL_UP_EVENT
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_CAPTURED
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.TRADE_COMPLETED
|
||||
import com.cobblemon.mod.common.api.net.serializers.IdentifierDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.Vec3DataSerializer
|
||||
@@ -33,15 +35,14 @@ import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroups
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.StandardExperienceCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.*
|
||||
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.EvCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Generation8EvCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.StatProvider
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
|
||||
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
|
||||
@@ -54,6 +55,7 @@ import com.cobblemon.mod.common.api.storage.adapter.flatfile.FileStoreAdapter
|
||||
import com.cobblemon.mod.common.api.storage.adapter.flatfile.JSONStoreAdapter
|
||||
import com.cobblemon.mod.common.api.storage.adapter.flatfile.NBTStoreAdapter
|
||||
import com.cobblemon.mod.common.api.storage.factory.FileBackedPokemonStoreFactory
|
||||
import com.cobblemon.mod.common.api.storage.molang.NbtMoLangDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCStore
|
||||
import com.cobblemon.mod.common.api.storage.pc.link.PCLinkManager
|
||||
import com.cobblemon.mod.common.api.storage.player.PlayerDataStoreManager
|
||||
@@ -67,6 +69,7 @@ import com.cobblemon.mod.common.battles.BattleSide
|
||||
import com.cobblemon.mod.common.battles.ShowdownThread
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.command.argument.DialogueArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.MoveArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.PartySlotArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.PokemonArgumentType
|
||||
@@ -80,6 +83,7 @@ import com.cobblemon.mod.common.config.starter.StarterConfig
|
||||
import com.cobblemon.mod.common.data.CobblemonDataProvider
|
||||
import com.cobblemon.mod.common.events.AdvancementHandler
|
||||
import com.cobblemon.mod.common.events.ServerTickHandler
|
||||
import com.cobblemon.mod.common.item.CobblemonItem
|
||||
import com.cobblemon.mod.common.item.PokeBallItem
|
||||
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
||||
import com.cobblemon.mod.common.permission.LaxPermissionValidator
|
||||
@@ -90,10 +94,12 @@ import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
|
||||
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.misc.GimmighoulStashHandler
|
||||
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.sherds.CobblemonSherds
|
||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||
import com.cobblemon.mod.common.trade.TradeManager
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
@@ -125,6 +131,7 @@ import net.minecraft.entity.data.TrackedDataHandlerRegistry
|
||||
import net.minecraft.item.Items
|
||||
import net.minecraft.item.NameTagItem
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.sound.SoundCategory
|
||||
import net.minecraft.util.WorldSavePath
|
||||
import net.minecraft.world.World
|
||||
import org.apache.logging.log4j.LogManager
|
||||
@@ -153,6 +160,7 @@ object Cobblemon {
|
||||
val bestSpawner = BestSpawner
|
||||
val battleRegistry = BattleRegistry
|
||||
var storage = PokemonStoreManager()
|
||||
var molangData = NbtMoLangDataStoreFactory
|
||||
lateinit var playerData: PlayerDataStoreManager
|
||||
lateinit var starterConfig: StarterConfig
|
||||
val dataProvider: DataProvider = CobblemonDataProvider
|
||||
@@ -224,6 +232,9 @@ object Cobblemon {
|
||||
}
|
||||
}
|
||||
|
||||
// Register the grow_tumblestone advancement
|
||||
PlatformEvents.RIGHT_CLICK_BLOCK.subscribe { AdvancementHandler.onTumbleStonePlaced(it) }
|
||||
|
||||
PlatformEvents.CHANGE_DIMENSION.subscribe {
|
||||
it.player.party().forEach { pokemon -> pokemon.entity?.recallWithAnimation() }
|
||||
}
|
||||
@@ -231,6 +242,7 @@ object Cobblemon {
|
||||
TrackedDataHandlerRegistry.register(Vec3DataSerializer)
|
||||
TrackedDataHandlerRegistry.register(StringSetDataSerializer)
|
||||
TrackedDataHandlerRegistry.register(PoseTypeDataSerializer)
|
||||
TrackedDataHandlerRegistry.register(IdentifierDataSerializer)
|
||||
|
||||
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
|
||||
}
|
||||
@@ -246,6 +258,7 @@ object Cobblemon {
|
||||
|
||||
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
|
||||
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
|
||||
SpeciesFeatures.types["integer"] = IntSpeciesFeatureProvider::class.java
|
||||
|
||||
SpeciesFeatures.register(
|
||||
DataKeys.CAN_BE_MILKED,
|
||||
@@ -260,9 +273,15 @@ object Cobblemon {
|
||||
|
||||
ifDedicatedServer {
|
||||
isDedicatedServer = true
|
||||
PlatformEvents.SERVER_TICK_POST.subscribe { ScheduledTaskTracker.update() }
|
||||
}
|
||||
|
||||
PlatformEvents.SERVER_TICK_POST.subscribe {
|
||||
ServerTaskTracker.update(1/20F)
|
||||
ServerRealTimeTaskTracker.update()
|
||||
}
|
||||
PlatformEvents.SERVER_TICK_PRE.subscribe {
|
||||
ServerRealTimeTaskTracker.update()
|
||||
}
|
||||
PlatformEvents.SERVER_STARTING.subscribe { event ->
|
||||
val server = event.server
|
||||
playerData = PlayerDataStoreManager().also { it.setup(server) }
|
||||
@@ -375,6 +394,8 @@ object Cobblemon {
|
||||
true
|
||||
).ifSuccessful { it.mute = true }
|
||||
}
|
||||
|
||||
CobblemonSherds.registerSherds()
|
||||
}
|
||||
|
||||
fun getLevel(dimension: RegistryKey<World>): World? {
|
||||
@@ -478,6 +499,7 @@ object Cobblemon {
|
||||
this.implementation.registerCommandArgument(cobblemonResource("move"), MoveArgumentType::class, ConstantArgumentSerializer.of(MoveArgumentType::move))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("party_slot"), PartySlotArgumentType::class, ConstantArgumentSerializer.of(PartySlotArgumentType::partySlot))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("pokemon_store"), PokemonStoreArgumentType::class, ConstantArgumentSerializer.of(PokemonStoreArgumentType::pokemonStore))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("dialogue"), DialogueArgumentType::class, ConstantArgumentSerializer.of(DialogueArgumentType::dialogue))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
import net.minecraft.entity.ai.brain.Activity
|
||||
|
||||
object CobblemonActivities {
|
||||
val activities = mutableListOf<Activity>()
|
||||
val BATTLING_ACTIVITY = Activity("pokemon_battling")
|
||||
|
||||
fun register(activity: Activity): Activity {
|
||||
activities.add(activity)
|
||||
return activity
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,16 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.PCBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.FossilAnalyzerBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||
import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
|
||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
||||
import com.cobblemon.mod.common.block.entity.*
|
||||
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.block.entity.BlockEntityType
|
||||
import net.minecraft.registry.Registries
|
||||
@@ -23,14 +32,57 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
|
||||
@JvmField
|
||||
val HEALING_MACHINE: BlockEntityType<HealingMachineBlockEntity> = this.create("healing_machine", BlockEntityType.Builder.create(::HealingMachineBlockEntity, CobblemonBlocks.HEALING_MACHINE).build(null))
|
||||
|
||||
@JvmField
|
||||
val PC: BlockEntityType<PCBlockEntity> = this.create("pc", BlockEntityType.Builder.create(::PCBlockEntity, CobblemonBlocks.PC).build(null))
|
||||
|
||||
@JvmField
|
||||
val BERRY = this.create("berry", BlockEntityType.Builder.create(::BerryBlockEntity, *CobblemonBlocks.berries().values.toTypedArray()).build(null))
|
||||
|
||||
@JvmField
|
||||
val PASTURE: BlockEntityType<PokemonPastureBlockEntity> = this.create("pasture", BlockEntityType.Builder.create(::PokemonPastureBlockEntity, CobblemonBlocks.PASTURE).build(null))
|
||||
@JvmField
|
||||
val SIGN: BlockEntityType<CobblemonSignBlockEntity> = this.create("sign", BlockEntityType.Builder.create(::CobblemonSignBlockEntity, CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN).build(null))
|
||||
@JvmField
|
||||
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.create(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN).build(null))
|
||||
@JvmField
|
||||
val TM_BLOCK: BlockEntityType<TMBlockEntity> = this.create("tm_block", BlockEntityType.Builder.create(::TMBlockEntity, CobblemonBlocks.TM_MACHINE).build(null))
|
||||
|
||||
}
|
||||
@JvmField
|
||||
val GILDED_CHEST: BlockEntityType<GildedChestBlockEntity> = this.create("chest", BlockEntityType.Builder.create(::GildedChestBlockEntity,
|
||||
CobblemonBlocks.GILDED_CHEST,
|
||||
CobblemonBlocks.BLUE_GILDED_CHEST,
|
||||
CobblemonBlocks.YELLOW_GILDED_CHEST,
|
||||
CobblemonBlocks.PINK_GILDED_CHEST,
|
||||
CobblemonBlocks.BLACK_GILDED_CHEST,
|
||||
CobblemonBlocks.WHITE_GILDED_CHEST,
|
||||
CobblemonBlocks.GREEN_GILDED_CHEST,
|
||||
CobblemonBlocks.GIMMIGHOUL_CHEST
|
||||
).build(null))
|
||||
|
||||
@JvmField
|
||||
val FOSSIL_MULTIBLOCK: BlockEntityType<FossilMultiblockEntity> = this.create("fossil_multiblock",
|
||||
BlockEntityType.Builder.create({ pos, state -> FossilMultiblockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
||||
CobblemonBlocks.MONITOR
|
||||
).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val RESTORATION_TANK: BlockEntityType<RestorationTankBlockEntity> = this.create("restoration_tank",
|
||||
BlockEntityType.Builder.create({ pos, state -> RestorationTankBlockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
||||
CobblemonBlocks.RESTORATION_TANK
|
||||
).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val FOSSIL_ANALYZER: BlockEntityType<FossilAnalyzerBlockEntity> = this.create("fossil_analyzer",
|
||||
BlockEntityType.Builder.create({ pos, state -> FossilAnalyzerBlockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
||||
CobblemonBlocks.FOSSIL_ANALYZER
|
||||
).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val DISPLAY_CASE: BlockEntityType<DisplayCaseBlockEntity> = this.create("display_case",
|
||||
BlockEntityType.Builder.create(::DisplayCaseBlockEntity, CobblemonBlocks.DISPLAY_CASE).build(null)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ package com.cobblemon.mod.common
|
||||
import com.cobblemon.mod.common.api.apricorn.Apricorn
|
||||
import com.cobblemon.mod.common.block.*
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
import com.cobblemon.mod.common.block.FossilAnalyzerBlock
|
||||
import com.cobblemon.mod.common.block.MonitorBlock
|
||||
import com.cobblemon.mod.common.block.RestorationTankBlock
|
||||
import com.cobblemon.mod.common.mixin.invoker.DoorBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.PressurePlateBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.StairsBlockInvoker
|
||||
@@ -19,11 +22,13 @@ import com.cobblemon.mod.common.mixin.invoker.*
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.block.BerryBlock
|
||||
import com.cobblemon.mod.common.block.chest.GildedChestBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
|
||||
import net.minecraft.block.*
|
||||
import net.minecraft.block.enums.Instrument
|
||||
import net.minecraft.block.piston.PistonBehavior
|
||||
import net.minecraft.entity.effect.StatusEffects
|
||||
import net.minecraft.registry.Registries
|
||||
@@ -53,6 +58,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore")
|
||||
@JvmField
|
||||
val NETHER_FIRE_STONE_ORE = evolutionStoneOre("nether_fire_stone_ore")
|
||||
@JvmField
|
||||
val ICE_STONE_ORE = evolutionStoneOre("ice_stone_ore")
|
||||
@JvmField
|
||||
val LEAF_STONE_ORE = evolutionStoneOre("leaf_stone_ore")
|
||||
@@ -100,17 +107,17 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val STRIPPED_APRICORN_WOOD = log("stripped_apricorn_wood")
|
||||
@JvmField
|
||||
val APRICORN_PLANKS = this.create("apricorn_planks", Block(AbstractBlock.Settings.create().mapColor(MapColor.DIRT_BROWN).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
val APRICORN_PLANKS = this.create("apricorn_planks", Block(AbstractBlock.Settings.create().mapColor(MapColor.DIRT_BROWN).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
@JvmField
|
||||
val APRICORN_LEAVES = leaves("apricorn_leaves")
|
||||
@JvmField
|
||||
val APRICORN_FENCE = this.create("apricorn_fence", FenceBlock(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
val APRICORN_FENCE = this.create("apricorn_fence", FenceBlock(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
@JvmField
|
||||
val APRICORN_FENCE_GATE = this.create("apricorn_fence_gate", FenceGateBlock(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD), APRICORN_WOOD_TYPE))
|
||||
val APRICORN_FENCE_GATE = this.create("apricorn_fence_gate", FenceGateBlock(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD), APRICORN_WOOD_TYPE))
|
||||
@JvmField // Note At the time of 1.20.0 we don't need our own BlockSetType for Apricorn wood
|
||||
val APRICORN_BUTTON = this.create("apricorn_button", BlocksInvoker.createWoodenButtonBlock(BlockSetType.OAK))
|
||||
@JvmField
|
||||
val APRICORN_PRESSURE_PLATE = this.create("apricorn_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(PressurePlateBlock.ActivationRule.EVERYTHING, AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD), APRICORN_BLOCK_SET_TYPE))
|
||||
val APRICORN_PRESSURE_PLATE = this.create("apricorn_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(PressurePlateBlock.ActivationRule.EVERYTHING, AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD), APRICORN_BLOCK_SET_TYPE))
|
||||
@JvmField
|
||||
val APRICORN_SIGN = this.create("apricorn_sign", CobblemonSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_SIGN), APRICORN_WOOD_TYPE))
|
||||
@JvmField
|
||||
@@ -120,13 +127,13 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val APRICORN_WALL_HANGING_SIGN = this.create("apricorn_wall_hanging_sign", CobblemonWallHangingSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_HANGING_SIGN), APRICORN_WOOD_TYPE))
|
||||
@JvmField
|
||||
val APRICORN_SLAB = this.create("apricorn_slab", SlabBlock(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
val APRICORN_SLAB = this.create("apricorn_slab", SlabBlock(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
@JvmField
|
||||
val APRICORN_STAIRS = this.create("apricorn_stairs", StairsBlockInvoker.`cobblemon$create`(APRICORN_PLANKS.defaultState, AbstractBlock.Settings.copy(APRICORN_PLANKS)))
|
||||
@JvmField
|
||||
val APRICORN_DOOR = this.create("apricorn_door", DoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque(), APRICORN_BLOCK_SET_TYPE))
|
||||
val APRICORN_DOOR = this.create("apricorn_door", DoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque(), APRICORN_BLOCK_SET_TYPE))
|
||||
@JvmField
|
||||
val APRICORN_TRAPDOOR = this.create("apricorn_trapdoor", TrapdoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque().allowsSpawning { _, _, _, _ -> false }, APRICORN_BLOCK_SET_TYPE))
|
||||
val APRICORN_TRAPDOOR = this.create("apricorn_trapdoor", TrapdoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).instrument(Instrument.BASS).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque().allowsSpawning { _, _, _, _ -> false }, APRICORN_BLOCK_SET_TYPE))
|
||||
|
||||
private val PLANT_PROPERTIES = AbstractBlock.Settings.create().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.GRASS).pistonBehavior(PistonBehavior.DESTROY)
|
||||
@JvmField
|
||||
@@ -145,14 +152,66 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
val YELLOW_APRICORN_SAPLING = this.create("yellow_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.YELLOW))
|
||||
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
|
||||
@JvmField
|
||||
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.ROOTS)))
|
||||
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.ENERGY_ROOT_SOUNDS)))
|
||||
@JvmField
|
||||
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.ROOTS)))
|
||||
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.BIG_ROOT_SOUNDS)))
|
||||
@JvmField
|
||||
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).mapColor(MapColor.DARK_GREEN).burnable().noCollision().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_TUMBLESTONE = tumblestoneBlock("large_budding_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, TUMBLESTONE_CLUSTER)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_TUMBLESTONE = tumblestoneBlock("medium_budding_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_TUMBLESTONE)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_TUMBLESTONE = tumblestoneBlock("small_budding_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_TUMBLESTONE)
|
||||
|
||||
@JvmField
|
||||
val SKY_TUMBLESTONE_CLUSTER = tumblestoneBlock("sky_tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("large_budding_sky_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, SKY_TUMBLESTONE_CLUSTER)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("medium_budding_sky_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_SKY_TUMBLESTONE)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("small_budding_sky_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_SKY_TUMBLESTONE)
|
||||
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_CLUSTER = tumblestoneBlock("black_tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("large_budding_black_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, BLACK_TUMBLESTONE_CLUSTER)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("medium_budding_black_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_BLACK_TUMBLESTONE)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("small_budding_black_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_BLACK_TUMBLESTONE)
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_BLOCK = this.create("tumblestone_block", Block(AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.TERRACOTTA_ORANGE)
|
||||
.strength(1.0F)
|
||||
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
|
||||
.requiresTool()
|
||||
.instrument(Instrument.BASEDRUM)
|
||||
))
|
||||
@JvmField
|
||||
val SKY_TUMBLESTONE_BLOCK = this.create("sky_tumblestone_block", Block(AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.LIGHT_BLUE)
|
||||
.strength(1.0F)
|
||||
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
|
||||
.requiresTool()
|
||||
.instrument(Instrument.BASEDRUM)
|
||||
))
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_BLOCK = this.create("black_tumblestone_block", Block(AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.TERRACOTTA_BLACK)
|
||||
.strength(1.0F)
|
||||
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
|
||||
.requiresTool()
|
||||
.instrument(Instrument.BASEDRUM)
|
||||
))
|
||||
|
||||
@JvmField
|
||||
val BLACK_APRICORN = apricornBlock("black_apricorn", Apricorn.BLACK)
|
||||
@JvmField
|
||||
@@ -168,6 +227,138 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val YELLOW_APRICORN = apricornBlock("yellow_apricorn", Apricorn.YELLOW)
|
||||
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH = create(
|
||||
"relic_coin_pouch",
|
||||
CoinPouchBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.strength(0.4f)
|
||||
.nonOpaque(), true
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val RELIC_COIN_SACK = create(
|
||||
"relic_coin_sack",
|
||||
CoinPouchBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.strength(0.4f), false
|
||||
))
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST = create(
|
||||
"gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.RED
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BLUE_GILDED_CHEST = create(
|
||||
"blue_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.BLUE
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BLACK_GILDED_CHEST = create(
|
||||
"black_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.BLACK
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val YELLOW_GILDED_CHEST = create(
|
||||
"yellow_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.YELLOW
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val WHITE_GILDED_CHEST = create(
|
||||
"white_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.WHITE
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GREEN_GILDED_CHEST = create(
|
||||
"green_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.GREEN
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val PINK_GILDED_CHEST = create(
|
||||
"pink_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.PINK
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GIMMIGHOUL_CHEST = create(
|
||||
"gimmighoul_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.FAKE
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MONITOR = create(
|
||||
"monitor",
|
||||
MonitorBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.IRON_GRAY)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
.pistonBehavior(PistonBehavior.BLOCK)
|
||||
.requiresTool()
|
||||
.strength(5.0F, 6.0F)
|
||||
.luminance { if (it.get(MonitorBlock.SCREEN) != MonitorBlock.MonitorScreen.OFF) 15 else 0 }
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val FOSSIL_ANALYZER = create(
|
||||
"fossil_analyzer",
|
||||
FossilAnalyzerBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.IRON_GRAY)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
.pistonBehavior(PistonBehavior.BLOCK)
|
||||
.requiresTool()
|
||||
.strength(5.0F, 6.0F)
|
||||
.nonOpaque()
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val RESTORATION_TANK = create(
|
||||
"restoration_tank",
|
||||
RestorationTankBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.IRON_GRAY)
|
||||
.sounds(BlockSoundGroup.GLASS)
|
||||
.pistonBehavior(PistonBehavior.BLOCK)
|
||||
.requiresTool()
|
||||
.strength(5.0F, 6.0F)
|
||||
.nonOpaque()
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val HEALING_MACHINE = create(
|
||||
"healing_machine",
|
||||
@@ -194,19 +385,55 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
.luminance { if ((it.get(PCBlock.ON) as Boolean) && (it.get(PCBlock.PART) == PCBlock.PCPart.TOP)) 10 else 0 }
|
||||
)
|
||||
)
|
||||
val TM_MACHINE = create(
|
||||
"tm_machine",
|
||||
TMBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.GREEN)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
.pistonBehavior(PistonBehavior.BLOCK)
|
||||
.nonOpaque()
|
||||
.luminance { if (it.get(TMBlock.ON) as Boolean) 10 else 0 }
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val DISPLAY_CASE = create(
|
||||
"display_case",
|
||||
DisplayCaseBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.DISPLAY_CASE_SOUNDS)
|
||||
.nonOpaque()
|
||||
.pistonBehavior(PistonBehavior.BLOCK)
|
||||
.mapColor(MapColor.STONE_GRAY)
|
||||
.strength(0.3f)
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val MODIFICATION_STATION = create(
|
||||
"modification_station",
|
||||
ModStationBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(BlockSoundGroup.WOOD)
|
||||
.nonOpaque()
|
||||
.pistonBehavior(PistonBehavior.BLOCK)
|
||||
.mapColor(MapColor.BROWN)
|
||||
.strength(0.3f)
|
||||
)
|
||||
)
|
||||
|
||||
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val WHITE_MINT = create("white_mint", MintBlock(MintType.WHITE, AbstractBlock.Settings.create().mapColor(MapColor.WHITE).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val WHITE_MINT = create("white_mint", MintBlock(MintType.WHITE, AbstractBlock.Settings.create().mapColor(MapColor.WHITE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
|
||||
@JvmField
|
||||
val PASTURE = create(
|
||||
@@ -229,6 +456,67 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val POTTED_PEP_UP_FLOWER = this.create("potted_pep_up_flower", BlocksInvoker.createFlowerPotBlock(PEP_UP_FLOWER))
|
||||
|
||||
@JvmField
|
||||
val NORMAL_TYPE_GEM_BLOCK = this.create("normal_type_gem_block", Block(AbstractBlock.Settings.copy(Blocks.AMETHYST_BLOCK)))
|
||||
@JvmField
|
||||
val NORMAL_TYPE_GEM = typeGem(
|
||||
"normal_type_gem",
|
||||
GrowableStoneBlock.STAGE_3,
|
||||
7,
|
||||
3,
|
||||
null,
|
||||
NORMAL_TYPE_GEM_BLOCK
|
||||
)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_NORMAL_TYPE_GEM = typeGem(
|
||||
"large_budding_normal_type_gem",
|
||||
GrowableStoneBlock.STAGE_2,
|
||||
5,
|
||||
3,
|
||||
NORMAL_TYPE_GEM,
|
||||
NORMAL_TYPE_GEM_BLOCK
|
||||
)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_NORMAL_TYPE_GEM = typeGem(
|
||||
"medium_budding_normal_type_gem",
|
||||
GrowableStoneBlock.STAGE_1,
|
||||
4,
|
||||
3,
|
||||
LARGE_BUDDING_NORMAL_TYPE_GEM,
|
||||
NORMAL_TYPE_GEM_BLOCK
|
||||
)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_NORMAL_TYPE_GEM = typeGem(
|
||||
"small_budding_normal_type_gem",
|
||||
GrowableStoneBlock.STAGE_0,
|
||||
3,
|
||||
4,
|
||||
MEDIUM_BUDDING_NORMAL_TYPE_GEM,
|
||||
NORMAL_TYPE_GEM_BLOCK
|
||||
)
|
||||
|
||||
private fun typeGem(
|
||||
name: String,
|
||||
stage: Int,
|
||||
height: Int,
|
||||
xzOffset: Int,
|
||||
nextStage: Block?,
|
||||
baseBlock: Block
|
||||
): TypeGemBlock {
|
||||
return this.create(name, TypeGemBlock(
|
||||
settings = AbstractBlock.Settings.create()
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.nonOpaque()
|
||||
.strength(1.5F)
|
||||
.sounds(CobblemonSounds.TYPE_GEM_SOUNDS),
|
||||
stage = stage,
|
||||
height = height,
|
||||
xzOffset = xzOffset,
|
||||
nextStage = nextStage,
|
||||
baseBlock = baseBlock
|
||||
))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map of all the blocks that can be stripped with an axe in the format of input - output.
|
||||
*
|
||||
@@ -239,10 +527,17 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
APRICORN_LOG to STRIPPED_APRICORN_LOG
|
||||
)
|
||||
|
||||
|
||||
|
||||
private fun apricornBlock(name: String, apricorn: Apricorn): ApricornBlock = this.create(name, ApricornBlock(AbstractBlock.Settings.create().mapColor(apricorn.mapColor()).ticksRandomly().strength(Blocks.OAK_LOG.hardness, Blocks.OAK_LOG.blastResistance).sounds(BlockSoundGroup.WOOD).nonOpaque(), apricorn))
|
||||
|
||||
private fun tumblestoneBlock(name: String, stage: Int, height: Int, xzOffset: Int, nextStage: Block?) : Block {
|
||||
return this.create(name, TumblestoneBlock(AbstractBlock.Settings.create()
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.nonOpaque()
|
||||
.strength(1.5F)
|
||||
.sounds(CobblemonSounds.TUMBLESTONE_SOUNDS),
|
||||
stage, height, xzOffset, nextStage))
|
||||
}
|
||||
|
||||
private val berries = mutableMapOf<Identifier, BerryBlock>()
|
||||
|
||||
val AGUAV_BERRY = this.berryBlock("aguav")
|
||||
@@ -338,7 +633,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
|
||||
private fun berryBlock(name: String): BerryBlock {
|
||||
val identifier = cobblemonResource("${name}_berry")
|
||||
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(BlockSoundGroup.CROP).strength(0.2F)))
|
||||
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(CobblemonSounds.BERRY_BUSH_SOUNDS).strength(0.2F)))
|
||||
this.berries[identifier] = block
|
||||
return block
|
||||
}
|
||||
|
||||
@@ -47,5 +47,6 @@ object CobblemonCommands {
|
||||
ClearPCCommand.register(dispatcher)
|
||||
PokemonRestartCommand.register(dispatcher)
|
||||
BedrockParticleCommand.register(dispatcher)
|
||||
OpenDialogueCommand.register(dispatcher)
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatEntity
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonChestBoatEntity
|
||||
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
@@ -65,6 +66,15 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey
|
||||
.build(CHEST_BOAT_KEY.toString())
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GENERIC_BEDROCK_ENTITY_KEY = cobblemonResource("generic_bedrock")
|
||||
@JvmField
|
||||
val GENERIC_BEDROCK_ENTITY: EntityType<GenericBedrockEntity> = this.create(
|
||||
GENERIC_BEDROCK_ENTITY_KEY.path,
|
||||
EntityType.Builder.create({ _, world -> GenericBedrockEntity(world) }, SpawnGroup.MISC)
|
||||
.build(GENERIC_BEDROCK_ENTITY_KEY.toString())
|
||||
)
|
||||
|
||||
fun registerAttributes(consumer: (EntityType<out LivingEntity>, DefaultAttributeContainer.Builder) -> Unit) {
|
||||
consumer(POKEMON, PokemonEntity.createAttributes())
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.resource.ResourceManager
|
||||
import net.minecraft.resource.ResourceReloader
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.screen.ScreenHandlerType
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.text.Text
|
||||
@@ -158,6 +159,8 @@ interface CobblemonImplementation {
|
||||
*/
|
||||
fun registerResourceReloader(identifier: Identifier, reloader: ResourceReloader, type: ResourceType, dependencies: Collection<Identifier>)
|
||||
|
||||
fun registerScreenHandlerType(identifier: Identifier, screenHandlerType: ScreenHandlerType<*>)
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.item.ability.AbilityChanger
|
||||
import com.cobblemon.mod.common.api.mulch.MulchVariant
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
@@ -18,6 +19,7 @@ import com.cobblemon.mod.common.block.MintBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
||||
import com.cobblemon.mod.common.item.*
|
||||
import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
|
||||
import com.cobblemon.mod.common.item.battle.DireHitItem
|
||||
import com.cobblemon.mod.common.item.battle.GuardSpecItem
|
||||
import com.cobblemon.mod.common.item.battle.XStatItem
|
||||
@@ -28,6 +30,7 @@ import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.interactive.*
|
||||
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
@@ -42,6 +45,7 @@ import net.minecraft.item.HangingSignItem
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.SignItem
|
||||
import net.minecraft.item.SmithingTemplateItem
|
||||
import net.minecraft.item.StewItem
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.Registry
|
||||
@@ -121,6 +125,38 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val MASTER_BALL = pokeBallItem(PokeBalls.MASTER_BALL)
|
||||
@JvmField
|
||||
val CHERISH_BALL = pokeBallItem(PokeBalls.CHERISH_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_POKE_BALL = pokeBallItem(PokeBalls.ANCIENT_POKE_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_CITRINE_BALL = pokeBallItem(PokeBalls.ANCIENT_CITRINE_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_VERDANT_BALL = pokeBallItem(PokeBalls.ANCIENT_VERDANT_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_AZURE_BALL = pokeBallItem(PokeBalls.ANCIENT_AZURE_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_ROSEATE_BALL = pokeBallItem(PokeBalls.ANCIENT_ROSEATE_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_SLATE_BALL = pokeBallItem(PokeBalls.ANCIENT_SLATE_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_IVORY_BALL = pokeBallItem(PokeBalls.ANCIENT_IVORY_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_GREAT_BALL = pokeBallItem(PokeBalls.ANCIENT_GREAT_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_ULTRA_BALL = pokeBallItem(PokeBalls.ANCIENT_ULTRA_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_FEATHER_BALL = pokeBallItem(PokeBalls.ANCIENT_FEATHER_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_WING_BALL = pokeBallItem(PokeBalls.ANCIENT_WING_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_JET_BALL = pokeBallItem(PokeBalls.ANCIENT_JET_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_HEAVY_BALL = pokeBallItem(PokeBalls.ANCIENT_HEAVY_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_LEADEN_BALL = pokeBallItem(PokeBalls.ANCIENT_LEADEN_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_GIGATON_BALL = pokeBallItem(PokeBalls.ANCIENT_GIGATON_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_ORIGIN_BALL = pokeBallItem(PokeBalls.ANCIENT_ORIGIN_BALL)
|
||||
|
||||
@JvmField
|
||||
val VIVICHOKE = compostableItem("vivichoke")
|
||||
@@ -144,19 +180,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val WHITE_APRICORN = apricornItem("white", ApricornItem(CobblemonBlocks.WHITE_APRICORN))
|
||||
|
||||
@JvmField
|
||||
val RED_APRICORN_SEED = apricornSeedItem("red", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING))
|
||||
val RED_APRICORN_SEED = apricornSeedItem("red", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING, CobblemonBlocks.RED_APRICORN))
|
||||
@JvmField
|
||||
val YELLOW_APRICORN_SEED = apricornSeedItem("yellow", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING))
|
||||
val YELLOW_APRICORN_SEED = apricornSeedItem("yellow", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING, CobblemonBlocks.YELLOW_APRICORN))
|
||||
@JvmField
|
||||
val GREEN_APRICORN_SEED = apricornSeedItem("green", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING))
|
||||
val GREEN_APRICORN_SEED = apricornSeedItem("green", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING, CobblemonBlocks.GREEN_APRICORN))
|
||||
@JvmField
|
||||
val BLUE_APRICORN_SEED = apricornSeedItem("blue", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING))
|
||||
val BLUE_APRICORN_SEED = apricornSeedItem("blue", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING, CobblemonBlocks.BLUE_APRICORN))
|
||||
@JvmField
|
||||
val PINK_APRICORN_SEED = apricornSeedItem("pink", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING))
|
||||
val PINK_APRICORN_SEED = apricornSeedItem("pink", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING, CobblemonBlocks.PINK_APRICORN))
|
||||
@JvmField
|
||||
val BLACK_APRICORN_SEED = apricornSeedItem("black", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING))
|
||||
val BLACK_APRICORN_SEED = apricornSeedItem("black", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING, CobblemonBlocks.BLACK_APRICORN))
|
||||
@JvmField
|
||||
val WHITE_APRICORN_SEED = apricornSeedItem("white", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING))
|
||||
val WHITE_APRICORN_SEED = apricornSeedItem("white", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING, CobblemonBlocks.WHITE_APRICORN))
|
||||
|
||||
@JvmField
|
||||
val APRICORN_LOG = blockItem("apricorn_log", CobblemonBlocks.APRICORN_LOG)
|
||||
@@ -195,13 +231,40 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val APRICORN_SIGN = this.create("apricorn_sign", SignItem(Item.Settings().maxCount(16), CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN))
|
||||
@JvmField
|
||||
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", HangingSignItem(CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN, Item.Settings().maxCount(16)))
|
||||
@JvmField
|
||||
val GILDED_CHEST = this.create("gilded_chest", BlockItem(CobblemonBlocks.GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val BLUE_GILDED_CHEST = this.create("blue_gilded_chest", BlockItem(CobblemonBlocks.BLUE_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val YELLOW_GILDED_CHEST = this.create("yellow_gilded_chest", BlockItem(CobblemonBlocks.YELLOW_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val PINK_GILDED_CHEST = this.create("pink_gilded_chest", BlockItem(CobblemonBlocks.PINK_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val BLACK_GILDED_CHEST = this.create("black_gilded_chest", BlockItem(CobblemonBlocks.BLACK_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val WHITE_GILDED_CHEST = this.create("white_gilded_chest", BlockItem(CobblemonBlocks.WHITE_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val GREEN_GILDED_CHEST = this.create("green_gilded_chest", BlockItem(CobblemonBlocks.GREEN_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val GIMMIGHOUL_CHEST = this.create("gimmighoul_chest", BlockItem(CobblemonBlocks.GIMMIGHOUL_CHEST, Item.Settings()))
|
||||
|
||||
@JvmField
|
||||
val RESTORATION_TANK = blockItem("restoration_tank", CobblemonBlocks.RESTORATION_TANK)
|
||||
@JvmField
|
||||
val FOSSIL_ANALYZER = blockItem("fossil_analyzer", CobblemonBlocks.FOSSIL_ANALYZER)
|
||||
@JvmField
|
||||
val MONITOR = blockItem("monitor", CobblemonBlocks.MONITOR)
|
||||
@JvmField
|
||||
val HEALING_MACHINE = blockItem("healing_machine", CobblemonBlocks.HEALING_MACHINE)
|
||||
@JvmField
|
||||
val PC = blockItem("pc", CobblemonBlocks.PC)
|
||||
val TM_MACHINE = blockItem("tm_machine", CobblemonBlocks.TM_MACHINE)
|
||||
@JvmField
|
||||
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
|
||||
@JvmField
|
||||
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
|
||||
@JvmField
|
||||
val MOD_STATION = blockItem("modification_station", CobblemonBlocks.MODIFICATION_STATION)
|
||||
|
||||
// Evolution items
|
||||
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
|
||||
@@ -340,6 +403,18 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE))
|
||||
@JvmField
|
||||
val GENIUS_FEATHER = create("genius_feather", FeatherItem(Stats.SPECIAL_ATTACK))
|
||||
@JvmField
|
||||
val SWIFT_FEATHER = create("swift_feather", FeatherItem(Stats.SPEED))
|
||||
@JvmField
|
||||
val HEALTH_FEATHER = create("health_feather", FeatherItem(Stats.HP))
|
||||
@JvmField
|
||||
val RESIST_FEATHER = create("resist_feather", FeatherItem(Stats.DEFENCE))
|
||||
@JvmField
|
||||
val MUSCLE_FEATHER = create("muscle_feather", FeatherItem(Stats.ATTACK))
|
||||
@JvmField
|
||||
val CLEVER_FEATHER = create("clever_feather", FeatherItem(Stats.SPECIAL_DEFENCE))
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK = create("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Settings().food(FoodComponent.Builder().snack().hunger(1).saturationModifier(0.2f).build())))
|
||||
@JvmField
|
||||
val ROASTED_LEEK = create("roasted_leek", Item(Item.Settings().food(FoodComponent.Builder().snack().hunger(3).saturationModifier(0.3f).build())))
|
||||
@@ -490,6 +565,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField val ELIXIR = create("elixir", ElixirItem(max = false))
|
||||
@JvmField val MAX_ELIXIR = create("max_elixir", ElixirItem(max = true))
|
||||
|
||||
@JvmField
|
||||
val ABILITY_CAPSULE = this.create("ability_capsule", AbilityChangeItem(AbilityChanger.COMMON_ABILITY))
|
||||
@JvmField
|
||||
val ABILITY_PATCH = this.create("ability_patch", AbilityChangeItem(AbilityChanger.HIDDEN_ABILITY))
|
||||
|
||||
/**
|
||||
* Evolution Ores and Stones
|
||||
*/
|
||||
@@ -535,6 +615,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val DEEPSLATE_WATER_STONE_ORE = blockItem("deepslate_water_stone_ore", CobblemonBlocks.DEEPSLATE_WATER_STONE_ORE)
|
||||
@JvmField
|
||||
val DRIPSTONE_MOON_STONE_ORE = blockItem("dripstone_moon_stone_ore", CobblemonBlocks.DRIPSTONE_MOON_STONE_ORE)
|
||||
@JvmField
|
||||
val NETHER_FIRE_STONE_ORE = blockItem("nether_fire_stone_ore", CobblemonBlocks.NETHER_FIRE_STONE_ORE)
|
||||
|
||||
@JvmField
|
||||
val DAWN_STONE = noSettingsItem("dawn_stone")
|
||||
@JvmField
|
||||
@@ -686,9 +769,149 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val SURPRISE_MULCH = mulchItem("surprise_mulch", MulchVariant.SURPRISE)
|
||||
|
||||
// Archaeology
|
||||
@JvmField
|
||||
val ARMOR_FOSSIL = noSettingsItem("armor_fossil")
|
||||
@JvmField
|
||||
val FOSSILIZED_BIRD = noSettingsItem("fossilized_bird")
|
||||
@JvmField
|
||||
val CLAW_FOSSIL = noSettingsItem("claw_fossil")
|
||||
@JvmField
|
||||
val COVER_FOSSIL = noSettingsItem("cover_fossil")
|
||||
@JvmField
|
||||
val FOSSILIZED_DINO = noSettingsItem("fossilized_dino")
|
||||
@JvmField
|
||||
val DOME_FOSSIL = noSettingsItem("dome_fossil")
|
||||
@JvmField
|
||||
val FOSSILIZED_DRAKE = noSettingsItem("fossilized_drake")
|
||||
@JvmField
|
||||
val FOSSILIZED_FISH = noSettingsItem("fossilized_fish")
|
||||
@JvmField
|
||||
val HELIX_FOSSIL = noSettingsItem("helix_fossil")
|
||||
@JvmField
|
||||
val JAW_FOSSIL = noSettingsItem("jaw_fossil")
|
||||
@JvmField
|
||||
val OLD_AMBER_FOSSIL = noSettingsItem("old_amber_fossil")
|
||||
@JvmField
|
||||
val PLUME_FOSSIL = noSettingsItem("plume_fossil")
|
||||
@JvmField
|
||||
val ROOT_FOSSIL = noSettingsItem("root_fossil")
|
||||
@JvmField
|
||||
val SAIL_FOSSIL = noSettingsItem("sail_fossil")
|
||||
@JvmField
|
||||
val SKULL_FOSSIL = noSettingsItem("skull_fossil")
|
||||
|
||||
@JvmField
|
||||
val BYGONE_SHERD = noSettingsItem("bygone_sherd")
|
||||
@JvmField
|
||||
val CAPTURE_SHERD = noSettingsItem("capture_sherd")
|
||||
@JvmField
|
||||
val DOME_SHERD = noSettingsItem("dome_sherd")
|
||||
@JvmField
|
||||
val HELIX_SHERD = noSettingsItem("helix_sherd")
|
||||
@JvmField
|
||||
val NOSTALGIC_SHERD = noSettingsItem("nostalgic_sherd")
|
||||
@JvmField
|
||||
val SUSPICIOUS_SHERD = noSettingsItem("suspicious_sherd")
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE = this.create("tumblestone", TumblestoneItem(Item.Settings(), CobblemonBlocks.SMALL_BUDDING_TUMBLESTONE))
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE = this.create("black_tumblestone", TumblestoneItem(Item.Settings(), CobblemonBlocks.SMALL_BUDDING_BLACK_TUMBLESTONE))
|
||||
@JvmField
|
||||
val SKY_TUMBLESTONE = this.create("sky_tumblestone", TumblestoneItem(Item.Settings(), CobblemonBlocks.SMALL_BUDDING_SKY_TUMBLESTONE))
|
||||
|
||||
@JvmField
|
||||
val SMALL_BUDDING_TUMBLESTONE = blockItem("small_budding_tumblestone", CobblemonBlocks.SMALL_BUDDING_TUMBLESTONE)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_TUMBLESTONE = blockItem("medium_budding_tumblestone", CobblemonBlocks.MEDIUM_BUDDING_TUMBLESTONE)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_TUMBLESTONE = blockItem("large_budding_tumblestone", CobblemonBlocks.LARGE_BUDDING_TUMBLESTONE)
|
||||
@JvmField
|
||||
val TUMBLESTONE_CLUSTER = blockItem("tumblestone_cluster", CobblemonBlocks.TUMBLESTONE_CLUSTER)
|
||||
|
||||
@JvmField
|
||||
val SMALL_BUDDING_SKY_TUMBLESTONE = blockItem("small_budding_sky_tumblestone", CobblemonBlocks.SMALL_BUDDING_SKY_TUMBLESTONE)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_SKY_TUMBLESTONE = blockItem("medium_budding_sky_tumblestone", CobblemonBlocks.MEDIUM_BUDDING_SKY_TUMBLESTONE)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_SKY_TUMBLESTONE = blockItem("large_budding_sky_tumblestone", CobblemonBlocks.LARGE_BUDDING_SKY_TUMBLESTONE)
|
||||
@JvmField
|
||||
val SKY_TUMBLESTONE_CLUSTER = blockItem("sky_tumblestone_cluster", CobblemonBlocks.SKY_TUMBLESTONE_CLUSTER)
|
||||
|
||||
@JvmField
|
||||
val SMALL_BUDDING_BLACK_TUMBLESTONE = blockItem("small_budding_black_tumblestone", CobblemonBlocks.SMALL_BUDDING_BLACK_TUMBLESTONE)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = blockItem("medium_budding_black_tumblestone", CobblemonBlocks.MEDIUM_BUDDING_BLACK_TUMBLESTONE)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_BLACK_TUMBLESTONE = blockItem("large_budding_black_tumblestone", CobblemonBlocks.LARGE_BUDDING_BLACK_TUMBLESTONE)
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_CLUSTER = blockItem("black_tumblestone_cluster", CobblemonBlocks.BLACK_TUMBLESTONE_CLUSTER)
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_BLOCK = blockItem("tumblestone_block", CobblemonBlocks.TUMBLESTONE_BLOCK)
|
||||
@JvmField
|
||||
val SKY_TUMBLESTONE_BLOCK = blockItem("sky_tumblestone_block", CobblemonBlocks.SKY_TUMBLESTONE_BLOCK)
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_BLOCK = blockItem("black_tumblestone_block", CobblemonBlocks.BLACK_TUMBLESTONE_BLOCK)
|
||||
|
||||
@JvmField
|
||||
val AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE: SmithingTemplateItem = this.create(
|
||||
"automaton_armor_trim_smithing_template",
|
||||
SmithingTemplateItem.of(CobblemonArmorTrims.AUTOMATON)
|
||||
)
|
||||
|
||||
// Misc
|
||||
@JvmField
|
||||
val POKEMON_MODEL = this.create("pokemon_model", PokemonItem())
|
||||
@JvmField
|
||||
val RELIC_COIN = noSettingsItem("relic_coin")
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH = blockItem("relic_coin_pouch", CobblemonBlocks.RELIC_COIN_POUCH)
|
||||
@JvmField
|
||||
val RELIC_COIN_SACK = blockItem("relic_coin_sack", CobblemonBlocks.RELIC_COIN_SACK)
|
||||
@JvmField
|
||||
val TECHNICAL_MACHINE = this.create("technical_machine", TechnicalMachineItem(Item.Settings()))
|
||||
@JvmField
|
||||
val BLANK_TM = this.create("blank_tm", CobblemonItem(Item.Settings()))
|
||||
|
||||
// Type Gems
|
||||
@JvmField
|
||||
val NORMAL_GEM = noSettingsItem("normal_gem")
|
||||
@JvmField
|
||||
val FIRE_GEM = noSettingsItem("fire_gem")
|
||||
@JvmField
|
||||
val WATER_GEM = noSettingsItem("water_gem")
|
||||
@JvmField
|
||||
val GRASS_GEM = noSettingsItem("grass_gem")
|
||||
@JvmField
|
||||
val ELECTRIC_GEM = noSettingsItem("electric_gem")
|
||||
@JvmField
|
||||
val ICE_GEM = noSettingsItem("ice_gem")
|
||||
@JvmField
|
||||
val FIGHTING_GEM = noSettingsItem("fighting_gem")
|
||||
@JvmField
|
||||
val POISON_GEM = noSettingsItem("poison_gem")
|
||||
@JvmField
|
||||
val GROUND_GEM = noSettingsItem("ground_gem")
|
||||
@JvmField
|
||||
val FLYING_GEM = noSettingsItem("flying_gem")
|
||||
@JvmField
|
||||
val PSYCHIC_GEM = noSettingsItem("psychic_gem")
|
||||
@JvmField
|
||||
val BUG_GEM = noSettingsItem("bug_gem")
|
||||
@JvmField
|
||||
val ROCK_GEM = noSettingsItem("rock_gem")
|
||||
@JvmField
|
||||
val GHOST_GEM = noSettingsItem("ghost_gem")
|
||||
@JvmField
|
||||
val DRAGON_GEM = noSettingsItem("dragon_gem")
|
||||
@JvmField
|
||||
val DARK_GEM = noSettingsItem("dark_gem")
|
||||
@JvmField
|
||||
val STEEL_GEM = noSettingsItem("steel_gem")
|
||||
@JvmField
|
||||
val FAIRY_GEM = noSettingsItem("fairy_gem")
|
||||
|
||||
private fun blockItem(name: String, block: Block): BlockItem = this.create(name, BlockItem(block, Item.Settings()))
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
|
||||
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
|
||||
import com.cobblemon.mod.common.client.net.animation.PlayPoseableAnimationHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleApplyPassResponseHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleCaptureEndHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleCaptureShakeHandler
|
||||
@@ -37,7 +38,13 @@ import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandl
|
||||
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.data.UnlockReloadPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.CraftBlankTMPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.CraftTMPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
|
||||
@@ -46,7 +53,6 @@ import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
|
||||
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.sound.PokemonCryHandler
|
||||
import com.cobblemon.mod.common.client.net.sound.UnvalidatedPlaySoundS2CPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.spawn.SpawnExtraDataEntityHandler
|
||||
import com.cobblemon.mod.common.client.net.starter.StarterUIPacketHandler
|
||||
@@ -71,17 +77,27 @@ import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.AbilityRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.BerryRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.GlobalSpeciesFeatureSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.PropertiesCompletionRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesFeatureAssignmentSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.StandardSpeciesFeatureSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.fossil.FossilRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.fossil.NaturalMaterialRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
|
||||
@@ -91,8 +107,8 @@ import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.Add
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClearEvolutionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.RemoveEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.sound.PokemonCryPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnGenericBedrockPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokeballPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.starter.OpenStarterUIPacket
|
||||
@@ -117,6 +133,8 @@ import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacke
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.CraftBlankTMPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.CraftTMPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.*
|
||||
@@ -129,6 +147,8 @@ import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonS
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.party.PartySelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyMoveSelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPokemonMoveSelectedPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPacket
|
||||
@@ -162,6 +182,8 @@ import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSe
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartySelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyMoveSelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyPokemonMoveSelectedHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
|
||||
@@ -233,6 +255,8 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(PokemonStateUpdatePacket.ID, PokemonStateUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(TetheringUpdatePacket.ID, TetheringUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(TradeableUpdatePacket.ID, TradeableUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(SpeciesFeatureUpdatePacket.ID, SpeciesFeatureUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(OriginalTrainerUpdatePacket.ID, OriginalTrainerUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
|
||||
// Evolution start
|
||||
this.createClientBound(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler())
|
||||
@@ -298,15 +322,23 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(PropertiesCompletionRegistrySyncPacket.ID, PropertiesCompletionRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(UnlockReloadPacket.ID, UnlockReloadPacket::decode, UnlockReloadPacketHandler)
|
||||
this.createClientBound(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(StandardSpeciesFeatureSyncPacket.ID, StandardSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(GlobalSpeciesFeatureSyncPacket.ID, GlobalSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(SpeciesFeatureAssignmentSyncPacket.ID, SpeciesFeatureAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(NaturalMaterialRegistrySyncPacket.ID, NaturalMaterialRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(FossilRegistrySyncPacket.ID, FossilRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
|
||||
// Effects
|
||||
this.createClientBound(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler)
|
||||
this.createClientBound(SpawnSnowstormEntityParticlePacket.ID, SpawnSnowstormEntityParticlePacket::decode, SpawnSnowstormEntityParticleHandler)
|
||||
this.createClientBound(RunPosableMoLangPacket.ID, RunPosableMoLangPacket::decode, RunPosableMoLangHandler)
|
||||
|
||||
// Hax
|
||||
this.createClientBound(UnvalidatedPlaySoundS2CPacket.ID, UnvalidatedPlaySoundS2CPacket::decode, UnvalidatedPlaySoundS2CPacketHandler)
|
||||
this.createClientBound(SpawnPokemonPacket.ID, SpawnPokemonPacket::decode, SpawnExtraDataEntityHandler())
|
||||
this.createClientBound(SpawnPokeballPacket.ID, SpawnPokeballPacket::decode, SpawnExtraDataEntityHandler())
|
||||
this.createClientBound(ToastPacket.ID, ToastPacket::decode, ToastPacketHandler)
|
||||
this.createClientBound(SpawnGenericBedrockPacket.ID, SpawnGenericBedrockPacket::decode, SpawnExtraDataEntityHandler())
|
||||
|
||||
// Trade packets
|
||||
this.createClientBound(TradeAcceptanceChangedPacket.ID, TradeAcceptanceChangedPacket::decode, TradeAcceptanceChangedHandler)
|
||||
@@ -324,7 +356,7 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler)
|
||||
|
||||
// Behaviours
|
||||
this.createClientBound(PokemonCryPacket.ID, PokemonCryPacket::decode, PokemonCryHandler)
|
||||
this.createClientBound(PlayPoseableAnimationPacket.ID, PlayPoseableAnimationPacket::decode, PlayPoseableAnimationHandler)
|
||||
|
||||
// Move select packets
|
||||
this.createClientBound(OpenMoveCallbackPacket.ID, OpenMoveCallbackPacket::decode, OpenMoveCallbackHandler)
|
||||
@@ -334,6 +366,10 @@ object CobblemonNetwork : NetworkManager {
|
||||
|
||||
// Party move select packets
|
||||
this.createClientBound(OpenPartyMoveCallbackPacket.ID, OpenPartyMoveCallbackPacket::decode, OpenPartyMoveCallbackHandler)
|
||||
|
||||
// Dialogue packets
|
||||
this.createClientBound(DialogueClosedPacket.ID, DialogueClosedPacket::decode, DialogueClosedHandler)
|
||||
this.createClientBound(DialogueOpenedPacket.ID, DialogueOpenedPacket::decode, DialogueOpenedHandler)
|
||||
}
|
||||
|
||||
override fun registerServerBound() {
|
||||
@@ -399,6 +435,14 @@ object CobblemonNetwork : NetworkManager {
|
||||
// Party move select packets
|
||||
this.createServerBound(PartyPokemonMoveSelectedPacket.ID, PartyPokemonMoveSelectedPacket::decode, PartyPokemonMoveSelectedHandler)
|
||||
this.createServerBound(PartyMoveSelectCancelledPacket.ID, PartyMoveSelectCancelledPacket::decode, PartyMoveSelectCancelledHandler)
|
||||
|
||||
// TM Machine packets
|
||||
this.createServerBound(CraftTMPacket.ID, CraftTMPacket::decode, CraftTMPacketHandler)
|
||||
this.createServerBound(CraftBlankTMPacket.ID, CraftBlankTMPacket::decode, CraftBlankTMPacketHandler)
|
||||
|
||||
// Dialogue packets
|
||||
this.createServerBound(EscapeDialoguePacket.ID, EscapeDialoguePacket::decode, EscapeDialogueHandler)
|
||||
this.createServerBound(InputToDialoguePacket.ID, InputToDialoguePacket::decode, InputToDialogueHandler)
|
||||
}
|
||||
|
||||
private inline fun <reified T : NetworkPacket<T>> createClientBound(identifier: Identifier, noinline decoder: (PacketByteBuf) -> T, handler: ClientNetworkPacketHandler<T>) {
|
||||
|
||||
@@ -14,7 +14,9 @@ import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.sound.BlockSoundGroup
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.sound.SoundEvents
|
||||
|
||||
object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Registry<SoundEvent>>, SoundEvent>() {
|
||||
|
||||
@@ -54,6 +56,10 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
val POKE_BALL_SEND_OUT = this.create("poke_ball.send_out")
|
||||
@JvmField
|
||||
val POKE_BALL_RECALL = this.create("poke_ball.recall")
|
||||
@JvmField
|
||||
val POKE_BALL_THROW = this.create("poke_ball.throw")
|
||||
@JvmField
|
||||
val POKE_BALL_TRAIL = this.create("poke_ball.trail")
|
||||
|
||||
@JvmField
|
||||
val ITEM_USE = this.create("item.use")
|
||||
@@ -61,6 +67,8 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
val CAN_EVOLVE = this.create("pokemon.can_evolve")
|
||||
@JvmField
|
||||
val EVOLVING = this.create("pokemon.evolving")
|
||||
@JvmField
|
||||
val EVOLVE = this.create("evolution.evolve")
|
||||
|
||||
@JvmField
|
||||
val PVN_BATTLE = this.create("battle.pvn.default")
|
||||
@@ -77,6 +85,8 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
val MEDICINE_PILLS_USE = this.create("medicine_pills.use")
|
||||
@JvmField
|
||||
val MEDICINE_SPRAY_USE = this.create("medicine_spray.use")
|
||||
@JvmField
|
||||
val MEDICINE_FEATHER_USE = this.create("medicine_feather.use")
|
||||
|
||||
@JvmField
|
||||
val BERRY_HARVEST = this.create("berry.harvest")
|
||||
@@ -88,6 +98,237 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
@JvmField
|
||||
val MULCH_REMOVE = this.create("mulch.remove")
|
||||
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_ACTIVATE = this.create("fossilmachine.activate")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_ACTIVE_LOOP = this.create("fossilmachine.active_loop")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_ASSEMBLE = this.create("fossilmachine.assemble")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_DNA_FULL = this.create("fossilmachine.dna_full")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_FINISHED = this.create("fossilmachine.finished")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_INSERT_DNA = this.create("fossilmachine.insert_dna")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_INSERT_DNA_SMALL = this.create("fossilmachine.insert_dna_small")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_INSERT_FOSSIL = this.create("fossilmachine.insert_fossil")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_RETRIEVE_FOSSIL = this.create("fossilmachine.retrieve_fossil")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_RETRIEVE_POKEMON = this.create("fossilmachine.retrieve_pokemon")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossilmachine.unprotected")
|
||||
|
||||
@JvmField
|
||||
val COIN_POUCH_BREAK = this.create("coin_pouch.break")
|
||||
@JvmField
|
||||
val COIN_POUCH_HIT = this.create("coin_pouch.hit")
|
||||
@JvmField
|
||||
val COIN_POUCH_STEP = this.create("coin_pouch.step")
|
||||
@JvmField
|
||||
val COIN_POUCH_PLACE = this.create("coin_pouch.place")
|
||||
@JvmField
|
||||
val TUMBLESTONE_BREAK = this.create("tumblestone.break")
|
||||
@JvmField
|
||||
val TUMBLESTONE_BLOCK_BREAK = this.create("tumblestone.block_break")
|
||||
@JvmField
|
||||
val TUMBLESTONE_HIT = this.create("tumblestone.hit")
|
||||
@JvmField
|
||||
val TUMBLESTONE_PLACE = this.create("tumblestone.place")
|
||||
@JvmField
|
||||
val TUMBLESTONE_STEP = this.create("tumblestone.step")
|
||||
|
||||
@JvmField
|
||||
val GIMMIGHOUL_GIVE_ITEM_SMALL = this.create("gimmighoul.give_item_small")
|
||||
@JvmField
|
||||
val GIMMIGHOUL_REVEAL = this.create("gimmighoul.reveal")
|
||||
|
||||
@JvmField
|
||||
val BERRY_BUSH_BREAK = this.create("berry_bush.break")
|
||||
@JvmField
|
||||
val BERRY_BUSH_PLACE = this.create("berry_bush.place")
|
||||
|
||||
@JvmField
|
||||
val BIG_ROOT_BREAK = this.create("big_root.break")
|
||||
@JvmField
|
||||
val ENERGY_ROOT_PLACE = this.create("energy_root.place")
|
||||
|
||||
@JvmField
|
||||
val MINT_BREAK = this.create("mint.break")
|
||||
@JvmField
|
||||
val MINT_PLACE = this.create("mint.place")
|
||||
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK_BREAK = this.create("medicinal_leek.break")
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK_PLACE = this.create("medicinal_leek.plant")
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST_OPEN = this.create("gilded_chest.open")
|
||||
@JvmField
|
||||
val GILDED_CHEST_CLOSE = this.create("gilded_chest.close")
|
||||
@JvmField
|
||||
val GILDED_CHEST_STEP = this.create("gilded_chest.step")
|
||||
@JvmField
|
||||
val GILDED_CHEST_HIT = this.create("gilded_chest.hit")
|
||||
@JvmField
|
||||
val GILDED_CHEST_BREAK = this.create("gilded_chest.break")
|
||||
@JvmField
|
||||
val GILDED_CHEST_PLACE = this.create("gilded_chest.place")
|
||||
|
||||
@JvmField
|
||||
val COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
COIN_POUCH_BREAK,
|
||||
COIN_POUCH_STEP,
|
||||
COIN_POUCH_PLACE,
|
||||
COIN_POUCH_HIT,
|
||||
COIN_POUCH_STEP
|
||||
)
|
||||
@JvmField
|
||||
val IMPACT_NORMAL = this.create("impact.normal")
|
||||
@JvmField
|
||||
val IMPACT_BUG = this.create("impact.bug")
|
||||
@JvmField
|
||||
val IMPACT_DARK = this.create("impact.dark")
|
||||
@JvmField
|
||||
val IMPACT_DRAGON = this.create("impact.dragon")
|
||||
@JvmField
|
||||
val IMPACT_ELECTRIC = this.create("impact.electric")
|
||||
@JvmField
|
||||
val IMPACT_FAIRY = this.create("impact.fairy")
|
||||
@JvmField
|
||||
val IMPACT_FIGHTING = this.create("impact.fighting")
|
||||
@JvmField
|
||||
val IMPACT_FIRE = this.create("impact.fire")
|
||||
@JvmField
|
||||
val IMPACT_FLYING = this.create("impact.flying")
|
||||
@JvmField
|
||||
val IMPACT_GHOST = this.create("impact.ghost")
|
||||
@JvmField
|
||||
val IMPACT_GRASS = this.create("impact.grass")
|
||||
@JvmField
|
||||
val IMPACT_GROUND = this.create("impact.ground")
|
||||
@JvmField
|
||||
val IMPACT_ICE = this.create("impact.ice")
|
||||
@JvmField
|
||||
val IMPACT_POISON = this.create("impact.poison")
|
||||
@JvmField
|
||||
val IMPACT_PSYCHIC = this.create("impact.psychic")
|
||||
@JvmField
|
||||
val IMPACT_ROCK = this.create("impact.rock")
|
||||
@JvmField
|
||||
val IMPACT_STEEL = this.create("impact.steel")
|
||||
@JvmField
|
||||
val IMPACT_WATER = this.create("impact.water")
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
TUMBLESTONE_BREAK,
|
||||
TUMBLESTONE_STEP,
|
||||
TUMBLESTONE_PLACE,
|
||||
TUMBLESTONE_HIT,
|
||||
TUMBLESTONE_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_BLOCK_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
TUMBLESTONE_BLOCK_BREAK,
|
||||
TUMBLESTONE_STEP,
|
||||
TUMBLESTONE_PLACE,
|
||||
TUMBLESTONE_HIT,
|
||||
TUMBLESTONE_STEP
|
||||
)
|
||||
@JvmField
|
||||
val TM_USE = this.create("tm.use")
|
||||
@JvmField
|
||||
val TMM_CRAFT = this.create("tmm.craft")
|
||||
@JvmField
|
||||
val TMM_CRAFT_BLANK = this.create("tmm.craft_blank")
|
||||
@JvmField
|
||||
val TMM_OFF = this.create("tmm.off")
|
||||
@JvmField
|
||||
val TMM_ON = this.create("tmm.on")
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_SOUNDS = TUMBLESTONE_BLOCK_SOUNDS
|
||||
|
||||
@JvmField
|
||||
val BERRY_BUSH_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
BERRY_BUSH_BREAK,
|
||||
SoundEvents.BLOCK_GRASS_STEP,
|
||||
BERRY_BUSH_PLACE,
|
||||
SoundEvents.BLOCK_GRASS_HIT,
|
||||
SoundEvents.BLOCK_GRASS_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BIG_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
BIG_ROOT_BREAK,
|
||||
SoundEvents.BLOCK_ROOTS_STEP,
|
||||
SoundEvents.BLOCK_ROOTS_PLACE,
|
||||
SoundEvents.BLOCK_ROOTS_HIT,
|
||||
SoundEvents.BLOCK_ROOTS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val ENERGY_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
SoundEvents.BLOCK_ROOTS_BREAK,
|
||||
SoundEvents.BLOCK_ROOTS_STEP,
|
||||
ENERGY_ROOT_PLACE,
|
||||
SoundEvents.BLOCK_ROOTS_HIT,
|
||||
SoundEvents.BLOCK_ROOTS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
MEDICINAL_LEEK_BREAK,
|
||||
SoundEvents.BLOCK_GRASS_STEP,
|
||||
MEDICINAL_LEEK_PLACE,
|
||||
SoundEvents.BLOCK_GRASS_HIT,
|
||||
SoundEvents.BLOCK_GRASS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MINT_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
MINT_BREAK,
|
||||
SoundEvents.BLOCK_GRASS_STEP,
|
||||
MINT_PLACE,
|
||||
SoundEvents.BLOCK_GRASS_HIT,
|
||||
SoundEvents.BLOCK_GRASS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
GILDED_CHEST_BREAK,
|
||||
GILDED_CHEST_STEP,
|
||||
GILDED_CHEST_PLACE,
|
||||
GILDED_CHEST_HIT,
|
||||
GILDED_CHEST_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val DISPLAY_CASE_ADD_ITEM = this.create("display_case.add_item")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_REMOVE_ITEM = this.create("display_case.remove_item")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_BREAK = this.create("display_case.break")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_HIT = this.create("display_case.hit")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_PLACE = this.create("display_case.place")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_STEP = this.create("display_case.step")
|
||||
|
||||
@JvmField
|
||||
val DISPLAY_CASE_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
DISPLAY_CASE_BREAK,
|
||||
DISPLAY_CASE_STEP,
|
||||
DISPLAY_CASE_PLACE,
|
||||
DISPLAY_CASE_HIT,
|
||||
DISPLAY_CASE_STEP
|
||||
)
|
||||
|
||||
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.of(cobblemonResource(name)))
|
||||
}
|
||||
@@ -99,6 +99,13 @@ object CobblemonCriteria {
|
||||
)
|
||||
)
|
||||
|
||||
val RESURRECT_POKEMON = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("resurrect_pokemon"),
|
||||
PickStarterCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
|
||||
val TRADE_POKEMON = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("trade_pokemon"),
|
||||
@@ -106,6 +113,14 @@ object CobblemonCriteria {
|
||||
)
|
||||
)
|
||||
|
||||
// Advancement criteria for [grow_tumblestone.json]
|
||||
val PLANT_TUMBLESTONE = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("plant_tumblestone"),
|
||||
PlantTumblestoneCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
|
||||
private fun <T : Criterion<*>> create(criteria: T): T = Cobblemon.implementation.registerCriteria(criteria)
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.block.TumblestoneBlock
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
/**
|
||||
* A criterion condition for when a tumblestone block is planted
|
||||
* @param id The identifier of the criterion
|
||||
* @param predicate The predicate for the criterion
|
||||
*
|
||||
* @author Aethen
|
||||
* @since 02/28/2024
|
||||
*/
|
||||
class PlantTumblestoneCriterionCondition(id: Identifier, predicate: LootContextPredicate) :
|
||||
SimpleCriterionCondition<PlantTumblestoneContext>(id, predicate) {
|
||||
override fun toJson(json: JsonObject) {
|
||||
// Add properties to json if needed. None needed for this criterion
|
||||
}
|
||||
|
||||
override fun fromJson(json: JsonObject) {
|
||||
// Parse properties from json if needed. None needed for this criterion
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the tumblestone block can grow at the given position
|
||||
* @param player The player that planted the tumblestone block
|
||||
* @param context The context of the criterion
|
||||
* @return True if the tumblestone block can grow at the given position, false otherwise
|
||||
*/
|
||||
override fun matches(player: ServerPlayerEntity, context: PlantTumblestoneContext): Boolean {
|
||||
return context.tumbleStoneBlock.canGrow(context.pos, player.world)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The context of the [PlantTumblestoneCriterionCondition]
|
||||
* @param pos The position of the tumblestone block
|
||||
* @param tumbleStoneBlock The tumblestone block
|
||||
*/
|
||||
open class PlantTumblestoneContext(var pos: BlockPos, var tumbleStoneBlock: TumblestoneBlock)
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.abilities
|
||||
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
@@ -21,7 +22,7 @@ import net.minecraft.nbt.NbtCompound
|
||||
* @author Qu
|
||||
* @since January 9th, 2022
|
||||
*/
|
||||
open class Ability internal constructor(var template: AbilityTemplate, var forced: Boolean) {
|
||||
open class Ability internal constructor(var template: AbilityTemplate, forced: Boolean) {
|
||||
|
||||
val name: String
|
||||
get() = template.name
|
||||
@@ -34,16 +35,26 @@ open class Ability internal constructor(var template: AbilityTemplate, var force
|
||||
|
||||
/**
|
||||
* This represents the last known index of this backing ability in the species data.
|
||||
* If -1 the ability will attempt to find the correct index or reroll itself, this is done in order to be compatible with existing data
|
||||
* The value can be mutated however this is not recommended by API users.
|
||||
* @see [Pokemon.updateAbility].
|
||||
*/
|
||||
var forced: Boolean = forced
|
||||
internal set
|
||||
|
||||
/**
|
||||
* This represents the last known index of this backing ability in the species data.
|
||||
*
|
||||
* @see [Pokemon.updateAbility].
|
||||
*/
|
||||
var index: Int = -1
|
||||
internal set
|
||||
|
||||
/**
|
||||
* The last known priority of this ability in the species data.
|
||||
* The value can be mutated however this is not recommended by API users.
|
||||
*
|
||||
* @see [Pokemon.updateAbility].
|
||||
*/
|
||||
var priority = Priority.LOWEST
|
||||
internal set
|
||||
|
||||
open fun saveToNBT(nbt: NbtCompound): NbtCompound {
|
||||
nbt.putString(DataKeys.POKEMON_ABILITY_NAME, name)
|
||||
@@ -62,19 +73,23 @@ open class Ability internal constructor(var template: AbilityTemplate, var force
|
||||
}
|
||||
|
||||
open fun loadFromNBT(nbt: NbtCompound): Ability {
|
||||
forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
|
||||
this.template = Abilities.getOrException(nbt.getString(DataKeys.POKEMON_ABILITY_NAME))
|
||||
this.forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
|
||||
if (nbt.contains(DataKeys.POKEMON_ABILITY_INDEX) && nbt.contains(DataKeys.POKEMON_ABILITY_PRIORITY)) {
|
||||
this.index = nbt.getInt(DataKeys.POKEMON_ABILITY_INDEX)
|
||||
this.priority = Priority.valueOf(nbt.getString(DataKeys.POKEMON_ABILITY_PRIORITY))
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
open fun loadFromJSON(json: JsonObject): Ability {
|
||||
forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
|
||||
this.template = Abilities.getOrException(json.get(DataKeys.POKEMON_ABILITY_NAME).asString)
|
||||
this.forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
|
||||
if (json.has(DataKeys.POKEMON_ABILITY_INDEX) && json.has(DataKeys.POKEMON_ABILITY_PRIORITY)) {
|
||||
this.index = json.get(DataKeys.POKEMON_ABILITY_INDEX).asInt
|
||||
this.priority = Priority.valueOf(json.get(DataKeys.POKEMON_ABILITY_PRIORITY).asString)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,7 +28,6 @@ class AbilityTemplate(
|
||||
*/
|
||||
fun create(forced: Boolean = false) = builder(this, forced)
|
||||
|
||||
|
||||
/**
|
||||
* Returns the Ability and loads the given NBT Tag into it.
|
||||
*
|
||||
@@ -42,4 +41,5 @@ class AbilityTemplate(
|
||||
* Ability extensions need to write and read their needed data from here.
|
||||
*/
|
||||
fun create(json: JsonObject) = create().loadFromJSON(json)
|
||||
|
||||
}
|
||||
@@ -8,9 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.battles.model
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangEnvironment
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.Environment
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
@@ -18,6 +22,8 @@ import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
@@ -464,4 +470,13 @@ open class PokemonBattle(
|
||||
LOGGER.error("Missing interpretation on '{}' action: \nPublic » {}\nPrivate » {}", publicMessage.id, publicMessage.rawMessage, privateMessage.rawMessage)
|
||||
return Text.literal("Missing interpretation on '${publicMessage.id}' action please report to the developers").red()
|
||||
}
|
||||
|
||||
fun addQueryFunctions(queryStruct: QueryStruct): QueryStruct {
|
||||
queryStruct.addFunction("pvp") { DoubleValue(isPvP) }
|
||||
queryStruct.addFunction("pvn") { DoubleValue(isPvN) }
|
||||
queryStruct.addFunction("pvw") { DoubleValue(isPvW) }
|
||||
queryStruct.addFunction("has_rule") { params -> DoubleValue(params.getString(0) in format.ruleSet) }
|
||||
|
||||
return queryStruct
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.dialogue.input.ActiveInput
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
import java.util.UUID
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
/**
|
||||
* An active instance of [Dialogue]. Bound to a player. These all need to be created through DialogueManager
|
||||
* or things will go to shit.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class ActiveDialogue(var playerEntity: ServerPlayerEntity, var dialogueReference: Dialogue) {
|
||||
val dialogueId = UUID.randomUUID()
|
||||
val runtime = MoLangRuntime().setup()
|
||||
var currentPage = dialogueReference.pages[0]
|
||||
val playerStruct = playerEntity.asMoLangValue()
|
||||
var activeInput = ActiveInput(this, currentPage.input)
|
||||
|
||||
init {
|
||||
runtime.environment.getQueryStruct().addFunctions(
|
||||
mapOf(
|
||||
"dialogue" to java.util.function.Function { _ -> toMoLangStruct() },
|
||||
"player" to java.util.function.Function { _ -> playerStruct }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val currentPageIndex
|
||||
get() = dialogueReference.pages.indexOf(currentPage)
|
||||
|
||||
fun setPage(value: MoValue) {
|
||||
val page = if (value is StringValue) {
|
||||
dialogueReference.pages.find { it.id == value.value }
|
||||
?: return Cobblemon.LOGGER.error("Dialogue requested page ${value.value} but it doesn't exist")
|
||||
} else {
|
||||
val pageNum = value.asDouble().toInt()
|
||||
if (pageNum < 0 || pageNum >= dialogueReference.pages.size) {
|
||||
return Cobblemon.LOGGER.error("Dialogue requested page $pageNum but it doesn't exist")
|
||||
} else {
|
||||
dialogueReference.pages[pageNum]
|
||||
}
|
||||
}
|
||||
setPage(page)
|
||||
}
|
||||
|
||||
fun isActive() = DialogueManager.activeDialogues[playerEntity.uuid] == this
|
||||
|
||||
fun incrementPage() {
|
||||
setPage(currentPageIndex + 1)
|
||||
}
|
||||
|
||||
fun setPage(page: DialoguePage) {
|
||||
currentPage = page
|
||||
activeInput = ActiveInput(this, currentPage.input)
|
||||
val deadline = currentPage.input.timeout?.duration
|
||||
val inputId = activeInput.inputId
|
||||
if (deadline != null && deadline > 0) {
|
||||
ServerRealTimeTaskTracker.after(seconds = deadline) {
|
||||
if (inputId == activeInput.inputId && isActive()) {
|
||||
activeInput.dialogueInput.timeout?.action?.invoke(this, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
playerEntity.sendPacket(DialogueOpenedPacket(this, false))
|
||||
}
|
||||
|
||||
fun setPage(index: Int) {
|
||||
if (index == dialogueReference.pages.size) {
|
||||
return close()
|
||||
}
|
||||
|
||||
if (index < 0 || index > dialogueReference.pages.size) {
|
||||
return Cobblemon.LOGGER.error("Dialogue requested page $index but it doesn't exist")
|
||||
}
|
||||
|
||||
setPage(dialogueReference.pages[index])
|
||||
}
|
||||
|
||||
fun toMoLangStruct(): MoStruct {
|
||||
return QueryStruct(
|
||||
hashMapOf(
|
||||
"current_page" to java.util.function.Function { _ -> currentPage.toMoLangStruct(this) },
|
||||
"current_page_number" to java.util.function.Function { _ -> DoubleValue(currentPageIndex) },
|
||||
"next_page" to java.util.function.Function { _ -> incrementPage() },
|
||||
"set_page" to java.util.function.Function { args -> setPage(args[0]) },
|
||||
"close" to java.util.function.Function { _ -> close() },
|
||||
"input" to java.util.function.Function { params -> activeInput.handle(if (params.params.size > 0) params.get<MoValue>(0).asString() else "") },
|
||||
)
|
||||
).addStandardFunctions()
|
||||
}
|
||||
|
||||
fun close() {
|
||||
DialogueManager.stopDialogue(playerEntity)
|
||||
}
|
||||
|
||||
fun escape() {
|
||||
val action = currentPage.escapeAction ?: dialogueReference.escapeAction
|
||||
action(this, null)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
|
||||
/**
|
||||
* A dialogue that could be sent to players.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class Dialogue(
|
||||
val pages: List<DialoguePage> = mutableListOf(),
|
||||
val escapeAction: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.close() },
|
||||
val speakers: Map<String, DialogueSpeaker> = emptyMap()
|
||||
) {
|
||||
companion object {
|
||||
fun of(
|
||||
pages: Iterable<DialoguePage>,
|
||||
escapeAction: ExpressionLike,
|
||||
speakers: Map<String, DialogueSpeaker>
|
||||
): Dialogue {
|
||||
return Dialogue(
|
||||
pages = pages.toList(),
|
||||
escapeAction = ExpressionLikeDialogueAction(escapeAction),
|
||||
speakers = speakers
|
||||
)
|
||||
}
|
||||
|
||||
fun of(
|
||||
pages: Iterable<DialoguePage>,
|
||||
escapeAction: (ActiveDialogue) -> Unit,
|
||||
speakers: Map<String, DialogueSpeaker>
|
||||
): Dialogue {
|
||||
val dialogue = Dialogue(
|
||||
pages = pages.toList(),
|
||||
escapeAction = FunctionDialogueAction { activeDialogue, _ -> escapeAction(activeDialogue) },
|
||||
speakers = speakers
|
||||
)
|
||||
return dialogue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue
|
||||
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
|
||||
/**
|
||||
* Something that can happen in the context of an [ActiveDialogue]. The input field is nullable because I'm reusing
|
||||
* this for dialogue input timeouts which don't have an input. It'll be fine.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2023
|
||||
*/
|
||||
interface DialogueAction {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
val types = mutableMapOf<String, Class<out DialogueAction>>()
|
||||
}
|
||||
|
||||
operator fun invoke(dialogue: ActiveDialogue, input: String? = null)
|
||||
}
|
||||
|
||||
class FunctionDialogueAction(val consumer: (ActiveDialogue, String?) -> Unit) : DialogueAction {
|
||||
override fun invoke(dialogue: ActiveDialogue, input: String?) {
|
||||
consumer(dialogue, input)
|
||||
}
|
||||
}
|
||||
|
||||
class ExpressionLikeDialogueAction(val expression: ExpressionLike) : DialogueAction {
|
||||
override fun invoke(dialogue: ActiveDialogue, input: String?) {
|
||||
if (input != null) {
|
||||
dialogue.runtime.environment.setSimpleVariable("selected_option", StringValue(input))
|
||||
}
|
||||
dialogue.runtime.resolve(expression)
|
||||
}
|
||||
}
|
||||
@@ -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.api.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import java.util.UUID
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Something that produces a dialogue's renderable face. This is sealed because the client has very particular handling for this.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 1st, 2024
|
||||
*/
|
||||
sealed interface DialogueFaceProvider {
|
||||
companion object {
|
||||
val types = mutableMapOf(
|
||||
"player" to PlayerDialogueFaceProvider::class.java,
|
||||
"standard" to ArtificialDialogueFaceProvider::class.java,
|
||||
"expression" to ExpressionLikeDialogueFaceProvider::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ArtificialDialogueFaceProvider(
|
||||
val modelType: String = "",
|
||||
val identifier: Identifier = cobblemonResource("bulbasaur"),
|
||||
val aspects: Set<String> = setOf()
|
||||
) : DialogueFaceProvider
|
||||
|
||||
class ReferenceDialogueFaceProvider(
|
||||
val entityId: Int
|
||||
): DialogueFaceProvider
|
||||
|
||||
class PlayerDialogueFaceProvider(val playerId: UUID) : DialogueFaceProvider
|
||||
|
||||
class ExpressionLikeDialogueFaceProvider(
|
||||
val providerExpression: ExpressionLike
|
||||
): DialogueFaceProvider
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
import com.cobblemon.mod.common.util.activeDialogue
|
||||
import java.util.UUID
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
/**
|
||||
* Manages the active dialogues for players. Map is indexed by player UUID.
|
||||
* You really need to make sure any dialogues you start with a player go through this otherwise
|
||||
* the player won't be able to close the dialogue.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
object DialogueManager {
|
||||
val activeDialogues = mutableMapOf<UUID, ActiveDialogue>()
|
||||
|
||||
fun startDialogue(playerEntity: ServerPlayerEntity, dialogue: Dialogue) {
|
||||
val activeDialogue = ActiveDialogue(playerEntity, dialogue)
|
||||
activeDialogues[playerEntity.uuid] = activeDialogue
|
||||
val packet = DialogueOpenedPacket(activeDialogue, includeFaces = true)
|
||||
playerEntity.sendPacket(packet)
|
||||
}
|
||||
|
||||
fun stopDialogue(playerEntity: ServerPlayerEntity) {
|
||||
val activeDialogue = playerEntity.activeDialogue ?: return
|
||||
DialogueClosedPacket(activeDialogue.dialogueId).sendToPlayer(playerEntity)
|
||||
activeDialogues.remove(activeDialogue.dialogueId)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.dialogue.input.DialogueInput
|
||||
import com.cobblemon.mod.common.api.dialogue.input.DialogueNoInput
|
||||
import com.google.gson.JsonArray
|
||||
import net.minecraft.text.MutableText
|
||||
|
||||
/**
|
||||
* A page of a dialogue. This has lines of text and also some kind of input expected from the player.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class DialoguePage(
|
||||
var id: String = "",
|
||||
var speaker: String? = null,
|
||||
var lines: MutableList<DialogueText> = mutableListOf(),
|
||||
var input: DialogueInput = DialogueNoInput(),
|
||||
var clientActions: MutableList<Expression> = mutableListOf(),
|
||||
var escapeAction: DialogueAction? = null,
|
||||
) {
|
||||
companion object {
|
||||
@JvmOverloads
|
||||
fun of(
|
||||
/** The ID is optional, but if you want to be able to jump to this page from other pages then you probably want to set this. */
|
||||
id: String = "",
|
||||
speaker: String? = null,
|
||||
lines: Iterable<MutableText>,
|
||||
input: DialogueInput = DialogueNoInput(),
|
||||
clientActions: Iterable<Expression> = emptyList(),
|
||||
/** The thing to do when the player presses ESC while on this page. If null, falls back to the same property on [Dialogue]. */
|
||||
escapeAction: ((ActiveDialogue) -> Unit)? = null,
|
||||
): DialoguePage {
|
||||
return DialoguePage(
|
||||
id = id,
|
||||
speaker = speaker,
|
||||
lines = lines.map { WrappedDialogueText(it) }.toMutableList(),
|
||||
input = input,
|
||||
clientActions = clientActions.toMutableList(),
|
||||
escapeAction = escapeAction?.let { func -> FunctionDialogueAction { activeDialogue, _ -> func(activeDialogue) } }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun toMoLangStruct(activeDialogue: ActiveDialogue): MoStruct {
|
||||
return QueryStruct(
|
||||
hashMapOf(
|
||||
"id" to java.util.function.Function { _ -> StringValue(id) },
|
||||
"input" to java.util.function.Function { _ -> activeDialogue.activeInput.struct },
|
||||
"lines" to java.util.function.Function { _ ->
|
||||
val array = JsonArray()
|
||||
lines.forEach { array.add(it(activeDialogue).string) }
|
||||
MoValue.of(array)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
|
||||
/**
|
||||
* A predicate loaded for a particular dialogue. Tests arbitrary conditions about the dialogue context.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2023
|
||||
*/
|
||||
interface DialoguePredicate {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out DialoguePredicate>>()
|
||||
}
|
||||
|
||||
operator fun invoke(dialogue: ActiveDialogue): Boolean
|
||||
}
|
||||
|
||||
class ExpressionLikeDialoguePredicate(val expression: ExpressionLike = "true".asExpressionLike()) : DialoguePredicate {
|
||||
override fun invoke(dialogue: ActiveDialogue) = dialogue.runtime.resolveBoolean(expression)
|
||||
}
|
||||
|
||||
class FunctionDialoguePredicate(val predicate: (ActiveDialogue) -> Boolean = { true }) : DialoguePredicate {
|
||||
override fun invoke(dialogue: ActiveDialogue) = predicate(dialogue)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import net.minecraft.text.MutableText
|
||||
|
||||
/**
|
||||
* A kind of speaker in a dialogue. They include a name and a face, each optional.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 1st, 2024
|
||||
*/
|
||||
class DialogueSpeaker(
|
||||
val name: DialogueText? = null,
|
||||
val face: DialogueFaceProvider? = null
|
||||
) {
|
||||
fun of(name: MutableText = "".text(), face: DialogueFaceProvider? = null) = DialogueSpeaker(WrappedDialogueText(name), face)
|
||||
}
|
||||
@@ -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.api.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveString
|
||||
import net.minecraft.text.MutableText
|
||||
|
||||
/**
|
||||
* Some kind of text-resolving property. This is to hide where sometimes we want literals,
|
||||
* sometimes we want the text to come from a function, and sometimes we want it to be the
|
||||
* product of a MoLang script.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2023
|
||||
*/
|
||||
interface DialogueText {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out DialogueText>>(
|
||||
"expression" to ExpressionLikeDialogueText::class.java,
|
||||
)
|
||||
}
|
||||
|
||||
operator fun invoke(activeDialogue: ActiveDialogue): MutableText
|
||||
}
|
||||
|
||||
class FunctionDialogueText(val function: (ActiveDialogue) -> MutableText = { "".text() }) : DialogueText {
|
||||
override fun invoke(activeDialogue: ActiveDialogue) = function(activeDialogue)
|
||||
}
|
||||
|
||||
class WrappedDialogueText(val text: MutableText = "".text()) : DialogueText {
|
||||
override fun invoke(activeDialogue: ActiveDialogue) = text.copy()
|
||||
}
|
||||
|
||||
class ExpressionLikeDialogueText(val expression: ExpressionLike = "''".asExpressionLike()) : DialogueText {
|
||||
override fun invoke(activeDialogue: ActiveDialogue): MutableText {
|
||||
return activeDialogue.runtime.resolveString(expression).text()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.dialogue.input.DialogueInput
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.util.adapters.DialogueActionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.DialogueFaceProviderAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.DialogueInputAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.DialoguePredicateAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.DialogueTextAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TextAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Registry for dialogue data.
|
||||
*
|
||||
* @see Dialogue
|
||||
* @since December 29th, 2023
|
||||
* @author Hiroku
|
||||
*/
|
||||
object Dialogues : JsonDataRegistry<Dialogue> {
|
||||
override val id = cobblemonResource("dialogues")
|
||||
override val type = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<Dialogues>()
|
||||
|
||||
val dialogues = mutableMapOf<Identifier, Dialogue>()
|
||||
/** If you need custom adapters registered, subscribe to this and register them. */
|
||||
val gsonObservable: SimpleObservable<GsonBuilder> = SimpleObservable()
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {}
|
||||
|
||||
override val gson = GsonBuilder()
|
||||
.registerTypeAdapter(DialogueAction::class.java, DialogueActionAdapter)
|
||||
.registerTypeAdapter(DialoguePredicate::class.java, DialoguePredicateAdapter)
|
||||
.registerTypeAdapter(DialogueInput::class.java, DialogueInputAdapter)
|
||||
.registerTypeAdapter(DialogueFaceProvider::class.java, DialogueFaceProviderAdapter)
|
||||
.registerTypeAdapter(DialogueText::class.java, DialogueTextAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(MutableText::class.java, TextAdapter)
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.also { gsonObservable.emit(it) }
|
||||
.create()
|
||||
|
||||
override val typeToken = TypeToken.get(Dialogue::class.java)
|
||||
override val resourcePath = "dialogues"
|
||||
|
||||
override fun reload(data: Map<Identifier, Dialogue>) {
|
||||
dialogues.putAll(data)
|
||||
observable.emit(this)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue.input
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.dialogue.ActiveDialogue
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* An active input waiting for the player as part of an [ActiveDialogue]. The purpose of this is to
|
||||
* maintain some data integrity and track how long it's taken to choose an action.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class ActiveInput(
|
||||
val activeDialogue: ActiveDialogue,
|
||||
val dialogueInput: DialogueInput
|
||||
) {
|
||||
val inputId = UUID.randomUUID()
|
||||
val startTime = server()!!.overworld.time
|
||||
|
||||
val struct = toMoLangStruct()
|
||||
|
||||
fun handle(input: String) {
|
||||
val secondsToChoose = (server()!!.overworld.time - startTime) / 20F
|
||||
activeDialogue.runtime.environment.setSimpleVariable("seconds_taken_to_input", DoubleValue(secondsToChoose))
|
||||
dialogueInput.handle(this, input)
|
||||
}
|
||||
|
||||
fun toMoLangStruct(): MoValue {
|
||||
return dialogueInput.toMoLangStruct(this)
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue.input
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.dialogue.DialogueAction
|
||||
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
|
||||
|
||||
/**
|
||||
* Input that has no input but has an action that will run after a delay.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class DialogueAutoContinueInput : DialogueInput {
|
||||
val delay = 5F
|
||||
/** Whether the player can click to move on in a hurry or if they must wait. */
|
||||
var allowSkip = true
|
||||
var showTimer = false
|
||||
val action: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.incrementPage() }
|
||||
|
||||
override var timeout: DialogueTimeout?
|
||||
get() = DialogueTimeout(duration = delay, showTimer = showTimer, action)
|
||||
set(_) {}
|
||||
|
||||
override fun toMoLangStruct(activeInput: ActiveInput) = QueryStruct(hashMapOf())
|
||||
|
||||
|
||||
override fun handle(activeInput: ActiveInput, value: String) {
|
||||
if (!allowSkip) {
|
||||
return Cobblemon.LOGGER.warn("A no-skip dialogue received input from ${activeInput.activeDialogue.playerEntity.gameProfile.name}, is this person a hacker or something")
|
||||
}
|
||||
|
||||
action.invoke(activeInput.activeDialogue)
|
||||
}
|
||||
}
|
||||
@@ -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.api.dialogue.input
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.cobblemon.mod.common.api.dialogue.DialoguePage
|
||||
|
||||
/**
|
||||
* A type of input to [DialoguePage]s. This is sealed because the client needs to know about it. Sorry.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
sealed interface DialogueInput {
|
||||
var timeout: DialogueTimeout?
|
||||
fun toMoLangStruct(activeInput: ActiveInput): MoStruct
|
||||
fun handle(activeInput: ActiveInput, value: String)
|
||||
}
|
||||
@@ -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.api.dialogue.input
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.cobblemon.mod.common.api.dialogue.DialogueAction
|
||||
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
|
||||
|
||||
/**
|
||||
* An input type that's really just waiting for the player to click or something.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
|
||||
*/
|
||||
class DialogueNoInput(
|
||||
var action: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.incrementPage() }
|
||||
) : DialogueInput {
|
||||
override var timeout: DialogueTimeout?
|
||||
get() = null
|
||||
set(_) {}
|
||||
|
||||
override fun toMoLangStruct(activeInput: ActiveInput) = VariableStruct()
|
||||
override fun handle(activeInput: ActiveInput, value: String) {
|
||||
action(activeInput.activeDialogue)
|
||||
}
|
||||
}
|
||||
@@ -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.api.dialogue.input
|
||||
|
||||
import com.cobblemon.mod.common.api.dialogue.DialogueAction
|
||||
import com.cobblemon.mod.common.api.dialogue.DialoguePredicate
|
||||
import com.cobblemon.mod.common.api.dialogue.DialogueText
|
||||
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
|
||||
import com.cobblemon.mod.common.api.dialogue.FunctionDialoguePredicate
|
||||
import com.cobblemon.mod.common.api.dialogue.WrappedDialogueText
|
||||
|
||||
/**
|
||||
* A choosable option as part of a [DialogueOptionSetInput].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class DialogueOption(
|
||||
var text: DialogueText = WrappedDialogueText(),
|
||||
/** The value is a unique identifier so the client can tell the server what they selected. Don't forget this. */
|
||||
var value: String = "",
|
||||
/** The action to run when they click it. */
|
||||
var action: DialogueAction = FunctionDialogueAction { _, _ -> },
|
||||
val isVisible: DialoguePredicate = FunctionDialoguePredicate(),
|
||||
val isSelectable: DialoguePredicate = FunctionDialoguePredicate()
|
||||
)
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue.input
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.dialogue.ActiveDialogue
|
||||
|
||||
/**
|
||||
* A type of [DialogueInput] that has the player choose from a list of options.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class DialogueOptionSetInput(
|
||||
var options: MutableList<DialogueOption>,
|
||||
override var timeout: DialogueTimeout? = null,
|
||||
/** Whether the buttons should be stacked vertically. */
|
||||
var vertical: Boolean = false,
|
||||
) : DialogueInput {
|
||||
|
||||
// JSON uses this. Basically so that the main constructor can force people to specify options
|
||||
constructor() : this(mutableListOf(), null, false)
|
||||
|
||||
fun getVisibleOptions(activeDialogue: ActiveDialogue) = options.filter { it.isVisible(activeDialogue) }
|
||||
override fun toMoLangStruct(activeInput: ActiveInput) = QueryStruct(hashMapOf())
|
||||
override fun handle(activeInput: ActiveInput, value: String) {
|
||||
val option = options.firstOrNull { it.value == value }
|
||||
if (option != null) {
|
||||
if (!option.isSelectable(activeInput.activeDialogue)) {
|
||||
Cobblemon.LOGGER.warn("Dialogue option $value is not selectable but ${activeInput.activeDialogue.playerEntity.gameProfile.name} selected it anyway")
|
||||
activeInput.activeDialogue.close()
|
||||
} else if (!option.isVisible(activeInput.activeDialogue)) {
|
||||
Cobblemon.LOGGER.warn("Dialogue option $value is not visible but ${activeInput.activeDialogue.playerEntity.gameProfile.name} selected it anyway")
|
||||
activeInput.activeDialogue.close()
|
||||
}
|
||||
|
||||
option.action(activeInput.activeDialogue, value)
|
||||
} else {
|
||||
Cobblemon.LOGGER.warn("No option with value $value found in dialogue option set")
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue.input
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.dialogue.DialogueAction
|
||||
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
|
||||
|
||||
/**
|
||||
* A text input for dialogues where the player can enter free text.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class DialogueTextInput : DialogueInput {
|
||||
override var timeout: DialogueTimeout? = null
|
||||
val action: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.setPage(dialogue.currentPageIndex + 1) }
|
||||
override fun toMoLangStruct(activeInput: ActiveInput) = QueryStruct(hashMapOf())
|
||||
|
||||
override fun handle(activeInput: ActiveInput, value: String) {
|
||||
action.invoke(activeInput.activeDialogue, value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue.input
|
||||
|
||||
import com.cobblemon.mod.common.api.dialogue.DialogueAction
|
||||
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
|
||||
|
||||
/**
|
||||
* A deadline for dialogue input. This is used to have something occur if the player spends
|
||||
* too long on one page of dialogue.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class DialogueTimeout(
|
||||
var duration: Float = 10F,
|
||||
var showTimer: Boolean = true,
|
||||
var action: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.close() }
|
||||
)
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.drop
|
||||
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.LOOT_DROPPED
|
||||
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
@@ -88,6 +89,8 @@ class DropTable {
|
||||
amount: IntRange = this.amount
|
||||
) {
|
||||
val drops = getDrops(amount).toMutableList()
|
||||
val heldItem = (entity as PokemonEntity).pokemon.heldItemNoCopy()
|
||||
if (!heldItem.isEmpty) entity.dropItem(heldItem.item)
|
||||
LOOT_DROPPED.postThen(
|
||||
event = LootDroppedEvent(this, player, entity, drops),
|
||||
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
|
||||
|
||||
@@ -31,14 +31,14 @@ import net.minecraft.util.math.Vec3d
|
||||
* @author Hiroku
|
||||
* @since July 24th, 2022
|
||||
*/
|
||||
class ItemDropEntry : DropEntry {
|
||||
open class ItemDropEntry : DropEntry {
|
||||
override val percentage = 100F
|
||||
override val quantity = 1
|
||||
val quantityRange: IntRange? = null
|
||||
open val quantityRange: IntRange? = null
|
||||
override val maxSelectableTimes = 1
|
||||
val dropMethod: ItemDropMethod? = null
|
||||
val item = Identifier("minecraft:fish")
|
||||
val nbt: NbtCompound? = null
|
||||
open val dropMethod: ItemDropMethod? = null
|
||||
open val item = Identifier("minecraft:fish")
|
||||
open val nbt: NbtCompound? = null
|
||||
|
||||
override fun drop(entity: LivingEntity?, world: ServerWorld, pos: Vec3d, player: ServerPlayerEntity?) {
|
||||
val item = world.registryManager.get(RegistryKeys.ITEM).get(item) ?: return LOGGER.error("Unable to load drop item: $item")
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.entity
|
||||
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.data.TrackedData
|
||||
|
||||
/**
|
||||
* Represents a delegation of a portion of an entity's logic to a particular side.
|
||||
@@ -16,4 +17,5 @@ import net.minecraft.entity.Entity
|
||||
interface EntitySideDelegate<T : Entity> {
|
||||
fun initialize(entity: T) {}
|
||||
fun tick(entity: T) {}
|
||||
fun onTrackedDataSet(data: TrackedData<*>) {}
|
||||
}
|
||||
@@ -33,6 +33,8 @@ import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEv
|
||||
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionDisplayEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionTestedEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.interaction.ExperienceCandyUseEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.interaction.HeldItemUpdatedEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.interaction.PokemonInteractionGUICreationEvent
|
||||
import com.cobblemon.mod.common.api.events.starter.StarterChosenEvent
|
||||
import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent
|
||||
import com.cobblemon.mod.common.api.events.world.BigRootPropagatedEvent
|
||||
@@ -65,6 +67,8 @@ object CobblemonEvents {
|
||||
val EVOLUTION_COMPLETE = EventObservable<EvolutionCompleteEvent>()
|
||||
@JvmField
|
||||
val POKEMON_NICKNAMED = CancelableObservable<PokemonNicknamedEvent>()
|
||||
@JvmField
|
||||
val HELD_ITEM_UPDATED = CancelableObservable<HeldItemUpdatedEvent>()
|
||||
|
||||
@JvmField
|
||||
val THROWN_POKEBALL_HIT = CancelableObservable<ThrownPokeballHitEvent>()
|
||||
@@ -100,6 +104,9 @@ object CobblemonEvents {
|
||||
@JvmField
|
||||
val LEVEL_UP_EVENT = EventObservable<LevelUpEvent>()
|
||||
|
||||
@JvmField
|
||||
/** CLIENT ONLY! */
|
||||
val POKEMON_INTERACTION_GUI_CREATION = EventObservable<PokemonInteractionGUICreationEvent>()
|
||||
@JvmField
|
||||
val POKEMON_ENTITY_SAVE = EventObservable<PokemonEntitySaveEvent>()
|
||||
@JvmField
|
||||
@@ -153,4 +160,8 @@ object CobblemonEvents {
|
||||
val LEFTOVERS_CREATED = CancelableObservable<LeftoversCreatedEvent>()
|
||||
@JvmField
|
||||
val BIG_ROOT_PROPAGATED = CancelableObservable<BigRootPropagatedEvent>()
|
||||
@JvmField
|
||||
val HELD_ITEM_PRE = CancelableObservable<HeldItemEvent.Pre>()
|
||||
@JvmField
|
||||
val HELD_ITEM_POST = EventObservable<HeldItemEvent.Post>()
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
/**
|
||||
* The base for all the events related to held items.
|
||||
*
|
||||
* @see [Pre]
|
||||
* @see [Post]
|
||||
*/
|
||||
interface HeldItemEvent {
|
||||
|
||||
/**
|
||||
* The [Pokemon] triggering this event.
|
||||
*/
|
||||
val pokemon: Pokemon
|
||||
|
||||
/**
|
||||
* Fired at the start of [Pokemon.swapHeldItem].
|
||||
*
|
||||
* This event should be used to mutate the results of this transaction.
|
||||
*
|
||||
* Canceling this event will prevent the operation and causes the return to be item attempted to be given originally.
|
||||
*
|
||||
* @property pokemon The [Pokemon] triggering this event.
|
||||
* @property receiving The [ItemStack] being sent received from the transaction. By default, this is the item that triggered the interaction.
|
||||
* @property returning The [ItemStack] being sent back from the transaction. By default, this is the currently held item.
|
||||
* @property decrement If the operation should decrement the [receiving] [ItemStack.count], this is handled in the implementation.
|
||||
*
|
||||
* @see [Post]
|
||||
*/
|
||||
data class Pre(override val pokemon: Pokemon, var receiving: ItemStack, var returning: ItemStack, var decrement: Boolean) : HeldItemEvent, Cancelable()
|
||||
|
||||
/**
|
||||
* Fired at the end of [Pokemon.swapHeldItem].
|
||||
*
|
||||
* @property pokemon The [Pokemon] triggering this event.
|
||||
* @property received The [ItemStack] considered as received and set to the [pokemon]. This is a copy and mutation will not be taken into account.
|
||||
* @property returned The [ItemStack] returned by the method call. This is a copy and mutation will not be taken into account.
|
||||
* @property decremented If the [received] [ItemStack] got decremented.
|
||||
*
|
||||
* @see [Pre]
|
||||
*/
|
||||
data class Post(override val pokemon: Pokemon, val received: ItemStack, val returned: ItemStack, val decremented: Boolean) : HeldItemEvent
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon.interaction
|
||||
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
/**
|
||||
* Event published when a held item is being updated on a [Pokemon].
|
||||
* Cancelling the event will prevent any action from being taken on
|
||||
* the Pokémon.
|
||||
*
|
||||
* [newItem] differs from [originalStack] in that the former is a
|
||||
* one-sized version of the original (Pokémon cannot hold stacks) and
|
||||
* changing it in any way will not affect the original item held by
|
||||
* the player.
|
||||
*
|
||||
* @author Whatsy, Hiroku
|
||||
* @since November 13th, 2023
|
||||
*/
|
||||
data class HeldItemUpdatedEvent(
|
||||
val cause: LivingEntity?,
|
||||
val pokemon: Pokemon,
|
||||
val originalStack: ItemStack,
|
||||
val decrement: Boolean,
|
||||
val oldItem: ItemStack,
|
||||
val newItem: ItemStack
|
||||
) : Cancelable()
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon.interaction
|
||||
|
||||
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelOption
|
||||
import com.cobblemon.mod.common.client.gui.interact.wheel.Orientation
|
||||
import com.google.common.collect.Multimap
|
||||
import java.util.UUID
|
||||
|
||||
data class PokemonInteractionGUICreationEvent(
|
||||
val pokemonID: UUID,
|
||||
val mountShoulder: Boolean,
|
||||
val options: Multimap<Orientation, InteractWheelOption>
|
||||
) {
|
||||
fun addFillingOption(option: InteractWheelOption) {
|
||||
options.put(getNextFreeOrientation(), option)
|
||||
}
|
||||
|
||||
fun addOption(orientation: Orientation, option: InteractWheelOption) {
|
||||
options.put(orientation, option)
|
||||
}
|
||||
|
||||
private fun getNextFreeOrientation(): Orientation {
|
||||
var largest = Orientation.TOP_LEFT
|
||||
for(orientation in Orientation.values()) {
|
||||
if(!options.containsKey(orientation)) {
|
||||
return orientation
|
||||
} else {
|
||||
if(options.get(orientation).size < options.get(largest).size) {
|
||||
largest = orientation
|
||||
}
|
||||
}
|
||||
}
|
||||
return largest
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.fossil
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.pokemon.evolution.predicate.NbtItemPredicate
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
|
||||
class Fossil(
|
||||
identifier: Identifier,
|
||||
val result: PokemonProperties,
|
||||
val fossils: List<NbtItemPredicate>
|
||||
): StringIdentifiable {
|
||||
|
||||
@Transient
|
||||
var identifier: Identifier = identifier
|
||||
internal set
|
||||
|
||||
override fun asString(): String {
|
||||
return identifier.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the fossil.
|
||||
* @return The name of the fossil.
|
||||
*/
|
||||
fun getName(): MutableText = Text.translatable("${identifier.namespace}.fossil.${identifier.path}.name")
|
||||
|
||||
/**
|
||||
* Whether the fossil ingredients match this fossil.
|
||||
* @param ingredients The ingredients to check.
|
||||
* @return True if the ingredients match, false otherwise.
|
||||
*/
|
||||
fun matchesIngredients(ingredients: List<ItemStack>): Boolean {
|
||||
if (this.fossils.size != ingredients.size) {
|
||||
return false
|
||||
}
|
||||
|
||||
return this.fossils.all { fossil ->
|
||||
ingredients.any { fossil.item.fits(it.item, Registries.ITEM) && fossil.nbt.test(it) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the fossil ingredients match a subset of this fossil.
|
||||
* @param ingredients The ingredients to check.
|
||||
* @return True if the ingredients are a subset, false otherwise.
|
||||
*/
|
||||
fun matchesIngredientsSubSet(ingredients: List<ItemStack>): Boolean {
|
||||
if (this.fossils.size < ingredients.size) {
|
||||
return false
|
||||
}
|
||||
|
||||
return ingredients.all { ingredient ->
|
||||
ingredients.count { item -> ingredient.itemMatches(item.registryEntry) } <=
|
||||
this.fossils.count { fossil -> fossil.item.fits(ingredient.item, Registries.ITEM) && fossil.nbt.test(ingredient) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the [ItemStack] is an ingredient for this fossil.
|
||||
* @param itemStack The [ItemStack] to check.
|
||||
* @return True if the [ItemStack] is an ingredient, false otherwise.
|
||||
*/
|
||||
fun isIngredient(itemStack: ItemStack): Boolean {
|
||||
return this.fossils.any { it.item.fits(itemStack.item, Registries.ITEM) && it.nbt.test(itemStack) }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.fossil
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.fossil.FossilRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.NbtItemPredicateAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.predicate.NbtItemPredicate
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
object Fossils: JsonDataRegistry<Fossil> {
|
||||
|
||||
override val id: Identifier = cobblemonResource("fossils")
|
||||
override val type: ResourceType = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<Fossils>()
|
||||
|
||||
override val gson = GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
|
||||
.registerTypeAdapter(NbtItemPredicate::class.java, NbtItemPredicateAdapter)
|
||||
.create()
|
||||
|
||||
override val typeToken: TypeToken<Fossil> = TypeToken.get(Fossil::class.java)
|
||||
override val resourcePath: String = "fossils"
|
||||
|
||||
private val fossils = hashMapOf<Identifier, Fossil>()
|
||||
|
||||
override fun reload(data: Map<Identifier, Fossil>) {
|
||||
this.fossils.clear()
|
||||
data.forEach { (identifier, fossil) ->
|
||||
try {
|
||||
fossil.identifier = identifier
|
||||
this.fossils[identifier] = fossil
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Skipped loading the {} fossil", identifier, e)
|
||||
}
|
||||
}
|
||||
Cobblemon.LOGGER.info("Loaded {} fossils", this.fossils.size)
|
||||
this.observable.emit(this)
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
FossilRegistrySyncPacket(this.all()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all loaded [Fossil]s.
|
||||
*/
|
||||
fun all() = this.fossils.values.toList()
|
||||
|
||||
/**
|
||||
* Gets a [Fossil] by its [Identifier].
|
||||
* @param identifier The identifier of the fossil.
|
||||
* @return The [Fossil] if loaded, otherwise null.
|
||||
*/
|
||||
fun getByIdentifier(identifier: Identifier): Fossil? = this.fossils[identifier]
|
||||
|
||||
/**
|
||||
* Looks for a [Fossil] that matches a [ItemStack].
|
||||
* @param fossilStacks The fossil [ItemStack]'s.
|
||||
* @return The [Fossil] if found, otherwise null.
|
||||
*/
|
||||
fun getFossilByItemStacks(fossilStacks: List<ItemStack>): Fossil? {
|
||||
return this.all().firstOrNull { it.matchesIngredients(fossilStacks) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for a [Fossil] that is a superset of [ItemStack].
|
||||
* @param fossilStacks The fossil [ItemStack]'s.
|
||||
* @return The [Fossil] if found to be a superset, otherwise null.
|
||||
*/
|
||||
fun getSubFossilByItemStacks(fossilStacks: List<ItemStack>): Fossil? {
|
||||
return this.all().firstOrNull { it.matchesIngredientsSubSet(fossilStacks) }
|
||||
}
|
||||
/**
|
||||
* Checks if a [ItemStack] is a fossil ingredient.
|
||||
* @param itemStack The ingredient [ItemStack].
|
||||
* @return true if it's a fossil ingredient, otherwise false.
|
||||
*/
|
||||
fun isFossilIngredient(itemStack: ItemStack): Boolean {
|
||||
return this.all().any { it.isIngredient(itemStack) }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.fossil
|
||||
|
||||
import com.cobblemon.mod.common.registry.ItemTagCondition
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
data class NaturalMaterial(
|
||||
val content: Int = 0,
|
||||
val item: Identifier?,
|
||||
val tag: ItemTagCondition? = null,
|
||||
val returnItem: Identifier? = null
|
||||
)
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.fossil
|
||||
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.fossil.NaturalMaterialRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.registry.ItemTagCondition
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
|
||||
override val id = cobblemonResource("natural_materials")
|
||||
override val type = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<NaturalMaterials>()
|
||||
override val typeToken: TypeToken<List<NaturalMaterial>> =
|
||||
TypeToken.getParameterized(List::class.java, NaturalMaterial::class.java) as TypeToken<List<NaturalMaterial>>
|
||||
override val resourcePath = "natural_materials"
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(ItemTagCondition::class.java, ItemLikeConditionAdapter)
|
||||
.create()
|
||||
|
||||
private val itemMap = mutableMapOf<Identifier, NaturalMaterial>()
|
||||
private val tagMap = mutableMapOf<ItemTagCondition, NaturalMaterial>()
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
NaturalMaterialRegistrySyncPacket(this.itemMap.values.toList() + this.tagMap.values.toList()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
override fun reload(data: Map<Identifier, List<NaturalMaterial>>) {
|
||||
data.forEach { entry ->
|
||||
entry.value.forEach {
|
||||
itemMap.remove(it.item)
|
||||
if (it.item != null) {
|
||||
itemMap[it.item] = it
|
||||
}
|
||||
if (it.tag != null) {
|
||||
tagMap[it.tag] = it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isNaturalMaterial(item: ItemStack): Boolean {
|
||||
val itemId = Registries.ITEM.getId(item.item)
|
||||
return itemId in itemMap.keys || tagMap.keys.any {
|
||||
it.fits(item.item, Registries.ITEM)
|
||||
}
|
||||
}
|
||||
|
||||
fun getContent(item: ItemStack): Int? {
|
||||
val itemId = Registries.ITEM.getId(item.item)
|
||||
if (itemId in itemMap.keys) {
|
||||
return itemMap[itemId]?.content
|
||||
}
|
||||
val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
if (tag != null) {
|
||||
return tagMap[tag]?.content
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun getReturnItem(item: ItemStack): Identifier? {
|
||||
val itemId = Registries.ITEM.getId(item.item)
|
||||
if (itemId in itemMap.keys) {
|
||||
return itemMap[itemId]?.returnItem
|
||||
}
|
||||
val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
if (tag != null) {
|
||||
return tagMap[tag]?.returnItem
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -208,10 +208,12 @@ fun drawPortraitPokemon(
|
||||
if (state == null) {
|
||||
model.setupAnimStateless(setOf(PoseType.PORTRAIT, PoseType.PROFILE))
|
||||
} else {
|
||||
val originalPose = state.currentPose
|
||||
model.getPose(PoseType.PORTRAIT)?.let { state.setPose(it.poseName) }
|
||||
state.timeEnteredPose = 0F
|
||||
state.updatePartialTicks(partialTicks)
|
||||
model.setupAnimStateful(null, state, 0F, 0F, 0F, 0F, 0F)
|
||||
originalPose?.let { state.setPose(it) }
|
||||
}
|
||||
|
||||
matrixStack.push()
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.item.ability
|
||||
|
||||
import com.cobblemon.mod.common.api.abilities.*
|
||||
import com.cobblemon.mod.common.item.interactive.ability.AbilityTypeChanger
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
|
||||
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbilityType
|
||||
|
||||
/**
|
||||
* Represents a change operation for a [Pokemon.ability].
|
||||
* This is backed by the associated [PotentialAbility].
|
||||
*
|
||||
* @param T The type of [PotentialAbility].
|
||||
*/
|
||||
interface AbilityChanger<T : PotentialAbility> {
|
||||
|
||||
/**
|
||||
* The [PotentialAbilityType] of type [T].
|
||||
*/
|
||||
val type: PotentialAbilityType<T>
|
||||
|
||||
/**
|
||||
* Collects all the possible targets for the [type] and the given [pokemon].
|
||||
*
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
* @return A set containing all their legal abilities associated with [type], can be empty.
|
||||
*/
|
||||
fun queryPossible(pokemon: Pokemon): Set<AbilityTemplate>
|
||||
|
||||
/**
|
||||
* Attempts to update the ability of the given [pokemon].
|
||||
*
|
||||
* @param pokemon The [Pokemon] attempting to change an ability.
|
||||
* @return If the operation was successful.
|
||||
*/
|
||||
fun performChange(pokemon: Pokemon): Boolean
|
||||
|
||||
/**
|
||||
* Checks if the current [PotentialAbilityType] of a [Pokemon.ability] is possible to swap from with this.
|
||||
*
|
||||
* @param type The [PotentialAbilityType] or null if the ability is forced and/or illegal.
|
||||
* @return If the operation can be performed.
|
||||
*/
|
||||
fun canChangeFrom(type: PotentialAbilityType<*>?): Boolean
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* An implementation of [AbilityChanger] for [CommonAbility].
|
||||
*
|
||||
* While this can be used in custom data scenarios this functions most "game-like" if the Pokémon only has 2 common abilities.
|
||||
*/
|
||||
@JvmStatic
|
||||
val COMMON_ABILITY: AbilityChanger<CommonAbility> = AbilityTypeChanger(CommonAbilityType) { other -> other == CommonAbilityType }
|
||||
|
||||
/**
|
||||
* An implementation of [AbilityChanger] for [HiddenAbility].
|
||||
*
|
||||
* While this can be used in custom data scenarios this functions most "game-like" if the Pokémon only has 1 hidden ability.
|
||||
*/
|
||||
@JvmStatic
|
||||
val HIDDEN_ABILITY: AbilityChanger<HiddenAbility> = AbilityTypeChanger(HiddenAbilityType) { other -> other == CommonAbilityType || other == HiddenAbilityType }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.molang
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
|
||||
/**
|
||||
* An object that can be given a [MoLangRuntime] to produce a single [MoValue]. This abstracts
|
||||
* the use of simple and complex [Expression]s as MoLang can be a single line or multiple.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 22nd, 2023
|
||||
*/
|
||||
interface ExpressionLike {
|
||||
/** Produces a [MoValue] for a [MoLangRuntime] to supply an environment. */
|
||||
fun resolve(runtime: MoLangRuntime): MoValue
|
||||
|
||||
fun resolveDouble(runtime: MoLangRuntime) = resolve(runtime).asDouble()
|
||||
fun resolveFloat(runtime: MoLangRuntime) = resolveDouble(runtime).toFloat()
|
||||
fun resolveString(runtime: MoLangRuntime) = resolve(runtime).asString()
|
||||
fun resolveInt(runtime: MoLangRuntime) = resolveDouble(runtime).toInt()
|
||||
fun resolveBoolean(runtime: MoLangRuntime) = resolveDouble(runtime) == 1.0
|
||||
fun resolveObject(runtime: MoLangRuntime) = resolve(runtime) as ObjectValue<*>
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.molang
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
|
||||
/**
|
||||
* An [ExpressionLike] that produces MoValues by evaluating a series of [Expression]s.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 22nd, 2023
|
||||
*/
|
||||
class ListExpression(val exprs: List<Expression>): ExpressionLike {
|
||||
override fun resolve(runtime: MoLangRuntime) = exprs.resolve(runtime)
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.molang
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangEnvironment
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.MoParams
|
||||
import com.bedrockk.molang.runtime.struct.ArrayStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.dialogue.PlayerDialogueFaceProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunction
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunctions
|
||||
import com.cobblemon.mod.common.util.isInt
|
||||
import com.cobblemon.mod.common.util.itemRegistry
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtDouble
|
||||
import net.minecraft.nbt.NbtElement
|
||||
import net.minecraft.nbt.NbtList
|
||||
import net.minecraft.nbt.NbtString
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.registry.entry.RegistryEntry
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.biome.Biome
|
||||
import net.minecraft.world.dimension.DimensionType
|
||||
|
||||
/**
|
||||
* Holds a bunch of useful MoLang trickery that can be used or extended in API
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 2nd, 2023
|
||||
*/
|
||||
object MoLangFunctions {
|
||||
val generalFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>(
|
||||
"is_int" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().isInt()) },
|
||||
"is_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() != null) },
|
||||
"to_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() ?: 0.0) },
|
||||
"to_int" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toIntOrNull() ?: 0) },
|
||||
"to_string" to java.util.function.Function { params -> StringValue(params.get<MoValue>(0).asString()) },
|
||||
"do_effect_walks" to java.util.function.Function { _ ->
|
||||
DoubleValue(Cobblemon.config.walkingInBattleAnimations)
|
||||
},
|
||||
"random" to java.util.function.Function { params ->
|
||||
val options = mutableListOf<MoValue>()
|
||||
var index = 0
|
||||
while (params.contains(index)) {
|
||||
options.add(params.get(index))
|
||||
index++
|
||||
}
|
||||
return@Function options.random() // Can throw an exception if they specified no args. They'd be idiots though.
|
||||
},
|
||||
"curve" to java.util.function.Function { params ->
|
||||
val curveName = params.getString(0)
|
||||
val curve = WaveFunctions.functions[curveName] ?: throw IllegalArgumentException("Unknown curve: $curveName")
|
||||
return@Function ObjectValue(curve)
|
||||
},
|
||||
"array" to java.util.function.Function { params ->
|
||||
val values = params.params
|
||||
val array = ArrayStruct(hashMapOf())
|
||||
values.forEachIndexed { index, moValue -> array.setDirectly("$index", moValue) }
|
||||
return@Function array
|
||||
}
|
||||
)
|
||||
val biomeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val worldFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val dimensionTypeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val blockFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val playerFunctions = mutableListOf<(ServerPlayerEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ player ->
|
||||
hashMapOf(
|
||||
"username" to java.util.function.Function { _ -> StringValue(player.gameProfile.name) },
|
||||
"uuid" to java.util.function.Function { _ -> StringValue(player.gameProfile.id.toString()) },
|
||||
"data" to java.util.function.Function { _ -> return@Function Cobblemon.molangData.load(player.uuid) },
|
||||
"save_data" to java.util.function.Function { _ -> Cobblemon.molangData.save(player.uuid) },
|
||||
"main_held_item" to java.util.function.Function { _ -> player.world.itemRegistry.getEntry(player.mainHandStack.item).asMoLangValue(RegistryKeys.ITEM) },
|
||||
"off_held_item" to java.util.function.Function { _ -> player.world.itemRegistry.getEntry(player.offHandStack.item).asMoLangValue(RegistryKeys.ITEM) },
|
||||
"face" to java.util.function.Function { _ -> ObjectValue(PlayerDialogueFaceProvider(player.uuid)) }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
fun RegistryEntry<Biome>.asBiomeMoLangValue() = asMoLangValue(RegistryKeys.BIOME).addFunctions(biomeFunctions)
|
||||
fun RegistryEntry<World>.asWorldMoLangValue() = asMoLangValue(RegistryKeys.WORLD).addFunctions(worldFunctions)
|
||||
fun RegistryEntry<Block>.asBlockMoLangValue() = asMoLangValue(RegistryKeys.BLOCK).addFunctions(blockFunctions)
|
||||
fun RegistryEntry<DimensionType>.asDimensionTypeMoLangValue() = asMoLangValue(RegistryKeys.DIMENSION_TYPE).addFunctions(dimensionTypeFunctions)
|
||||
fun ServerPlayerEntity.asMoLangValue(): ObjectValue<ServerPlayerEntity> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
stringify = { it.entityName }
|
||||
)
|
||||
value.addFunctions(playerFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
return value
|
||||
}
|
||||
|
||||
fun <T> RegistryEntry<T>.asMoLangValue(key: RegistryKey<Registry<T>>): ObjectValue<RegistryEntry<T>> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
stringify = { it.key.get().value.toString() }
|
||||
)
|
||||
value.functions.put("is_in") {
|
||||
val tag = TagKey.of(key, Identifier(it.getString(0).replace("#", "")))
|
||||
return@put DoubleValue(if (value.obj.isIn(tag)) 1.0 else 0.0)
|
||||
}
|
||||
value.functions.put("is_of") {
|
||||
val identifier = Identifier(it.getString(0))
|
||||
return@put DoubleValue(if (value.obj.matchesId(identifier)) 1.0 else 0.0)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
fun QueryStruct.addStandardFunctions(): QueryStruct {
|
||||
functions.putAll(generalFunctions)
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : QueryStruct> T.addFunctions(functions: Map<String, java.util.function.Function<MoParams, Any>>): T {
|
||||
this.functions.putAll(functions)
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : QueryStruct> T.addFunction(name: String, function: java.util.function.Function<MoParams, Any>): T {
|
||||
this.functions[name] = function
|
||||
return this
|
||||
}
|
||||
|
||||
fun MoLangEnvironment.getQueryStruct(name: String = "query") = structs.getOrPut(name) { QueryStruct(hashMapOf()) } as QueryStruct
|
||||
|
||||
fun MoLangRuntime.setup(): MoLangRuntime {
|
||||
environment.getQueryStruct().addStandardFunctions()
|
||||
return this
|
||||
}
|
||||
|
||||
fun writeMoValueToNBT(value: MoValue): NbtElement? {
|
||||
return when (value) {
|
||||
is DoubleValue -> NbtDouble.of(value.value)
|
||||
is StringValue -> NbtString.of(value.value)
|
||||
is ArrayStruct -> {
|
||||
val list = value.map.values
|
||||
val nbtList = NbtList()
|
||||
list.mapNotNull(::writeMoValueToNBT).forEach(nbtList::add)
|
||||
nbtList
|
||||
}
|
||||
is VariableStruct -> {
|
||||
val nbt = NbtCompound()
|
||||
value.map.forEach { (key, value) ->
|
||||
val element = writeMoValueToNBT(value) ?: return@forEach
|
||||
nbt.put(key, element)
|
||||
}
|
||||
nbt
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun readMoValueFromNBT(nbt: NbtElement): MoValue {
|
||||
return when (nbt) {
|
||||
is NbtDouble -> DoubleValue(nbt.doubleValue())
|
||||
is NbtString -> StringValue(nbt.asString())
|
||||
is NbtList -> {
|
||||
val array = ArrayStruct(hashMapOf())
|
||||
var index = 0
|
||||
nbt.forEach { element ->
|
||||
val value = readMoValueFromNBT(element)
|
||||
array.setDirectly("$index", value)
|
||||
index++
|
||||
}
|
||||
array
|
||||
}
|
||||
is NbtCompound -> {
|
||||
val variable = VariableStruct(hashMapOf())
|
||||
nbt.keys.toList().forEach { key ->
|
||||
val value = readMoValueFromNBT(nbt[key]!!)
|
||||
variable.map[key] = value
|
||||
}
|
||||
variable
|
||||
}
|
||||
else -> null
|
||||
} ?: throw IllegalArgumentException("Invalid NBT element type: ${nbt.type}")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.molang
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
|
||||
/**
|
||||
* A [MoValue] that just wraps around some other object value. It's for good and valid reasons.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 2nd, 2023
|
||||
*/
|
||||
class ObjectValue<T>(
|
||||
var obj: T,
|
||||
val stringify: (T) -> String = { it.toString() },
|
||||
val doublify: (T) -> Double = { throw NotImplementedError("Doublify not implemented for this object value, are you doing weird molang") }
|
||||
) : QueryStruct(hashMapOf()) {
|
||||
override fun value() = this
|
||||
override fun asDouble() = doublify(obj)
|
||||
override fun asString() = stringify(obj)
|
||||
}
|
||||
@@ -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.api.molang
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
|
||||
/**
|
||||
* A simple implementation of [ExpressionLike] that is just a single [Expression]. This
|
||||
* is as opposed to [ListExpression]s.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 22nd, 2023
|
||||
*/
|
||||
class SingleExpression(val expr: Expression) : ExpressionLike {
|
||||
override fun resolve(runtime: MoLangRuntime) = runtime.resolve(expr)
|
||||
}
|
||||
@@ -8,6 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
@@ -45,8 +51,22 @@ open class MoveTemplate(
|
||||
val pp: Int,
|
||||
val priority: Int,
|
||||
val critRatio: Double,
|
||||
val effectChances: Array<Double>
|
||||
val effectChances: Array<Double>,
|
||||
val actionEffect: ActionEffectTimeline?
|
||||
) {
|
||||
val struct: MoStruct by lazy {
|
||||
QueryStruct(hashMapOf())
|
||||
.addFunction("name") { StringValue(name) }
|
||||
.addFunction("type") { StringValue(elementalType.name) }
|
||||
.addFunction("damage_category") { StringValue(damageCategory.name) }
|
||||
.addFunction("power") { DoubleValue(power) }
|
||||
.addFunction("target") { StringValue(target.name) }
|
||||
.addFunction("accuracy") { DoubleValue(accuracy) }
|
||||
.addFunction("pp") { DoubleValue(pp) }
|
||||
.addFunction("priority") { DoubleValue(priority) }
|
||||
.addFunction("crit_ratio") { DoubleValue(critRatio) }
|
||||
}
|
||||
|
||||
|
||||
val displayName: MutableText
|
||||
get() = lang("move.$name")
|
||||
@@ -65,7 +85,8 @@ open class MoveTemplate(
|
||||
pp = 5,
|
||||
priority = 0,
|
||||
critRatio = 0.0,
|
||||
effectChances = emptyArray()
|
||||
effectChances = emptyArray(),
|
||||
actionEffect = null
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -10,12 +10,15 @@ package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.battles.MoveTarget
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
@@ -72,7 +75,18 @@ object Moves : DataRegistry {
|
||||
effectChances += secondaryMember.get("chance").asDouble
|
||||
}
|
||||
}
|
||||
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray())
|
||||
val actionEffect = ActionEffects.actionEffects[id.asIdentifierDefaultingNamespace()]
|
||||
?: run {
|
||||
ActionEffects.actionEffects["generic_move".asIdentifierDefaultingNamespace()]
|
||||
// if (damageCategory == DamageCategories.STATUS) {
|
||||
// ActionEffects.actionEffects[cobblemonResource("status")]
|
||||
// } else {
|
||||
// val type = elementalType.name.lowercase()
|
||||
// val category = damageCategory.name.lowercase()
|
||||
// ActionEffects.actionEffects["${category}_$type".asIdentifierDefaultingNamespace()]
|
||||
// }
|
||||
}
|
||||
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray(), actionEffect)
|
||||
this.register(move)
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Caught exception trying to resolve the move '{}'", id, e)
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.cobblemon.mod.common.api.moves.animations.keyframes.ActionEffectKeyframe
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.entity.Entity
|
||||
|
||||
/**
|
||||
* An action effect will run and execute a series of 'keyframes', with each running once
|
||||
* the previous has completed. The entire effect is considered complete for the given context
|
||||
* once all the 'holds' provided in the context have been cleared or once every keyframe
|
||||
* has finished.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 20th, 2023
|
||||
*/
|
||||
class ActionEffectTimeline(
|
||||
val timeline: List<ActionEffectKeyframe> = mutableListOf(),
|
||||
val condition: Expression = "true".asExpression()
|
||||
) {
|
||||
companion object {
|
||||
val NONE = ActionEffectTimeline()
|
||||
}
|
||||
|
||||
fun run(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
return if (timeline.isEmpty() || !context.runtime.resolveBoolean(condition)) {
|
||||
CompletableFuture.completedFuture(Unit)
|
||||
} else {
|
||||
val finalFuture = CompletableFuture<Unit>()
|
||||
// .toList copy because I'm paranoid about iterators being trying to share between identical effects playing
|
||||
chainKeyframes(context, timeline.toList().iterator(), finalFuture)
|
||||
finalFuture
|
||||
}
|
||||
}
|
||||
|
||||
fun chainKeyframes(context: ActionEffectContext, iterator: Iterator<ActionEffectKeyframe>, finalFuture: CompletableFuture<Unit>) {
|
||||
if (!iterator.hasNext()) {
|
||||
finalFuture.complete(Unit)
|
||||
} else {
|
||||
val keyframe = iterator.next()
|
||||
context.currentKeyframes.add(keyframe)
|
||||
keyframe.play(context)
|
||||
.thenRun { context.currentKeyframes.remove(keyframe) }
|
||||
.thenApply { chainKeyframes(context, iterator, finalFuture) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ActionEffectContext(
|
||||
val actionEffect: ActionEffectTimeline,
|
||||
val holds: MutableSet<String> = mutableSetOf(),
|
||||
val providers: MutableList<Any> = mutableListOf(),
|
||||
val runtime: MoLangRuntime,
|
||||
var canBeInterrupted: Boolean = false,
|
||||
var interrupted: Boolean = false,
|
||||
var currentKeyframes: MutableList<ActionEffectKeyframe> = mutableListOf()
|
||||
) {
|
||||
inline fun <reified T> findOneProvider() = providers.filterIsInstance<T>().firstOrNull()
|
||||
|
||||
|
||||
}
|
||||
|
||||
class UsersProvider(users: List<Entity>): EntityProvider {
|
||||
override val entities = users
|
||||
constructor(vararg users: Entity): this(users.toList())
|
||||
}
|
||||
|
||||
class TargetsProvider(targets: List<Entity>): EntityProvider {
|
||||
override val entities = targets
|
||||
constructor(vararg targets: Entity): this(targets.toList())
|
||||
}
|
||||
|
||||
interface EntityProvider {
|
||||
val entities: List<Entity>
|
||||
}
|
||||
|
||||
//class MoveAnimationKeyframe(
|
||||
// val sound: Identifier? = null,
|
||||
// val animation: List<AnimationWithMoments> = listOf(),
|
||||
// val effects: List<ActionEffect> = listOf()
|
||||
//)
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.keyframes.*
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.pokemon.adapters.CobblemonStatTypeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import java.awt.Color
|
||||
import net.minecraft.predicate.NumberRange
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Box
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
/**
|
||||
* Data registry containing all of the [ActionEffectTimeline]s that can be triggered from various actions.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 21st, 2023
|
||||
*/
|
||||
object ActionEffects : JsonDataRegistry<ActionEffectTimeline> {
|
||||
override val id: Identifier = cobblemonResource("action_effects")
|
||||
override val type: ResourceType = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<ActionEffects>()
|
||||
|
||||
init {
|
||||
ActionEffectKeyframe.register<AnimationActionEffectKeyframe>("animation")
|
||||
ActionEffectKeyframe.register<EntityMoLangActionEffectKeyframe>("entity_molang")
|
||||
ActionEffectKeyframe.register<MoLangActionEffectKeyframe>("molang")
|
||||
ActionEffectKeyframe.register<ParallelActionEffectKeyframe>("parallel")
|
||||
ActionEffectKeyframe.register<CanInterruptActionEffectKeyframe>("can_interrupt")
|
||||
ActionEffectKeyframe.register<CannotInterruptActionEffectKeyframe>("cannot_interrupt")
|
||||
ActionEffectKeyframe.register<RemoveHoldsActionEffectKeyframe>("remove_holds")
|
||||
ActionEffectKeyframe.register<AddHoldsActionEffectKeyframe>("add_holds")
|
||||
ActionEffectKeyframe.register<MoveToTargetActionEffectKeyframe>("move_to_target")
|
||||
ActionEffectKeyframe.register<ReturnToPositionActionEffectKeyframe>("return_to_position")
|
||||
ActionEffectKeyframe.register<PauseActionEffectKeyframe>("pause")
|
||||
ActionEffectKeyframe.register<SavePositionActionEffectKeyframe>("save_position")
|
||||
ActionEffectKeyframe.register<ForkActionEffectKeyframe>("fork")
|
||||
ActionEffectKeyframe.register<SequenceActionEffectKeyframe>("sequence")
|
||||
ActionEffectKeyframe.register<RunActionEffectKeyframe>("run_action_effect")
|
||||
ActionEffectKeyframe.register<EntityParticlesActionEffectKeyframe>("entity_particles")
|
||||
ActionEffectKeyframe.register<EntitySoundActionEffectKeyframe>("entity_sound")
|
||||
}
|
||||
|
||||
override val gson = GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(ActionEffectKeyframe::class.java, ActionEffectKeyframeAdapter)
|
||||
.registerTypeAdapter(NumberRange.FloatRange::class.java, FloatNumberRangeAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(Collection::class.java, Box::class.java).type, BoxCollectionAdapter)
|
||||
.registerTypeAdapter(Box::class.java, BoxAdapter)
|
||||
.registerTypeAdapter(Vec3d::class.java, VerboseVec3dAdapter)
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(IntRange::class.java, VerboseIntRangeAdapter)
|
||||
.registerTypeAdapter(Color::class.java, LiteralHexColorAdapter)
|
||||
.registerTypeAdapter(Stat::class.java, CobblemonStatTypeAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(
|
||||
TypeToken.getParameterized(
|
||||
TypeToken.get(List::class.java).type,
|
||||
TypeToken.get(ActionEffectKeyframe::class.java).type
|
||||
).type,
|
||||
SingleToPluralAdapter(ActionEffectKeyframe::class.java) { it }
|
||||
)
|
||||
.create()
|
||||
|
||||
override val typeToken: TypeToken<ActionEffectTimeline> = TypeToken.get(ActionEffectTimeline::class.java)
|
||||
override val resourcePath = "action_effects"
|
||||
|
||||
val actionEffects = mutableMapOf<Identifier, ActionEffectTimeline>()
|
||||
override fun reload(data: Map<Identifier, ActionEffectTimeline>) {
|
||||
actionEffects.clear()
|
||||
actionEffects.putAll(data)
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* A single component of an action effect. When played it must return a completable future that completes
|
||||
* when the action this keyframe represents is finished. [interrupt] is provided for when something successfully
|
||||
* interrupts the effect so that if any cancellation logic is necessary, it can be provided.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 26th, 2023
|
||||
*/
|
||||
interface ActionEffectKeyframe {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out ActionEffectKeyframe>>()
|
||||
|
||||
inline fun <reified T : ActionEffectKeyframe> register(type: String) {
|
||||
types[type] = T::class.java
|
||||
}
|
||||
}
|
||||
|
||||
fun play(context: ActionEffectContext): CompletableFuture<Unit>
|
||||
fun interrupt(context: ActionEffectContext) {}
|
||||
fun skip(): CompletableFuture<Unit> = CompletableFuture.completedFuture(Unit)
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* An [ActionEffectKeyframe] that adds some holds from the context for future code to recognize as blocking some
|
||||
* functionality from proceeding.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 27th, 2023
|
||||
*/
|
||||
class AddHoldsActionEffectKeyframe : ActionEffectKeyframe {
|
||||
val holds = mutableSetOf<String>()
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
context.holds.addAll(holds)
|
||||
return CompletableFuture.completedFuture(Unit)
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
|
||||
class AnimationActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityConditionalActionEffectKeyframe {
|
||||
var delay = "0".asExpressionLike()
|
||||
var visibilityRange = 200
|
||||
var animation: Set<String> = setOf("physical")
|
||||
var variables: List<Expression> = listOf()
|
||||
override val entityCondition = "q.entity.is_user".asExpressionLike()
|
||||
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val entities = context.providers
|
||||
.filterIsInstance<EntityProvider>()
|
||||
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||
|
||||
val expressions = variables.map { it.originalString }.toSet()
|
||||
|
||||
// Treat them as expressions if possible but otherwise yeah just send them as strings
|
||||
val animation = animation.map {
|
||||
try {
|
||||
it.asExpressionLike().resolveString(context.runtime).takeIf { it != "0.0" } ?: it
|
||||
} catch (e: Exception) {
|
||||
it
|
||||
}
|
||||
}.toSet()
|
||||
|
||||
for (entity in entities) {
|
||||
val world = entity.world as ServerWorld
|
||||
val players = world.getPlayers { it.distanceTo(entity) <= visibilityRange }
|
||||
val pkt = PlayPoseableAnimationPacket(entity.id, animation = animation, expressions = expressions)
|
||||
players.forEach { it.sendPacket(pkt) }
|
||||
}
|
||||
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class CanInterruptActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
context.canBeInterrupted = true
|
||||
return CompletableFuture.completedFuture(Unit)
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class CannotInterruptActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
context.canBeInterrupted = true
|
||||
return CompletableFuture.completedFuture(Unit)
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
abstract class ConditionalActionEffectKeyframe : ActionEffectKeyframe {
|
||||
var condition: ExpressionLike = "true".asExpressionLike()
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
return if (condition.resolveBoolean(context.runtime)) {
|
||||
playWhenTrue(context)
|
||||
} else {
|
||||
skip()
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit>
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import net.minecraft.entity.Entity
|
||||
|
||||
/**
|
||||
* An action effect keyframe that plays for all entities for which the condition is true.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 21st, 2024
|
||||
*/
|
||||
interface EntityConditionalActionEffectKeyframe {
|
||||
val entityCondition: ExpressionLike
|
||||
fun test(context: ActionEffectContext, entity: Entity, isUser: Boolean): Boolean {
|
||||
// TODO this should use the entity's own query struct
|
||||
context.runtime.environment.getQueryStruct().addFunction("entity") {
|
||||
QueryStruct(hashMapOf())
|
||||
.addFunction("uuid") { StringValue(entity.uuidAsString) }
|
||||
.addFunction("is_user") { DoubleValue(isUser) }
|
||||
}
|
||||
return entityCondition.resolveBoolean(context.runtime)
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
|
||||
/**
|
||||
* An action effect keyframe that will run client-side MoLang for all entities that fit the entity condition.
|
||||
*
|
||||
* This MoLang executes within that entity's runtime, meaning you can trigger animations or locational particles
|
||||
* or sounds.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 30th, 2023
|
||||
*/
|
||||
class EntityMoLangActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityConditionalActionEffectKeyframe {
|
||||
var delay = "0".asExpressionLike()
|
||||
val expressions = mutableSetOf<String>()
|
||||
val visibilityRange = 200
|
||||
override val entityCondition: ExpressionLike = "q.entity.is_user".asExpressionLike()
|
||||
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val entities = context.providers
|
||||
.filterIsInstance<EntityProvider>()
|
||||
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||
|
||||
for (entity in entities) {
|
||||
val world = entity.world as ServerWorld
|
||||
val players = world.getPlayers { it.distanceTo(entity) <= visibilityRange }
|
||||
val pkt = RunPosableMoLangPacket(entityId = entity.id, expressions = expressions)
|
||||
players.forEach { it.sendPacket(pkt) }
|
||||
}
|
||||
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.entity.Poseable
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
|
||||
/**
|
||||
* Spawns particles on the entity based on the given particle effect and locator.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 21st, 2024
|
||||
*/
|
||||
class EntityParticlesActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityConditionalActionEffectKeyframe {
|
||||
override val entityCondition = "q.entity.is_user".asExpressionLike()
|
||||
var effect: String? = null
|
||||
var locator: String = "root"
|
||||
val delay: ExpressionLike = "0".asExpressionLike()
|
||||
val visibilityRange = 200
|
||||
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val entities = context.providers
|
||||
.filterIsInstance<EntityProvider>()
|
||||
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||
|
||||
val effectIdentifier = try {
|
||||
effect?.asExpressionLike()?.resolveString(context.runtime)
|
||||
} catch (e: Exception) {
|
||||
effect
|
||||
}?.asIdentifierDefaultingNamespace() ?: return skip()
|
||||
|
||||
entities.filter { it is Poseable }.forEach { entity ->
|
||||
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locator)
|
||||
val players = (entity.world as ServerWorld).getPlayers { it.distanceTo(entity) <= visibilityRange }
|
||||
packet.sendToPlayers(players)
|
||||
}
|
||||
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
|
||||
/**
|
||||
* An action effect keyframe that plays a positioned sound for all matching entities.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 21st, 2024
|
||||
*/
|
||||
class EntitySoundActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityConditionalActionEffectKeyframe {
|
||||
override val entityCondition = "q.entity.is_user".asExpressionLike()
|
||||
var sound: String? = null
|
||||
val delay: ExpressionLike = "0".asExpressionLike()
|
||||
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val entities = context.providers
|
||||
.filterIsInstance<EntityProvider>()
|
||||
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||
|
||||
val soundIdentifier = try {
|
||||
sound?.asExpressionLike()?.resolveString(context.runtime)?.takeIf { it != "0.0" } ?: sound
|
||||
} catch (e: Exception) {
|
||||
sound
|
||||
}?.asIdentifierDefaultingNamespace() ?: return skip()
|
||||
|
||||
entities.forEach { entity ->
|
||||
val soundEvent = entity.world.registryManager.get(RegistryKeys.SOUND_EVENT).get(soundIdentifier) ?: return skip()
|
||||
entity.playSound(soundEvent, 1f, 1f)
|
||||
}
|
||||
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class ForkActionEffectKeyframe(
|
||||
val condition: ExpressionLike = "true".asExpressionLike(),
|
||||
val ifTrue: List<ActionEffectKeyframe> = listOf(),
|
||||
val ifFalse: List<ActionEffectKeyframe> = listOf()
|
||||
) : ActionEffectKeyframe {
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val future = CompletableFuture<Unit>()
|
||||
/*
|
||||
* Using .toList() before running chainKeyframes because iterators can be weird about sharing,
|
||||
* .toList() creates a copy of the list and then grabs its iterator so much safer (three parachutes)
|
||||
*/
|
||||
if (!condition.resolveBoolean(context.runtime)) {
|
||||
context.actionEffect.chainKeyframes(context, ifFalse.toList().iterator(), future)
|
||||
} else {
|
||||
context.actionEffect.chainKeyframes(context, ifTrue.toList().iterator(), future)
|
||||
}
|
||||
|
||||
return future
|
||||
}
|
||||
}
|
||||
+30
@@ -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.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* An action effect keyframe that simply executes some MoLang on the effect context's runtime.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 21st, 2024
|
||||
*/
|
||||
class MoLangActionEffectKeyframe : ActionEffectKeyframe {
|
||||
val expressions: ExpressionLike = "0".asExpressionLike()
|
||||
val delay: ExpressionLike = "0".asExpressionLike()
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
expressions.resolve(context.runtime)
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.afterOnServer
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonNavigation
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class MoveToTargetActionEffectKeyframe : ActionEffectKeyframe {
|
||||
val speed = 1F
|
||||
val timeout = "4".asExpressionLike()
|
||||
var proximity = -1F
|
||||
val timeoutActionEffect: Identifier? = null
|
||||
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val user = context.findOneProvider<UsersProvider>()?.entities?.firstOrNull() as? PokemonEntity ?: return CompletableFuture.completedFuture(Unit)
|
||||
val target = context.findOneProvider<TargetsProvider>()?.entities?.firstOrNull() ?: return CompletableFuture.completedFuture(Unit)
|
||||
|
||||
val future = CompletableFuture<Unit>()
|
||||
|
||||
var timedOut = false
|
||||
|
||||
val proximity = this.proximity.takeIf { it != -1F } ?: (sqrt(2 * user.boundingBox.xLength.pow(2)) + 1.5F + sqrt(2 * target.boundingBox.xLength.pow(2))).toFloat()
|
||||
|
||||
if (target.distanceTo(user) !in proximity..20F) {
|
||||
future.complete(Unit)
|
||||
return future
|
||||
}
|
||||
|
||||
val timeoutEffect = timeoutActionEffect?.let { ActionEffects.actionEffects[it] } ?: ActionEffectTimeline.NONE
|
||||
|
||||
val nav = user.navigation
|
||||
val navContext = PokemonNavigation.NavigationContext(
|
||||
destinationProximity = proximity,
|
||||
onArrival = {
|
||||
if (!future.isDone && !timedOut) {
|
||||
future.complete(Unit)
|
||||
}
|
||||
},
|
||||
onCannotReach = {
|
||||
if (!future.isDone && !timedOut) {
|
||||
timedOut = true
|
||||
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
afterOnServer(seconds = timeout.resolveFloat(context.runtime)) {
|
||||
if (!future.isDone && !timedOut) {
|
||||
timedOut = true
|
||||
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||
nav.stop()
|
||||
}
|
||||
}
|
||||
|
||||
nav.startMovingTo(target.x, target.y, target.z, speed.toDouble(), navContext)
|
||||
return future
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class ParallelActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||
var keyframes: MutableList<ActionEffectKeyframe> = mutableListOf()
|
||||
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
return CompletableFuture.allOf(
|
||||
*keyframes.map {
|
||||
context.currentKeyframes.add(it)
|
||||
it.play(context).thenRun { context.currentKeyframes.remove(it) }
|
||||
}.toTypedArray()
|
||||
).thenApply {} // Map Void -> Unit at the end
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
|
||||
class PauseActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||
val pause = "1".asExpressionLike()
|
||||
override fun playWhenTrue(context: ActionEffectContext) = delayedFuture(seconds = pause.resolveFloat(context.runtime), serverThread = true)
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* An [ActionEffectKeyframe] that clears some holds from the context, potentially marking the effect as
|
||||
* complete as far as any blocked actions are concerned. If no holds are specified, then all holds are
|
||||
* removed.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 27th, 2023
|
||||
*/
|
||||
class RemoveHoldsActionEffectKeyframe : ActionEffectKeyframe {
|
||||
val delay = 0F
|
||||
val holds = mutableSetOf<String>()
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
return delayedFuture(seconds = delay, serverThread = true).thenApply {
|
||||
if (holds.isEmpty()) {
|
||||
context.holds.clear()
|
||||
} else {
|
||||
context.holds.removeAll(holds)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.after
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonNavigation
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
class ReturnToPositionActionEffectKeyframe : ActionEffectKeyframe {
|
||||
val speed = 1F
|
||||
val timeout = "4".asExpressionLike()
|
||||
val timeoutActionEffect: Identifier? = null
|
||||
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val user = context.findOneProvider<UsersProvider>()?.entities?.firstOrNull() as? PokemonEntity ?: return skip()
|
||||
val future = CompletableFuture<Unit>()
|
||||
|
||||
val pos = (context.runtime.environment.getValue(setOf("${user.uuidAsString}-pos").iterator())?.value() as? ObjectValue<*>)?.obj as? Vec3d ?: return skip()
|
||||
|
||||
var timedOut = false
|
||||
|
||||
if (pos.distanceTo(user.pos) > 20) {
|
||||
future.complete(Unit)
|
||||
return future
|
||||
}
|
||||
|
||||
val timeoutEffect = timeoutActionEffect?.let { ActionEffects.actionEffects[it] } ?: ActionEffectTimeline.NONE
|
||||
|
||||
val nav = user.navigation
|
||||
val navContext = PokemonNavigation.NavigationContext(
|
||||
onArrival = {
|
||||
if (!future.isDone && !timedOut) {
|
||||
future.complete(Unit)
|
||||
}
|
||||
},
|
||||
onCannotReach = {
|
||||
if (!future.isDone && !timedOut) {
|
||||
timedOut = true
|
||||
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
after(seconds = timeout.resolveFloat(context.runtime), serverThread = true) {
|
||||
if (!future.isDone && !timedOut) {
|
||||
timedOut = true
|
||||
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||
nav.stop()
|
||||
}
|
||||
}
|
||||
|
||||
nav.startMovingTo(pos.x, pos.y, pos.z, speed.toDouble(), navContext)
|
||||
return future
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* An action effect keyframe that simply runs another action effect based on an identifier. This action
|
||||
* effect is marked complete only when the action effect it runs is complete unless [waitForActionEffect] is
|
||||
* false.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 21st, 2024
|
||||
*/
|
||||
class RunActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||
val actionEffect: Identifier? = null
|
||||
val waitForActionEffect = true
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
return if (actionEffect != null) {
|
||||
ActionEffects.actionEffects[actionEffect]?.run(context)?.takeIf { waitForActionEffect } ?: skip()
|
||||
} else {
|
||||
skip()
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class SavePositionActionEffectKeyframe: ConditionalActionEffectKeyframe() {
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val user = context.findOneProvider<UsersProvider>()?.entities?.firstOrNull() ?: return skip()
|
||||
context.runtime.environment.setSimpleVariable("${user.uuidAsString}-pos", ObjectValue(user.pos))
|
||||
return skip()
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* A sequence of action effects that are dependent on a condition.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 29th, 2023
|
||||
*/
|
||||
class SequenceActionEffectKeyframe(val keyframes: List<ActionEffectKeyframe> = listOf()) : ConditionalActionEffectKeyframe() {
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val future = CompletableFuture<Unit>()
|
||||
context.actionEffect.chainKeyframes(context, keyframes.toList().iterator(), future)
|
||||
return future
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.multiblock
|
||||
|
||||
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||
import net.minecraft.block.*
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
|
||||
/**
|
||||
* A block that can be part of a [MultiblockStructure]
|
||||
*/
|
||||
abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(properties) {
|
||||
|
||||
override fun onPlaced(
|
||||
world: World,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
placer: LivingEntity?,
|
||||
itemStack: ItemStack?
|
||||
) {
|
||||
if (world is ServerWorld) {
|
||||
val multiblockEntity = world.getBlockEntity(pos) as MultiblockEntity
|
||||
multiblockEntity.multiblockBuilder?.validate(world)
|
||||
}
|
||||
super.onPlaced(world, pos, state, placer, itemStack)
|
||||
}
|
||||
|
||||
override fun onUse(
|
||||
state: BlockState,
|
||||
world: World,
|
||||
pos: BlockPos,
|
||||
player: PlayerEntity,
|
||||
hand: Hand,
|
||||
hit: BlockHitResult
|
||||
): ActionResult {
|
||||
if(hand == Hand.OFF_HAND) {
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
val entity = world.getBlockEntity(pos) as MultiblockEntity
|
||||
if (entity.multiblockStructure != null) {
|
||||
return entity.multiblockStructure!!.onUse(state, world, pos, player, hand, hit)
|
||||
}
|
||||
return super.onUse(state, world, pos, player, hand, hit)
|
||||
}
|
||||
|
||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
|
||||
super.onBreak(world, pos, state, player)
|
||||
if (!world.isClient) {
|
||||
val entity = world.getBlockEntity(pos)
|
||||
if (entity is MultiblockEntity && entity.multiblockStructure != null) {
|
||||
entity.multiblockStructure!!.onBreak(world, pos, state, player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity? {
|
||||
return createMultiBlockEntity(pos, state)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun getRenderType(state: BlockState?): BlockRenderType {
|
||||
return BlockRenderType.MODEL
|
||||
}
|
||||
|
||||
override fun getPickStack(world: BlockView, pos: BlockPos, state: BlockState): ItemStack {
|
||||
val blockEntity = world.getBlockEntity(pos) as? MultiblockEntity ?: return ItemStack.EMPTY
|
||||
return if (blockEntity.multiblockStructure == null) super.getPickStack(world, pos, state) else ItemStack.EMPTY
|
||||
}
|
||||
|
||||
abstract fun createMultiBlockEntity(pos: BlockPos, state: BlockState): FossilMultiblockEntity
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.multiblock
|
||||
|
||||
import com.cobblemon.mod.common.api.multiblock.MultiblockStructure
|
||||
import com.cobblemon.mod.common.api.multiblock.builder.MultiblockStructureBuilder
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.block.entity.BlockEntityType
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtHelper
|
||||
import net.minecraft.network.listener.ClientPlayPacketListener
|
||||
import net.minecraft.network.packet.Packet
|
||||
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
/**
|
||||
* Multiblock entities are kind of complicated. Basically every multiblock entity should have a MultiBlockStructureBuilder
|
||||
* that is checked when this block entity is created. The multiblock entity also contains a reference to a MultiblockStructure
|
||||
* which is shared between all MultiblockEntities in the structure. Finally, every Multiblock contains the location of the
|
||||
* block that controls this blockentities associated structure
|
||||
*/
|
||||
abstract class MultiblockEntity(
|
||||
type: BlockEntityType<*>,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
var multiblockBuilder: MultiblockStructureBuilder?
|
||||
) : BlockEntity(type, pos, state) {
|
||||
|
||||
abstract var multiblockStructure: MultiblockStructure?
|
||||
abstract var masterBlockPos: BlockPos?
|
||||
|
||||
override fun toUpdatePacket(): Packet<ClientPlayPacketListener>? {
|
||||
return BlockEntityUpdateS2CPacket.create(this)
|
||||
}
|
||||
|
||||
override fun toInitialChunkDataNbt(): NbtCompound {
|
||||
val result = NbtCompound()
|
||||
writeNbt(result)
|
||||
return result
|
||||
}
|
||||
|
||||
override fun writeNbt(nbt: NbtCompound) {
|
||||
super.writeNbt(nbt)
|
||||
//Used for checking build conditions in multiblocks (Dont count a block if it has the FORMED flag)
|
||||
nbt.putBoolean(DataKeys.FORMED, masterBlockPos != null)
|
||||
if (multiblockStructure != null && multiblockStructure!!.controllerBlockPos == pos) {
|
||||
nbt.put(DataKeys.MULTIBLOCK_STORAGE, multiblockStructure!!.writeToNbt())
|
||||
}
|
||||
else if (masterBlockPos != null) {
|
||||
nbt.put(DataKeys.CONTROLLER_BLOCK, NbtHelper.fromBlockPos(masterBlockPos))
|
||||
}
|
||||
}
|
||||
|
||||
abstract override fun readNbt(nbt: NbtCompound)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.multiblock
|
||||
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.random.Random
|
||||
import net.minecraft.world.World
|
||||
|
||||
interface MultiblockStructure {
|
||||
val controllerBlockPos: BlockPos
|
||||
|
||||
fun onUse(
|
||||
blockState: BlockState,
|
||||
world: World,
|
||||
blockPos: BlockPos,
|
||||
player: PlayerEntity,
|
||||
interactionHand: Hand,
|
||||
blockHitResult: BlockHitResult
|
||||
): ActionResult
|
||||
|
||||
fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?)
|
||||
|
||||
fun tick(world: World)
|
||||
|
||||
fun syncToClient(world: World)
|
||||
|
||||
fun markDirty(world: World)
|
||||
fun writeToNbt(): NbtCompound
|
||||
fun getComparatorOutput(state: BlockState, world: World?, pos: BlockPos?): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
fun markRemoved(world: World):Unit
|
||||
fun onTriggerEvent(state: BlockState?, world: ServerWorld?, pos: BlockPos?, random: Random?)
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.multiblock.builder
|
||||
|
||||
import com.cobblemon.mod.common.api.multiblock.condition.MultiblockCondition
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.Box
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
|
||||
/**
|
||||
* Represents an area that has a potential to form a MultiBlockStructure
|
||||
* @property boundingBox The box that each condition checks in
|
||||
* @property conditions The [MultiblockCondition]s that must be met for the multiblock to form. All must be true.
|
||||
*
|
||||
* @author Apion
|
||||
* @since August 24, 2023
|
||||
*/
|
||||
interface MultiblockStructureBuilder {
|
||||
val boundingBox: VoxelShape
|
||||
val conditions: List<MultiblockCondition>
|
||||
|
||||
fun validate(world: ServerWorld): Boolean {
|
||||
conditions.forEach {
|
||||
if (!it.test(world, boundingBox)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
form(world)
|
||||
return true
|
||||
}
|
||||
|
||||
fun form(world: ServerWorld)
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.multiblock.condition
|
||||
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.Box
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
|
||||
class AndCondition(val conditionOne: MultiblockCondition, val conditionTwo: MultiblockCondition) :
|
||||
MultiblockCondition {
|
||||
override fun test(world: ServerWorld, box: VoxelShape): Boolean {
|
||||
return conditionOne.test(world, box) and conditionTwo.test(world, box)
|
||||
}
|
||||
|
||||
}
|
||||
+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.api.multiblock.condition
|
||||
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsList
|
||||
import net.minecraft.predicate.BlockPredicate
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
|
||||
/**
|
||||
* Checks that a block adjacent to another block matches a predicate. Basically we find a block that
|
||||
* matched relToBlock, then we look in each direction to see if there is an adjacent block that matches
|
||||
* target block.
|
||||
*
|
||||
* @param relToBlock The [BlockPredicate] for the main block. The block that matches this predicate is the block whose adjacent blocks we check
|
||||
* @param targetBlock The [BlockPredicate] that is checked for blocks adjacent to relToBlock
|
||||
* @param directionsToCheck The [Direction]s that we check from the target relToBlock
|
||||
*
|
||||
* @author Apion
|
||||
* @since August 24th, 2023
|
||||
*/
|
||||
class BlockRelativeCondition(
|
||||
val relToBlock: BlockPredicate,
|
||||
val targetBlock: BlockPredicate,
|
||||
val directionsToCheck: Array<Direction> = Direction.values()
|
||||
) : MultiblockCondition {
|
||||
override fun test(world: ServerWorld, box: VoxelShape): Boolean {
|
||||
val relToBlockBlockPositions = box.blockPositionsAsList().filter { relToBlock.test(world, it) }
|
||||
relToBlockBlockPositions.forEach { pos ->
|
||||
directionsToCheck.forEach {
|
||||
if (targetBlock.test(world, pos.offset(it))) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.multiblock.condition
|
||||
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.Box
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
interface MultiblockCondition {
|
||||
fun test(world: ServerWorld, box: VoxelShape): Boolean
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.multiblock.condition
|
||||
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.Box
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
|
||||
class OrCondition(
|
||||
val conditionOne: MultiblockCondition,
|
||||
val conditionTwo: MultiblockCondition
|
||||
) : MultiblockCondition {
|
||||
override fun test(world: ServerWorld, box: VoxelShape): Boolean {
|
||||
return conditionOne.test(world, box) or conditionTwo.test(world, box)
|
||||
}
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.net.serializers
|
||||
|
||||
import net.minecraft.entity.data.TrackedDataHandler
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Data serializer of [Identifier] for DataTracker things.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since May 22nd, 2023
|
||||
*/
|
||||
object IdentifierDataSerializer : TrackedDataHandler<Identifier> {
|
||||
override fun copy(value: Identifier) = Identifier(value.namespace, value.path)
|
||||
override fun read(buf: PacketByteBuf) = Identifier(buf.readString(), buf.readString())
|
||||
override fun write(buf: PacketByteBuf, value: Identifier) {
|
||||
buf.writeString(value.namespace)
|
||||
buf.writeString(value.path)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user