Compare commits
836
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb4c288fb0 | ||
|
|
06821e3ad2 | ||
|
|
3428d489eb | ||
|
|
c84303e236 | ||
|
|
08e3c7a09c | ||
|
|
bb2bc39bad | ||
|
|
5fee18b551 | ||
|
|
e8ae11d574 | ||
|
|
d24ef111a3 | ||
|
|
1e75141ca8 | ||
|
|
f33d17b85e | ||
|
|
25dc1464cd | ||
|
|
f4be87e267 | ||
|
|
25ef74f7da | ||
|
|
2d50c0afdf | ||
|
|
62389c904c | ||
|
|
2f17d95923 | ||
|
|
d547e8b010 | ||
|
|
bff54163db | ||
|
|
d9d08e6930 | ||
|
|
6cfc07897d | ||
|
|
6505975c7b | ||
|
|
05df3f9267 | ||
|
|
d4efa59ac5 | ||
|
|
27f94db349 | ||
|
|
686b0efdb7 | ||
|
|
49a1e82d06 | ||
|
|
c950b5e648 | ||
|
|
8c5f803b59 | ||
|
|
cfafff1c15 | ||
|
|
bff3223e58 | ||
|
|
96426b332c | ||
|
|
79e5a4d4d0 | ||
|
|
bf6b141e3d | ||
|
|
32dc1db701 | ||
|
|
f5d3b4ad1f | ||
|
|
5947b086ec | ||
|
|
aac0c8b30a | ||
|
|
b67527564e | ||
|
|
90447f2da9 | ||
|
|
b410b752bd | ||
|
|
945e055915 | ||
|
|
9acc8a9b00 | ||
|
|
20e2f00d84 | ||
|
|
02a47d1c35 | ||
|
|
ba1ee9b08b | ||
|
|
5e3280ea77 | ||
|
|
da45c99b0a | ||
|
|
08386bb4b2 | ||
|
|
35811fe551 | ||
|
|
efbb66c8d8 | ||
|
|
0a853cb1fd | ||
|
|
844b976826 | ||
|
|
a37d85c6ae | ||
|
|
e9109fcc11 | ||
|
|
b67e40da02 | ||
|
|
c8848f0c37 | ||
|
|
8ab2e3b237 | ||
|
|
6a2677e89e | ||
|
|
b2673aa763 | ||
|
|
cd43b44576 | ||
|
|
5f65bf084c | ||
|
|
930bb9096a | ||
|
|
3f0eaf3ac2 | ||
|
|
0d497d017b | ||
|
|
d40e74c2d3 | ||
|
|
cda248ac25 | ||
|
|
5dd64fd414 | ||
|
|
9d76a6dadf | ||
|
|
3b2c08add3 | ||
|
|
e8416baf7f | ||
|
|
c29a422b48 | ||
|
|
ab3390c818 | ||
|
|
bbb49e57aa | ||
|
|
77c57387cf | ||
|
|
b6e87def02 | ||
|
|
405d97d051 | ||
|
|
febe34c990 | ||
|
|
91261e9563 | ||
|
|
f3d9af34b1 | ||
|
|
acffaa7a7d | ||
|
|
f05e6639fd | ||
|
|
54809f8c71 | ||
|
|
1a7a43641e | ||
|
|
bc452fcce6 | ||
|
|
12b121f6bd | ||
|
|
9165f2bfaa | ||
|
|
9063631dfe | ||
|
|
5028db35bb | ||
|
|
1108f38440 | ||
|
|
60c681b8cd | ||
|
|
439140d326 | ||
|
|
908fa71c6a | ||
|
|
64fdd885ae | ||
|
|
a20e5b8dc7 | ||
|
|
7d74c7f6dc | ||
|
|
d6d8062498 | ||
|
|
0750bedb49 | ||
|
|
0c8e51a16e | ||
|
|
b4d4942bf3 | ||
|
|
b89419e972 | ||
|
|
e7dde99aa1 | ||
|
|
50bf3c1141 | ||
|
|
ab7b1e3d56 | ||
|
|
897a73e823 | ||
|
|
65ca915e79 | ||
|
|
70a0bbccbc | ||
|
|
5faba02091 | ||
|
|
68739cd78b | ||
|
|
7311e65cdf | ||
|
|
f0176901dd | ||
|
|
3902561418 | ||
|
|
78c96b3e83 | ||
|
|
cc3308243b | ||
|
|
e8700bf60f | ||
|
|
843cfe20f4 | ||
|
|
f4e0dadf2b | ||
|
|
a57e4984b7 | ||
|
|
0f607ba729 | ||
|
|
a50621b16f | ||
|
|
4227baa87a | ||
|
|
f254d8467f | ||
|
|
f8595ca1ac | ||
|
|
a1001963d0 | ||
|
|
0b97c55679 | ||
|
|
079486e4dc | ||
|
|
50b360dd09 | ||
|
|
a45917c9d2 | ||
|
|
858d00cf89 | ||
|
|
7190444988 | ||
|
|
c9dfb30cab | ||
|
|
7618b1fb27 | ||
|
|
fb725dc4ec | ||
|
|
d5fbbbffb0 | ||
|
|
9b04d8ba1b | ||
|
|
8d2f51dc1a | ||
|
|
401abad5fd | ||
|
|
3f67b339ba | ||
|
|
c083cbabed | ||
|
|
23f7c11512 | ||
|
|
12d5f752af | ||
|
|
be23df3313 | ||
|
|
fb9d6e48f8 | ||
|
|
459032943b | ||
|
|
404dad8d89 | ||
|
|
27297942f3 | ||
|
|
0d32a9e610 | ||
|
|
046628a7e3 | ||
|
|
07af49e6db | ||
|
|
13f08afaf5 | ||
|
|
3d57122eaf | ||
|
|
3f13807e87 | ||
|
|
ce8cdba97f | ||
|
|
d975986196 | ||
|
|
b82f46beb4 | ||
|
|
c947b868ba | ||
|
|
32c75c78b0 | ||
|
|
b71c11882a | ||
|
|
990efdd6d2 | ||
|
|
3c89193fff | ||
|
|
aff9dc3c25 | ||
|
|
6b17d5fd0e | ||
|
|
319dca27ae | ||
|
|
5d20372645 | ||
|
|
74108a2088 | ||
|
|
aab710dd8b | ||
|
|
4a65251817 | ||
|
|
1fb1a73060 | ||
|
|
6811bc71fc | ||
|
|
6205a23edd | ||
|
|
2f844bc56e | ||
|
|
5ca4082675 | ||
|
|
078bc139f7 | ||
|
|
37d07d3b03 | ||
|
|
5bccfe831d | ||
|
|
3fbaa0a0e6 | ||
|
|
931d26569c | ||
|
|
b207fe233e | ||
|
|
0cc0910455 | ||
|
|
b5acee4911 | ||
|
|
ccada109b1 | ||
|
|
16c0d37b54 | ||
|
|
f6c16ea567 | ||
|
|
b9934f5130 | ||
|
|
3c48b6edab | ||
|
|
fdf8bc26a5 | ||
|
|
900cbed5fa | ||
|
|
233cd2a7d7 | ||
|
|
0c8b60018a | ||
|
|
a54787152d | ||
|
|
2932f0a40c | ||
|
|
94d47391af | ||
|
|
9964478ce1 | ||
|
|
d3667e1add | ||
|
|
04e1459d9e | ||
|
|
e99855bdc5 | ||
|
|
028a526c51 | ||
|
|
9650cdb4f2 | ||
|
|
5326845c7a | ||
|
|
7646df0563 | ||
|
|
23369cf1d6 | ||
|
|
864e9de3e8 | ||
|
|
68b4fa7805 | ||
|
|
c7e1fda7bb | ||
|
|
6c42bdcd4e | ||
|
|
439cbc6db3 | ||
|
|
652b66202d | ||
|
|
9f031e638a | ||
|
|
45da02e7c0 | ||
|
|
68a04d05f8 | ||
|
|
e329171b11 | ||
|
|
b8121543ee | ||
|
|
70cf56fad6 | ||
|
|
f88a114e0e | ||
|
|
ff888f8c73 | ||
|
|
66a250eb9e | ||
|
|
3c56ba9880 | ||
|
|
514a48e508 | ||
|
|
32b66cb4ff | ||
|
|
057de4d4e2 | ||
|
|
081e2d3b2b | ||
|
|
856a51e574 | ||
|
|
a4786a16c0 | ||
|
|
c904f14c7b | ||
|
|
896cf12b71 | ||
|
|
1506c97ffc | ||
|
|
9107586fc1 | ||
|
|
bc96460eb3 | ||
|
|
94705fcd09 | ||
|
|
7ae935f5e3 | ||
|
|
6d06b9b559 | ||
|
|
bae421ff27 | ||
|
|
f81743e07f | ||
|
|
b0e4693f2b | ||
|
|
e569483f63 | ||
|
|
164d16dce9 | ||
|
|
a504b8f595 | ||
|
|
0a9ea97aa6 | ||
|
|
91e281514b | ||
|
|
a03c8bbdbd | ||
|
|
22074dc228 | ||
|
|
3a40ba8b29 | ||
|
|
0d84b4e958 | ||
|
|
098399f754 | ||
|
|
334a356446 | ||
|
|
acac69e750 | ||
|
|
f8aa54855d | ||
|
|
7d928d581f | ||
|
|
31394f472f | ||
|
|
f721b1850c | ||
|
|
4419646f11 | ||
|
|
40bbd2eb2e | ||
|
|
6cfe71da9b | ||
|
|
393357d9f6 | ||
|
|
dcf0c73005 | ||
|
|
856ec6c655 | ||
|
|
54a10f77db | ||
|
|
0f50bde4db | ||
|
|
d7368ceba6 | ||
|
|
1e8fc587af | ||
|
|
75bcac7a49 | ||
|
|
111cc7aafd | ||
|
|
924dcf9014 | ||
|
|
63aa1ed632 | ||
|
|
eda4dc7236 | ||
|
|
acfef61eac | ||
|
|
85e1e20e41 | ||
|
|
fe09db6636 | ||
|
|
b6a79b74b6 | ||
|
|
9f305370f8 | ||
|
|
b0df15cab0 | ||
|
|
316711f796 | ||
|
|
8718a7e140 | ||
|
|
9930adb2a8 | ||
|
|
8d7abe318e | ||
|
|
23547bd4ab | ||
|
|
02378b9385 | ||
|
|
f818e59021 | ||
|
|
1c8a91b027 | ||
|
|
cf37307bcb | ||
|
|
cd243008cd | ||
|
|
9b63c5117e | ||
|
|
1ed1c70070 | ||
|
|
24d7cfeff9 | ||
|
|
5c149495e0 | ||
|
|
4a78268389 | ||
|
|
367941a418 | ||
|
|
f1aa07fae3 | ||
|
|
b21e1432d1 | ||
|
|
a259ae5dc3 | ||
|
|
98dbc8f6dd | ||
|
|
dfc3c6eafe | ||
|
|
85ed4bac2e | ||
|
|
75c7103cb5 | ||
|
|
3163e5e8e8 | ||
|
|
efcae7bea5 | ||
|
|
563ec57e66 | ||
|
|
8993b77374 | ||
|
|
af1c592266 | ||
|
|
910ea942fb | ||
|
|
2e45b1f74b | ||
|
|
7b7a3f0d60 | ||
|
|
d94a3f6e86 | ||
|
|
51ac086ce7 | ||
|
|
92cc9a32b4 | ||
|
|
6b0708ed80 | ||
|
|
5de181ccad | ||
|
|
ae71e204d8 | ||
|
|
554063f82b | ||
|
|
56df4e122f | ||
|
|
3715591e37 | ||
|
|
f5a67a48ea | ||
|
|
95830492c4 | ||
|
|
850e1da3d4 | ||
|
|
8b27dcbb52 | ||
|
|
73a688b6f1 | ||
|
|
26a8ec8cf1 | ||
|
|
83d20afa12 | ||
|
|
165a6a591c | ||
|
|
26367a5eb9 | ||
|
|
783240c06f | ||
|
|
fbcad3e605 | ||
|
|
10c1a1350c | ||
|
|
69875008c3 | ||
|
|
e39eb89f59 | ||
|
|
71015ec3c7 | ||
|
|
09b8071f5b | ||
|
|
e011b2dbbd | ||
|
|
7208842b0c | ||
|
|
2830856812 | ||
|
|
50f9b6ecbd | ||
|
|
f31182419f | ||
|
|
918dbf28ce | ||
|
|
5c73e7d0f1 | ||
|
|
950d7a7a86 | ||
|
|
0f068c763f | ||
|
|
32b799735a | ||
|
|
fba015809f | ||
|
|
917d115a54 | ||
|
|
bf2de308ed | ||
|
|
0d278ed756 | ||
|
|
99cab0a346 | ||
|
|
b83c04ddca | ||
|
|
83fba052a5 | ||
|
|
66438dd0c0 | ||
|
|
470776e49e | ||
|
|
c1e02d5731 | ||
|
|
9303ca77bb | ||
|
|
f2043ff12e | ||
|
|
9fc6e2f696 | ||
|
|
6fb84703d0 | ||
|
|
35ca5dcfe9 | ||
|
|
77d07fb444 | ||
|
|
dbce0b70e5 | ||
|
|
83bb7eaf64 | ||
|
|
ec0b723ae9 | ||
|
|
e2049c7998 | ||
|
|
8968acf214 | ||
|
|
405b679d68 | ||
|
|
dcc134ef37 | ||
|
|
b356c1d162 | ||
|
|
c4f224f406 | ||
|
|
10ff3cefb5 | ||
|
|
5c80e28c7d | ||
|
|
bdb1330706 | ||
|
|
b30f4e18da | ||
|
|
7563b53fa1 | ||
|
|
f852f16c9c | ||
|
|
de730d73c0 | ||
|
|
dbe72a7fbf | ||
|
|
c1225cb920 | ||
|
|
17927c11bf | ||
|
|
66f6bd72d0 | ||
|
|
6816df7a93 | ||
|
|
7e0699d1bb | ||
|
|
1ce5a530ff | ||
|
|
61e506437b | ||
|
|
a23e1a10f4 | ||
|
|
d1f6a47519 | ||
|
|
4cb6de2cb1 | ||
|
|
000758e7f1 | ||
|
|
57157d068e | ||
|
|
368db15026 | ||
|
|
a0b1d290b5 | ||
|
|
e75b987a6e | ||
|
|
7955563931 | ||
|
|
cd9e22aad4 | ||
|
|
cf66554afe | ||
|
|
a179f3e625 | ||
|
|
fe96f848ad | ||
|
|
37b12ac56b | ||
|
|
6846e2d6a3 | ||
|
|
5da77e2aa5 | ||
|
|
7ac3d4104f | ||
|
|
1c1f1d7031 | ||
|
|
47a26f86dc | ||
|
|
9e054c2b6c | ||
|
|
c685c47d16 | ||
|
|
b968bd98f3 | ||
|
|
5902fec4a8 | ||
|
|
2171a57757 | ||
|
|
882990fe84 | ||
|
|
c1e070e7ba | ||
|
|
7e879aab9d | ||
|
|
08a73ba2c6 | ||
|
|
411d3577e8 | ||
|
|
a24f6ac26c | ||
|
|
58e05442fe | ||
|
|
c79928a8c8 | ||
|
|
994990e4df | ||
|
|
f6b55d3ca5 | ||
|
|
649ffe0f71 | ||
|
|
f861181959 | ||
|
|
bc2ebf7222 | ||
|
|
ac204c99b2 | ||
|
|
606a89ea61 | ||
|
|
4340962786 | ||
|
|
e2f22682bd | ||
|
|
f4ab6de6af | ||
|
|
7bb1f01f28 | ||
|
|
8d7217439f | ||
|
|
3308b4d7e3 | ||
|
|
f6513b5537 | ||
|
|
20217fd40b | ||
|
|
6c5ff42045 | ||
|
|
1e1a176b73 | ||
|
|
ba85055e5a | ||
|
|
caed9e1850 | ||
|
|
5acbb1d514 | ||
|
|
5532ae0c34 | ||
|
|
bc276d0ca9 | ||
|
|
251f1c13a9 | ||
|
|
9322d5d7b4 | ||
|
|
cf8f2d04f6 | ||
|
|
dc8329e2cd | ||
|
|
4351fb0531 | ||
|
|
3b9fcefae0 | ||
|
|
e90601f2b9 | ||
|
|
5fbbabadf7 | ||
|
|
105f0eceab | ||
|
|
8c15640a44 | ||
|
|
51b6141f91 | ||
|
|
a4624f6907 | ||
|
|
3ac459d42c | ||
|
|
726f6f84bf | ||
|
|
c880dbb4ce | ||
|
|
097b471aed | ||
|
|
069c503bda | ||
|
|
b7c8ca1683 | ||
|
|
27f4f34b16 | ||
|
|
d388d3f5db | ||
|
|
744be32389 | ||
|
|
8c97274929 | ||
|
|
a630dbe028 | ||
|
|
3e42fe9d5e | ||
|
|
06fad2ecaf | ||
|
|
3ddc1e846a | ||
|
|
af6c859b16 | ||
|
|
d138d0d602 | ||
|
|
70d0fa96c2 | ||
|
|
133e7dc490 | ||
|
|
4cb0a46797 | ||
|
|
4298031d3f | ||
|
|
f4c43735f7 | ||
|
|
61f90fe721 | ||
|
|
431200c855 | ||
|
|
481a115ba1 | ||
|
|
b0f6e49109 | ||
|
|
122ad4a93c | ||
|
|
464e61b6b0 | ||
|
|
1405faa391 | ||
|
|
1f93dff26c | ||
|
|
002b027e2b | ||
|
|
2a5b25e927 | ||
|
|
597e3ba820 | ||
|
|
20234319e6 | ||
|
|
8b76fd36d7 | ||
|
|
6ca375ff61 | ||
|
|
1836b14d5d | ||
|
|
618b6aca24 | ||
|
|
4a45918971 | ||
|
|
f8af107a1a | ||
|
|
94491d293b | ||
|
|
49debf6cd0 | ||
|
|
c87ae3af8b | ||
|
|
423f2d0711 | ||
|
|
9a0ec5d010 | ||
|
|
60ed674228 | ||
|
|
8bec79abc6 | ||
|
|
0ee4b2551f | ||
|
|
ad3cbd739a | ||
|
|
d9718b308f | ||
|
|
4b03892c86 | ||
|
|
7668ddb6d6 | ||
|
|
33582cd417 | ||
|
|
2474c550cc | ||
|
|
4f8357f5a1 | ||
|
|
b4ac002779 | ||
|
|
f04cadb38d | ||
|
|
79ec178845 | ||
|
|
a8da7dde72 | ||
|
|
576a67502b | ||
|
|
eb72a7c86d | ||
|
|
5d486a5707 | ||
|
|
9975d1a6bf | ||
|
|
dd74dc9737 | ||
|
|
bf37add382 | ||
|
|
432a0aed02 | ||
|
|
6a1a5f81ed | ||
|
|
a620149a93 | ||
|
|
4c21c11484 | ||
|
|
ca72cd5997 | ||
|
|
3952600032 | ||
|
|
d42bc4bec7 | ||
|
|
30a6e7c336 | ||
|
|
d82b168cd6 | ||
|
|
284effc237 | ||
|
|
e97566cd5f | ||
|
|
8c2b87f472 | ||
|
|
f3433f3011 | ||
|
|
587b317cb6 | ||
|
|
febe00e950 | ||
|
|
c7445019f9 | ||
|
|
ff1c3043b3 | ||
|
|
0b038d38e9 | ||
|
|
b0790af3e1 | ||
|
|
912939a5f4 | ||
|
|
7d30183af3 | ||
|
|
2ac8a86d4f | ||
|
|
d598ae0057 | ||
|
|
d3fde8025a | ||
|
|
7fe146db05 | ||
|
|
227458a633 | ||
|
|
e61fb9b3e4 | ||
|
|
97abaaf8ad | ||
|
|
1f3ac2a174 | ||
|
|
ff0629d0b7 | ||
|
|
9936984534 | ||
|
|
ca56975136 | ||
|
|
348daf6a52 | ||
|
|
d67b470ff6 | ||
|
|
130f9e1023 | ||
|
|
eaac8ad908 | ||
|
|
89f8696d88 | ||
|
|
940a1f819f | ||
|
|
3f01edba9d | ||
|
|
24409a5771 | ||
|
|
88e0f98241 | ||
|
|
fde99a7cbf | ||
|
|
1c3929834a | ||
|
|
3a839d7240 | ||
|
|
7737337a86 | ||
|
|
88dc6a42a9 | ||
|
|
bcc93aab4a | ||
|
|
b88561284c | ||
|
|
5fd8230884 | ||
|
|
ca0fa88a77 | ||
|
|
cbb3c1cc0f | ||
|
|
519968b85a | ||
|
|
6314b78e47 | ||
|
|
b791897dbc | ||
|
|
61af1d1e72 | ||
|
|
bf3fc94d92 | ||
|
|
4887415912 | ||
|
|
7f0838832d | ||
|
|
336efafbd3 | ||
|
|
782f8f8a09 | ||
|
|
c1858e49d8 | ||
|
|
7dce3a7a12 | ||
|
|
7786da7296 | ||
|
|
bc365176b1 | ||
|
|
7fe224c206 | ||
|
|
48e5f54341 | ||
|
|
5edf92f124 | ||
|
|
1c3e938f0f | ||
|
|
ec71581eae | ||
|
|
0904b61df0 | ||
|
|
c9e082257c | ||
|
|
53dd27e95d | ||
|
|
8875bbf991 | ||
|
|
e933186d2e | ||
|
|
89bec80b34 | ||
|
|
cc78eca02f | ||
|
|
77a91ec627 | ||
|
|
1036563b24 | ||
|
|
dd5ea74ae4 | ||
|
|
aa7a4dc155 | ||
|
|
3387365732 | ||
|
|
411aa4f2b2 | ||
|
|
63a8e394a9 | ||
|
|
9804b8b62f | ||
|
|
f59279ad51 | ||
|
|
f82cce32f6 | ||
|
|
474ae7dd27 | ||
|
|
d85c1d267b | ||
|
|
6ce2bcb9e9 | ||
|
|
48eff610c3 | ||
|
|
677dd044ff | ||
|
|
87f30eea37 | ||
|
|
370da407ce | ||
|
|
43e4c29f2c | ||
|
|
7924107b00 | ||
|
|
1ef4b4eec9 | ||
|
|
954eb8b51c | ||
|
|
84ceaa29dc | ||
|
|
6974d61b9d | ||
|
|
d9a3a890c8 | ||
|
|
c4495d995a | ||
|
|
9bd5c2db0b | ||
|
|
2518b23f8b | ||
|
|
bd2ceeeed4 | ||
|
|
a6d082b355 | ||
|
|
8af0dbc46d | ||
|
|
3fedd558d6 | ||
|
|
547a2965dd | ||
|
|
c19914e83f | ||
|
|
6c14faa51d | ||
|
|
6b4060e0c4 | ||
|
|
483706151b | ||
|
|
9dc128cc1d | ||
|
|
50b7e84f58 | ||
|
|
a77067ffe5 | ||
|
|
2a49635497 | ||
|
|
a158019d66 | ||
|
|
5f7d296b4d | ||
|
|
c4cd8136bf | ||
|
|
dbc0c11795 | ||
|
|
d30b024bd3 | ||
|
|
a3e979abc8 | ||
|
|
497d72e13b | ||
|
|
02c5021ce2 | ||
|
|
e5bd42c15a | ||
|
|
67a25de202 | ||
|
|
187d70d1f1 | ||
|
|
31fd590968 | ||
|
|
2f57704bae | ||
|
|
4385073234 | ||
|
|
93f14a5b40 | ||
|
|
39a812c5ff | ||
|
|
367aac0274 | ||
|
|
2de0f49af9 | ||
|
|
c749a560fd | ||
|
|
3c6742d040 | ||
|
|
5dc3e08f22 | ||
|
|
1fb5762351 | ||
|
|
b51b661e23 | ||
|
|
a540a9abb7 | ||
|
|
9035180db8 | ||
|
|
5a6f87fe22 | ||
|
|
fe95424e28 | ||
|
|
d70e778f2d | ||
|
|
8faa0db0ed | ||
|
|
c4f133891d | ||
|
|
4b6eeadcc9 | ||
|
|
9028135f61 | ||
|
|
8307e58449 | ||
|
|
33766b11bc | ||
|
|
44fa35e6c7 | ||
|
|
26f205173e | ||
|
|
7ff1ed0307 | ||
|
|
e50348ee32 | ||
|
|
aee84e92cb | ||
|
|
a1f376bdb1 | ||
|
|
6483debd0a | ||
|
|
946c7a97a9 | ||
|
|
39a53db067 | ||
|
|
b2db9ed9ff | ||
|
|
3059f21ce6 | ||
|
|
b48f898c77 | ||
|
|
6f63743bd8 | ||
|
|
21e15f9b8a | ||
|
|
e505d2b2cd | ||
|
|
c83b374830 | ||
|
|
1bdca2dae5 | ||
|
|
91241dec7d | ||
|
|
651b0bd83e | ||
|
|
7f71f809c0 | ||
|
|
05444e6f56 | ||
|
|
e9e84f5548 | ||
|
|
62cb82de6a | ||
|
|
d10f7619e4 | ||
|
|
16e464719b | ||
|
|
21f22a8446 | ||
|
|
9bfc7d7d9b | ||
|
|
7c93eda985 | ||
|
|
1e7a858aa0 | ||
|
|
11fba1b6bd | ||
|
|
f02d1383c8 | ||
|
|
b65f42a480 | ||
|
|
e829c25c82 | ||
|
|
30c2d361a3 | ||
|
|
15984b0a94 | ||
|
|
97de474b79 | ||
|
|
cea13a719d | ||
|
|
faa471b197 | ||
|
|
ce9d66c199 | ||
|
|
d0eb36c87a | ||
|
|
60f8812efd | ||
|
|
7e82f19961 | ||
|
|
27aae68f14 | ||
|
|
a65f24424f | ||
|
|
bfd3433423 | ||
|
|
09e6cec6ef | ||
|
|
4ffe6f4fc5 | ||
|
|
4aaeb579e7 | ||
|
|
487e9c6590 | ||
|
|
bdf7eb7c06 | ||
|
|
c70e5b8fff | ||
|
|
9599b1c631 | ||
|
|
85b42fa90e | ||
|
|
0c1a6c7775 | ||
|
|
d4508fa36b | ||
|
|
3cb1bb3792 | ||
|
|
faf0c7d3d6 | ||
|
|
c8ff1109e1 | ||
|
|
de0c28beab | ||
|
|
acdacffcc0 | ||
|
|
3cab3fe680 | ||
|
|
880a7b5e74 | ||
|
|
504e667d40 | ||
|
|
f8aa611a4b | ||
|
|
c4848efc8a | ||
|
|
0ddf0b5d22 | ||
|
|
fde6e03b98 | ||
|
|
55c084216d | ||
|
|
f3074e3934 | ||
|
|
28be03b978 | ||
|
|
e3ccbe2449 | ||
|
|
5782d356fb | ||
|
|
999d7c7016 | ||
|
|
270db6995c | ||
|
|
bafb169b76 | ||
|
|
5bc0f06500 | ||
|
|
1e244ed37b | ||
|
|
8b8a9b5ce7 | ||
|
|
129549bf2d | ||
|
|
ed7f9d80f8 | ||
|
|
c1054142e0 | ||
|
|
9ee0b82eab | ||
|
|
76f5f81f6a | ||
|
|
0c51152477 | ||
|
|
9b8a0b4969 | ||
|
|
a2528beaf9 | ||
|
|
a3de70d498 | ||
|
|
748eb398b8 | ||
|
|
ea85282f52 | ||
|
|
d723dec820 | ||
|
|
de03945f42 | ||
|
|
bb08c78e8a | ||
|
|
4da8ddbd12 | ||
|
|
8f89d3615b | ||
|
|
dc7f6dca93 | ||
|
|
03ea36ad28 | ||
|
|
472415e0d4 | ||
|
|
b27678c753 | ||
|
|
6eb99263a2 | ||
|
|
bde44f5136 | ||
|
|
da61ff673a | ||
|
|
8a09be435e | ||
|
|
7af6cfbb3b | ||
|
|
ce8aee5b8c | ||
|
|
d5927578a9 | ||
|
|
01ca8c894e | ||
|
|
f724d6d78e | ||
|
|
ee6183db90 | ||
|
|
e959ef37db | ||
|
|
f62d8602b8 | ||
|
|
bf44dd6855 | ||
|
|
cc9273d05d | ||
|
|
c354b4481d | ||
|
|
ba8c411ed4 | ||
|
|
1beedd77c3 | ||
|
|
c34ad88a13 | ||
|
|
619e7f1404 | ||
|
|
da1468e858 | ||
|
|
927b330c4b | ||
|
|
bff6854189 | ||
|
|
290bf9032e | ||
|
|
2629536ad7 | ||
|
|
9708ebc821 | ||
|
|
a38f341965 | ||
|
|
fad39af575 | ||
|
|
4e4492e417 | ||
|
|
5374ee3c0d | ||
|
|
262de24cbf | ||
|
|
936662db2d | ||
|
|
16bb09aee0 | ||
|
|
330a9782bc | ||
|
|
7ac2319c07 | ||
|
|
89a795a7e6 | ||
|
|
510247f3b4 | ||
|
|
a61b710e81 | ||
|
|
049c30f8b1 | ||
|
|
21a7bdd395 | ||
|
|
598caa9259 | ||
|
|
0d28fa3a9d | ||
|
|
87c5c1d6c7 | ||
|
|
dde9cea757 | ||
|
|
1fe77a1dd6 | ||
|
|
72a2dfdde4 | ||
|
|
f6ef1df29d | ||
|
|
4c039e612b | ||
|
|
b0cd32622e | ||
|
|
3445a0220f | ||
|
|
f1a1e46edc | ||
|
|
343e9ef16d | ||
|
|
c4c063418a | ||
|
|
95955b81f6 | ||
|
|
f4cb19c113 | ||
|
|
f313d0897d | ||
|
|
0293606dc9 | ||
|
|
705f223a70 | ||
|
|
409b1ae646 | ||
|
|
13bd66de7b | ||
|
|
b3d59788b3 | ||
|
|
c58ae74a41 | ||
|
|
aa6d07f893 | ||
|
|
cef044c4fe | ||
|
|
e8c7b9066f | ||
|
|
7f0dbdbc28 | ||
|
|
3890d12105 | ||
|
|
d62755bc01 | ||
|
|
dfc8c988d1 | ||
|
|
508daaa472 | ||
|
|
a765065f98 | ||
|
|
7add2b6658 | ||
|
|
b3d780b52b | ||
|
|
1e46837fec | ||
|
|
ac516060c0 | ||
|
|
a5c34a0829 | ||
|
|
06fa4bab17 | ||
|
|
aabead19ec | ||
|
|
af60e07327 | ||
|
|
b72fafaa47 | ||
|
|
e35845cf7d | ||
|
|
0c78830524 |
No files matched your search
+1
-1
@@ -5,4 +5,4 @@ name = "java"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
runtime_version = "16"
|
||||
runtime_version = "17"
|
||||
@@ -0,0 +1,17 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = 100
|
||||
tab_width = 4
|
||||
|
||||
# intellij specific configuration
|
||||
ij_continuation_indent_size = 8
|
||||
ij_formatter_off_tag = @formatter:off
|
||||
ij_formatter_on_tag = @formatter:on
|
||||
ij_formatter_tags_enabled = false
|
||||
ij_smart_tabs = false
|
||||
ij_wrap_on_typing = false
|
||||
@@ -34,7 +34,7 @@ body:
|
||||
attributes:
|
||||
label: Plugins
|
||||
description: |
|
||||
List all plugins running on your server. To list plugins, run `/plugins`.
|
||||
List all plugins or mods running on your server. To list plugins on bukkit, run `/plugins`.
|
||||
If your server is behind a proxy such as Bungeecord, you should list the proxy's plugins as well.
|
||||
validations:
|
||||
required: true
|
||||
required: true
|
||||
@@ -39,11 +39,23 @@ body:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: type
|
||||
attributes:
|
||||
label: Affected Platform(s)
|
||||
description: Which platforms does this issue affect? If you aren't sure, select both.
|
||||
options:
|
||||
- "Bukkit"
|
||||
- "Fabric"
|
||||
multiple: true
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Plugins
|
||||
label: Plugins/mods
|
||||
description: |
|
||||
List all plugins running on your server. To list plugins, run `/plugins`.
|
||||
List all plugins or mods running on your server. To list plugins on bukkit, run `/plugins`.
|
||||
If your server is behind a proxy such as Bungeecord, you should list the proxy's plugins as well.
|
||||
validations:
|
||||
required: true
|
||||
required: true
|
||||
@@ -46,7 +46,7 @@ body:
|
||||
attributes:
|
||||
label: Plugins
|
||||
description: |
|
||||
List all plugins running on your server. To list plugins, run `/plugins`.
|
||||
List all plugins or mods running on your server. To list plugins on bukkit, run `/plugins`.
|
||||
If your server is behind a proxy such as Bungeecord, you should list the proxy's plugins as well.
|
||||
validations:
|
||||
required: true
|
||||
required: true
|
||||
@@ -1,5 +1,5 @@
|
||||
name: Plugin incompatibility or other bug
|
||||
description: Report a bug or plugin incompatibility here
|
||||
name: Plugin/mod incompatibility or other bug
|
||||
description: Report a bug or plugin/mod incompatibility here
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: textarea
|
||||
@@ -30,11 +30,23 @@ body:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: type
|
||||
attributes:
|
||||
label: Affected Platform(s)
|
||||
description: Which platforms does this issue affect? If you aren't sure, select both.
|
||||
options:
|
||||
- "Bukkit"
|
||||
- "Fabric"
|
||||
multiple: true
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Plugins
|
||||
description: |
|
||||
List all plugins running on your server. To list plugins, run `/plugins`.
|
||||
List all plugins or mods running on your server. To list plugins on bukkit, run `/plugins`.
|
||||
If your server is behind a proxy such as Bungeecord, you should list the proxy's plugins as well.
|
||||
validations:
|
||||
required: true
|
||||
required: true
|
||||
@@ -45,7 +45,7 @@ body:
|
||||
attributes:
|
||||
label: Plugins
|
||||
description: |
|
||||
List all plugins running on your server. To list plugins, run `/plugins`.
|
||||
List all plugins or mods running on your server. To list plugins on bukkit, run `/plugins`.
|
||||
If your server is behind a proxy such as Bungeecord, you should list the proxy's plugins as well.
|
||||
validations:
|
||||
required: true
|
||||
required: true
|
||||
@@ -39,11 +39,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -68,4 +68,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v3
|
||||
@@ -7,32 +7,53 @@
|
||||
|
||||
name: Gradle Package
|
||||
|
||||
on:
|
||||
[push, workflow_dispatch]
|
||||
on: [push, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
||||
|
||||
- name: Build with Gradle
|
||||
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4 # Handles Gradle wrapper validation and basic caching
|
||||
|
||||
- name: Cache Gradle Loom Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
arguments: build
|
||||
- name: Upload a Build Artifact
|
||||
uses: actions/upload-artifact@v3.1.0
|
||||
path: .gradle/loom-cache # Path to Loom cache relative to workspace root
|
||||
key: loom-cache-${{ runner.os }}-${{ hashFiles('**/libs.versions.toml', 'fabric/**/build.gradle.kts') }}
|
||||
restore-keys: |
|
||||
loom-cache-${{ runner.os }}
|
||||
|
||||
- name: Build with Gradle (Actual Build for Artifacts)
|
||||
run: ./gradlew build
|
||||
|
||||
- name: Upload Bukkit Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: /home/runner/work/Grim/Grim/build/libs/**.jar
|
||||
name: grimac-bukkit
|
||||
# Adding if-no-files-found for robustness
|
||||
path: ${{ github.workspace }}/bukkit/build/libs/grimac-bukkit-*.jar
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload Fabric Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: grimac-fabric
|
||||
# Adding if-no-files-found for robustness
|
||||
path: ${{ github.workspace }}/fabric/build/libs/grimac-fabric-*.jar
|
||||
if-no-files-found: error
|
||||
|
||||
+8
-1
@@ -19,6 +19,7 @@ build/
|
||||
.gradletasknamecache
|
||||
gradle-app.setting
|
||||
!gradle-wrapper.jar
|
||||
buildSrc/.kotlin
|
||||
|
||||
##############################
|
||||
## IntelliJ
|
||||
@@ -65,4 +66,10 @@ nb-configuration.xml
|
||||
##############################
|
||||
## OS X
|
||||
##############################
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
|
||||
##############################
|
||||
## Fabric
|
||||
##############################
|
||||
run/
|
||||
fabric/run/
|
||||
@@ -0,0 +1,6 @@
|
||||
[submodule "GrimAPI"]
|
||||
path = GrimAPI
|
||||
url = https://github.com/GrimAnticheat/GrimAPI
|
||||
[submodule "api"]
|
||||
path = api
|
||||
url = https://github.com/GrimAnticheat/GrimAPI
|
||||
@@ -1,27 +1,48 @@
|
||||
# GrimAC
|
||||
|
||||
This project is considered feature complete for the 2.0 (open-source) branch of this project. If you would like a bugfix or enhancement and cannot sponsor the work, pull requests are welcome. You can join the [discord](https://discord.com/invite/kqQAhTmkUF) for jar releases & changelogs.
|
||||
|
||||
GrimAC is an open source Minecraft anticheat designed for 1.21 and supports 1.8-1.21. It is free while in beta. It will eventually become paid and/or will include offering additional subscription based paid checks. Geyser players are fully exempt.
|
||||
|
||||
### Compiling through terminal/command prompt
|
||||
1. git clone https://github.com/GrimAnticheat/Grim.git (or click the green code button, download ZIP, then unzip it.)
|
||||
2. cd Grim
|
||||
3. gradlew build
|
||||
4. The final jar is located in build/libs
|
||||
This project is considered feature complete for the 2.0 (open-source) branch of this project. If you would like a bugfix or enhancement and cannot sponsor the work, pull requests are welcome.
|
||||
|
||||
### API Information
|
||||
Grim's API allows you to integrate Grim into your own plugins. For more information, check out the API's GitHub repository [here](https://github.com/GrimAnticheat/GrimAPI).
|
||||
## Downloads
|
||||
- [Modrinth](https://modrinth.com/plugin/grimac)
|
||||
- [Hangar](https://hangar.papermc.io/GrimAnticheat/GrimAnticheat)
|
||||
- [SpigotMC](https://www.spigotmc.org/resources/grim-anticheat.99923/)
|
||||
- *For bleeding edge builds use GitHub artifacts*: [Bukkit](https://nightly.link/GrimAnticheat/Grim/workflows/gradle-publish/2.0/grimac-bukkit.zip), [Fabric](https://nightly.link/GrimAnticheat/Grim/workflows/gradle-publish/2.0/grimac-fabric.zip)
|
||||
|
||||
## Installation notes
|
||||
> [!WARNING]
|
||||
> Java 17 is now required. More information [here](https://github.com/GrimAnticheat/Grim/wiki/Updating-to-Java-17).
|
||||
- Paper, Spigot, Folia, and Fabric are currently supported.
|
||||
- If you use Geyser, place Floodgate on the backend server so grim can exempt bedrock players. Grim cannot access the Floodgate API if it is on the proxy.
|
||||
- If you use ViaVersion, it should be on the backend server as movement is highly dependent on client version.
|
||||
|
||||
## Support & wiki information
|
||||
- Support & discussion: [Discord](https://discord.com/invite/kqQAhTmkUF)
|
||||
- Report issues: [Issues](https://github.com/GrimAnticheat/Grim/issues/new/choose)
|
||||
- Wiki & examples: [Wiki](https://github.com/GrimAnticheat/Grim/wiki)
|
||||
|
||||
## Developer API
|
||||
Grim's API allows you to integrate Grim into your own plugins.
|
||||
- API repository: [GrimAPI](https://github.com/GrimAnticheat/GrimAPI)
|
||||
- Wiki info: [Wiki](https://github.com/GrimAnticheat/GrimAPI)
|
||||
|
||||
## How to compile
|
||||
|
||||
1. `git clone https://github.com/GrimAnticheat/Grim.git`
|
||||
2. `cd Grim`
|
||||
3. `./gradlew build`
|
||||
4. The final jars will compile into the `<platform>/build/libs` folders
|
||||
|
||||
## Grim supremacy
|
||||
|
||||
Here are the main cores that make Grim stand out against other anticheats
|
||||
What makes Grim stand out against other anticheats?
|
||||
|
||||
### Movement Simulation Engine
|
||||
|
||||
* We have a 1:1 replication of the player's possible movements
|
||||
* This covers everything from basic walking, swimming, knockback, cobwebs, to bubble columns
|
||||
* It even covers riding entities from boats to pigs to striders
|
||||
* This covers everything from basic walking, swimming, knockback, cobwebs, to bubble columns
|
||||
* It even covers riding entities from boats to pigs to striders
|
||||
* Built upon covering edge cases to confirm accuracy
|
||||
* 1.13+ clients on 1.13+ servers, 1.12- clients on 1.13+ servers, 1.13+ clients on 1.12- servers, and 1.12- clients on 1.12- servers are all supported regardless of the large technical changes between these versions.
|
||||
* The order of collisions depends on the client version and is correct
|
||||
|
||||
Submodule
+1
Submodule api added at 6061ddc684.
+37
-145
@@ -1,153 +1,45 @@
|
||||
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription.Permission
|
||||
/**
|
||||
* ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
* ┃ GrimAC Build Configuration ┃
|
||||
* ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
*
|
||||
* 🔧 Build Flags:
|
||||
* -PshadePE=true → Enables 'lite' mode
|
||||
* -Prelocate=false → Adds 'no_relocate' modifier
|
||||
* -Prelease=true → Removes commit/modifiers for release build
|
||||
*
|
||||
* Logic in: buildSrc/versioning/BuildConfig.kt & VersionUtil.kt
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("java")
|
||||
id("maven-publish")
|
||||
id("com.github.johnrengelman.shadow") version "8.1.1"
|
||||
id("io.freefair.lombok") version "8.6"
|
||||
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
|
||||
}
|
||||
import versioning.BuildConfig
|
||||
import versioning.VersionUtil
|
||||
|
||||
BuildConfig.init(project)
|
||||
|
||||
val baseVersion = "2.3.72"
|
||||
group = "ac.grim.grimac"
|
||||
version = "2.3.67"
|
||||
description = "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0."
|
||||
java.sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
java.targetCompatibility = JavaVersion.VERSION_1_8
|
||||
version = VersionUtil.computeVersion(baseVersion)
|
||||
description = "Libre simulation anticheat designed for 1.21 with 1.8–1.21 support, powered by PacketEvents 2.0."
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot
|
||||
maven("https://jitpack.io/") { // Grim API
|
||||
content {
|
||||
includeGroup("com.github.grimanticheat")
|
||||
}
|
||||
}
|
||||
maven("https://repo.viaversion.com") // ViaVersion
|
||||
maven("https://repo.aikar.co/content/groups/aikar/") // ACF
|
||||
maven("https://nexus.scarsz.me/content/repositories/releases") // Configuralize
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/") // Floodgate
|
||||
maven("https://repo.opencollab.dev/maven-releases/") // Cumulus (for Floodgate)
|
||||
maven("https://repo.codemc.io/repository/maven-releases/") // PacketEvents
|
||||
maven("https://repo.codemc.io/repository/maven-snapshots/")
|
||||
mavenCentral()
|
||||
// FastUtil, Discord-Webhooks
|
||||
}
|
||||
println("⚙️ Build configuration:")
|
||||
println(" shadePE = ${BuildConfig.shadePE}")
|
||||
println(" relocate = ${BuildConfig.relocate}")
|
||||
println(" mavenLocalOverride = ${BuildConfig.mavenLocalOverride}")
|
||||
println(" release = ${BuildConfig.release}")
|
||||
println(" version = $version")
|
||||
|
||||
dependencies {
|
||||
implementation("com.github.retrooper:packetevents-spigot:2.5.0-SNAPSHOT")
|
||||
implementation("co.aikar:acf-paper:0.5.1-SNAPSHOT")
|
||||
implementation("club.minnced:discord-webhooks:0.8.0") // Newer versions include kotlin-stdlib, which leads to incompatibility with plugins that use Kotlin
|
||||
implementation("it.unimi.dsi:fastutil:8.5.13")
|
||||
implementation("github.scarsz:configuralize:1.4.0")
|
||||
|
||||
implementation("com.github.grimanticheat:grimapi:1193c4fa41")
|
||||
// Used for local testing: implementation("ac.grim.grimac:grimapi:1.0")
|
||||
|
||||
implementation("org.jetbrains:annotations:24.1.0")
|
||||
compileOnly("org.geysermc.floodgate:api:2.0-SNAPSHOT")
|
||||
compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
|
||||
compileOnly("com.viaversion:viaversion-api:4.9.4-SNAPSHOT")
|
||||
//
|
||||
compileOnly("io.netty:netty-all:4.1.85.Final")
|
||||
}
|
||||
|
||||
bukkit {
|
||||
name = "GrimAC"
|
||||
author = "GrimAC"
|
||||
main = "ac.grim.grimac.GrimAC"
|
||||
apiVersion = "1.13"
|
||||
foliaSupported = true
|
||||
|
||||
softDepend = listOf(
|
||||
"ProtocolLib",
|
||||
"ProtocolSupport",
|
||||
"Essentials",
|
||||
"ViaVersion",
|
||||
"ViaBackwards",
|
||||
"ViaRewind",
|
||||
"Geyser-Spigot",
|
||||
"floodgate",
|
||||
"FastLogin"
|
||||
)
|
||||
|
||||
permissions {
|
||||
register("grim.alerts") {
|
||||
description = "Receive alerts for violations"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.alerts.enable-on-join") {
|
||||
description = "Enable alerts on join"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.performance") {
|
||||
description = "Check performance metrics"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.profile") {
|
||||
description = "Check user profile"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.brand") {
|
||||
description = "Show client brands on join"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.sendalert") {
|
||||
description = "Send cheater alert"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.nosetback") {
|
||||
description = "Disable setback"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
|
||||
register("grim.nomodifypacket") {
|
||||
description = "Disable modifying packets"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
|
||||
register("grim.exempt") {
|
||||
description = "Exempt from all checks"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
tasks.register("printVersion") {
|
||||
group = "versioning"
|
||||
description = "Prints the computed project version"
|
||||
doLast {
|
||||
println("VERSION=$version")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn(tasks.shadowJar)
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
publishing.publications.create<MavenPublication>("maven") {
|
||||
artifact(tasks["shadowJar"])
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
minimize()
|
||||
archiveFileName.set("${project.name}-${project.version}.jar")
|
||||
relocate("io.github.retrooper.packetevents", "ac.grim.grimac.shaded.io.github.retrooper.packetevents")
|
||||
relocate("com.github.retrooper.packetevents", "ac.grim.grimac.shaded.com.github.retrooper.packetevents")
|
||||
relocate("co.aikar.commands", "ac.grim.grimac.shaded.acf")
|
||||
relocate("co.aikar.locale", "ac.grim.grimac.shaded.locale")
|
||||
relocate("club.minnced", "ac.grim.grimac.shaded.discord-webhooks")
|
||||
relocate("github.scarsz.configuralize", "ac.grim.grimac.shaded.configuralize")
|
||||
relocate("com.github.puregero", "ac.grim.grimac.shaded.com.github.puregero")
|
||||
relocate("com.google.code.gson", "ac.grim.grimac.shaded.gson")
|
||||
relocate("alexh", "ac.grim.grimac.shaded.maps")
|
||||
relocate("it.unimi.dsi.fastutil", "ac.grim.grimac.shaded.fastutil")
|
||||
relocate("net.kyori", "ac.grim.grimac.shaded.kyori")
|
||||
relocate("okhttp3", "ac.grim.grimac.shaded.okhttp3")
|
||||
relocate("okio", "ac.grim.grimac.shaded.okio")
|
||||
relocate("org.yaml.snakeyaml", "ac.grim.grimac.shaded.snakeyaml")
|
||||
relocate("org.json", "ac.grim.grimac.shaded.json")
|
||||
relocate("org.intellij", "ac.grim.grimac.shaded.intellij")
|
||||
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
|
||||
}
|
||||
// ---------- Java Compile Optimization ----------
|
||||
subprojects {
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
options.isFork = true
|
||||
options.isIncremental = true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
kotlin("plugin.serialization") version "1.9.0" // Use the same Kotlin version as your main project
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.spotless)
|
||||
implementation(libs.lombok)
|
||||
implementation(libs.shadow)
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
dependencyResolutionManagement {
|
||||
versionCatalogs {
|
||||
create("libs") {
|
||||
from(files("../libs.versions.toml"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
plugins {
|
||||
`java-library`
|
||||
id("io.freefair.lombok")
|
||||
id("com.diffplug.spotless")
|
||||
}
|
||||
|
||||
group = rootProject.group
|
||||
version = rootProject.version
|
||||
description = rootProject.description
|
||||
|
||||
// Java compilation settings
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
||||
disableAutoTargetJvm()
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
// Lombok configuration
|
||||
//lombok {
|
||||
// version.set("1.18.30") // Use the version from your version catalog if available
|
||||
//}
|
||||
|
||||
// Spotless configuration
|
||||
spotless {
|
||||
java {
|
||||
endWithNewline()
|
||||
indentWithSpaces(4)
|
||||
removeUnusedImports()
|
||||
trimTrailingWhitespace()
|
||||
targetExclude("build/generated/**/*")
|
||||
}
|
||||
|
||||
kotlinGradle {
|
||||
endWithNewline()
|
||||
indentWithSpaces(4)
|
||||
trimTrailingWhitespace()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tasks {
|
||||
withType<JavaCompile>().configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
options.release.set(17)
|
||||
}
|
||||
|
||||
build {
|
||||
// Ensure spotlessApply runs before build
|
||||
dependsOn(tasks.named("spotlessApply"))
|
||||
}
|
||||
|
||||
// Process resources (e.g., for plugin metadata files)
|
||||
processResources {
|
||||
inputs.property("version", project.version)
|
||||
filesMatching(listOf( // "plugin.yml", Bukkit variable expansion taken care of by net.minecrell.plugin-yml.bukkit
|
||||
"bungee.yml", "velocity-plugin.json", "fabric.mod.json")
|
||||
) {
|
||||
expand("version" to project.version)
|
||||
}
|
||||
}
|
||||
|
||||
javadoc {
|
||||
title = "${rootProject.name}-${project.name} v${rootProject.version}"
|
||||
options.encoding = "UTF-8"
|
||||
options.overview =
|
||||
rootProject.file("buildSrc/src/main/resources/javadoc-overview.html").toString()
|
||||
setDestinationDir(file("${project.layout.buildDirectory.asFile.get()}/docs/javadoc"))
|
||||
options {
|
||||
(this as CoreJavadocOptions).addBooleanOption("Xdoclint:none", true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default tasks
|
||||
defaultTasks("build")
|
||||
@@ -0,0 +1,407 @@
|
||||
import kotlinx.serialization.json.*
|
||||
import java.util.jar.JarFile
|
||||
import java.util.zip.ZipEntry
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
}
|
||||
|
||||
val jijDependencies: Configuration by project.configurations.creating {
|
||||
isCanBeResolved = true
|
||||
isCanBeConsumed = false
|
||||
extendsFrom(project.configurations.getByName("implementation"))
|
||||
project.configurations.findByName("modImplementation")?.let { extendsFrom(it) }
|
||||
}
|
||||
|
||||
data class DependencyIdentifier(
|
||||
val group: String,
|
||||
val name: String,
|
||||
val version: String,
|
||||
val classifier: String = "" // Add classifier field, default to empty string
|
||||
) {
|
||||
override fun toString() = "$group:$name:$version${if (classifier.isNotEmpty()) ":$classifier" else ""}"
|
||||
}
|
||||
|
||||
// Does not support extracting classifiers but while the fabric standard is ambiguous on whether they can be included
|
||||
// It does not appear dependency classifiers are in use by any mod I am aware of or can find
|
||||
fun parseFabricModJson(jarFile: File, project: Project): Set<DependencyIdentifier> {
|
||||
val nestedJars = mutableSetOf<DependencyIdentifier>()
|
||||
try {
|
||||
JarFile(jarFile).use { jar ->
|
||||
val fabricModJsonEntry: ZipEntry? = jar.getEntry("fabric.mod.json")
|
||||
if (fabricModJsonEntry != null) {
|
||||
jar.getInputStream(fabricModJsonEntry).bufferedReader().use { reader ->
|
||||
val jsonContent = reader.readText()
|
||||
val jsonElement = Json.parseToJsonElement(jsonContent)
|
||||
val jsonObject = jsonElement.jsonObject
|
||||
val jarsArray = jsonObject["jars"]?.jsonArray ?: return@use
|
||||
jarsArray.forEach { jarEntry: JsonElement ->
|
||||
val filePath =
|
||||
jarEntry.jsonObject["file"]?.jsonPrimitive?.content ?: return@forEach
|
||||
project.logger.debug(
|
||||
"Found nested JAR in fabric.mod.json: {} in {}",
|
||||
filePath,
|
||||
jarFile
|
||||
)
|
||||
val jarName = filePath.substringAfterLast("/")
|
||||
val parts = jarName.removeSuffix(".jar").split("-")
|
||||
if (parts.size >= 2) {
|
||||
val inferredName = parts.dropLast(1).joinToString("-")
|
||||
val inferredVersion = parts.last()
|
||||
nestedJars.add(DependencyIdentifier("", inferredName, inferredVersion))
|
||||
project.logger.debug("Inferred nested dependency from fabric.mod.json: :$inferredName:$inferredVersion")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
project.logger.error("Failed to parse fabric.mod.json in $jarFile: ${e.message}")
|
||||
}
|
||||
return nestedJars
|
||||
}
|
||||
|
||||
fun extractEmbeddedJars(jarFile: File, project: Project): Set<DependencyIdentifier> {
|
||||
val embeddedJars = mutableSetOf<DependencyIdentifier>()
|
||||
embeddedJars.addAll(parseFabricModJson(jarFile, project)) // Retain existing logic for top-level fabric.mod.json parsing
|
||||
try {
|
||||
JarFile(jarFile).use { jar ->
|
||||
val entries = jar.entries()
|
||||
while (entries.hasMoreElements()) {
|
||||
val entry = entries.nextElement()
|
||||
val entryName = entry.name
|
||||
if (entryName.endsWith(".jar") && (entryName.startsWith("META-INF/jarjar/") || entryName.startsWith(
|
||||
"libs/"
|
||||
) || entryName.startsWith("META-INF/jars/"))
|
||||
) {
|
||||
project.logger.debug("Found embedded JAR: {} in {}", entryName, jarFile)
|
||||
val tempFile = File.createTempFile("embedded-", ".jar")
|
||||
tempFile.deleteOnExit()
|
||||
jar.getInputStream(entry).use { input ->
|
||||
tempFile.outputStream().use { output ->
|
||||
input.copyTo(output)
|
||||
}
|
||||
}
|
||||
JarFile(tempFile).use { embeddedJar ->
|
||||
val fabricModJsonEntry: ZipEntry? = embeddedJar.getEntry("fabric.mod.json")
|
||||
if (fabricModJsonEntry != null) {
|
||||
embeddedJar.getInputStream(fabricModJsonEntry).bufferedReader().use { reader ->
|
||||
val jsonContent = reader.readText()
|
||||
val jsonElement = Json.parseToJsonElement(jsonContent)
|
||||
val jsonObject = jsonElement.jsonObject
|
||||
|
||||
// Extract id and parse into group
|
||||
val id = jsonObject["id"]?.jsonPrimitive?.content
|
||||
?: throw IllegalStateException("Missing 'id' in fabric.mod.json of embedded JAR: $entryName")
|
||||
val idWithDots = id.replace("_", ".")
|
||||
val lastDotIndex = idWithDots.lastIndexOf(".")
|
||||
val group = if (lastDotIndex != -1) idWithDots.substring(0, lastDotIndex) else ""
|
||||
|
||||
// Extract name and version from the JAR filename
|
||||
val jarName = entryName.substringAfterLast("/").removeSuffix(".jar")
|
||||
val (name, version) = parseNameAndVersionFromJarName(jarName)
|
||||
?: throw IllegalStateException("Could not parse name and version from JAR filename: $jarName")
|
||||
|
||||
// Create DependencyIdentifier (classifier is empty for now)
|
||||
val depId = DependencyIdentifier(group, name, version)
|
||||
embeddedJars.add(depId)
|
||||
project.logger.debug("Identified embedded dependency from fabric.mod.json and filename: {}", depId)
|
||||
}
|
||||
} else {
|
||||
project.logger.error("No fabric.mod.json found in embedded JAR: {}. Skipping.", entryName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
project.logger.error("Failed to analyze JAR file $jarFile for embedded JARs: ${e.message}")
|
||||
}
|
||||
return embeddedJars
|
||||
}
|
||||
|
||||
fun parseNameAndVersionFromJarName(jarName: String): Pair<String, String>? {
|
||||
val versionStartRegex = Regex("-(?=\\d)")
|
||||
// Use regex to find the position of the hyphen followed by a digit
|
||||
val versionStartMatch = versionStartRegex.find(jarName) ?: return null
|
||||
val versionStartIndex = versionStartMatch.range.first
|
||||
|
||||
// Split the JAR name into name and version at the version start index
|
||||
val name = jarName.substring(0, versionStartIndex)
|
||||
val version = jarName.substring(versionStartIndex + 1) // Skip the hyphen
|
||||
|
||||
return if (name.isNotEmpty() && version.isNotEmpty()) {
|
||||
Pair(name, version)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun shouldExcludeDependency(
|
||||
dependency: ResolvedDependency,
|
||||
allEmbeddedDependencies: Set<DependencyIdentifier>,
|
||||
actuallyIncludedDependencies: Set<DependencyIdentifier>,
|
||||
project: Project
|
||||
): Boolean {
|
||||
val group = dependency.moduleGroup
|
||||
val name = dependency.moduleName
|
||||
val version = dependency.moduleVersion
|
||||
// Extract classifier from resolved dependency (if available)
|
||||
val classifier = dependency.moduleArtifacts.firstOrNull()?.classifier ?: ""
|
||||
val depId = DependencyIdentifier(group, name, version, classifier)
|
||||
|
||||
if (group.startsWith("net.minecraft") ||
|
||||
group.startsWith("net.fabricmc") ||
|
||||
name == "minecraft" ||
|
||||
name == "fabric-loader" ||
|
||||
name == "fastutil" ||
|
||||
name.startsWith("fabric_") ||
|
||||
name.startsWith("fabric-api")
|
||||
) {
|
||||
project.logger.debug("Excluding platform dependency: {}", depId)
|
||||
return true
|
||||
}
|
||||
|
||||
if (name.endsWith("-bom") || name.contains("_bom")) {
|
||||
project.logger.debug("Excluding BOM file: {}", depId)
|
||||
return true
|
||||
}
|
||||
|
||||
if (allEmbeddedDependencies.any { it.name == name && it.version == version && it.classifier == classifier }) {
|
||||
project.logger.debug("Excluding dependency already embedded in another JAR: {}", depId)
|
||||
return true
|
||||
}
|
||||
|
||||
if (actuallyIncludedDependencies.any { it.name == name && it.version == version && it.classifier == classifier }) {
|
||||
project.logger.debug("Excluding duplicate dependency: {}", depId)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun isJijTarget(
|
||||
dependency: ResolvedDependency,
|
||||
allEmbeddedDependencies: Set<DependencyIdentifier>,
|
||||
actuallyIncludedDependencies: Set<DependencyIdentifier>,
|
||||
project: Project
|
||||
): Boolean {
|
||||
val classifier = dependency.moduleArtifacts.firstOrNull()?.classifier ?: ""
|
||||
project.logger.debug(
|
||||
"Checking JIJ target: {}",
|
||||
DependencyIdentifier(
|
||||
dependency.moduleGroup,
|
||||
dependency.moduleName,
|
||||
dependency.moduleVersion,
|
||||
classifier
|
||||
)
|
||||
)
|
||||
return !shouldExcludeDependency(
|
||||
dependency,
|
||||
allEmbeddedDependencies,
|
||||
actuallyIncludedDependencies,
|
||||
project
|
||||
)
|
||||
}
|
||||
|
||||
fun includeDependencyWithExclusions(
|
||||
depId: DependencyIdentifier,
|
||||
project: Project,
|
||||
actuallyIncludedDependencies: MutableSet<DependencyIdentifier>,
|
||||
allEmbeddedDependencies: Set<DependencyIdentifier>
|
||||
) {
|
||||
project.logger.debug("Including external dependency as JIJ with dynamic exclusions: {}", depId)
|
||||
project.dependencies {
|
||||
// Include dependency with classifier (if present)
|
||||
"include"("${depId.group}:${depId.name}:${depId.version}${if (depId.classifier.isNotEmpty()) ":${depId.classifier}" else ""}") {
|
||||
allEmbeddedDependencies.forEach { embeddedDep ->
|
||||
if (embeddedDep.group.isNotEmpty()) {
|
||||
exclude(group = embeddedDep.group, module = embeddedDep.name)
|
||||
} else {
|
||||
exclude(module = embeddedDep.name)
|
||||
}
|
||||
project.logger.debug("Excluding embedded transitive dependency: ${embeddedDep.name}:${embeddedDep.version}${if (embeddedDep.classifier.isNotEmpty()) ":${embeddedDep.classifier}" else ""}")
|
||||
}
|
||||
}
|
||||
}
|
||||
actuallyIncludedDependencies.add(depId)
|
||||
}
|
||||
|
||||
fun processDependencies(
|
||||
dependencies: Set<ResolvedDependency>,
|
||||
processed: MutableSet<String>,
|
||||
allEmbeddedDependencies: MutableMap<DependencyIdentifier, File>,
|
||||
actuallyIncludedDependencies: MutableSet<DependencyIdentifier>,
|
||||
project: Project
|
||||
) {
|
||||
dependencies.forEach { dep: ResolvedDependency ->
|
||||
val classifier = dep.moduleArtifacts.firstOrNull()?.classifier ?: ""
|
||||
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}${if (classifier.isNotEmpty()) ":$classifier" else ""}"
|
||||
val depId = DependencyIdentifier(dep.moduleGroup, dep.moduleName, dep.moduleVersion, classifier)
|
||||
if (!processed.contains(depKey)) {
|
||||
processed.add(depKey)
|
||||
project.logger.debug("Resolved dependency: {}", depId)
|
||||
|
||||
val jarFile = dep.moduleArtifacts.firstOrNull()?.file
|
||||
if (jarFile != null && jarFile.exists()) {
|
||||
val embeddedJars = extractEmbeddedJars(jarFile, project)
|
||||
embeddedJars.forEach { embeddedDep ->
|
||||
allEmbeddedDependencies[embeddedDep] = jarFile
|
||||
}
|
||||
}
|
||||
|
||||
if (isJijTarget(
|
||||
dep,
|
||||
allEmbeddedDependencies.keys,
|
||||
actuallyIncludedDependencies,
|
||||
project
|
||||
)
|
||||
) {
|
||||
project.logger.debug("Processing JIJ dependency: {}", depId)
|
||||
val isProjectDependency = project.rootProject.allprojects.any { subproject ->
|
||||
subproject.name == dep.moduleName && (subproject.group == dep.moduleGroup || dep.moduleGroup.isEmpty())
|
||||
}
|
||||
if (isProjectDependency) {
|
||||
val projectPath = project.rootProject.allprojects.find { subproject ->
|
||||
subproject.name == dep.moduleName && (subproject.group == dep.moduleGroup || dep.moduleGroup.isEmpty())
|
||||
}?.path
|
||||
?: throw IllegalStateException("Project dependency not found: ${dep.moduleName}")
|
||||
project.logger.debug("Including project dependency as JIJ: $projectPath")
|
||||
project.dependencies {
|
||||
"include"(project.project(projectPath))
|
||||
}
|
||||
actuallyIncludedDependencies.add(depId)
|
||||
} else {
|
||||
includeDependencyWithExclusions(
|
||||
depId,
|
||||
project,
|
||||
actuallyIncludedDependencies,
|
||||
allEmbeddedDependencies.keys
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
processDependencies(
|
||||
dep.children,
|
||||
processed,
|
||||
allEmbeddedDependencies,
|
||||
actuallyIncludedDependencies,
|
||||
project
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
project.logger.debug("Resolving jijDependencies configuration")
|
||||
val resolvedDependencies = jijDependencies.resolvedConfiguration.firstLevelModuleDependencies
|
||||
|
||||
val processed = mutableSetOf<String>()
|
||||
val allEmbeddedDependencies = mutableMapOf<DependencyIdentifier, File>()
|
||||
val actuallyIncludedDependencies = mutableSetOf<DependencyIdentifier>()
|
||||
|
||||
fun collectAllEmbeddedDependencies(dependencies: Set<ResolvedDependency>) {
|
||||
dependencies.forEach { dep ->
|
||||
val classifier = dep.moduleArtifacts.firstOrNull()?.classifier ?: ""
|
||||
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}${if (classifier.isNotEmpty()) ":$classifier" else ""}"
|
||||
if (!processed.contains(depKey)) {
|
||||
processed.add(depKey)
|
||||
val jarFile = dep.moduleArtifacts.firstOrNull()?.file
|
||||
if (jarFile != null && jarFile.exists()) {
|
||||
val embeddedJars = extractEmbeddedJars(jarFile, project)
|
||||
embeddedJars.forEach { embeddedDep ->
|
||||
allEmbeddedDependencies[embeddedDep] = jarFile
|
||||
project.logger.debug(
|
||||
"Collected embedded dependency: {} from {}",
|
||||
embeddedDep,
|
||||
jarFile
|
||||
)
|
||||
}
|
||||
}
|
||||
collectAllEmbeddedDependencies(dep.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processed.clear()
|
||||
collectAllEmbeddedDependencies(resolvedDependencies)
|
||||
|
||||
processed.clear()
|
||||
processDependencies(
|
||||
resolvedDependencies,
|
||||
processed,
|
||||
allEmbeddedDependencies,
|
||||
actuallyIncludedDependencies,
|
||||
project
|
||||
)
|
||||
}
|
||||
|
||||
tasks.withType<Jar>().configureEach {
|
||||
doFirst {
|
||||
project.logger.debug("Resolving JIJ dependencies for JAR inclusion")
|
||||
val resolvedDependencies =
|
||||
jijDependencies.resolvedConfiguration.firstLevelModuleDependencies
|
||||
val processed = mutableSetOf<String>()
|
||||
val allEmbeddedDependencies = mutableMapOf<DependencyIdentifier, File>()
|
||||
val actuallyIncludedDependencies = mutableSetOf<DependencyIdentifier>()
|
||||
|
||||
fun collectAllEmbeddedDependencies(dependencies: Set<ResolvedDependency>) {
|
||||
dependencies.forEach { dep ->
|
||||
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}"
|
||||
if (!processed.contains(depKey)) {
|
||||
processed.add(depKey)
|
||||
val jarFile = dep.moduleArtifacts.firstOrNull()?.file
|
||||
if (jarFile != null && jarFile.exists()) {
|
||||
val embeddedJars = extractEmbeddedJars(jarFile, project)
|
||||
embeddedJars.forEach { embeddedDep ->
|
||||
allEmbeddedDependencies[embeddedDep] = jarFile
|
||||
project.logger.debug(
|
||||
"Collected embedded dependency for JAR: {} from {}",
|
||||
embeddedDep,
|
||||
jarFile
|
||||
)
|
||||
}
|
||||
}
|
||||
collectAllEmbeddedDependencies(dep.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processed.clear()
|
||||
collectAllEmbeddedDependencies(resolvedDependencies)
|
||||
|
||||
processed.clear()
|
||||
|
||||
fun logDependencies(dependencies: Set<ResolvedDependency>) {
|
||||
dependencies.forEach { dep ->
|
||||
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}"
|
||||
val depId = DependencyIdentifier(dep.moduleGroup, dep.moduleName, dep.moduleVersion)
|
||||
if (!processed.contains(depKey)) {
|
||||
processed.add(depKey)
|
||||
project.logger.debug("Resolved JIJ dependency for JAR: {}", depId)
|
||||
|
||||
val jarFile = dep.moduleArtifacts.firstOrNull()?.file
|
||||
if (jarFile != null && jarFile.exists()) {
|
||||
val embeddedJars = extractEmbeddedJars(jarFile, project)
|
||||
embeddedJars.forEach { embeddedDep ->
|
||||
allEmbeddedDependencies[embeddedDep] = jarFile
|
||||
}
|
||||
}
|
||||
|
||||
if (isJijTarget(
|
||||
dep,
|
||||
allEmbeddedDependencies.keys,
|
||||
actuallyIncludedDependencies,
|
||||
project
|
||||
)
|
||||
) {
|
||||
project.logger.debug("Including JIJ dependency in JAR: {}", depId)
|
||||
actuallyIncludedDependencies.add(depId)
|
||||
}
|
||||
logDependencies(dep.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
logDependencies(resolvedDependencies)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import versioning.BuildConfig
|
||||
|
||||
plugins {
|
||||
id("com.gradleup.shadow")
|
||||
}
|
||||
|
||||
// Create a configuration for shading dependencies from common
|
||||
val shadowCommon: Configuration by project.configurations.creating {
|
||||
isCanBeResolved = true
|
||||
isCanBeConsumed = false
|
||||
// Extend from the "implementation" configuration of the current project
|
||||
extendsFrom(project.configurations.getByName("implementation"))
|
||||
}
|
||||
|
||||
tasks.named<ShadowJar>("shadowJar") {
|
||||
archiveFileName.set("${rootProject.name}-${project.name}-${rootProject.version}.jar")
|
||||
from(shadowCommon) // Use from() instead of direct assignment
|
||||
|
||||
if (BuildConfig.relocate) {
|
||||
if (BuildConfig.shadePE) {
|
||||
relocate("io.github.retrooper.packetevents", "ac.grim.grimac.shaded.io.github.retrooper.packetevents")
|
||||
relocate("com.github.retrooper.packetevents", "ac.grim.grimac.shaded.com.github.retrooper.packetevents")
|
||||
relocate("net.kyori", "ac.grim.grimac.shaded.kyori") // use PE's built-in adventure instead when not shading PE
|
||||
}
|
||||
relocate("club.minnced", "ac.grim.grimac.shaded.discord-webhooks")
|
||||
relocate("org.slf4j", "ac.grim.grimac.shaded.slf4j") // Required by discord-webhooks
|
||||
relocate("github.scarsz.configuralize", "ac.grim.grimac.shaded.configuralize")
|
||||
relocate("com.github.puregero", "ac.grim.grimac.shaded.com.github.puregero")
|
||||
relocate("com.google.code.gson", "ac.grim.grimac.shaded.gson")
|
||||
relocate("alexh", "ac.grim.grimac.shaded.maps")
|
||||
relocate("it.unimi.dsi.fastutil", "ac.grim.grimac.shaded.fastutil")
|
||||
relocate("okhttp3", "ac.grim.grimac.shaded.okhttp3")
|
||||
relocate("okio", "ac.grim.grimac.shaded.okio")
|
||||
relocate("org.yaml.snakeyaml", "ac.grim.grimac.shaded.snakeyaml")
|
||||
relocate("org.json", "ac.grim.grimac.shaded.json")
|
||||
relocate("org.intellij", "ac.grim.grimac.shaded.intellij")
|
||||
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
|
||||
relocate("org.incendo", "ac.grim.grimac.shaded.incendo")
|
||||
relocate("io.leangen.geantyref", "ac.grim.grimac.shaded.geantyref") // Required by cloud
|
||||
}
|
||||
mergeServiceFiles()
|
||||
minimize()
|
||||
}
|
||||
|
||||
tasks.named("assemble") {
|
||||
dependsOn(tasks.named("shadowJar"))
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package versioning
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.internal.extensions.stdlib.toDefaultLowerCase
|
||||
|
||||
/**
|
||||
* BuildConfig provides access to user-defined build flags that control how a Grim
|
||||
* build is assembled. These flags are resolved once at configuration time using
|
||||
* [init], and are then exposed as fast, memoized values.
|
||||
*
|
||||
* Flags can be defined in three ways:
|
||||
*
|
||||
* ① JVM system properties (-Dflag=value)
|
||||
* ② Gradle project properties (-Pflag=value or in gradle.properties)
|
||||
* ③ Environment variables (FLAG=value)
|
||||
*
|
||||
* You can use these to enable/disable features like shading, relocation, or release mode.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* Using Gradle -P properties:
|
||||
* ```
|
||||
* ./gradlew build -PshadePE=true -Prelocate=false -Prelease=true
|
||||
* ```
|
||||
*
|
||||
* Using environment variables:
|
||||
* ```
|
||||
* SHADE_PE=true RELOCATE_JAR=false RELEASE=true ./gradlew build
|
||||
* ```
|
||||
*
|
||||
* Using JVM system properties:
|
||||
* ```
|
||||
* ./gradlew build -DshadePE=true -Drelease=true
|
||||
* ```
|
||||
*
|
||||
* @property shadePE If true, shades PacketEvents into the jar. Default: true.
|
||||
* @property relocate If true, relocates shaded dependencies to avoid conflicts. Default: true.
|
||||
* @property release If true, omits commit hash and modifiers from version string. Default: false.
|
||||
* @property mavenLocalOverride If true, will make artifacts in mavenLocal() will be used instead of their remote counterparts for this build. Default: false
|
||||
*/
|
||||
object BuildConfig {
|
||||
|
||||
/**
|
||||
* Must be called once from your root build script to initialize the flags.
|
||||
* Example (in build.gradle.kts):
|
||||
* ```
|
||||
* BuildConfig.init(project)
|
||||
* ```
|
||||
*/
|
||||
fun init(project: Project) {
|
||||
_shadePE = resolveBool(project, "shadePE", altKey = "SHADE_PE", default = true)
|
||||
_relocate = resolveBool(project, "relocate", altKey = "RELOCATE_JAR", default = true)
|
||||
_release = resolveBool(project, "release", default = false)
|
||||
_mavenLocalOverride = resolveBool(project, "mavenLocalOverride", altKey = "MAVEN_LOCAL_OVERRIDE", default = false)
|
||||
}
|
||||
|
||||
// Unified resolution logic (System > Gradle > Env)
|
||||
private fun resolveRaw(project: Project, key: String): String? =
|
||||
System.getProperty(key) // ① JVM (-Dkey=value)
|
||||
?: project.findProperty(key)?.toString() // ② Gradle (-Pkey=value or gradle.properties)
|
||||
?: System.getenv(key.uppercase()) // ③ ENV (KEY=value)
|
||||
|
||||
private fun resolveBool(project: Project, key: String, altKey: String? = null, default: Boolean): Boolean {
|
||||
val primaryValue = resolveRaw(project, key)?.toDefaultLowerCase()?.toBooleanStrictOrNull()
|
||||
if (primaryValue != null) {
|
||||
return primaryValue
|
||||
}
|
||||
|
||||
if (altKey != null) {
|
||||
val altValue = resolveRaw(project, altKey)?.toDefaultLowerCase()?.toBooleanStrictOrNull()
|
||||
if (altValue != null) {
|
||||
return altValue
|
||||
}
|
||||
}
|
||||
|
||||
return default
|
||||
}
|
||||
|
||||
// Private backing vars (nullable because we can't use lateinit with primitives)
|
||||
private var _shadePE: Boolean? = null
|
||||
private var _relocate: Boolean? = null
|
||||
private var _release: Boolean? = null
|
||||
private var _mavenLocalOverride: Boolean? = null
|
||||
|
||||
/** If true, shades PacketEvents into the jar. Default: true. */
|
||||
val shadePE: Boolean get() = _shadePE
|
||||
?: error("BuildConfig.shadePE accessed before init() was called")
|
||||
|
||||
/** If true, relocates shaded dependencies to avoid conflicts. Default: true. */
|
||||
val relocate: Boolean get() = _relocate
|
||||
?: error("BuildConfig.relocate accessed before init() was called")
|
||||
|
||||
/** If true, omits commit hash and modifiers from version string. Default: false. */
|
||||
val release: Boolean get() = _release
|
||||
?: error("BuildConfig.release accessed before init() was called")
|
||||
|
||||
val mavenLocalOverride: Boolean get() = _mavenLocalOverride
|
||||
?: error("BuildConfig.release accessed before init() was called")
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package versioning
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
/**
|
||||
* Utility for computing the version string of GrimAC artifacts.
|
||||
*
|
||||
* The version string is constructed based on:
|
||||
* - A base semantic version (e.g., "2.3.72")
|
||||
* - Git commit hash (unless in release mode)
|
||||
* - Git branch name (unless in release mode or main)
|
||||
* - Modifiers (e.g., lite, no_relocate) for non-default build configurations
|
||||
*
|
||||
* Example outputs:
|
||||
* - `2.3.72` (release build)
|
||||
* - `2.3.72-a4f8b21+lite` (preview build without PE shading)
|
||||
* - `2.3.72-feature_branch-a4f8b21+lite-no_relocate`
|
||||
*
|
||||
* @see BuildConfig for controlling the release/modifier behavior
|
||||
*/
|
||||
object VersionUtil {
|
||||
|
||||
/**
|
||||
* Computes the full version string for the build.
|
||||
*
|
||||
* @param baseVersion The base semantic version (e.g., "2.3.72")
|
||||
* @return Full version string including commit hash, branch, and modifiers if applicable
|
||||
*/
|
||||
fun computeVersion(baseVersion: String): String {
|
||||
if (BuildConfig.release) {
|
||||
return baseVersion
|
||||
}
|
||||
|
||||
val commitHash = getGitCommitHash()
|
||||
val branch = getGitBranch()
|
||||
|
||||
val modifiers = buildList {
|
||||
if (!BuildConfig.shadePE) add("lite")
|
||||
if (!BuildConfig.relocate) add("no_relocate")
|
||||
}.takeIf { it.isNotEmpty() }?.joinToString("-")
|
||||
|
||||
return buildString {
|
||||
append(baseVersion)
|
||||
append("-")
|
||||
branch?.let { append("$it-") }
|
||||
append(commitHash)
|
||||
modifiers?.let { append("+$modifiers") }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current Git commit as a short hash.
|
||||
*/
|
||||
private fun getGitCommitHash(): String {
|
||||
val stdout = ByteArrayOutputStream()
|
||||
ProcessBuilder("git", "rev-parse", "--short", "HEAD")
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
.apply { waitFor() }
|
||||
.inputStream
|
||||
.use { stdout.writeBytes(it.readAllBytes()) }
|
||||
return stdout.toString().trim()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current Git branch, sanitised for use in file names.
|
||||
* If the branch is "main" or "2.0", returns null.
|
||||
*
|
||||
* Any slash (/) in the branch name is replaced with an underscore (_)
|
||||
* to avoid filesystem issues.
|
||||
*/
|
||||
private fun getGitBranch(): String? {
|
||||
val stdout = ByteArrayOutputStream()
|
||||
|
||||
ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD")
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
.apply { waitFor() }
|
||||
.inputStream.use { stdout.writeBytes(it.readAllBytes()) }
|
||||
|
||||
val branch = stdout.toString().trim()
|
||||
|
||||
return when (branch) {
|
||||
"main", "2.0" -> null // ← ignore these branches
|
||||
else -> branch.replace("/", "_")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription.Permission
|
||||
import versioning.BuildConfig
|
||||
|
||||
plugins {
|
||||
`maven-publish`
|
||||
grim.`base-conventions`
|
||||
grim.`shadow-conventions`
|
||||
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
|
||||
}
|
||||
|
||||
repositories {
|
||||
if (BuildConfig.mavenLocalOverride) {
|
||||
mavenLocal()
|
||||
}
|
||||
maven {
|
||||
name = "papermc"
|
||||
url = uri("https://repo.papermc.io/repository/maven-public/")
|
||||
}
|
||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot
|
||||
maven("https://repo.grim.ac/snapshots") { // Grim API
|
||||
content {
|
||||
includeGroup("ac.grim.grimac")
|
||||
includeGroup("com.github.retrooper")
|
||||
}
|
||||
}
|
||||
maven("https://repo.viaversion.com") // ViaVersion
|
||||
maven("https://nexus.scarsz.me/content/repositories/releases") // Configuralize
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/") // Floodgate
|
||||
maven("https://repo.opencollab.dev/maven-releases/") // Cumulus (for Floodgate)
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // placeholderapi
|
||||
mavenCentral() // FastUtil
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.paper.api)
|
||||
compileOnly(libs.placeholderapi)
|
||||
|
||||
if (BuildConfig.shadePE) {
|
||||
implementation(libs.packetevents.spigot)
|
||||
} else {
|
||||
compileOnly(libs.packetevents.spigot)
|
||||
}
|
||||
implementation(libs.cloud.paper)
|
||||
implementation(libs.adventure.platform.bukkit)
|
||||
|
||||
shadowCommon(project(":common", "default"))
|
||||
implementation(project(":api"))
|
||||
implementation(project(":api:packetevents"))
|
||||
}
|
||||
|
||||
bukkit {
|
||||
name = "GrimAC"
|
||||
author = "GrimAC"
|
||||
main = "ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin"
|
||||
website = "https://grim.ac/"
|
||||
apiVersion = "1.13"
|
||||
foliaSupported = true
|
||||
|
||||
if (!BuildConfig.shadePE) {
|
||||
depend = listOf("packetevents")
|
||||
}
|
||||
|
||||
softDepend = listOf(
|
||||
"ProtocolLib",
|
||||
"ProtocolSupport",
|
||||
"Essentials",
|
||||
"ViaVersion",
|
||||
"ViaBackwards",
|
||||
"ViaRewind",
|
||||
"Geyser-Spigot",
|
||||
"floodgate",
|
||||
"FastLogin",
|
||||
"PlaceholderAPI",
|
||||
)
|
||||
|
||||
permissions {
|
||||
register("grim.alerts") {
|
||||
description = "Receive alerts for violations"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.alerts.enable-on-join") {
|
||||
description = "Enable alerts on join"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.performance") {
|
||||
description = "Check performance metrics"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.profile") {
|
||||
description = "Check user profile"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.brand") {
|
||||
description = "Show client brands on join"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.brand.enable-on-join") {
|
||||
description = "Enable showing client brands on join"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.sendalert") {
|
||||
description = "Send cheater alert"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.nosetback") {
|
||||
description = "Disable setback"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
|
||||
register("grim.nomodifypacket") {
|
||||
description = "Disable modifying packets"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
|
||||
register("grim.exempt") {
|
||||
description = "Exempt from all checks"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
|
||||
register("grim.verbose") {
|
||||
description = "Receive verbose alerts for violations. Requires grim.alerts"
|
||||
default = Permission.Default.OP
|
||||
}
|
||||
|
||||
register("grim.verbose.enable-on-join") {
|
||||
description =
|
||||
"Enable verbose alerts on join. Requires grim.alerts and grim.alerts.enable-on-join"
|
||||
default = Permission.Default.FALSE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publishing.publications.create<MavenPublication>("maven") {
|
||||
artifact(tasks["shadowJar"])
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
manifest {
|
||||
attributes["paperweight-mappings-namespace"] = "mojang"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package ac.grim.grimac.platform.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.platform.PlatformPlugin;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class BukkitPlatformPlugin implements PlatformPlugin {
|
||||
private final Plugin plugin;
|
||||
|
||||
public BukkitPlatformPlugin(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return plugin.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return plugin.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return plugin.getDescription().getVersion();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package ac.grim.grimac.platform.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.platform.PlatformServer;
|
||||
import ac.grim.grimac.api.platform.sender.Sender;
|
||||
import io.github.retrooper.packetevents.util.SpigotReflectionUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
|
||||
public class BukkitPlatformServer implements PlatformServer {
|
||||
|
||||
@Override
|
||||
public String getPlatformImplementationString() {
|
||||
return Bukkit.getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchCommand(Sender sender, String command) {
|
||||
CommandSender commandSender = GrimACBukkitLoaderPlugin.LOADER.getBukkitSenderFactory().reverse(sender);
|
||||
Bukkit.dispatchCommand(commandSender, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sender getConsoleSender() {
|
||||
return GrimACBukkitLoaderPlugin.LOADER.getBukkitSenderFactory().map(Bukkit.getConsoleSender());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOutgoingPluginChannel(String name) {
|
||||
GrimACBukkitLoaderPlugin.LOADER.getServer().getMessenger().registerOutgoingPluginChannel(GrimACBukkitLoaderPlugin.LOADER, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTPS() {
|
||||
return SpigotReflectionUtil.getTPS();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package ac.grim.grimac.platform.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.lazy.LazyHolder;
|
||||
import ac.grim.grimac.api.packet.MCPacketAPI;
|
||||
import ac.grim.grimac.api.packet.pe.PEPacketAPI;
|
||||
import ac.grim.grimac.api.platform.CoreLoader;
|
||||
import ac.grim.grimac.api.platform.init.Initable;
|
||||
import ac.grim.grimac.api.plugin.BasicGrimPlugin;
|
||||
import ac.grim.grimac.api.GrimAPIProvider;
|
||||
import ac.grim.grimac.api.GrimAbstractAPI;
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.api.platform.init.StartableInitable;
|
||||
import ac.grim.grimac.api.platform.Platform;
|
||||
import ac.grim.grimac.api.platform.PlatformLoader;
|
||||
import ac.grim.grimac.api.platform.PlatformServer;
|
||||
import ac.grim.grimac.api.platform.manager.ItemResetHandler;
|
||||
import ac.grim.grimac.api.platform.manager.MessagePlaceHolderManager;
|
||||
import ac.grim.grimac.api.platform.manager.ParserDescriptorFactory;
|
||||
import ac.grim.grimac.api.platform.manager.PermissionRegistrationManager;
|
||||
import ac.grim.grimac.api.platform.manager.PlatformPluginManager;
|
||||
import ac.grim.grimac.api.platform.player.PlatformPlayerFactory;
|
||||
import ac.grim.grimac.api.platform.scheduler.PlatformScheduler;
|
||||
import ac.grim.grimac.api.platform.sender.Sender;
|
||||
import ac.grim.grimac.api.platform.sender.SenderFactory;
|
||||
import ac.grim.grimac.platform.bukkit.initables.BukkitBStats;
|
||||
import ac.grim.grimac.platform.bukkit.initables.BukkitEventManager;
|
||||
import ac.grim.grimac.platform.bukkit.initables.BukkitTickEndEvent;
|
||||
import ac.grim.grimac.platform.bukkit.manager.BukkitItemResetHandler;
|
||||
import ac.grim.grimac.platform.bukkit.manager.BukkitMessagePlaceHolderManager;
|
||||
import ac.grim.grimac.platform.bukkit.manager.BukkitParserDescriptorFactory;
|
||||
import ac.grim.grimac.platform.bukkit.manager.BukkitPermissionRegistrationManager;
|
||||
import ac.grim.grimac.platform.bukkit.manager.BukkitPlatformPluginManager;
|
||||
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayerFactory;
|
||||
import ac.grim.grimac.platform.bukkit.scheduler.bukkit.BukkitPlatformScheduler;
|
||||
import ac.grim.grimac.platform.bukkit.scheduler.folia.FoliaPlatformScheduler;
|
||||
import ac.grim.grimac.platform.bukkit.sender.BukkitSenderFactory;
|
||||
import ac.grim.grimac.platform.bukkit.utils.placeholder.PlaceholderAPIExpansion;
|
||||
import com.github.retrooper.packetevents.PacketEventsAPI;
|
||||
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.brigadier.BrigadierSetting;
|
||||
import org.incendo.cloud.brigadier.CloudBrigadierManager;
|
||||
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.paper.LegacyPaperCommandManager;
|
||||
import org.incendo.cloud.setting.Configurable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class GrimACBukkitLoaderPlugin extends JavaPlugin implements PlatformLoader {
|
||||
|
||||
public static GrimACBukkitLoaderPlugin LOADER;
|
||||
|
||||
private final LazyHolder<PlatformScheduler> scheduler = LazyHolder.simple(this::createScheduler);
|
||||
private final LazyHolder<PacketEventsAPI<?>> packetEvents = LazyHolder.simple(() -> SpigotPacketEventsBuilder.build(this));
|
||||
private final LazyHolder<BukkitSenderFactory> senderFactory = LazyHolder.simple(BukkitSenderFactory::new);
|
||||
private final LazyHolder<CommandManager<Sender>> commandManager = LazyHolder.simple(this::createCommandManager);
|
||||
private final LazyHolder<ItemResetHandler> itemResetHandler = LazyHolder.simple(BukkitItemResetHandler::new);
|
||||
|
||||
private final PlatformPlayerFactory playerFactory = new BukkitPlatformPlayerFactory();
|
||||
private final ParserDescriptorFactory parserFactory = new BukkitParserDescriptorFactory();
|
||||
private final PlatformPluginManager platformPluginManager = new BukkitPlatformPluginManager();
|
||||
private final GrimPlugin plugin;
|
||||
private final PlatformServer platformServer = new BukkitPlatformServer();
|
||||
private final MessagePlaceHolderManager messagePlaceHolderManager = new BukkitMessagePlaceHolderManager();
|
||||
private final BukkitPermissionRegistrationManager bukkitPermissionRegistrationManager = new BukkitPermissionRegistrationManager();
|
||||
private final MCPacketAPI mcPacketAPI = new PEPacketAPI();
|
||||
|
||||
public GrimACBukkitLoaderPlugin() {
|
||||
this.plugin = new BasicGrimPlugin(
|
||||
this.getLogger(),
|
||||
this.getDataFolder(),
|
||||
this.getDescription().getVersion(),
|
||||
this.getDescription().getDescription(),
|
||||
this.getDescription().getAuthors()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
LOADER = this;
|
||||
CoreLoader.Manager.loadAll(this, this.getBukkitInitTasks());
|
||||
}
|
||||
|
||||
private Initable[] getBukkitInitTasks() {
|
||||
return new Initable[] {
|
||||
new BukkitEventManager(),
|
||||
new BukkitTickEndEvent(),
|
||||
new BukkitBStats(),
|
||||
(StartableInitable) () -> {
|
||||
if (BukkitMessagePlaceHolderManager.hasPlaceholderAPI) {
|
||||
new PlaceholderAPIExpansion().register();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
CoreLoader.Manager.startAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
CoreLoader.Manager.stopAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformScheduler getScheduler() {
|
||||
return scheduler.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformPlayerFactory getPlatformPlayerFactory() {
|
||||
return playerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParserDescriptorFactory getParserDescriptorFactory() {
|
||||
return parserFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketEventsAPI<?> getPacketAPI() {
|
||||
return packetEvents.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandManager<Sender> getCommandManager() {
|
||||
return commandManager.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemResetHandler getItemResetHandler() {
|
||||
return itemResetHandler.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SenderFactory<CommandSender> getSenderFactory() {
|
||||
return senderFactory.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GrimPlugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformPluginManager getPluginManager() {
|
||||
return platformPluginManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformServer getPlatformServer() {
|
||||
return platformServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAPIService(GrimAbstractAPI api) {
|
||||
GrimAPIProvider.init(api);
|
||||
Bukkit.getServicesManager().register(GrimAbstractAPI.class, api, GrimACBukkitLoaderPlugin.LOADER, ServicePriority.Normal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull MessagePlaceHolderManager getMessagePlaceHolderManager() {
|
||||
return messagePlaceHolderManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionRegistrationManager getPermissionManager() {
|
||||
return bukkitPermissionRegistrationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MCPacketAPI getMCPacketAPI() {
|
||||
return mcPacketAPI;
|
||||
}
|
||||
|
||||
private PlatformScheduler createScheduler() {
|
||||
return GrimAPIProvider.getDirect().getPlatform() == Platform.FOLIA ? new FoliaPlatformScheduler() : new BukkitPlatformScheduler();
|
||||
}
|
||||
|
||||
private CommandManager<Sender> createCommandManager() {
|
||||
LegacyPaperCommandManager<Sender> manager = new LegacyPaperCommandManager<>(
|
||||
this,
|
||||
ExecutionCoordinator.simpleCoordinator(),
|
||||
senderFactory.get()
|
||||
);
|
||||
if (manager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
|
||||
manager.registerBrigadier();
|
||||
CloudBrigadierManager<Sender, ?> cbm = manager.brigadierManager();
|
||||
Configurable<BrigadierSetting> settings = cbm.settings();
|
||||
settings.set(BrigadierSetting.FORCE_EXECUTABLE, true);
|
||||
} else if (manager.hasCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) {
|
||||
manager.registerAsynchronousCompletions();
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
public BukkitSenderFactory getBukkitSenderFactory() {
|
||||
return LOADER.senderFactory.get();
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package ac.grim.grimac.platform.bukkit.command;
|
||||
|
||||
import ac.grim.grimac.api.GrimAPIProvider;
|
||||
import ac.grim.grimac.api.platform.command.PlayerSelector;
|
||||
import ac.grim.grimac.api.platform.sender.Sender;
|
||||
import ac.grim.grimac.platform.bukkit.sender.BukkitSenderFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public class BukkitPlayerSelectorAdapter implements PlayerSelector {
|
||||
private final org.incendo.cloud.bukkit.data.SinglePlayerSelector bukkitSelector;
|
||||
|
||||
public BukkitPlayerSelectorAdapter(org.incendo.cloud.bukkit.data.SinglePlayerSelector bukkitSelector) {
|
||||
this.bukkitSelector = bukkitSelector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sender getSinglePlayer() {
|
||||
return ((BukkitSenderFactory) GrimAPIProvider.getDirect().getPlatformLoader().getSenderFactory()).map(bukkitSelector.single());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Sender> getPlayers() {
|
||||
return Collections.singletonList(((BukkitSenderFactory) GrimAPIProvider.getDirect().getPlatformLoader().getSenderFactory()).map(bukkitSelector.single()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String inputString() {
|
||||
return bukkitSelector.inputString();
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package ac.grim.grimac.platform.bukkit.command;
|
||||
|
||||
import ac.grim.grimac.api.platform.command.AbstractPlayerSelectorParser;
|
||||
import ac.grim.grimac.api.platform.command.PlayerSelector;
|
||||
import org.incendo.cloud.bukkit.parser.selector.SinglePlayerSelectorParser;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
import org.incendo.cloud.parser.ParserDescriptor;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class BukkitPlayerSelectorParser<C> extends AbstractPlayerSelectorParser<C> {
|
||||
|
||||
@Override
|
||||
public ParserDescriptor<C, PlayerSelector> descriptor() {
|
||||
return super.createDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ParserDescriptor<C, ?> getPlatformSpecificDescriptor() {
|
||||
return SinglePlayerSelectorParser.singlePlayerSelectorParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletableFuture<PlayerSelector> adaptToCommonSelector(CommandContext<C> context, Object platformSpecificSelector) {
|
||||
return CompletableFuture.completedFuture(new BukkitPlayerSelectorAdapter((org.incendo.cloud.bukkit.data.SinglePlayerSelector) platformSpecificSelector));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package ac.grim.grimac.platform.bukkit.entity;
|
||||
|
||||
import ac.grim.grimac.api.platform.entity.GrimEntity;
|
||||
import ac.grim.grimac.api.platform.world.PlatformWorld;
|
||||
import ac.grim.grimac.platform.bukkit.utils.convert.BukkitConversionUtils;
|
||||
import ac.grim.grimac.platform.bukkit.utils.reflection.PaperUtils;
|
||||
import ac.grim.grimac.platform.bukkit.world.BukkitPlatformWorld;
|
||||
import ac.grim.grimac.api.math.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class BukkitGrimEntity implements GrimEntity {
|
||||
|
||||
private final Entity entity;
|
||||
private BukkitPlatformWorld bukkitPlatformWorld;
|
||||
|
||||
public BukkitGrimEntity(Entity entity) {
|
||||
Objects.requireNonNull(entity);
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public Entity getBukkitEntity() {
|
||||
return this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId() {
|
||||
return entity.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eject() {
|
||||
return entity.eject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> teleportAsync(Location location) {
|
||||
org.bukkit.Location bLoc = BukkitConversionUtils.toBukkitLocation(location);
|
||||
return PaperUtils.teleportAsync(this.entity, bLoc);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Entity getNative() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDead() {
|
||||
return this.entity.isDead();
|
||||
}
|
||||
|
||||
// TODO replace with PlayerWorldChangeEvent listener instead of checking for equality for better performance
|
||||
@Override
|
||||
public PlatformWorld getWorld() {
|
||||
if (bukkitPlatformWorld == null || !bukkitPlatformWorld.getBukkitWorld().equals(entity.getWorld())) {
|
||||
bukkitPlatformWorld = new BukkitPlatformWorld(entity.getWorld());
|
||||
}
|
||||
|
||||
return bukkitPlatformWorld;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
org.bukkit.Location location = this.entity.getLocation();
|
||||
return new Location(
|
||||
this.getWorld(),
|
||||
location.getX(),
|
||||
location.getY(),
|
||||
location.getZ(),
|
||||
location.getYaw(),
|
||||
location.getPitch()
|
||||
);
|
||||
}
|
||||
}
|
||||
+36
-26
@@ -1,11 +1,11 @@
|
||||
package ac.grim.grimac.events.bukkit;
|
||||
package ac.grim.grimac.platform.bukkit.events;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.blockstate.helper.BlockFaceHelper;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.PistonData;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import ac.grim.grimac.api.GrimAPIProvider;
|
||||
import ac.grim.grimac.api.GrimUser;
|
||||
import ac.grim.grimac.api.data.PistonData;
|
||||
import ac.grim.grimac.api.data.boxes.BaseSCB;
|
||||
import ac.grim.grimac.platform.bukkit.utils.convert.BukkitConversionUtils;
|
||||
import ac.grim.grimac.api.packet.world.enums.BlockFace;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -26,13 +26,13 @@ public class PistonEvent implements Listener {
|
||||
boolean hasSlimeBlock = false;
|
||||
boolean hasHoneyBlock = false;
|
||||
|
||||
List<SimpleCollisionBox> boxes = new ArrayList<>();
|
||||
List<BaseSCB> boxes = new ArrayList<>();
|
||||
for (Block block : event.getBlocks()) {
|
||||
boxes.add(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true)
|
||||
boxes.add(new BaseSCB(0, 0, 0, 1, 1, 1, true)
|
||||
.offset(block.getX(),
|
||||
block.getY(),
|
||||
block.getZ()));
|
||||
boxes.add(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true)
|
||||
boxes.add(new BaseSCB(0, 0, 0, 1, 1, 1, true)
|
||||
.offset(block.getX() + event.getDirection().getModX(),
|
||||
block.getY() + event.getDirection().getModY(),
|
||||
block.getZ() + event.getDirection().getModZ()));
|
||||
@@ -50,16 +50,21 @@ public class PistonEvent implements Listener {
|
||||
Block piston = event.getBlock();
|
||||
|
||||
// Add bounding box of the actual piston head pushing
|
||||
boxes.add(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true)
|
||||
boxes.add(new BaseSCB(0, 0, 0, 1, 1, 1, true)
|
||||
.offset(piston.getX() + event.getDirection().getModX(),
|
||||
piston.getY() + event.getDirection().getModY(),
|
||||
piston.getZ() + event.getDirection().getModZ()));
|
||||
|
||||
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
|
||||
if (player.compensatedWorld.isChunkLoaded(event.getBlock().getX() >> 4, event.getBlock().getZ() >> 4)) {
|
||||
PistonData data = new PistonData(BlockFaceHelper.fromBukkitFace(event.getDirection()), boxes, player.lastTransactionSent.get(), true, hasSlimeBlock, hasHoneyBlock);
|
||||
player.latencyUtils.addRealTimeTaskAsync(player.lastTransactionSent.get(), () -> player.compensatedWorld.activePistons.add(data));
|
||||
}
|
||||
boolean finalHasSlimeBlock = hasSlimeBlock;
|
||||
boolean finalHasHoneyBlock = hasHoneyBlock;
|
||||
for (GrimUser player : GrimAPIProvider.getDirect().getGrimUsers()) {
|
||||
int lastTrans = player.getLastTransactionSent();
|
||||
player.runSafely(() -> {
|
||||
if (player.getCompensatedWorld().isChunkLoaded(event.getBlock().getX() >> 4, event.getBlock().getZ() >> 4)) {
|
||||
PistonData data = new PistonData(BukkitConversionUtils.fromBukkitFace(event.getDirection()), boxes, lastTrans, true, finalHasSlimeBlock, finalHasHoneyBlock);
|
||||
player.addRealTimeTask(lastTrans, () -> player.getCompensatedWorld().addActivePistons(data));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,24 +83,24 @@ public class PistonEvent implements Listener {
|
||||
boolean hasSlimeBlock = false;
|
||||
boolean hasHoneyBlock = false;
|
||||
|
||||
List<SimpleCollisionBox> boxes = new ArrayList<>();
|
||||
BlockFace face = BlockFaceHelper.fromBukkitFace(event.getDirection());
|
||||
List<BaseSCB> boxes = new ArrayList<>();
|
||||
BlockFace face = BukkitConversionUtils.fromBukkitFace(event.getDirection());
|
||||
|
||||
// The event was called without blocks and is therefore in the right direction
|
||||
if (event.getBlocks().isEmpty()) {
|
||||
Block piston = event.getBlock();
|
||||
|
||||
// Add bounding box of the actual piston head pushing
|
||||
boxes.add(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true)
|
||||
boxes.add(new BaseSCB(0, 0, 0, 1, 1, 1, true)
|
||||
.offset(piston.getX() + face.getModX(),
|
||||
piston.getY() + face.getModY(),
|
||||
piston.getZ() + face.getModZ()));
|
||||
}
|
||||
|
||||
for (Block block : event.getBlocks()) {
|
||||
boxes.add(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true)
|
||||
boxes.add(new BaseSCB(0, 0, 0, 1, 1, 1, true)
|
||||
.offset(block.getX(), block.getY(), block.getZ()));
|
||||
boxes.add(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true)
|
||||
boxes.add(new BaseSCB(0, 0, 0, 1, 1, 1, true)
|
||||
.offset(block.getX() + face.getModX(), block.getY() + face.getModY(), block.getZ() + face.getModZ()));
|
||||
|
||||
// Support honey block like this because ViaVersion replacement
|
||||
@@ -108,11 +113,16 @@ public class PistonEvent implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
|
||||
if (player.compensatedWorld.isChunkLoaded(event.getBlock().getX() >> 4, event.getBlock().getZ() >> 4)) {
|
||||
PistonData data = new PistonData(BlockFaceHelper.fromBukkitFace(event.getDirection()), boxes, player.lastTransactionSent.get(), false, hasSlimeBlock, hasHoneyBlock);
|
||||
player.latencyUtils.addRealTimeTaskAsync(player.lastTransactionSent.get(), () -> player.compensatedWorld.activePistons.add(data));
|
||||
}
|
||||
boolean finalHasSlimeBlock = hasSlimeBlock;
|
||||
boolean finalHasHoneyBlock = hasHoneyBlock;
|
||||
for (GrimUser player : GrimAPIProvider.getDirect().getGrimUsers()) {
|
||||
int lastTrans = player.getLastTransactionSent();
|
||||
player.runSafely(() -> {
|
||||
if (player.getCompensatedWorld().isChunkLoaded(event.getBlock().getX() >> 4, event.getBlock().getZ() >> 4)) {
|
||||
PistonData data = new PistonData(BukkitConversionUtils.fromBukkitFace(event.getDirection()), boxes, lastTrans, false, finalHasSlimeBlock, finalHasHoneyBlock);
|
||||
player.addRealTimeTask(lastTrans, () -> player.getCompensatedWorld().addActivePistons(data));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package ac.grim.grimac.platform.bukkit.initables;
|
||||
|
||||
import ac.grim.grimac.api.platform.init.StartableInitable;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import io.github.retrooper.packetevents.bstats.bukkit.Metrics;
|
||||
|
||||
public class BukkitBStats implements StartableInitable {
|
||||
@Override
|
||||
public void start() {
|
||||
int pluginId = 12820; // <-- Replace with the id of your plugin!
|
||||
try {
|
||||
new Metrics(GrimACBukkitLoaderPlugin.LOADER, pluginId);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package ac.grim.grimac.platform.bukkit.initables;
|
||||
|
||||
import ac.grim.grimac.api.platform.init.StartableInitable;
|
||||
import ac.grim.grimac.api.util.LogUtil;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import ac.grim.grimac.platform.bukkit.events.PistonEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class BukkitEventManager implements StartableInitable {
|
||||
public void start() {
|
||||
LogUtil.info("Registering singular bukkit event... (PistonEvent)");
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(new PistonEvent(), GrimACBukkitLoaderPlugin.LOADER);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package ac.grim.grimac.platform.bukkit.initables;
|
||||
|
||||
import ac.grim.grimac.api.GrimAPIProvider;
|
||||
import ac.grim.grimac.api.GrimUser;
|
||||
import ac.grim.grimac.api.packet.protocol.version.server.ServerVersions;
|
||||
import ac.grim.grimac.api.platform.Platform;
|
||||
import ac.grim.grimac.api.platform.init.AbstractTickEndEvent;
|
||||
import ac.grim.grimac.api.util.LogUtil;
|
||||
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayer;
|
||||
import ac.grim.grimac.platform.bukkit.utils.list.HookedListWrapper;
|
||||
import ac.grim.grimac.platform.bukkit.utils.reflection.PaperUtils;
|
||||
import com.github.retrooper.packetevents.util.reflection.Reflection;
|
||||
import io.github.retrooper.packetevents.util.SpigotReflectionUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
// Copied from: https://github.com/ThomasOM/Pledge/blob/master/src/main/java/dev/thomazz/pledge/inject/ServerInjector.java
|
||||
@SuppressWarnings(value = {"unchecked", "deprecated"})
|
||||
public class BukkitTickEndEvent extends AbstractTickEndEvent implements Listener {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (!super.shouldInjectEndTick()) {
|
||||
return;
|
||||
}
|
||||
if (ServerVersions.getServerVersion().isNewerThan(ServerVersions.V_1_11_2) && !Boolean.getBoolean("paper.explicit-flush")) {
|
||||
LogUtil.warn("Reach.enable-post-packet=true but paper.explicit-flush=false, add \"-Dpaper.explicit-flush=true\" to your server's startup flags for fully functional extra reach accuracy.");
|
||||
}
|
||||
// this is necessary for folia
|
||||
if (GrimAPIProvider.getDirect().getPlatform() == Platform.FOLIA) {
|
||||
PaperUtils.registerTickEndEvent(this, this::tickAllFoliaPlayers);
|
||||
return;
|
||||
}
|
||||
// if it fails to inject, try to use paper's event
|
||||
if (!injectWithReflection() && !PaperUtils.registerTickEndEvent(this, this::tickAllPlayers)) {
|
||||
LogUtil.error("Failed to inject into the end of tick event!");
|
||||
}
|
||||
}
|
||||
|
||||
private void tickAllPlayers() {
|
||||
for (GrimUser player : GrimAPIProvider.getDirect().getGrimUsers()) {
|
||||
if (player.isGrimDisabled()) continue;
|
||||
player.onEndOfTick();
|
||||
}
|
||||
}
|
||||
|
||||
private void tickAllFoliaPlayers() {
|
||||
for (GrimUser player : GrimAPIProvider.getDirect().getGrimUsers()) {
|
||||
if (player.isGrimDisabled()) continue;
|
||||
if (player.getPlatformPlayer() == null) continue;
|
||||
Player p = ((BukkitPlatformPlayer) player.getPlatformPlayer()).getNative();
|
||||
if (!Bukkit.isOwnedByCurrentRegion(p)) continue;
|
||||
player.onEndOfTick();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean injectWithReflection() {
|
||||
// Inject so we can add the final transaction pre-flush event
|
||||
try {
|
||||
Object connection = SpigotReflectionUtil.getMinecraftServerConnectionInstance();
|
||||
|
||||
Field connectionsList = Reflection.getField(connection.getClass(), List.class, 1);
|
||||
List<Object> endOfTickObject = (List<Object>) connectionsList.get(connection);
|
||||
|
||||
// Use a list wrapper to check when the size method is called
|
||||
// Unsure why synchronized is needed because the object itself gets synchronized
|
||||
// but whatever. At least plugins can't break it, I guess.
|
||||
//
|
||||
// Pledge injects into another list, so we should be safe injecting into this one
|
||||
List<?> wrapper = Collections.synchronizedList(new HookedListWrapper<>(endOfTickObject) {
|
||||
@Override
|
||||
public void onIterator() {
|
||||
tickAllPlayers();
|
||||
}
|
||||
});
|
||||
|
||||
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
Unsafe unsafe = (Unsafe) unsafeField.get(null);
|
||||
unsafe.putObject(connection, unsafe.objectFieldOffset(connectionsList), wrapper);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
LogUtil.exception("Failed to inject into the end of tick event via reflection", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package ac.grim.grimac.platform.bukkit.manager;
|
||||
|
||||
import ac.grim.grimac.api.packet.protocol.version.server.PacketServerVersion;
|
||||
import ac.grim.grimac.api.packet.protocol.version.server.ServerVersions;
|
||||
import ac.grim.grimac.api.platform.manager.ItemResetHandler;
|
||||
import ac.grim.grimac.api.platform.player.PlatformPlayer;
|
||||
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayer;
|
||||
import ac.grim.grimac.platform.bukkit.utils.reflection.PaperUtils;
|
||||
import lombok.SneakyThrows;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BukkitItemResetHandler implements ItemResetHandler {
|
||||
// resets item usage, then returns whether the player was using an item
|
||||
private final @NotNull ItemUsageReset resetItemUsage = createItemUsageResetFunction();
|
||||
|
||||
@SneakyThrows
|
||||
public void resetItemUsage(@Nullable PlatformPlayer player) {
|
||||
if (player != null) {
|
||||
resetItemUsage.accept(((BukkitPlatformPlayer) player).getNative());
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private @NotNull ItemUsageReset createItemUsageResetFunction() {
|
||||
PacketServerVersion version = ServerVersions.getServerVersion();
|
||||
if (version.isNewerThan(ServerVersions.V_1_17) && PaperUtils.PAPER) {
|
||||
if (version.isOlderThan(ServerVersions.V_1_19)) {
|
||||
return LivingEntity::clearActiveItem;
|
||||
}
|
||||
Method setLivingEntityFlag = Class.forName(version.isOlderThan(ServerVersions.V_1_20_5) ? "net.minecraft.world.entity.EntityLiving" : "net.minecraft.world.entity.LivingEntity")
|
||||
.getDeclaredMethod(version.isOlderThan(ServerVersions.V_1_20_5) ? "c" : "setLivingEntityFlag", int.class, boolean.class);
|
||||
Method getHandle = (version.isOlderThan(ServerVersions.V_1_20_5)
|
||||
? Class.forName("org.bukkit.craftbukkit." + Bukkit.getServer().getClass().getPackageName().split("\\.")[3] + ".entity.CraftPlayer")
|
||||
: Class.forName("org.bukkit.craftbukkit.entity.CraftPlayer")
|
||||
).getMethod("getHandle");
|
||||
|
||||
setLivingEntityFlag.setAccessible(true);
|
||||
|
||||
return player -> {
|
||||
// don't trigger gameevents
|
||||
setLivingEntityFlag.invoke(getHandle.invoke(player), 1, false);
|
||||
player.clearActiveItem();
|
||||
};
|
||||
}
|
||||
|
||||
if (version == ServerVersions.V_1_8_8) {
|
||||
Class<?> EntityHuman = Class.forName("net.minecraft.server.v1_8_R3.EntityHuman");
|
||||
Method getHandle = Class.forName("org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer").getMethod("getHandle");
|
||||
Method clearActiveItem = EntityHuman.getMethod("bV");
|
||||
Method isUsingItem = EntityHuman.getMethod("bS");
|
||||
|
||||
return player -> {
|
||||
Object handle = getHandle.invoke(player);
|
||||
clearActiveItem.invoke(handle);
|
||||
|
||||
// in 1.8 we need to resync item usage manually,
|
||||
// only do so if the player was using an item
|
||||
if ((boolean) isUsingItem.invoke(handle)) {
|
||||
player.updateInventory();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
String nmsPackage = Bukkit.getServer().getClass().getPackageName().split("\\.")[3];
|
||||
String livingEntityPackage = version.isNewerThan(ServerVersions.V_1_16_5) ? "net.minecraft.world.entity.EntityLiving" : "net.minecraft.server." + nmsPackage + ".EntityLiving";
|
||||
Method getHandle = Class.forName("org.bukkit.craftbukkit." + nmsPackage + ".entity.CraftPlayer").getMethod("getHandle");
|
||||
Method clearActiveItem = Class.forName(livingEntityPackage).getMethod(
|
||||
switch (nmsPackage) {
|
||||
case "v1_9_R1" -> "cz";
|
||||
case "v1_9_R2" -> "cA";
|
||||
case "v1_10_R1" -> "cE";
|
||||
case "v1_11_R1" -> "cF";
|
||||
case "v1_12_R1" -> "cN";
|
||||
case "v1_13_R1", "v1_13_R2" -> "da";
|
||||
case "v1_14_R1" -> "dp";
|
||||
case "v1_15_R1" -> "dH";
|
||||
case "v1_16_R1", "v1_16_R2", "v1_16_R3", "v1_17_R1" -> "clearActiveItem";
|
||||
case "v1_18_R1" -> "eR";
|
||||
case "v1_18_R2" -> "eS";
|
||||
default -> throw new IllegalStateException("You are using an unsupported server version! (" + version.getReleaseName() + ")");
|
||||
}
|
||||
);
|
||||
|
||||
return player -> clearActiveItem.invoke(getHandle.invoke(player));
|
||||
}
|
||||
|
||||
private interface ItemUsageReset {
|
||||
void accept(@NotNull Player player) throws Throwable;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package ac.grim.grimac.platform.bukkit.manager;
|
||||
|
||||
import ac.grim.grimac.api.platform.manager.MessagePlaceHolderManager;
|
||||
import ac.grim.grimac.api.platform.player.PlatformPlayer;
|
||||
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayer;
|
||||
import com.github.retrooper.packetevents.util.reflection.Reflection;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class BukkitMessagePlaceHolderManager implements MessagePlaceHolderManager {
|
||||
public static final boolean hasPlaceholderAPI = Reflection.getClassByNameWithoutException("me.clip.placeholderapi.PlaceholderAPI") != null;
|
||||
|
||||
@Override
|
||||
public @NonNull String replacePlaceholders(@Nullable PlatformPlayer player, @NonNull String string) {
|
||||
if (!hasPlaceholderAPI) return string;
|
||||
return PlaceholderAPI.setPlaceholders(player instanceof BukkitPlatformPlayer bukkitPlatformPlayer ? bukkitPlatformPlayer.getBukkitPlayer() : null, string);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package ac.grim.grimac.platform.bukkit.manager;
|
||||
|
||||
import ac.grim.grimac.api.platform.command.PlayerSelector;
|
||||
import ac.grim.grimac.api.platform.manager.ParserDescriptorFactory;
|
||||
import ac.grim.grimac.api.platform.sender.Sender;
|
||||
import ac.grim.grimac.platform.bukkit.command.BukkitPlayerSelectorParser;
|
||||
import org.incendo.cloud.parser.ParserDescriptor;
|
||||
|
||||
public class BukkitParserDescriptorFactory implements ParserDescriptorFactory {
|
||||
|
||||
BukkitPlayerSelectorParser<Sender> bukkitPlayerSelectorParser = new BukkitPlayerSelectorParser<>();
|
||||
|
||||
@Override
|
||||
public ParserDescriptor<Sender, PlayerSelector> getSinglePlayer() {
|
||||
return bukkitPlayerSelectorParser.descriptor();
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package ac.grim.grimac.platform.bukkit.manager;
|
||||
|
||||
import ac.grim.grimac.api.platform.manager.PermissionRegistrationManager;
|
||||
import ac.grim.grimac.api.platform.permissions.PermissionDefaultValue;
|
||||
import ac.grim.grimac.platform.bukkit.utils.convert.BukkitConversionUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.permissions.Permission;
|
||||
|
||||
public class BukkitPermissionRegistrationManager implements PermissionRegistrationManager {
|
||||
/**
|
||||
* Registers a permission with the specified default value on Bukkit.
|
||||
* This method is only called for dynamic permissions (e.g., check-specific permissions
|
||||
* like "grim.exempt.checkname") that are generated at runtime. Most other static permissions
|
||||
* (e.g., "grim.exempt", "grim.alerts.enable-on-join") are registered with their defaults
|
||||
* in the `plugin.yml` file, which is defined in the Bukkit Gradle build script.
|
||||
*
|
||||
* <p>Dynamic permissions are registered here to ensure they are available for autocomplete
|
||||
* and permission checks immediately on startup. If the permission already exists, its default
|
||||
* value is updated to match the specified value.</p>
|
||||
*
|
||||
* @param name The permission node to register (e.g., "grim.exempt.checkname").
|
||||
* @param defaultValue The default value for the permission.
|
||||
*/
|
||||
@Override
|
||||
public void registerPermission(String name, PermissionDefaultValue defaultValue) {
|
||||
final Permission bukkitPermission = Bukkit.getPluginManager().getPermission(name);
|
||||
if (bukkitPermission == null) {
|
||||
Bukkit.getPluginManager().addPermission(new Permission(name, BukkitConversionUtils.toBukkitPermissionDefault(defaultValue)));
|
||||
} else {
|
||||
bukkitPermission.setDefault(BukkitConversionUtils.toBukkitPermissionDefault(defaultValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package ac.grim.grimac.platform.bukkit.manager;
|
||||
|
||||
import ac.grim.grimac.api.platform.PlatformPlugin;
|
||||
import ac.grim.grimac.api.platform.manager.PlatformPluginManager;
|
||||
import ac.grim.grimac.platform.bukkit.BukkitPlatformPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class BukkitPlatformPluginManager implements PlatformPluginManager {
|
||||
|
||||
@Override
|
||||
public PlatformPlugin[] getPlugins() {
|
||||
Plugin[] bukkitPlugins = Bukkit.getPluginManager().getPlugins();
|
||||
PlatformPlugin[] plugins = new PlatformPlugin[bukkitPlugins.length];
|
||||
|
||||
for (int i = 0; i < bukkitPlugins.length; i++) {
|
||||
plugins[i] = new BukkitPlatformPlugin(bukkitPlugins[i]);
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PlatformPlugin getPlugin(String pluginName) {
|
||||
Plugin bukkitPlugin = Bukkit.getPluginManager().getPlugin(pluginName);
|
||||
return bukkitPlugin == null ? null : new BukkitPlatformPlugin(bukkitPlugin);
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package ac.grim.grimac.platform.bukkit.player;
|
||||
|
||||
import ac.grim.grimac.api.packet.item.PacketItemStack;
|
||||
import ac.grim.grimac.api.platform.player.PlatformPlayerInventory;
|
||||
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class BukkitPlatformInventory implements PlatformPlayerInventory {
|
||||
|
||||
private final Player bukkitPlayer;
|
||||
|
||||
public BukkitPlatformInventory(Player bukkitPlayer) {
|
||||
this.bukkitPlayer = bukkitPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketItemStack getItemInHand() {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getItemInHand());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketItemStack getItemInOffHand() {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getItemInOffHand());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketItemStack getStack(int bukkitSlot, int vanillaSlot) {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getItem(bukkitSlot));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketItemStack getHelmet() {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getHelmet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketItemStack getChestplate() {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getChestplate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketItemStack getLeggings() {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getLeggings());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketItemStack getBoots() {
|
||||
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getBoots());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketItemStack[] getContents() {
|
||||
org.bukkit.inventory.ItemStack[] bukkitItems = bukkitPlayer.getInventory().getContents();
|
||||
PacketItemStack[] items = new PacketItemStack[bukkitItems.length];
|
||||
for (int i = 0; i < bukkitItems.length; i++) {
|
||||
if (bukkitItems[i] == null) continue;
|
||||
items[i] = SpigotConversionUtil.fromBukkitItemStack(bukkitItems[i]);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOpenInventoryKey() {
|
||||
return bukkitPlayer.getOpenInventory().getType().toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package ac.grim.grimac.platform.bukkit.player;
|
||||
|
||||
import ac.grim.grimac.api.math.Vector3dm;
|
||||
import ac.grim.grimac.api.platform.entity.GrimEntity;
|
||||
import ac.grim.grimac.api.platform.player.PlatformPlayer;
|
||||
import ac.grim.grimac.api.platform.player.PlatformPlayerInventory;
|
||||
import ac.grim.grimac.api.platform.sender.Sender;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import ac.grim.grimac.platform.bukkit.entity.BukkitGrimEntity;
|
||||
import ac.grim.grimac.platform.bukkit.utils.anticheat.MultiLibUtil;
|
||||
import ac.grim.grimac.platform.bukkit.utils.convert.BukkitConversionUtils;
|
||||
import ac.grim.grimac.platform.bukkit.utils.reflection.PaperUtils;
|
||||
import ac.grim.grimac.api.math.Location;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class BukkitPlatformPlayer extends BukkitGrimEntity implements PlatformPlayer {
|
||||
private static final BukkitAudiences audiences = BukkitAudiences.create(GrimACBukkitLoaderPlugin.LOADER);
|
||||
|
||||
@Getter
|
||||
private final Player bukkitPlayer;
|
||||
private final PlatformPlayerInventory inventory;
|
||||
|
||||
public BukkitPlatformPlayer(Player bukkitPlayer) {
|
||||
super(bukkitPlayer);
|
||||
this.bukkitPlayer = bukkitPlayer;
|
||||
this.inventory = new BukkitPlatformInventory(bukkitPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kickPlayer(String textReason) {
|
||||
bukkitPlayer.kickPlayer(textReason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String s) {
|
||||
return bukkitPlayer.hasPermission(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String s, boolean defaultIfUnset) {
|
||||
return this.bukkitPlayer.hasPermission(new Permission(s, defaultIfUnset ? PermissionDefault.TRUE : PermissionDefault.FALSE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSneaking() {
|
||||
return bukkitPlayer.isSneaking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSneaking(boolean isSneaking) {
|
||||
bukkitPlayer.setSneaking(isSneaking);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
bukkitPlayer.sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(Component message) {
|
||||
audiences.player(bukkitPlayer).sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnline() {
|
||||
return bukkitPlayer.isOnline();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return bukkitPlayer.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInventory() {
|
||||
bukkitPlayer.updateInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3dm getPosition() {
|
||||
org.bukkit.Location location = this.bukkitPlayer.getLocation();
|
||||
return new Vector3dm(location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformPlayerInventory getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable GrimEntity getVehicle() {
|
||||
return bukkitPlayer.getVehicle() == null ? null : new BukkitGrimEntity(bukkitPlayer.getVehicle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGameModeID() {
|
||||
return bukkitPlayer.getGameMode().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameMode(int gameModeID) {
|
||||
bukkitPlayer.setGameMode(GameMode.getByValue(gameModeID));
|
||||
}
|
||||
|
||||
public World getBukkitWorld() {
|
||||
return bukkitPlayer.getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId() {
|
||||
return bukkitPlayer.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean eject() {
|
||||
return bukkitPlayer.eject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> teleportAsync(Location location) {
|
||||
org.bukkit.Location bLoc = BukkitConversionUtils.toBukkitLocation(location);
|
||||
return PaperUtils.teleportAsync(this.bukkitPlayer, bLoc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExternalPlayer() {
|
||||
return MultiLibUtil.isExternalPlayer(this.bukkitPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPluginMessage(String channelName, byte[] byteArray) {
|
||||
this.bukkitPlayer.sendPluginMessage(GrimACBukkitLoaderPlugin.LOADER, channelName, byteArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sender getSender() {
|
||||
return GrimACBukkitLoaderPlugin.LOADER.getBukkitSenderFactory().map(this.bukkitPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Player getNative() {
|
||||
return this.bukkitPlayer;
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package ac.grim.grimac.platform.bukkit.player;
|
||||
|
||||
import ac.grim.grimac.api.platform.player.AbstractPlatformPlayerFactory;
|
||||
import ac.grim.grimac.api.platform.player.PlatformPlayer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
public class BukkitPlatformPlayerFactory extends AbstractPlatformPlayerFactory<Player> {
|
||||
@Override
|
||||
protected Player getNativePlayer(@NotNull UUID uuid) {
|
||||
return Bukkit.getPlayer(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PlatformPlayer createPlatformPlayer(@NotNull Player nativePlayer) {
|
||||
return new BukkitPlatformPlayer(nativePlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isNativePlayerType(@NotNull Object playerObject) {
|
||||
return playerObject instanceof Player;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UUID getPlayerUUID(@NotNull Player nativePlayer) {
|
||||
return nativePlayer.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<Player> getNativePlayerClass() {
|
||||
return Player.class;
|
||||
}
|
||||
|
||||
// The cast is safe because Bukkit.getOnlinePlayers() is guaranteed to contain Player or its subtypes,
|
||||
// and we're only reading from it.
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Collection<Player> getNativeOnlinePlayers() {
|
||||
// Cast Collection<? extends Player> to Collection<Player>
|
||||
return (Collection<Player>) Bukkit.getOnlinePlayers();
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.api.platform.scheduler.AsyncScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.PlatformScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BukkitAsyncScheduler implements AsyncScheduler {
|
||||
|
||||
private final BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||
|
||||
@Override
|
||||
public TaskHandle runNow(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskAsynchronously(GrimACBukkitLoaderPlugin.LOADER, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, @NotNull TimeUnit timeUnit) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskLaterAsynchronously(GrimACBukkitLoaderPlugin.LOADER,
|
||||
task,
|
||||
PlatformScheduler.convertTimeToTicks(delay, timeUnit))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, long period, @NotNull TimeUnit timeUnit) {
|
||||
return new BukkitTaskHandle(
|
||||
bukkitScheduler.runTaskTimerAsynchronously(
|
||||
GrimACBukkitLoaderPlugin.LOADER,
|
||||
task,
|
||||
PlatformScheduler.convertTimeToTicks(delay, timeUnit),
|
||||
PlatformScheduler.convertTimeToTicks(period, timeUnit)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new BukkitTaskHandle(
|
||||
bukkitScheduler.runTaskTimerAsynchronously(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(@NotNull GrimPlugin plugin) {
|
||||
bukkitScheduler.cancelTasks(GrimACBukkitLoaderPlugin.LOADER);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.api.platform.entity.GrimEntity;
|
||||
import ac.grim.grimac.api.platform.scheduler.EntityScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class BukkitEntityScheduler implements EntityScheduler {
|
||||
|
||||
private final BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable run, @Nullable Runnable retired, long delay) {
|
||||
bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, run, delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long delayTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, task, delayTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long initialDelayTicks, long periodTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskTimer(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks));
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.api.platform.scheduler.GlobalRegionScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BukkitGlobalRegionScheduler implements GlobalRegionScheduler {
|
||||
|
||||
private final BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimPlugin plugin, @NotNull Runnable run) {
|
||||
bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, task, delay));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskTimer(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(@NotNull GrimPlugin plugin) {
|
||||
bukkitScheduler.cancelTasks(GrimACBukkitLoaderPlugin.LOADER);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.platform.scheduler.AsyncScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.EntityScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.GlobalRegionScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.PlatformScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.RegionScheduler;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public class BukkitPlatformScheduler implements PlatformScheduler {
|
||||
|
||||
private final BukkitAsyncScheduler bukkitAsyncScheduler = new BukkitAsyncScheduler();
|
||||
private final BukkitGlobalRegionScheduler bukkitGlobalRegionScheduler = new BukkitGlobalRegionScheduler();
|
||||
private final BukkitEntityScheduler bukkitEntityScheduler = new BukkitEntityScheduler();
|
||||
private final BukkitRegionScheduler bukkitRegionScheduler = new BukkitRegionScheduler();
|
||||
|
||||
@Override
|
||||
public @NonNull AsyncScheduler getAsyncScheduler() {
|
||||
return bukkitAsyncScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GlobalRegionScheduler getGlobalRegionScheduler() {
|
||||
return bukkitGlobalRegionScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull EntityScheduler getEntityScheduler() {
|
||||
return bukkitEntityScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull RegionScheduler getRegionScheduler() {
|
||||
return bukkitRegionScheduler;
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.api.platform.scheduler.RegionScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.api.platform.world.PlatformWorld;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import ac.grim.grimac.api.math.Location;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BukkitRegionScheduler implements RegionScheduler {
|
||||
|
||||
private final BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable run) {
|
||||
bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable run) {
|
||||
bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long delayTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, task, delayTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long delayTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, task, delayTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskTimer(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new BukkitTaskHandle(bukkitScheduler.runTaskTimer(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks));
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
|
||||
|
||||
import ac.grim.grimac.api.platform.scheduler.TaskHandle;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
public class BukkitTaskHandle implements TaskHandle {
|
||||
|
||||
private final BukkitTask bukkitTask;
|
||||
|
||||
public BukkitTaskHandle(BukkitTask bukkitTask) {
|
||||
this.bukkitTask = bukkitTask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSync() {
|
||||
return bukkitTask.isSync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return bukkitTask.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
bukkitTask.cancel();
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.folia;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.api.platform.scheduler.AsyncScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class FoliaAsyncScheduler implements AsyncScheduler {
|
||||
|
||||
private final io.papermc.paper.threadedregions.scheduler.AsyncScheduler asyncScheduler = Bukkit.getAsyncScheduler();
|
||||
|
||||
@Override
|
||||
public TaskHandle runNow(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
|
||||
return new FoliaTaskHandle(asyncScheduler.runNow(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, @NotNull TimeUnit timeUnit) {
|
||||
return new FoliaTaskHandle(
|
||||
asyncScheduler.runDelayed(
|
||||
GrimACBukkitLoaderPlugin.LOADER,
|
||||
(ignored) -> task.run(),
|
||||
delay,
|
||||
timeUnit
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, long period, @NotNull TimeUnit timeUnit) {
|
||||
return new FoliaTaskHandle(
|
||||
asyncScheduler.runAtFixedRate(
|
||||
GrimACBukkitLoaderPlugin.LOADER,
|
||||
(ignored) -> task.run(),
|
||||
delay,
|
||||
period,
|
||||
timeUnit
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new FoliaTaskHandle(
|
||||
asyncScheduler.runAtFixedRate(
|
||||
GrimACBukkitLoaderPlugin.LOADER,
|
||||
(ignored) -> task.run(),
|
||||
initialDelayTicks * 50,
|
||||
periodTicks * 50,
|
||||
TimeUnit.MILLISECONDS
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(@NotNull GrimPlugin plugin) {
|
||||
asyncScheduler.cancelTasks(GrimACBukkitLoaderPlugin.LOADER);
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.folia;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.api.platform.entity.GrimEntity;
|
||||
import ac.grim.grimac.api.platform.scheduler.EntityScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import ac.grim.grimac.platform.bukkit.entity.BukkitGrimEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class FoliaEntityScheduler implements EntityScheduler {
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable run, @Nullable Runnable retired, long delay) {
|
||||
((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().execute(GrimACBukkitLoaderPlugin.LOADER, run, retired, delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired) {
|
||||
return new FoliaTaskHandle(((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().run(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), retired));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long delayTicks) {
|
||||
return new FoliaTaskHandle(
|
||||
((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().runDelayed(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), retired, delayTicks)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long initialDelayTicks, long periodTicks) {
|
||||
return new FoliaTaskHandle(((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().runAtFixedRate(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), retired, initialDelayTicks, periodTicks));
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.folia;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.api.platform.scheduler.GlobalRegionScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class FoliaGlobalRegionScheduler implements GlobalRegionScheduler {
|
||||
|
||||
private final io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler globalRegionScheduler = Bukkit.getGlobalRegionScheduler();
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimPlugin plugin, @NotNull Runnable run) {
|
||||
globalRegionScheduler.execute(GrimACBukkitLoaderPlugin.LOADER, run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
|
||||
return new FoliaTaskHandle(globalRegionScheduler.run(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay) {
|
||||
return new FoliaTaskHandle(globalRegionScheduler.runDelayed(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), delay));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new FoliaTaskHandle(globalRegionScheduler.runAtFixedRate(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), initialDelayTicks, periodTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(@NotNull GrimPlugin plugin) {
|
||||
globalRegionScheduler.cancelTasks(GrimACBukkitLoaderPlugin.LOADER);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.folia;
|
||||
|
||||
import ac.grim.grimac.api.platform.scheduler.AsyncScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.EntityScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.GlobalRegionScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.PlatformScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.RegionScheduler;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public class FoliaPlatformScheduler implements PlatformScheduler {
|
||||
|
||||
private final FoliaAsyncScheduler foliaAsyncScheduler = new FoliaAsyncScheduler();
|
||||
private final FoliaGlobalRegionScheduler foliaGlobalRegionScheduler = new FoliaGlobalRegionScheduler();
|
||||
private final FoliaEntityScheduler foliaEntityScheduler = new FoliaEntityScheduler();
|
||||
private final FoliaRegionScheduler foliaRegionScheduler = new FoliaRegionScheduler();
|
||||
|
||||
@Override
|
||||
public @NonNull AsyncScheduler getAsyncScheduler() {
|
||||
return foliaAsyncScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull GlobalRegionScheduler getGlobalRegionScheduler() {
|
||||
return foliaGlobalRegionScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull EntityScheduler getEntityScheduler() {
|
||||
return foliaEntityScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull RegionScheduler getRegionScheduler() {
|
||||
return foliaRegionScheduler;
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.folia;
|
||||
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.api.platform.scheduler.RegionScheduler;
|
||||
import ac.grim.grimac.api.platform.scheduler.TaskHandle;
|
||||
import ac.grim.grimac.api.platform.world.PlatformWorld;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import ac.grim.grimac.platform.bukkit.world.BukkitPlatformWorld;
|
||||
import ac.grim.grimac.api.math.Location;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class FoliaRegionScheduler implements RegionScheduler {
|
||||
|
||||
private final io.papermc.paper.threadedregions.scheduler.RegionScheduler regionScheduler = Bukkit.getRegionScheduler();
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable run) {
|
||||
regionScheduler.execute(GrimACBukkitLoaderPlugin.LOADER, ((BukkitPlatformWorld) world).getBukkitWorld(), chunkX, chunkZ, run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable run) {
|
||||
execute(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, run);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task) {
|
||||
return new FoliaTaskHandle(regionScheduler.run(GrimACBukkitLoaderPlugin.LOADER, ((BukkitPlatformWorld) world).getBukkitWorld(), chunkX, chunkZ, (ignored) -> task.run()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task) {
|
||||
return run(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long delayTicks) {
|
||||
return new FoliaTaskHandle(regionScheduler.runDelayed(GrimACBukkitLoaderPlugin.LOADER,
|
||||
((BukkitPlatformWorld) world).getBukkitWorld(), chunkX, chunkZ, (ignored) -> task.run(), delayTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long delayTicks) {
|
||||
return runDelayed(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, delayTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return new FoliaTaskHandle(regionScheduler.runAtFixedRate(GrimACBukkitLoaderPlugin.LOADER,
|
||||
((BukkitPlatformWorld) world).getBukkitWorld(), chunkX, chunkZ, (ignored) -> task.run(), initialDelayTicks, periodTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
|
||||
return runAtFixedRate(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, initialDelayTicks, periodTicks);
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package ac.grim.grimac.platform.bukkit.scheduler.folia;
|
||||
|
||||
import ac.grim.grimac.api.platform.scheduler.TaskHandle;
|
||||
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
|
||||
|
||||
public class FoliaTaskHandle implements TaskHandle {
|
||||
|
||||
private final ScheduledTask task;
|
||||
|
||||
public FoliaTaskHandle(ScheduledTask task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSync() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return task.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package ac.grim.grimac.platform.bukkit.sender;
|
||||
|
||||
import ac.grim.grimac.api.GrimAPIProvider;
|
||||
import ac.grim.grimac.api.platform.sender.Sender;
|
||||
import ac.grim.grimac.api.platform.sender.SenderFactory;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.command.RemoteConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.incendo.cloud.SenderMapper;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitSenderFactory extends SenderFactory<CommandSender> implements SenderMapper<CommandSender, Sender> {
|
||||
private final BukkitAudiences audiences;
|
||||
|
||||
public BukkitSenderFactory() {
|
||||
this.audiences = BukkitAudiences.create(GrimACBukkitLoaderPlugin.LOADER);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName(CommandSender sender) {
|
||||
return sender instanceof Player ? sender.getName() : Sender.CONSOLE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UUID getUniqueId(CommandSender sender) {
|
||||
return sender instanceof Player ? ((Player) sender).getUniqueId() : Sender.CONSOLE_UUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, String message) {
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, Component message) {
|
||||
// we can safely send async for players and the console - otherwise, send it sync
|
||||
if (sender instanceof Player || sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) {
|
||||
this.audiences.sender(sender).sendMessage(message);
|
||||
} else {
|
||||
GrimAPIProvider.getDirect().getPlatformLoader().getScheduler().getGlobalRegionScheduler().run(
|
||||
GrimAPIProvider.getDirect().getPlatformLoader().getPlugin(),
|
||||
() -> this.audiences.sender(sender).sendMessage(message)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasPermission(CommandSender sender, String node) {
|
||||
return sender.hasPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasPermission(CommandSender sender, String node, boolean defaultIfUnset) {
|
||||
return sender.hasPermission(new Permission(node, defaultIfUnset ? PermissionDefault.TRUE : PermissionDefault.FALSE));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCommand(CommandSender sender, String command) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isConsole(CommandSender sender) {
|
||||
return sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPlayer(CommandSender sender) {
|
||||
return sender instanceof Player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Sender map(@NonNull CommandSender base) {
|
||||
return this.wrap(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull CommandSender reverse(@NonNull Sender mapped) {
|
||||
return this.unwrap(mapped);
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,7 +1,6 @@
|
||||
package ac.grim.grimac.utils.anticheat;
|
||||
package ac.grim.grimac.platform.bukkit.utils.anticheat;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import ac.grim.grimac.api.packet.protocol.version.server.ServerVersions;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
@@ -9,6 +8,7 @@ import java.lang.reflect.Method;
|
||||
public class MultiLibUtil {
|
||||
|
||||
public final static Method externalPlayerMethod = getMethod(Player.class, "isExternalPlayer");
|
||||
private static final boolean IS_PRE_1_18 = ServerVersions.getServerVersion().isOlderThan(ServerVersions.V_1_18);
|
||||
|
||||
public static Method getMethod(Class<?> clazz, String methodName) {
|
||||
try {
|
||||
@@ -20,7 +20,7 @@ public class MultiLibUtil {
|
||||
|
||||
// TODO: cache external players for better performance, but this only matters for people using multi-lib
|
||||
public static boolean isExternalPlayer(Player player) {
|
||||
if (externalPlayerMethod == null || (PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_18))) return false;
|
||||
if (externalPlayerMethod == null || IS_PRE_1_18) return false;
|
||||
try {
|
||||
return (boolean) externalPlayerMethod.invoke(player);
|
||||
} catch (Exception e) {
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package ac.grim.grimac.platform.bukkit.utils.convert;
|
||||
|
||||
import ac.grim.grimac.api.platform.permissions.PermissionDefaultValue;
|
||||
import ac.grim.grimac.platform.bukkit.world.BukkitPlatformWorld;
|
||||
import ac.grim.grimac.api.math.Location;
|
||||
import ac.grim.grimac.api.packet.world.enums.BlockFace;
|
||||
|
||||
public class BukkitConversionUtils {
|
||||
public static org.bukkit.Location toBukkitLocation(Location location) {
|
||||
return new org.bukkit.Location(((BukkitPlatformWorld) location.getWorld()).getBukkitWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this enum to a Bukkit PermissionDefault.
|
||||
*
|
||||
* @return The corresponding Bukkit PermissionDefault.
|
||||
*/
|
||||
public static org.bukkit.permissions.PermissionDefault toBukkitPermissionDefault(PermissionDefaultValue permissionDefaultValue) {
|
||||
return switch (permissionDefaultValue) {
|
||||
case TRUE -> org.bukkit.permissions.PermissionDefault.TRUE;
|
||||
case FALSE -> org.bukkit.permissions.PermissionDefault.FALSE;
|
||||
case OP -> org.bukkit.permissions.PermissionDefault.OP;
|
||||
case NOT_OP -> org.bukkit.permissions.PermissionDefault.NOT_OP;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* For use with bukkit events only
|
||||
* Grim is not meant to be restrained by bukkit!
|
||||
*/
|
||||
@Deprecated
|
||||
public static BlockFace fromBukkitFace(org.bukkit.block.BlockFace face) {
|
||||
return switch (face) {
|
||||
case NORTH -> BlockFace.NORTH;
|
||||
case SOUTH -> BlockFace.SOUTH;
|
||||
case WEST -> BlockFace.WEST;
|
||||
case EAST -> BlockFace.EAST;
|
||||
case UP -> BlockFace.UP;
|
||||
case DOWN -> BlockFace.DOWN;
|
||||
default -> BlockFace.OTHER;
|
||||
};
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -1,4 +1,6 @@
|
||||
package ac.grim.grimac.utils.lists;
|
||||
package ac.grim.grimac.platform.bukkit.utils.list;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
@@ -127,7 +129,7 @@ public abstract class HookedListWrapper<T> extends ListWrapper<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray(Object[] a) {
|
||||
public Object @NotNull [] toArray(Object[] a) {
|
||||
return this.base.toArray(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-10
@@ -1,16 +1,13 @@
|
||||
package ac.grim.grimac.utils.lists;
|
||||
package ac.grim.grimac.platform.bukkit.utils.list;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// https://github.com/ThomasOM/Pledge/blob/master/src/main/java/dev/thomazz/pledge/util/collection/ListWrapper.java
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public abstract class ListWrapper<T> implements List<T> {
|
||||
protected final List<T> base;
|
||||
|
||||
public ListWrapper(List<T> base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
public List<T> getBase() {
|
||||
return this.base;
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package ac.grim.grimac.platform.bukkit.utils.placeholder;
|
||||
|
||||
import ac.grim.grimac.api.GrimAPIProvider;
|
||||
import ac.grim.grimac.api.GrimUser;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class PlaceholderAPIExpansion extends PlaceholderExpansion {
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return "grim";
|
||||
}
|
||||
|
||||
public @NotNull String getAuthor() {
|
||||
return String.join(", ", GrimAPIProvider.getDirect().getPlatformLoader().getPlugin().getDescription().getAuthors());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getVersion() {
|
||||
return GrimAPIProvider.getDirect().getGrimVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persist() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<String> getPlaceholders() {
|
||||
Set<String> staticReplacements = GrimAPIProvider.getDirect().getStaticReplacements().keySet();
|
||||
Set<String> variableReplacements = GrimAPIProvider.getDirect().getVariableReplacements().keySet();
|
||||
ArrayList<String> placeholders = new ArrayList<>(staticReplacements.size() + variableReplacements.size());
|
||||
for (String s : staticReplacements) {
|
||||
placeholders.add(s.equals("%grim_version%") ? s : "%grim_" + s.replaceAll("%", "") + "%");
|
||||
}
|
||||
for (String s : variableReplacements) {
|
||||
placeholders.add(s.equals("%player%") ? "%grim_player%" : "%grim_player_" + s.replaceAll("%", "") + "%");
|
||||
}
|
||||
return placeholders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onRequest(OfflinePlayer offlinePlayer, @NotNull String params) {
|
||||
for (Map.Entry<String, String> entry : GrimAPIProvider.getDirect().getStaticReplacements().entrySet()) {
|
||||
String key = entry.getKey().equals("%grim_version%")
|
||||
? "version"
|
||||
: entry.getKey().replaceAll("%", "");
|
||||
if (params.equalsIgnoreCase(key)) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (offlinePlayer instanceof Player player) {
|
||||
GrimUser grimPlayer = GrimAPIProvider.getDirect().getGrimUser(player.getUniqueId());
|
||||
if (grimPlayer == null) return null;
|
||||
|
||||
for (Map.Entry<String, Function<GrimUser, String>> entry : GrimAPIProvider.getDirect().getVariableReplacements().entrySet()) {
|
||||
String key = entry.getKey().equals("%player%")
|
||||
? "player"
|
||||
: "player_" + entry.getKey().replaceAll("%", "");
|
||||
if (params.equalsIgnoreCase(key)) {
|
||||
return entry.getValue().apply(grimPlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package ac.grim.grimac.platform.bukkit.utils.reflection;
|
||||
|
||||
import ac.grim.grimac.api.reflection.ReflectionUtils;
|
||||
import ac.grim.grimac.api.util.LogUtil;
|
||||
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class PaperUtils {
|
||||
|
||||
public static final boolean PAPER;
|
||||
public static final boolean TICK_END_EVENT;
|
||||
public static final boolean ASYNC_TELEPORT;
|
||||
|
||||
static {
|
||||
PAPER = ReflectionUtils.hasClass("com.destroystokyo.paper.PaperConfig") || ReflectionUtils.hasClass("io.papermc.paper.configuration.Configuration");
|
||||
TICK_END_EVENT = ReflectionUtils.hasClass("com.destroystokyo.paper.event.server.ServerTickEndEvent");
|
||||
ASYNC_TELEPORT = ReflectionUtils.hasMethod(Entity.class, "teleportAsync", org.bukkit.Location.class);
|
||||
}
|
||||
|
||||
public static CompletableFuture<Boolean> teleportAsync(final Entity entity, final Location location) {
|
||||
if (PAPER) {
|
||||
return entity.teleportAsync(location);
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(entity.teleport(location));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static boolean registerTickEndEvent(Listener listener, Runnable runnable) {
|
||||
if (TICK_END_EVENT) {
|
||||
try {
|
||||
Class<?> clazz = ReflectionUtils.getClass("com.destroystokyo.paper.event.server.ServerTickEndEvent");
|
||||
if (clazz == null) return false;
|
||||
GrimACBukkitLoaderPlugin.LOADER.getServer().getPluginManager().registerEvent((Class<? extends Event>) clazz,
|
||||
listener,
|
||||
EventPriority.NORMAL,
|
||||
(l, event) -> runnable.run(), GrimACBukkitLoaderPlugin.LOADER);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
LogUtil.exception("Failed to register tick end event", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package ac.grim.grimac.platform.bukkit.world;
|
||||
|
||||
import ac.grim.grimac.api.packet.block.PacketBlockState;
|
||||
import ac.grim.grimac.api.platform.world.PlatformChunk;
|
||||
import ac.grim.grimac.api.packet.protocol.version.server.ServerVersions;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class BukkitPlatformChunk implements PlatformChunk {
|
||||
private static final Map<BlockData, Integer> blockDataToId = new HashMap<>();
|
||||
private static final boolean isFlat = ServerVersions.getServerVersion().isNewerThanOrEquals(ServerVersions.V_1_13);
|
||||
private final Chunk chunk;
|
||||
|
||||
public BukkitPlatformChunk(@NotNull Chunk chunkAt) {
|
||||
this.chunk = chunkAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockID(int x, int y, int z) {
|
||||
Block block = chunk.getBlock(x, y, z);
|
||||
|
||||
return isFlat // Cache blockDataToID because Strings are expensive
|
||||
? blockDataToId.computeIfAbsent(block.getBlockData(), data -> PacketBlockState.getByString(ServerVersions.getServerVersion().toClientVersion(), data.getAsString(false)).getGlobalId())
|
||||
: (block.getType().getId() << 4) | block.getData();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package ac.grim.grimac.platform.bukkit.world;
|
||||
|
||||
import ac.grim.grimac.api.platform.world.PlatformChunk;
|
||||
import ac.grim.grimac.api.platform.world.PlatformWorld;
|
||||
import ac.grim.grimac.api.packet.block.PacketBlockState;
|
||||
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
public class BukkitPlatformWorld implements PlatformWorld {
|
||||
|
||||
private final World bukkitWorld;
|
||||
|
||||
public BukkitPlatformWorld(@NotNull World world) {
|
||||
this.bukkitWorld = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkLoaded(int chunkX, int chunkZ) {
|
||||
return bukkitWorld.isChunkLoaded(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public getBlockAt(int x, int y, int z) {
|
||||
// return fromBukkitBlockData(bukkitWorld.getBlockAt(x, y, z).getBlockData());
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean isAirAt(int x, int y, int z) {
|
||||
PacketBlockState wrappedBlockState = SpigotConversionUtil.fromBukkitBlockData(bukkitWorld.getBlockData(x, y , z));
|
||||
return wrappedBlockState.getType().isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return bukkitWorld.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable UUID getUID() {
|
||||
return this.bukkitWorld.getUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformChunk getChunkAt(int currChunkX, int currChunkZ) {
|
||||
return new BukkitPlatformChunk(bukkitWorld.getChunkAt(currChunkX, currChunkZ));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoaded() {
|
||||
return Bukkit.getWorld(bukkitWorld.getUID()) != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import versioning.BuildConfig
|
||||
|
||||
plugins {
|
||||
`maven-publish`
|
||||
grim.`base-conventions`
|
||||
}
|
||||
|
||||
repositories {
|
||||
if (BuildConfig.mavenLocalOverride) {
|
||||
mavenLocal()
|
||||
}
|
||||
maven {
|
||||
name = "papermc"
|
||||
url = uri("https://repo.papermc.io/repository/maven-public/")
|
||||
}
|
||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot
|
||||
maven("https://repo.grim.ac/snapshots") { // Grim API
|
||||
content {
|
||||
includeGroup("ac.grim.grimac")
|
||||
includeGroup("com.github.retrooper")
|
||||
}
|
||||
}
|
||||
maven("https://repo.viaversion.com") // ViaVersion
|
||||
maven("https://nexus.scarsz.me/content/repositories/releases") // Configuralize
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/") // Floodgate
|
||||
maven("https://repo.opencollab.dev/maven-releases/") // Cumulus (for Floodgate)
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
mavenCentral() // FastUtil
|
||||
}
|
||||
|
||||
dependencies {
|
||||
if (BuildConfig.shadePE) {
|
||||
api(libs.packetevents.api)
|
||||
} else {
|
||||
compileOnly(libs.packetevents.api)
|
||||
}
|
||||
api(libs.cloud.core)
|
||||
api("org.incendo:cloud-processors-requirements:1.0.0-rc.1")
|
||||
api("github.scarsz:configuralize:1.4.1:slim") {
|
||||
exclude(group = "org.yaml", module = "snakeyaml")
|
||||
}
|
||||
// Bump snakeyaml (transitive dep of configuralize) 1.29 -> 2.2 for geyser-fabric
|
||||
api(libs.snakeyaml)
|
||||
api(libs.fastutil)
|
||||
api(libs.adventure.text.minimessage)
|
||||
api(libs.jetbrains.annotations)
|
||||
|
||||
implementation(project(":api"))
|
||||
implementation(project(":api:packetevents"))
|
||||
|
||||
compileOnly(libs.floodgate.api)
|
||||
compileOnly(libs.via.version.api)
|
||||
compileOnly(libs.netty)
|
||||
}
|
||||
|
||||
publishing.publications.create<MavenPublication>("maven") {
|
||||
from(components["java"])
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package ac.grim.grimac;
|
||||
|
||||
import ac.grim.grimac.api.event.EventBus;
|
||||
import ac.grim.grimac.api.event.OptimizedEventBus;
|
||||
import ac.grim.grimac.api.plugin.GrimPlugin;
|
||||
import ac.grim.grimac.manager.AlertManagerImpl;
|
||||
import ac.grim.grimac.manager.DiscordManager;
|
||||
import ac.grim.grimac.manager.InitManager;
|
||||
import ac.grim.grimac.manager.SpectateManager;
|
||||
import ac.grim.grimac.manager.TickManager;
|
||||
import ac.grim.grimac.manager.config.BaseConfigManager;
|
||||
import ac.grim.grimac.api.platform.init.Initable;
|
||||
import ac.grim.grimac.api.platform.Platform;
|
||||
import ac.grim.grimac.api.platform.PlatformLoader;
|
||||
import ac.grim.grimac.api.platform.PlatformServer;
|
||||
import ac.grim.grimac.api.platform.manager.ItemResetHandler;
|
||||
import ac.grim.grimac.api.platform.manager.MessagePlaceHolderManager;
|
||||
import ac.grim.grimac.api.platform.manager.ParserDescriptorFactory;
|
||||
import ac.grim.grimac.api.platform.manager.PermissionRegistrationManager;
|
||||
import ac.grim.grimac.api.platform.manager.PlatformPluginManager;
|
||||
import ac.grim.grimac.api.platform.player.PlatformPlayerFactory;
|
||||
import ac.grim.grimac.api.platform.scheduler.PlatformScheduler;
|
||||
import ac.grim.grimac.api.platform.sender.Sender;
|
||||
import ac.grim.grimac.api.platform.sender.SenderFactory;
|
||||
import ac.grim.grimac.utils.anticheat.PlayerDataManager;
|
||||
import ac.grim.grimac.api.reflection.ReflectionUtils;
|
||||
import com.github.retrooper.packetevents.PacketEventsAPI;
|
||||
import lombok.Getter;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
public final class GrimAPI {
|
||||
public final static GrimAPI INSTANCE = new GrimAPI();
|
||||
|
||||
@Getter
|
||||
private final Platform platform = detectPlatform();
|
||||
private final BaseConfigManager configManager;
|
||||
private final AlertManagerImpl alertManager;
|
||||
private final SpectateManager spectateManager;
|
||||
private final DiscordManager discordManager;
|
||||
private final PlayerDataManager playerDataManager;
|
||||
private final TickManager tickManager;
|
||||
private final EventBus eventBus;
|
||||
private final GrimExternalAPI externalAPI;
|
||||
private PlatformLoader loader;
|
||||
@Getter
|
||||
private InitManager initManager;
|
||||
private boolean initialized = false;
|
||||
|
||||
public GrimAPI() {
|
||||
this.configManager = new BaseConfigManager();
|
||||
this.alertManager = new AlertManagerImpl(this);
|
||||
this.spectateManager = new SpectateManager(this);
|
||||
this.discordManager = new DiscordManager(this);
|
||||
this.playerDataManager = new PlayerDataManager(this);
|
||||
this.tickManager = new TickManager();
|
||||
this.eventBus = new OptimizedEventBus();
|
||||
this.externalAPI = new GrimExternalAPI(this);
|
||||
System.out.println("GrimAPI classloader: " + GrimAPI.class.getClassLoader());
|
||||
System.out.println("GrimAPI instance: " + this);
|
||||
}
|
||||
|
||||
private static Platform detectPlatform() {
|
||||
final Map<String, Platform> platforms = Map.of(
|
||||
"io.papermc.paper.threadedregions.RegionizedServer", Platform.FOLIA,
|
||||
"org.bukkit.Bukkit", Platform.BUKKIT,
|
||||
"net.fabricmc.loader.api.FabricLoader", Platform.FABRIC
|
||||
);
|
||||
|
||||
return platforms.entrySet().stream()
|
||||
.filter(entry -> ReflectionUtils.hasClass(entry.getKey()))
|
||||
.map(Map.Entry::getValue)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Unknown platform!"));
|
||||
}
|
||||
|
||||
public void bootstrap(@NotNull PlatformLoader platformLoader, Initable... platformSpecificInitables) {
|
||||
this.loader = platformLoader;
|
||||
this.initManager = new InitManager((PacketEventsAPI<?>) loader.getPacketAPI(), loader::getCommandManager, platformSpecificInitables);
|
||||
this.initManager.load();
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
checkInitialized();
|
||||
initManager.start();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
checkInitialized();
|
||||
initManager.stop();
|
||||
}
|
||||
|
||||
public PlatformScheduler getScheduler() {
|
||||
return loader.getScheduler();
|
||||
}
|
||||
|
||||
public PlatformPlayerFactory getPlatformPlayerFactory() {
|
||||
return loader.getPlatformPlayerFactory();
|
||||
}
|
||||
|
||||
public ParserDescriptorFactory getParserDescriptors() {
|
||||
return loader.getParserDescriptorFactory();
|
||||
}
|
||||
|
||||
public GrimPlugin getGrimPlugin() {
|
||||
return loader.getPlugin();
|
||||
}
|
||||
|
||||
public SenderFactory<?> getSenderFactory() {
|
||||
return loader.getSenderFactory();
|
||||
}
|
||||
|
||||
public ItemResetHandler getItemResetHandler() {
|
||||
return loader.getItemResetHandler();
|
||||
}
|
||||
|
||||
public PlatformPluginManager getPluginManager() {
|
||||
return loader.getPluginManager();
|
||||
}
|
||||
|
||||
public PlatformServer getPlatformServer() {
|
||||
return loader.getPlatformServer();
|
||||
}
|
||||
|
||||
public @NotNull MessagePlaceHolderManager getMessagePlaceHolderManager() {
|
||||
return loader.getMessagePlaceHolderManager();
|
||||
}
|
||||
|
||||
public CommandManager<Sender> getCommandManager() {
|
||||
return loader.getCommandManager();
|
||||
}
|
||||
|
||||
private void checkInitialized() {
|
||||
if (!initialized) {
|
||||
throw new IllegalStateException("GrimAPI has not been initialized!");
|
||||
}
|
||||
}
|
||||
|
||||
public PermissionRegistrationManager getPermissionManager() {
|
||||
return loader.getPermissionManager();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package ac.grim.grimac;
|
||||
|
||||
import ac.grim.grimac.api.platform.CoreLoader;
|
||||
import ac.grim.grimac.api.platform.PlatformLoader;
|
||||
import ac.grim.grimac.api.platform.init.Initable;
|
||||
|
||||
/**
|
||||
* Service-loader entry that just forwards every call to the
|
||||
* canonical singleton GrimAPI.INSTANCE.
|
||||
* Ensures that ServiceLoader call to clazz.getDeclaredConstructor().newInstance(); will not create two instances
|
||||
*/
|
||||
public final class GrimAPICoreLoader implements CoreLoader {
|
||||
|
||||
@Override
|
||||
public void bootstrap(PlatformLoader platform, Initable... initables) {
|
||||
GrimAPI.INSTANCE.bootstrap(platform, initables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
GrimAPI.INSTANCE.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
GrimAPI.INSTANCE.stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
package ac.grim.grimac;
|
||||
|
||||
import ac.grim.grimac.api.GrimAbstractAPI;
|
||||
import ac.grim.grimac.api.platform.Platform;
|
||||
import ac.grim.grimac.api.platform.PlatformLoader;
|
||||
import ac.grim.grimac.api.platform.init.LoadableInitable;
|
||||
import ac.grim.grimac.api.plugin.GrimPluginDescription;
|
||||
import ac.grim.grimac.api.GrimUser;
|
||||
import ac.grim.grimac.api.alerts.AlertManager;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.api.event.EventBus;
|
||||
import ac.grim.grimac.api.event.events.GrimReloadEvent;
|
||||
import ac.grim.grimac.manager.config.ConfigManagerFileImpl;
|
||||
import ac.grim.grimac.api.platform.init.StartableInitable;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.api.util.LogUtil;
|
||||
import ac.grim.grimac.api.util.ChatUtil;
|
||||
import ac.grim.grimac.utils.common.ConfigReloadObserver;
|
||||
import com.github.retrooper.packetevents.netty.channel.ChannelHelper;
|
||||
import lombok.Getter;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
//This is used for grim's external API. It has its own class just for organization.
|
||||
|
||||
public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, StartableInitable, LoadableInitable {
|
||||
|
||||
private final GrimAPI api;
|
||||
@Getter
|
||||
private final Map<String, Function<GrimUser, String>> variableReplacements = new ConcurrentHashMap<>();
|
||||
@Getter
|
||||
private final Map<String, String> staticReplacements = new ConcurrentHashMap<>();
|
||||
private final Map<String, Function<Object, Object>> functions = new ConcurrentHashMap<>();
|
||||
private final ConfigManagerFileImpl configManagerFile;
|
||||
private ConfigManager configManager = null;
|
||||
private boolean started = false;
|
||||
|
||||
public GrimExternalAPI(GrimAPI api) {
|
||||
this.api = api;
|
||||
this.configManagerFile = new ConfigManagerFileImpl(api);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull EventBus getEventBus() {
|
||||
return api.getEventBus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable GrimUser getGrimUser(UUID uuid) {
|
||||
return api.getPlayerDataManager().getPlayer(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<GrimUser> getGrimUsers() {
|
||||
return (Collection) api.getPlayerDataManager().getEntries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerVariable(String string, Function<GrimUser, String> replacement) {
|
||||
if (replacement == null) {
|
||||
variableReplacements.remove(string);
|
||||
} else {
|
||||
variableReplacements.put(string, replacement);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerVariable(String variable, String replacement) {
|
||||
if (replacement == null) {
|
||||
staticReplacements.remove(variable);
|
||||
} else {
|
||||
staticReplacements.put(variable, replacement);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGrimVersion() {
|
||||
GrimPluginDescription description = api.getGrimPlugin().getDescription();
|
||||
return description.getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerFunction(String key, Function<Object, Object> function) {
|
||||
if (function == null) {
|
||||
functions.remove(key);
|
||||
} else {
|
||||
functions.put(key, function);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<Object, Object> getFunction(String key) {
|
||||
return functions.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlertManager getAlertManager() {
|
||||
return api.getAlertManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigManager getConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStarted() {
|
||||
return started;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentTick() {
|
||||
return api.getTickManager().currentTick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformLoader getPlatformLoader() {
|
||||
return api.getLoader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Platform getPlatform() {
|
||||
return api.getPlatform();
|
||||
}
|
||||
|
||||
// on load, load the config & register the service
|
||||
public void load() {
|
||||
reload(configManagerFile);
|
||||
api.getLoader().registerAPIService(this);
|
||||
}
|
||||
|
||||
// handles any config loading that's needed to be done after load
|
||||
@Override
|
||||
public void start() {
|
||||
started = true;
|
||||
try {
|
||||
api.getConfigManager().start();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(ConfigManager config) {
|
||||
if (config.isLoadedAsync() && started) {
|
||||
api.getScheduler().getAsyncScheduler().runNow(api.getGrimPlugin(),
|
||||
() -> successfulReload(config));
|
||||
} else {
|
||||
successfulReload(config);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> reloadAsync(ConfigManager config) {
|
||||
if (config.isLoadedAsync() && started) {
|
||||
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||
api.getScheduler().getAsyncScheduler().runNow(api.getGrimPlugin(),
|
||||
() -> future.complete(successfulReload(config)));
|
||||
return future;
|
||||
}
|
||||
return CompletableFuture.completedFuture(successfulReload(config));
|
||||
}
|
||||
|
||||
private boolean successfulReload(ConfigManager config) {
|
||||
try {
|
||||
config.reload();
|
||||
api.getConfigManager().load(config);
|
||||
if (started) api.getConfigManager().start();
|
||||
onReload(config);
|
||||
if (started)
|
||||
api.getScheduler().getAsyncScheduler().runNow(api.getGrimPlugin(),
|
||||
() -> api.getEventBus().post(new GrimReloadEvent(true)));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (started)
|
||||
api.getScheduler().getAsyncScheduler().runNow(api.getGrimPlugin(),
|
||||
() -> api.getEventBus().post(new GrimReloadEvent(false)));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager newConfig) {
|
||||
if (newConfig == null) {
|
||||
LogUtil.warn("ConfigManager not set. Using default config file manager.");
|
||||
configManager = configManagerFile;
|
||||
} else {
|
||||
configManager = newConfig;
|
||||
}
|
||||
// Update variables
|
||||
updateVariables();
|
||||
// Restart
|
||||
api.getAlertManager().reload(configManager);
|
||||
api.getDiscordManager().reload();
|
||||
api.getSpectateManager().reload();
|
||||
// Don't reload players if the plugin hasn't started yet
|
||||
if (!started) return;
|
||||
// Reload checks for all players
|
||||
for (GrimPlayer grimPlayer : api.getPlayerDataManager().getEntries()) {
|
||||
ChannelHelper.runInEventLoop(grimPlayer.user.getChannel(), () -> {
|
||||
grimPlayer.updatePermissions();
|
||||
grimPlayer.reload(configManager);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void updateVariables() {
|
||||
variableReplacements.putIfAbsent("%player%", GrimUser::getName);
|
||||
variableReplacements.putIfAbsent("%uuid%", user -> user.getUniqueId().toString());
|
||||
variableReplacements.putIfAbsent("%ping%", user -> user.getTransactionPing() + "");
|
||||
variableReplacements.putIfAbsent("%brand%", GrimUser::getBrand);
|
||||
variableReplacements.putIfAbsent("%h_sensitivity%", user -> ((int) Math.round(user.getHorizontalSensitivity() * 200)) + "");
|
||||
variableReplacements.putIfAbsent("%v_sensitivity%", user -> ((int) Math.round(user.getVerticalSensitivity() * 200)) + "");
|
||||
variableReplacements.putIfAbsent("%fast_math%", user -> !user.isVanillaMath() + "");
|
||||
variableReplacements.putIfAbsent("%tps%", user -> String.format("%.2f", api.getPlatformServer().getTPS()));
|
||||
variableReplacements.putIfAbsent("%version%", GrimUser::getVersionName);
|
||||
// static variables
|
||||
staticReplacements.put("%prefix%", ChatUtil.translateAlternateColorCodes('&', api.getConfigManager().getPrefix()));
|
||||
staticReplacements.putIfAbsent("%grim_version%", getGrimVersion());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
package ac.grim.grimac.checks;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.AbstractCheck;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.api.event.events.FlagEvent;
|
||||
import ac.grim.grimac.api.packet.MCPacket;
|
||||
import ac.grim.grimac.api.packet.protocol.PacketClientVersions;
|
||||
import ac.grim.grimac.api.packet.types.PacketType;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.types.PacketWrapperFactory;
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientPlayerFlyingMetaPacket;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
// Class from https://github.com/Tecnio/AntiCheatBase/blob/master/src/main/java/me/tecnio/anticheat/check/Check.java
|
||||
@Getter
|
||||
public class Check extends GrimProcessor implements AbstractCheck {
|
||||
protected @NotNull final GrimPlayer player;
|
||||
|
||||
public double violations;
|
||||
private double decay;
|
||||
private double setbackVL;
|
||||
|
||||
private String checkName;
|
||||
private String configName;
|
||||
private String alternativeName;
|
||||
private String displayName;
|
||||
private String description;
|
||||
|
||||
private boolean experimental;
|
||||
private @Setter boolean isEnabled;
|
||||
|
||||
private boolean exemptPermission;
|
||||
private boolean noSetbackPermission;
|
||||
private boolean noModifyPacketPermission;
|
||||
private long lastViolationTime;
|
||||
|
||||
protected PacketWrapperFactory packetFactory = MCPacket.getAPI().packetFactory();
|
||||
|
||||
public Check(final @NotNull GrimPlayer player) {
|
||||
this.player = Objects.requireNonNull(player);
|
||||
|
||||
final CheckData checkData = this.getClass().getAnnotation(CheckData.class);
|
||||
if (checkData != null) {
|
||||
this.checkName = checkData.name();
|
||||
this.configName = checkData.configName();
|
||||
// Fall back to check name
|
||||
if (this.configName.equals("DEFAULT")) this.configName = this.checkName;
|
||||
this.decay = checkData.decay();
|
||||
this.setbackVL = checkData.setback();
|
||||
this.alternativeName = checkData.alternativeName();
|
||||
this.experimental = checkData.experimental();
|
||||
this.description = checkData.description();
|
||||
this.displayName = this.checkName;
|
||||
}
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
public boolean shouldModifyPackets() {
|
||||
return isEnabled && !player.disableGrim && !player.noModifyPacketPermission && !exemptPermission;
|
||||
}
|
||||
|
||||
public void updatePermissions() {
|
||||
if (player.platformPlayer == null || configName == null) return;
|
||||
GrimAPI.INSTANCE.getScheduler().getEntityScheduler().run(
|
||||
player.platformPlayer,
|
||||
GrimAPI.INSTANCE.getGrimPlugin(),
|
||||
() -> {
|
||||
final String id = configName.toLowerCase();
|
||||
exemptPermission = player.platformPlayer.hasPermission("grim.exempt." + id);
|
||||
noSetbackPermission = player.platformPlayer.hasPermission("grim.nosetback." + id);
|
||||
noModifyPacketPermission = player.platformPlayer.hasPermission("grim.nomodifypacket." + id);
|
||||
},
|
||||
() -> {}
|
||||
);
|
||||
}
|
||||
|
||||
public final boolean flagAndAlert(String verbose) {
|
||||
if (flag(verbose)) {
|
||||
alert(verbose);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean flagAndAlert() {
|
||||
return flagAndAlert("");
|
||||
}
|
||||
|
||||
public final boolean flag() {
|
||||
return flag("");
|
||||
}
|
||||
|
||||
public final boolean flag(String verbose) {
|
||||
if (player.disableGrim || (experimental && !player.isExperimentalChecks()) || exemptPermission)
|
||||
return false; // Avoid calling event if disabled
|
||||
|
||||
FlagEvent event = new FlagEvent(player, this, verbose);
|
||||
GrimAPI.INSTANCE.getEventBus().post(event);
|
||||
if (event.isCancelled()) return false;
|
||||
|
||||
player.punishmentManager.handleViolation(this);
|
||||
lastViolationTime = System.currentTimeMillis();
|
||||
violations++;
|
||||
return true;
|
||||
}
|
||||
|
||||
public final boolean flagWithSetback() {
|
||||
return flagWithSetback("");
|
||||
}
|
||||
|
||||
public final boolean flagWithSetback(String verbose) {
|
||||
if (flag(verbose)) {
|
||||
setbackIfAboveSetbackVL();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean flagAndAlertWithSetback() {
|
||||
return flagAndAlertWithSetback("");
|
||||
}
|
||||
|
||||
public final boolean flagAndAlertWithSetback(String verbose) {
|
||||
if (flagAndAlert(verbose)) {
|
||||
setbackIfAboveSetbackVL();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final void reward() {
|
||||
violations = Math.max(0, violations - decay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(ConfigManager configuration) {
|
||||
decay = configuration.getDoubleElse(configName + ".decay", decay);
|
||||
setbackVL = configuration.getDoubleElse(configName + ".setbackvl", setbackVL);
|
||||
displayName = configuration.getStringElse(configName + ".displayname", checkName);
|
||||
description = configuration.getStringElse(configName + ".description", description);
|
||||
|
||||
if (setbackVL == -1) setbackVL = Double.MAX_VALUE;
|
||||
updatePermissions();
|
||||
onReload(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
|
||||
}
|
||||
|
||||
public boolean alert(String verbose) {
|
||||
return player.punishmentManager.handleAlert(player, verbose, this);
|
||||
}
|
||||
|
||||
public boolean setbackIfAboveSetbackVL() {
|
||||
if (shouldSetback()) {
|
||||
return player.getSetbackTeleportUtil().executeViolationSetback();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSetback() {
|
||||
return !noSetbackPermission && violations > setbackVL;
|
||||
}
|
||||
|
||||
public String formatOffset(double offset) {
|
||||
return offset > 0.001 ? String.format("%.5f", offset) : String.format("%.2E", offset);
|
||||
}
|
||||
|
||||
public boolean isTransaction(PacketType packetType) {
|
||||
return packetType == PacketTypes.Play.Client.PONG ||
|
||||
packetType == PacketTypes.Play.Client.WINDOW_CONFIRMATION;
|
||||
}
|
||||
|
||||
public boolean isFlying(PacketType type) {
|
||||
return ClientPlayerFlyingMetaPacket.isFlying(type);
|
||||
}
|
||||
|
||||
public boolean isUpdate(PacketType packetType) {
|
||||
return isFlying(packetType)
|
||||
|| packetType == PacketTypes.Play.Client.CLIENT_TICK_END
|
||||
|| isTransaction(packetType);
|
||||
}
|
||||
|
||||
public boolean isTickPacket(PacketType packetType) {
|
||||
if (isTickPacketIncludingNonMovement(packetType)) {
|
||||
if (isFlying(packetType)) {
|
||||
return !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTickPacketIncludingNonMovement(PacketType packetType) {
|
||||
// On 1.21.2+ fall back to the TICK_END packet IF the player did not send a movement packet for their tick
|
||||
// TickTimer checks to see if player did not send a tick end packet before new flying packet is sent
|
||||
if (player.getClientVersion().isNewerThanOrEquals(PacketClientVersions.V_1_21_2)
|
||||
&& !player.packetStateData.didSendMovementBeforeTickEnd) {
|
||||
if (packetType == PacketTypes.Play.Client.CLIENT_TICK_END) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return isFlying(packetType);
|
||||
}
|
||||
|
||||
|
||||
public static final PacketType[] POSSIBLE_TICK_PACKET_TYPES = new PacketType[]{PacketTypes.Play.Client.CLIENT_TICK_END, PacketTypes.Play.Client.PLAYER_FLYING, PacketTypes.Play.Client.PLAYER_POSITION, PacketTypes.Play.Client.PLAYER_ROTATION, PacketTypes.Play.Client.PLAYER_POSITION_AND_ROTATION};
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,17 @@
|
||||
package ac.grim.grimac.checks;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.AbstractProcessor;
|
||||
import ac.grim.grimac.api.config.ConfigReloadable;
|
||||
import ac.grim.grimac.utils.common.ConfigReloadObserver;
|
||||
|
||||
public abstract class GrimProcessor implements AbstractProcessor, ConfigReloadable, ConfigReloadObserver {
|
||||
|
||||
// Not everything has to be a check for it to process packets & be configurable
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
reload(GrimAPI.INSTANCE.getConfigManager().getConfig());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package ac.grim.grimac.checks.debug;
|
||||
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
|
||||
public abstract class AbstractDebugHandler extends Check {
|
||||
|
||||
protected final GrimPlayer grimPlayer;
|
||||
|
||||
public AbstractDebugHandler(GrimPlayer grimPlayer) {
|
||||
super(grimPlayer);
|
||||
this.grimPlayer = grimPlayer;
|
||||
}
|
||||
|
||||
public GrimPlayer getPlayer() {
|
||||
return grimPlayer;
|
||||
}
|
||||
|
||||
public abstract void toggleListener(GrimPlayer player);
|
||||
|
||||
public abstract boolean toggleConsoleOutput();
|
||||
}
|
||||
+3
-3
@@ -8,15 +8,15 @@ import ac.grim.grimac.utils.anticheat.update.RotationUpdate;
|
||||
|
||||
@CheckData(name = "AimDuplicateLook")
|
||||
public class AimDuplicateLook extends Check implements RotationCheck {
|
||||
boolean exempt = false;
|
||||
|
||||
public AimDuplicateLook(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
boolean exempt = false;
|
||||
|
||||
@Override
|
||||
public void process(final RotationUpdate rotationUpdate) {
|
||||
if (player.packetStateData.lastPacketWasTeleport || player.packetStateData.lastPacketWasOnePointSeventeenDuplicate || player.compensatedEntities.getSelf().getRiding() != null) {
|
||||
if (player.packetStateData.lastPacketWasTeleport || player.packetStateData.lastPacketWasOnePointSeventeenDuplicate || player.compensatedEntities.self.getRiding() != null) {
|
||||
exempt = true;
|
||||
return;
|
||||
}
|
||||
+12
-3
@@ -11,7 +11,8 @@ import ac.grim.grimac.utils.anticheat.update.RotationUpdate;
|
||||
// It works on clients who % 360 their rotation.
|
||||
@CheckData(name = "AimModulo360", decay = 0.005)
|
||||
public class AimModulo360 extends Check implements RotationCheck {
|
||||
float lastDeltaYaw;
|
||||
|
||||
private float lastDeltaYaw;
|
||||
|
||||
public AimModulo360(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
@@ -19,12 +20,20 @@ public class AimModulo360 extends Check implements RotationCheck {
|
||||
|
||||
@Override
|
||||
public void process(final RotationUpdate rotationUpdate) {
|
||||
lastDeltaYaw = rotationUpdate.getDeltaXRot();
|
||||
if (player.packetStateData.lastPacketWasTeleport) return;
|
||||
// Exempt for teleport, entering a vehicle due to rotation reset or
|
||||
// after forced, client-sided rotation change after interacting with a horse (not necessarily mounting it)
|
||||
if (player.packetStateData.lastPacketWasTeleport || player.vehicleData.wasVehicleSwitch
|
||||
|| player.packetStateData.horseInteractCausedForcedRotation) {
|
||||
lastDeltaYaw = rotationUpdate.getDeltaXRot();
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.xRot < 360 && player.xRot > -360 && Math.abs(rotationUpdate.getDeltaXRot()) > 320 && Math.abs(lastDeltaYaw) < 30) {
|
||||
flagAndAlert();
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
|
||||
lastDeltaYaw = rotationUpdate.getDeltaXRot();
|
||||
}
|
||||
}
|
||||
+20
-26
@@ -13,26 +13,26 @@ public class AimProcessor extends Check implements RotationCheck {
|
||||
|
||||
private static final int SIGNIFICANT_SAMPLES_THRESHOLD = 15;
|
||||
private static final int TOTAL_SAMPLES_THRESHOLD = 80;
|
||||
public double sensitivityX;
|
||||
public double sensitivityY;
|
||||
public double divisorX;
|
||||
public double divisorY;
|
||||
public double modeX, modeY;
|
||||
public double deltaDotsX, deltaDotsY;
|
||||
RunningMode xRotMode = new RunningMode(TOTAL_SAMPLES_THRESHOLD);
|
||||
RunningMode yRotMode = new RunningMode(TOTAL_SAMPLES_THRESHOLD);
|
||||
float lastXRot;
|
||||
float lastYRot;
|
||||
|
||||
public AimProcessor(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
RunningMode xRotMode = new RunningMode(TOTAL_SAMPLES_THRESHOLD);
|
||||
RunningMode yRotMode = new RunningMode(TOTAL_SAMPLES_THRESHOLD);
|
||||
|
||||
float lastXRot;
|
||||
float lastYRot;
|
||||
|
||||
public double sensitivityX;
|
||||
public double sensitivityY;
|
||||
|
||||
public double divisorX;
|
||||
public double divisorY;
|
||||
|
||||
public double modeX, modeY;
|
||||
|
||||
public double deltaDotsX, deltaDotsY;
|
||||
public static double convertToSensitivity(double var13) {
|
||||
double var11 = var13 / 0.15F / 8.0D;
|
||||
double var9 = Math.cbrt(var11);
|
||||
return (var9 - 0.2f) / 0.6f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(final RotationUpdate rotationUpdate) {
|
||||
@@ -59,15 +59,15 @@ public class AimProcessor extends Check implements RotationCheck {
|
||||
|
||||
if (this.xRotMode.size() > SIGNIFICANT_SAMPLES_THRESHOLD) {
|
||||
Pair<Double, Integer> modeX = this.xRotMode.getMode();
|
||||
if (modeX.getSecond() > SIGNIFICANT_SAMPLES_THRESHOLD) {
|
||||
this.modeX = modeX.getFirst();
|
||||
if (modeX.second() > SIGNIFICANT_SAMPLES_THRESHOLD) {
|
||||
this.modeX = modeX.first();
|
||||
this.sensitivityX = convertToSensitivity(this.modeX);
|
||||
}
|
||||
}
|
||||
if (this.yRotMode.size() > SIGNIFICANT_SAMPLES_THRESHOLD) {
|
||||
Pair<Double, Integer> modeY = this.yRotMode.getMode();
|
||||
if (modeY.getSecond() > SIGNIFICANT_SAMPLES_THRESHOLD) {
|
||||
this.modeY = modeY.getFirst();
|
||||
if (modeY.second() > SIGNIFICANT_SAMPLES_THRESHOLD) {
|
||||
this.modeY = modeY.first();
|
||||
this.sensitivityY = convertToSensitivity(this.modeY);
|
||||
}
|
||||
}
|
||||
@@ -75,10 +75,4 @@ public class AimProcessor extends Check implements RotationCheck {
|
||||
this.deltaDotsX = deltaXRot / modeX;
|
||||
this.deltaDotsY = deltaYRot / modeY;
|
||||
}
|
||||
|
||||
public static double convertToSensitivity(double var13) {
|
||||
double var11 = var13 / 0.15F / 8.0D;
|
||||
double var9 = Math.cbrt(var11);
|
||||
return (var9 - 0.2f) / 0.6f;
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-6
@@ -1,14 +1,13 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientHeldItemChange;
|
||||
|
||||
@CheckData(name = "BadPacketsA")
|
||||
@CheckData(name = "BadPacketsA", description = "Sent duplicate slot id")
|
||||
public class BadPacketsA extends Check implements PacketCheck {
|
||||
int lastSlot = -1;
|
||||
|
||||
@@ -18,8 +17,8 @@ public class BadPacketsA extends Check implements PacketCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.HELD_ITEM_CHANGE) {
|
||||
final int slot = new WrapperPlayClientHeldItemChange(event).getSlot();
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.HELD_ITEM_CHANGE) {
|
||||
final int slot = packetFactory.clientHeldItemChange(event).getSlot();
|
||||
|
||||
if (slot == lastSlot && flagAndAlert("slot=" + slot) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
@@ -0,0 +1,32 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
|
||||
@CheckData(name = "BadPacketsB", description = "Ignored set rotation packet")
|
||||
public class BadPacketsB extends Check implements PacketCheck {
|
||||
|
||||
public BadPacketsB(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (isTransaction(event.getPacketType())) {
|
||||
player.pendingRotations.removeIf(data -> {
|
||||
if (player.getLastTransactionReceived() > data.getTransaction()) {
|
||||
if (!data.isAccepted()) {
|
||||
flagAndAlert();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -1,14 +1,14 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.api.packet.player.enums.GameMode;
|
||||
|
||||
@CheckData(name = "BadPacketsC")
|
||||
@CheckData(name = "BadPacketsC", description = "Interacted with self")
|
||||
public class BadPacketsC extends Check implements PacketCheck {
|
||||
public BadPacketsC(GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -16,8 +16,9 @@ public class BadPacketsC extends Check implements PacketCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
if (new WrapperPlayClientInteractEntity(event).getEntityId() == player.entityID) {
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.INTERACT_ENTITY) {
|
||||
if (player.gamemode == GameMode.SPECTATOR) return;
|
||||
if (packetFactory.clientInteractEntity(event).getEntityId() == player.entityID) {
|
||||
// Instant ban
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
+6
-6
@@ -1,14 +1,14 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientPlayerFlyingMetaPacket;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
|
||||
@CheckData(name = "BadPacketsD")
|
||||
@CheckData(name = "BadPacketsD", description = "Impossible pitch")
|
||||
public class BadPacketsD extends Check implements PacketCheck {
|
||||
public BadPacketsD(GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -18,8 +18,8 @@ public class BadPacketsD extends Check implements PacketCheck {
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.packetStateData.lastPacketWasTeleport) return;
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_ROTATION || event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION) {
|
||||
final float pitch = new WrapperPlayClientPlayerFlying(event).getLocation().getPitch();
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.PLAYER_ROTATION || event.getPacketType() == PacketTypes.Play.Client.PLAYER_POSITION_AND_ROTATION) {
|
||||
final float pitch = ClientPlayerFlyingMetaPacket.from(event).getLocation().getPitch();
|
||||
if (pitch > 90 || pitch < -90) {
|
||||
// Ban.
|
||||
if (flagAndAlert("pitch=" + pitch)) {
|
||||
@@ -0,0 +1,41 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.protocol.PacketClientVersions;
|
||||
import ac.grim.grimac.api.packet.protocol.version.server.ServerVersions;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
|
||||
@CheckData(name = "BadPacketsE")
|
||||
public class BadPacketsE extends Check implements PacketCheck {
|
||||
private int noReminderTicks;
|
||||
|
||||
public BadPacketsE(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
final boolean isViaPleaseStopUsingProtocolHacksOnYourServer = player.getClientVersion().isNewerThanOrEquals(PacketClientVersions.V_1_21_2) || ServerVersions.getServerVersion().isNewerThanOrEquals(ServerVersions.V_1_21_2);
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.PLAYER_POSITION_AND_ROTATION ||
|
||||
event.getPacketType() == PacketTypes.Play.Client.PLAYER_POSITION) {
|
||||
noReminderTicks = 0;
|
||||
} else if (isFlying(event.getPacketType()) && !player.packetStateData.lastPacketWasTeleport) {
|
||||
noReminderTicks++;
|
||||
} else if (event.getPacketType() == PacketTypes.Play.Client.STEER_VEHICLE
|
||||
|| (isViaPleaseStopUsingProtocolHacksOnYourServer && player.inVehicle())) {
|
||||
noReminderTicks = 0; // Exempt vehicles
|
||||
}
|
||||
|
||||
if (noReminderTicks > 20) {
|
||||
flagAndAlert("ticks=" + noReminderTicks); // ban? I don't know how this would false
|
||||
}
|
||||
}
|
||||
|
||||
public void handleRespawn() {
|
||||
noReminderTicks = 0;
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -1,14 +1,14 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientEntityActionPacket;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
|
||||
@CheckData(name = "BadPacketsF")
|
||||
@CheckData(name = "BadPacketsF", description = "Sent duplicate sprinting status")
|
||||
public class BadPacketsF extends Check implements PacketCheck {
|
||||
public boolean lastSprinting;
|
||||
public boolean exemptNext = true; // Support 1.14+ clients starting on either true or false sprinting, we don't know
|
||||
@@ -19,10 +19,10 @@ public class BadPacketsF extends Check implements PacketCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
|
||||
WrapperPlayClientEntityAction packet = new WrapperPlayClientEntityAction(event);
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.ENTITY_ACTION) {
|
||||
ClientEntityActionPacket packet = packetFactory.clientEntityAction(event);
|
||||
|
||||
if (packet.getAction() == WrapperPlayClientEntityAction.Action.START_SPRINTING) {
|
||||
if (packet.getAction() == ClientEntityActionPacket.Action.START_SPRINTING) {
|
||||
if (lastSprinting) {
|
||||
if (exemptNext) {
|
||||
exemptNext = false;
|
||||
@@ -35,7 +35,7 @@ public class BadPacketsF extends Check implements PacketCheck {
|
||||
}
|
||||
|
||||
lastSprinting = true;
|
||||
} else if (packet.getAction() == WrapperPlayClientEntityAction.Action.STOP_SPRINTING) {
|
||||
} else if (packet.getAction() == ClientEntityActionPacket.Action.STOP_SPRINTING) {
|
||||
if (!lastSprinting) {
|
||||
if (exemptNext) {
|
||||
exemptNext = false;
|
||||
@@ -0,0 +1,53 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientEntityActionPacket;
|
||||
|
||||
@CheckData(name = "BadPacketsG", description = "Sent duplicate sneaking status")
|
||||
public class BadPacketsG extends Check implements PacketCheck {
|
||||
private boolean lastSneaking, respawn;
|
||||
|
||||
public BadPacketsG(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.ENTITY_ACTION) {
|
||||
ClientEntityActionPacket packet = packetFactory.clientEntityAction(event);
|
||||
|
||||
if (packet.getAction() == ClientEntityActionPacket.Action.START_SNEAKING) {
|
||||
// The player may send two START_SNEAKING packets if they respawned
|
||||
if (lastSneaking && !respawn) {
|
||||
if (flagAndAlert("state=true") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
lastSneaking = true;
|
||||
}
|
||||
respawn = false;
|
||||
} else if (packet.getAction() == ClientEntityActionPacket.Action.STOP_SNEAKING) {
|
||||
if (!lastSneaking && !respawn) {
|
||||
if (flagAndAlert("state=false") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
lastSneaking = false;
|
||||
}
|
||||
respawn = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleRespawn() {
|
||||
// Clients could potentially not send a STOP_SNEAKING packet when they die, so we need to track it
|
||||
respawn = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.protocol.PacketClientVersions;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.BlockPlaceCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
|
||||
import ac.grim.grimac.api.packet.protocol.version.server.ServerVersions;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
|
||||
@CheckData(name = "BadPacketsH", description = "Sent unexpected sequence id", experimental = true)
|
||||
public class BadPacketsH extends BlockPlaceCheck {
|
||||
private int lastSequence;
|
||||
private final boolean isSupportedVersion = player.getClientVersion().isNewerThanOrEquals(PacketClientVersions.V_1_19) && ServerVersions.getServerVersion().isNewerThanOrEquals(ServerVersions.V_1_19);
|
||||
|
||||
public BadPacketsH(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.USE_ITEM
|
||||
&& shouldCancel(packetFactory.clientPlayerUseItem(event).getSequence())) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockPlace(BlockPlace place) {
|
||||
if (shouldCancel(place.sequence) && shouldCancel()) {
|
||||
place.resync();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
switch (blockBreak.action) {
|
||||
case START_DIGGING, FINISHED_DIGGING -> {
|
||||
if (shouldCancel(blockBreak.sequence)) {
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
case CANCELLED_DIGGING -> { // other actions will be checked by BadPacketsL
|
||||
if (blockBreak.sequence != 0 && flagAndAlert("expected=0, id=" + blockBreak.sequence) && shouldModifyPackets()) {
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldCancel(int sequence) {
|
||||
if (isSupportedVersion && sequence != lastSequence + 1) {
|
||||
if (flagAndAlert("expected=" + (lastSequence + 1) + ", id=" + sequence) && shouldModifyPackets()) {
|
||||
lastSequence = sequence;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
lastSequence = sequence;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onWorldChange() {
|
||||
lastSequence = 0;
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -1,14 +1,14 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientPlayerAbilitiesPacket;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerAbilities;
|
||||
|
||||
@CheckData(name = "BadPacketsI")
|
||||
@CheckData(name = "BadPacketsI", description = "Claimed to be flying while unable to fly")
|
||||
public class BadPacketsI extends Check implements PacketCheck {
|
||||
public BadPacketsI(GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -16,8 +16,8 @@ public class BadPacketsI extends Check implements PacketCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_ABILITIES) {
|
||||
if (new WrapperPlayClientPlayerAbilities(event).isFlying() && !player.canFly) {
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.PLAYER_ABILITIES) {
|
||||
if (ClientPlayerAbilitiesPacket.from(event).isFlying() && !player.canFly) {
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
@@ -0,0 +1,58 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.player.enums.GameMode;
|
||||
import ac.grim.grimac.api.packet.protocol.PacketClientVersions;
|
||||
import ac.grim.grimac.api.packet.protocol.version.server.ServerVersions;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PostPredictionCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.data.HeadRotation;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientPlayerUseItemPacket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@CheckData(name = "BadPacketsJ", description = "Rotation in use item packet did not match tick rotation", experimental = true)
|
||||
public class BadPacketsJ extends Check implements PostPredictionCheck {
|
||||
private final List<HeadRotation> rotations = new ArrayList<>();
|
||||
|
||||
public BadPacketsJ(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.gamemode == GameMode.SPECTATOR) {
|
||||
rotations.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.USE_ITEM && player.getClientVersion().isNewerThanOrEquals(PacketClientVersions.V_1_21)
|
||||
&& ServerVersions.getServerVersion().isNewerThanOrEquals(ServerVersions.V_1_21)) {
|
||||
ClientPlayerUseItemPacket packet = packetFactory.clientPlayerUseItem(event);
|
||||
rotations.add(new HeadRotation(packet.getYaw(), packet.getPitch()));
|
||||
}
|
||||
|
||||
if (isTickPacket(event.getPacketType())) {
|
||||
// due to tick skipping, the rotations sent could be last tick's
|
||||
boolean allowLast = player.canSkipTicks() && (event.getPacketType() == PacketTypes.Play.Client.PLAYER_POSITION_AND_ROTATION || event.getPacketType() == PacketTypes.Play.Client.PLAYER_ROTATION);
|
||||
for (HeadRotation rotation : rotations) {
|
||||
if (rotation.getYaw() == player.xRot && rotation.getPitch() == player.yRot) {
|
||||
allowLast = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rotation.getYaw() == player.lastXRot && rotation.getPitch() == player.lastYRot && allowLast) {
|
||||
continue;
|
||||
}
|
||||
|
||||
flagAndAlert();
|
||||
}
|
||||
|
||||
rotations.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -1,14 +1,14 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.player.enums.GameMode;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
|
||||
@CheckData(name = "BadPacketsK")
|
||||
@CheckData(name = "BadPacketsK", description = "Sent spectate packets while not in spectator mode")
|
||||
public class BadPacketsK extends Check implements PacketCheck {
|
||||
public BadPacketsK(GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -16,7 +16,7 @@ public class BadPacketsK extends Check implements PacketCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.SPECTATE) {
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.SPECTATE) {
|
||||
if (player.gamemode != GameMode.SPECTATOR) {
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
@@ -0,0 +1,53 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.player.enums.DiggingAction;
|
||||
import ac.grim.grimac.api.packet.protocol.PacketClientVersions;
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientPlayerDiggingPacket;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@CheckData(name = "BadPacketsL", description = "Sent impossible dig packet")
|
||||
public class BadPacketsL extends Check implements PacketCheck {
|
||||
|
||||
public BadPacketsL(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.PLAYER_DIGGING) {
|
||||
final ClientPlayerDiggingPacket packet = packetFactory.clientPlayerDigging(event);
|
||||
|
||||
if (packet.getDiggingAction() == DiggingAction.START_DIGGING || packet.getDiggingAction() == DiggingAction.FINISHED_DIGGING || packet.getDiggingAction() == DiggingAction.CANCELLED_DIGGING)
|
||||
return;
|
||||
|
||||
// 1.8 and above clients always send digging packets that aren't used for digging at 0, 0, 0, facing DOWN
|
||||
// 1.7 and below clients do the same, except use SOUTH for RELEASE_USE_ITEM
|
||||
final int expectedFace = player.getClientVersion().isOlderThanOrEquals(PacketClientVersions.V_1_7_10) && packet.getDiggingAction() == DiggingAction.RELEASE_USE_ITEM
|
||||
? 255 : 0;
|
||||
|
||||
if (packet.getBlockFaceId() != expectedFace
|
||||
|| packet.getBlockPosition().getX() != 0
|
||||
|| packet.getBlockPosition().getY() != 0
|
||||
|| packet.getBlockPosition().getZ() != 0
|
||||
|| packet.getSequence() != 0
|
||||
) {
|
||||
if (flagAndAlert("pos="
|
||||
+ packet.getBlockPosition().getX() + ", " + packet.getBlockPosition().getY() + ", " + packet.getBlockPosition().getZ()
|
||||
+ ", face=" + packet.getBlockFace()
|
||||
+ ", sequence=" + packet.getSequence()
|
||||
+ ", action=" + packet.getDiggingAction().toString().toLowerCase(Locale.ROOT)
|
||||
) && shouldModifyPackets() && packet.getDiggingAction() != DiggingAction.RELEASE_USE_ITEM) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@ import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
|
||||
@CheckData(name = "BadPacketsN")
|
||||
@CheckData(name = "BadPacketsN", setback = 0)
|
||||
public class BadPacketsN extends Check implements PacketCheck {
|
||||
public BadPacketsN(final GrimPlayer player) {
|
||||
super(player);
|
||||
+11
-11
@@ -1,15 +1,15 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientKeepAlivePacket;
|
||||
import ac.grim.grimac.api.packet.types.server.play.ServerKeepAlivePacket;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.data.Pair;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.event.PacketSendEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientKeepAlive;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerKeepAlive;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketSendEvent;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
@@ -24,22 +24,22 @@ public class BadPacketsO extends Check implements PacketCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketSend(PacketSendEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Server.KEEP_ALIVE) {
|
||||
WrapperPlayServerKeepAlive packet = new WrapperPlayServerKeepAlive(event);
|
||||
if (event.getPacketType() == PacketTypes.Play.Server.KEEP_ALIVE) {
|
||||
ServerKeepAlivePacket packet = ServerKeepAlivePacket.from(event);
|
||||
keepaliveMap.add(new Pair<>(packet.getId(), System.nanoTime()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.KEEP_ALIVE) {
|
||||
WrapperPlayClientKeepAlive packet = new WrapperPlayClientKeepAlive(event);
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.KEEP_ALIVE) {
|
||||
ClientKeepAlivePacket packet = ClientKeepAlivePacket.from(event);
|
||||
|
||||
long id = packet.getId();
|
||||
boolean hasID = false;
|
||||
|
||||
for (Pair<Long, Long> iterator : keepaliveMap) {
|
||||
if (iterator.getFirst() == id) {
|
||||
if (iterator.first() == id) {
|
||||
hasID = true;
|
||||
break;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public class BadPacketsO extends Check implements PacketCheck {
|
||||
do {
|
||||
data = keepaliveMap.poll();
|
||||
if (data == null) break;
|
||||
} while (data.getFirst() != id);
|
||||
} while (data.first() != id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientClickWindowPacket;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketSendEvent;
|
||||
import ac.grim.grimac.api.packet.types.server.play.ServerOpenWindowPacket;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientClickWindowPacket.WindowClickType;
|
||||
|
||||
@CheckData(name = "BadPacketsP", experimental = true)
|
||||
public class BadPacketsP extends Check implements PacketCheck {
|
||||
|
||||
private int containerType = -1;
|
||||
private int containerId = -1;
|
||||
|
||||
public BadPacketsP(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(final PacketSendEvent event) {
|
||||
if (event.getPacketType() == PacketTypes.Play.Server.OPEN_WINDOW) {
|
||||
ServerOpenWindowPacket window = packetFactory.serverOpenWindow(event);
|
||||
this.containerType = window.getType();
|
||||
this.containerId = window.getContainerId();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.CLICK_WINDOW) {
|
||||
ClientClickWindowPacket wrapper = packetFactory.clientClickWindow(event);
|
||||
WindowClickType clickType = wrapper.getWindowClickType();
|
||||
int button = wrapper.getButton();
|
||||
|
||||
// TODO: Adjust for containers
|
||||
boolean flag = switch (clickType) {
|
||||
case PICKUP, QUICK_MOVE, CLONE -> button > 2 || button < 0;
|
||||
case SWAP -> (button > 8 || button < 0) && button != 40;
|
||||
case THROW -> button != 0 && button != 1;
|
||||
case QUICK_CRAFT -> button == 3 || button == 7 || button > 10 || button < 0;
|
||||
case PICKUP_ALL -> button != 0;
|
||||
case UNKNOWN -> true;
|
||||
};
|
||||
|
||||
// Allowing this to false flag to debug and find issues faster
|
||||
if (flag) {
|
||||
if (flagAndAlert("clickType=" + clickType.toString().toLowerCase() + ", button=" + button + (wrapper.getWindowId() == containerId ? ", container=" + containerType : "")) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-7
@@ -1,13 +1,13 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientEntityActionPacket;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType.Play.Client;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction.Action;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes.Play.Client;
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientEntityActionPacket.Action;
|
||||
|
||||
@CheckData(name = "BadPacketsQ")
|
||||
public class BadPacketsQ extends Check implements PacketCheck {
|
||||
@@ -18,9 +18,11 @@ public class BadPacketsQ extends Check implements PacketCheck {
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == Client.ENTITY_ACTION) {
|
||||
WrapperPlayClientEntityAction wrapper = new WrapperPlayClientEntityAction(event);
|
||||
|
||||
if (wrapper.getJumpBoost() < 0 || wrapper.getJumpBoost() > 100 || wrapper.getEntityId() != player.entityID || (wrapper.getAction() != Action.START_JUMPING_WITH_HORSE && wrapper.getJumpBoost() != 0)) {
|
||||
ClientEntityActionPacket wrapper = packetFactory.clientEntityAction(event);
|
||||
// you are able to send negative jump boost, how and why!?
|
||||
if (Math.abs(wrapper.getJumpBoost()) > 100
|
||||
|| wrapper.getEntityId() != player.entityID
|
||||
|| wrapper.getAction() != Action.START_JUMPING_WITH_HORSE && wrapper.getJumpBoost() != 0) {
|
||||
if (flagAndAlert("boost=" + wrapper.getJumpBoost() + ", action=" + wrapper.getAction() + ", entity=" + wrapper.getEntityId()) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
+13
-12
@@ -1,32 +1,32 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.api.packet.player.enums.GameMode;
|
||||
|
||||
@CheckData(name = "BadPacketsR", decay = 0.25, experimental = true)
|
||||
public class BadPacketsR extends Check implements PacketCheck {
|
||||
public BadPacketsR(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int positions = 0;
|
||||
private long clock = 0;
|
||||
private long lastTransTime;
|
||||
private int oldTransId = 0;
|
||||
|
||||
public BadPacketsR(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(final PacketReceiveEvent event) {
|
||||
if (isTransaction(event.getPacketType()) && player.packetStateData.lastTransactionPacketWasValid) {
|
||||
long ms = (player.getPlayerClockAtLeast() - clock) / 1000000L;
|
||||
long diff = (System.currentTimeMillis() - lastTransTime);
|
||||
if (diff > 2000 && ms > 2000) {
|
||||
if (positions == 0 && clock != 0 && player.gamemode != GameMode.SPECTATOR && !player.compensatedEntities.getSelf().isDead) {
|
||||
flagAndAlert("time=" + ms + "ms, " + "lst=" + diff + "ms, positions=" + positions);
|
||||
if (positions == 0 && clock != 0 && player.gamemode != GameMode.SPECTATOR && !player.compensatedEntities.self.isDead) {
|
||||
flag("time=" + ms + "ms, " + "lst=" + diff + "ms, positions=" + positions);
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
@@ -38,10 +38,11 @@ public class BadPacketsR extends Check implements PacketCheck {
|
||||
}
|
||||
}
|
||||
//
|
||||
if ((event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION ||
|
||||
event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION) && !player.compensatedEntities.getSelf().inVehicle()) {
|
||||
if ((event.getPacketType() == PacketTypes.Play.Client.PLAYER_POSITION_AND_ROTATION ||
|
||||
event.getPacketType() == PacketTypes.Play.Client.PLAYER_POSITION) && !player.inVehicle()) {
|
||||
positions++;
|
||||
} else if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE && player.compensatedEntities.getSelf().inVehicle()) {
|
||||
} else if ((event.getPacketType() == PacketTypes.Play.Client.STEER_VEHICLE || event.getPacketType() == PacketTypes.Play.Client.VEHICLE_MOVE)
|
||||
&& player.inVehicle()) {
|
||||
positions++;
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+19
-19
@@ -1,35 +1,35 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.protocol.PacketClientVersions;
|
||||
import ac.grim.grimac.api.packet.protocol.attribute.Attributes;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientInteractEntityPacket;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import ac.grim.grimac.api.packet.entity.PacketEntityTypes;
|
||||
|
||||
@CheckData(name = "BadPacketsT")
|
||||
public class BadPacketsT extends Check implements PacketCheck {
|
||||
public BadPacketsT(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
// 1.7 and 1.8 seem to have different hitbox "expansion" values than 1.9+
|
||||
// https://github.com/GrimAnticheat/Grim/pull/1274#issuecomment-1872458702
|
||||
// https://github.com/GrimAnticheat/Grim/pull/1274#issuecomment-1872533497
|
||||
private final boolean hasLegacyExpansion = player.getClientVersion().isOlderThan(ClientVersion.V_1_9);
|
||||
private final boolean hasLegacyExpansion = player.getClientVersion().isOlderThan(PacketClientVersions.V_1_9);
|
||||
private final double maxHorizontalDisplacement = 0.3001 + (hasLegacyExpansion ? 0.1 : 0);
|
||||
private final double minVerticalDisplacement = -0.0001 - (hasLegacyExpansion ? 0.1 : 0);
|
||||
private final double maxVerticalDisplacement = 1.8001 + (hasLegacyExpansion ? 0.1 : 0);
|
||||
|
||||
public BadPacketsT(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(final PacketReceiveEvent event) {
|
||||
if (event.getPacketType().equals(PacketType.Play.Client.INTERACT_ENTITY)) {
|
||||
final WrapperPlayClientInteractEntity wrapper = new WrapperPlayClientInteractEntity(event);
|
||||
if (event.getPacketType().equals(PacketTypes.Play.Client.INTERACT_ENTITY)) {
|
||||
final ClientInteractEntityPacket wrapper = packetFactory.clientInteractEntity(event);
|
||||
// Only INTERACT_AT actually has an interaction vector
|
||||
wrapper.getTarget().ifPresent(targetVector -> {
|
||||
final PacketEntity packetEntity = player.compensatedEntities.getEntity(wrapper.getEntityId());
|
||||
@@ -39,7 +39,7 @@ public class BadPacketsT extends Check implements PacketCheck {
|
||||
}
|
||||
|
||||
// Make sure our target entity is actually a player (Player NPCs work too)
|
||||
if (!EntityTypes.PLAYER.equals(packetEntity.getType())) {
|
||||
if (!PacketEntityTypes.PLAYER.equals(packetEntity.getType())) {
|
||||
// We can't check for any entity that is not a player
|
||||
return;
|
||||
}
|
||||
@@ -49,16 +49,16 @@ public class BadPacketsT extends Check implements PacketCheck {
|
||||
// 27/12/2023 - Dynamic values for more than just one entity type?
|
||||
// 28/12/2023 - Player-only is fine
|
||||
// 30/12/2023 - Expansions differ in 1.9+
|
||||
final float scale = (float) packetEntity.getAttributeValue(Attributes.GENERIC_SCALE);
|
||||
if (targetVector.y > (minVerticalDisplacement * scale) && targetVector.y < (maxVerticalDisplacement * scale)
|
||||
&& Math.abs(targetVector.x) < (maxHorizontalDisplacement * scale)
|
||||
&& Math.abs(targetVector.z) < (maxHorizontalDisplacement * scale)) {
|
||||
final float scale = (float) packetEntity.getAttributeValue(Attributes.SCALE);
|
||||
if (targetVector.getY() > (minVerticalDisplacement * scale) && targetVector.getY() < (maxVerticalDisplacement * scale)
|
||||
&& Math.abs(targetVector.getX()) < (maxHorizontalDisplacement * scale)
|
||||
&& Math.abs(targetVector.getZ()) < (maxHorizontalDisplacement * scale)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Log the vector
|
||||
final String verbose = String.format("%.5f/%.5f/%.5f",
|
||||
targetVector.x, targetVector.y, targetVector.z);
|
||||
targetVector.getX(), targetVector.getY(), targetVector.getZ());
|
||||
// We could pretty much ban the player at this point
|
||||
flagAndAlert(verbose);
|
||||
});
|
||||
+25
-26
@@ -1,21 +1,20 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.item.PacketItemStack;
|
||||
import ac.grim.grimac.api.packet.item.PacketItemTypes;
|
||||
import ac.grim.grimac.api.packet.protocol.PacketClientVersions;
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientPlayerBlockPlacementPacket;
|
||||
import ac.grim.grimac.api.packet.util.vec.ImmutableVector3f;
|
||||
import ac.grim.grimac.api.packet.world.enums.BlockFace;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.util.Vector3f;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerBlockPlacement;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.util.vec.ImmutableVector3i;
|
||||
|
||||
@CheckData(name = "BadPacketsU", experimental = true)
|
||||
@CheckData(name = "BadPacketsU", description = "Sent impossible use item packet")
|
||||
public class BadPacketsU extends Check implements PacketCheck {
|
||||
public BadPacketsU(GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -23,34 +22,34 @@ public class BadPacketsU extends Check implements PacketCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(final PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT) {
|
||||
final WrapperPlayClientPlayerBlockPlacement packet = new WrapperPlayClientPlayerBlockPlacement(event);
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.PLAYER_BLOCK_PLACEMENT) {
|
||||
final ClientPlayerBlockPlacementPacket packet = packetFactory.clientPlayerBlockPlacement(event);
|
||||
// BlockFace.OTHER is USE_ITEM for pre 1.9
|
||||
if (packet.getFace() == BlockFace.OTHER) {
|
||||
|
||||
// This packet is always sent at (-1, -1, -1) at (0, 0, 0) on the block
|
||||
// except y gets wrapped?
|
||||
final int expectedY = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) ? 4095 : 255;
|
||||
final int expectedY = player.getClientVersion().isNewerThanOrEquals(PacketClientVersions.V_1_8) ? 4095 : 255;
|
||||
|
||||
final boolean failedItemCheck = packet.getItemStack().isPresent() && isEmpty(packet.getItemStack().get())
|
||||
// ViaVersion can sometimes cause this part of the check to false
|
||||
&& player.getClientVersion().isOlderThan(ClientVersion.V_1_9);
|
||||
&& player.getClientVersion().isOlderThan(PacketClientVersions.V_1_9);
|
||||
|
||||
final Vector3i pos = packet.getBlockPosition();
|
||||
final Vector3f cursor = packet.getCursorPosition();
|
||||
final ImmutableVector3i pos = packet.getBlockPosition();
|
||||
final ImmutableVector3f cursor = packet.getCursorPosition();
|
||||
|
||||
if (failedItemCheck
|
||||
|| pos.x != -1
|
||||
|| pos.y != expectedY
|
||||
|| pos.z != -1
|
||||
|| cursor.x != 0
|
||||
|| cursor.y != 0
|
||||
|| cursor.z != 0
|
||||
|| pos.getX() != -1
|
||||
|| pos.getY() != expectedY
|
||||
|| pos.getZ() != -1
|
||||
|| cursor.getX() != 0
|
||||
|| cursor.getY() != 0
|
||||
|| cursor.getZ() != 0
|
||||
|| packet.getSequence() != 0
|
||||
) {
|
||||
final String verbose = String.format(
|
||||
"xyz=%s, %s, %s, cursor=%s, %s, %s, item=%s, sequence=%s",
|
||||
pos.x, pos.y, pos.z, cursor.x, cursor.y, cursor.z, !failedItemCheck, packet.getSequence()
|
||||
pos.getX(), pos.getY(), pos.getZ(), cursor.getX(), cursor.getY(), cursor.getZ(), !failedItemCheck, packet.getSequence()
|
||||
);
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets()) {
|
||||
player.onPacketCancel();
|
||||
@@ -61,7 +60,7 @@ public class BadPacketsU extends Check implements PacketCheck {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEmpty(ItemStack itemStack) {
|
||||
return itemStack.getType() == null || itemStack.getType() == ItemTypes.AIR;
|
||||
private boolean isEmpty(PacketItemStack itemStack) {
|
||||
return itemStack.getType() == null || itemStack.getType() == PacketItemTypes.AIR;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.MCPacket;
|
||||
import ac.grim.grimac.api.packet.protocol.PacketClientVersions;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.types.client.play.ClientPlayerFlyingMetaPacket;
|
||||
|
||||
@CheckData(name = "BadPacketsV", description = "Did not move far enough", experimental = true)
|
||||
public class BadPacketsV extends Check implements PacketCheck {
|
||||
private int noReminderTicks;
|
||||
|
||||
public BadPacketsV(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (!player.canSkipTicks() && isTickPacket(event.getPacketType())) {
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.PLAYER_POSITION || event.getPacketType() == PacketTypes.Play.Client.PLAYER_POSITION_AND_ROTATION) {
|
||||
int positionAtLeastEveryNTicks = player.getClientVersion().isOlderThanOrEquals(PacketClientVersions.V_1_8) ? 20 : 19;
|
||||
|
||||
if (noReminderTicks < positionAtLeastEveryNTicks && !player.uncertaintyHandler.lastTeleportTicks.hasOccurredSince(1)) {
|
||||
final double deltaSq = ClientPlayerFlyingMetaPacket.from(event).getLocation().getPosition()
|
||||
.distanceSquared(MCPacket.getAPI().getVectorFactory().getImmutableVec3d(player.lastX, player.lastY, player.lastZ));
|
||||
if (deltaSq <= player.getMovementThreshold() * player.getMovementThreshold()) {
|
||||
flagAndAlert("delta=" + Math.sqrt(deltaSq));
|
||||
}
|
||||
}
|
||||
|
||||
noReminderTicks = 0;
|
||||
} else {
|
||||
noReminderTicks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@ import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
|
||||
@CheckData(name = "BadPacketsW", experimental = true)
|
||||
@CheckData(name = "BadPacketsW", description = "Interacted with non-existent entity", experimental = true)
|
||||
public class BadPacketsW extends Check implements PacketCheck {
|
||||
public BadPacketsW(GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -0,0 +1,76 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PostPredictionCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.player.enums.GameMode;
|
||||
|
||||
@CheckData(name = "BadPacketsX", experimental = true)
|
||||
public class BadPacketsX extends Check implements PostPredictionCheck {
|
||||
private boolean sprint;
|
||||
private boolean sneak;
|
||||
private int flags;
|
||||
|
||||
public BadPacketsX(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(final PredictionComplete predictionComplete) {
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flags > 0) {
|
||||
setbackIfAboveSetbackVL();
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; flags > 0; flags--) {
|
||||
flagAndAlertWithSetback();
|
||||
}
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.gamemode == GameMode.SPECTATOR || isTickPacket(event.getPacketType())) {
|
||||
sprint = sneak = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.ENTITY_ACTION) {
|
||||
switch (packetFactory.clientEntityAction(event).getAction()) {
|
||||
case START_SNEAKING, STOP_SNEAKING -> {
|
||||
if (sneak) {
|
||||
if (player.canSkipTicks() || flagAndAlert()) {
|
||||
flags++;
|
||||
}
|
||||
}
|
||||
|
||||
sneak = true;
|
||||
}
|
||||
case START_SPRINTING, STOP_SPRINTING -> {
|
||||
if (player.inVehicle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sprint) {
|
||||
if (player.canSkipTicks() || flagAndAlert()) {
|
||||
flags++;
|
||||
}
|
||||
}
|
||||
|
||||
sprint = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-10
@@ -1,17 +1,13 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientHeldItemChange;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
|
||||
/**
|
||||
* Checks for out of bounds slot changes
|
||||
*/
|
||||
@CheckData(name = "BadPacketsY")
|
||||
@CheckData(name = "BadPacketsY", description = "Sent out of bounds slot id")
|
||||
public class BadPacketsY extends Check implements PacketCheck {
|
||||
public BadPacketsY(GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -19,10 +15,10 @@ public class BadPacketsY extends Check implements PacketCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.HELD_ITEM_CHANGE) {
|
||||
final int slot = new WrapperPlayClientHeldItemChange(event).getSlot();
|
||||
if (event.getPacketType() == PacketTypes.Play.Client.HELD_ITEM_CHANGE) {
|
||||
final int slot = packetFactory.clientHeldItemChange(event).getSlot();
|
||||
if (slot > 8 || slot < 0) { // ban
|
||||
if (flagAndAlert("slot="+slot) && shouldModifyPackets()) {
|
||||
if (flagAndAlert("slot=" + slot) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
+2
-2
@@ -12,12 +12,12 @@ import ac.grim.grimac.utils.math.GrimMath;
|
||||
// This check has been patched by Baritone for a long time and it also seems to false with cinematic camera now, so it is disabled.
|
||||
@CheckData(name = "Baritone")
|
||||
public class Baritone extends Check implements RotationCheck {
|
||||
private int verbose;
|
||||
|
||||
public Baritone(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
private int verbose;
|
||||
|
||||
@Override
|
||||
public void process(final RotationUpdate rotationUpdate) {
|
||||
final HeadRotation from = rotationUpdate.getFrom();
|
||||
@@ -0,0 +1,72 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.packet.MCPacket;
|
||||
import ac.grim.grimac.api.packet.item.PacketItemTypes;
|
||||
import ac.grim.grimac.api.packet.item.PacketStateType;
|
||||
import ac.grim.grimac.api.packet.protocol.PacketClientVersions;
|
||||
import ac.grim.grimac.api.packet.util.vec.ImmutableVector3i;
|
||||
import ac.grim.grimac.api.packet.world.PacketStateTypes;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.BlockBreakCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
|
||||
import ac.grim.grimac.api.packet.player.enums.DiggingAction;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
@CheckData(name = "AirLiquidBreak", description = "Breaking a block that cannot be broken")
|
||||
public class AirLiquidBreak extends Check implements BlockBreakCheck {
|
||||
public final boolean noFireHitbox = player.getClientVersion().isOlderThanOrEquals(PacketClientVersions.V_1_15_2);
|
||||
private int lastTick;
|
||||
private boolean didLastFlag;
|
||||
// Initialize to non-null values to prevent NPE when checking for blockType properties and if position equals old position
|
||||
private @NonNull ImmutableVector3i lastBreakLoc = MCPacket.getAPI().getVectorFactory().getImmutableVec3i();
|
||||
private @NonNull PacketStateType lastBlockType = PacketStateTypes.AIR;
|
||||
|
||||
public AirLiquidBreak(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.action != DiggingAction.START_DIGGING && blockBreak.action != DiggingAction.FINISHED_DIGGING)
|
||||
return;
|
||||
|
||||
final PacketStateType block = blockBreak.block.getType();
|
||||
|
||||
// Fixes false from breaking kelp underwater
|
||||
// The client sends two start digging packets to the server both in the same tick. AirLiquidBreak gets called twice, doesn't false the first time, but falses the second
|
||||
// One ends up breaking the kelp, the other ends up doing nothing besides falsing this check because we think they're trying to mine water
|
||||
// I am explicitly making this patch as narrow and specific as possible to potentially discover other blocks that exhibit similar behaviour
|
||||
int newTick = GrimAPI.INSTANCE.getTickManager().currentTick;
|
||||
if (lastTick == newTick
|
||||
&& lastBreakLoc.equals(blockBreak.position)
|
||||
&& !didLastFlag
|
||||
&& lastBlockType.getHardness() == 0.0F
|
||||
&& lastBlockType.getBlastResistance() == 0.0F
|
||||
&& block == PacketStateTypes.WATER
|
||||
) return;
|
||||
lastTick = newTick;
|
||||
lastBreakLoc = blockBreak.position;
|
||||
lastBlockType = block;
|
||||
|
||||
// the block does not have a hitbox
|
||||
boolean invalid = (block == PacketStateTypes.LIGHT && !(player.getInventory().getHeldItem() == PacketItemTypes.LIGHT || player.getInventory().getOffHand() == PacketItemTypes.LIGHT))
|
||||
|| block.isAir()
|
||||
|| block == PacketStateTypes.WATER
|
||||
|| block == PacketStateTypes.LAVA
|
||||
|| block == PacketStateTypes.BUBBLE_COLUMN
|
||||
|| block == PacketStateTypes.MOVING_PISTON
|
||||
|| block == PacketStateTypes.FIRE && noFireHitbox
|
||||
// or the client claims to have broken an unbreakable block
|
||||
|| block.getHardness() == -1.0f && blockBreak.action == DiggingAction.FINISHED_DIGGING;
|
||||
|
||||
if (invalid && flagAndAlert("block=" + block.getName() + ", type=" + blockBreak.action) && shouldModifyPackets()) {
|
||||
didLastFlag = true;
|
||||
blockBreak.cancel();
|
||||
} else {
|
||||
didLastFlag = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
import ac.grim.grimac.api.packet.player.enums.GameMode;
|
||||
import ac.grim.grimac.api.packet.protocol.attribute.Attributes;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.BlockBreakCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.api.math.Vector3dm;
|
||||
import ac.grim.grimac.utils.math.VectorUtils;
|
||||
import ac.grim.grimac.api.packet.player.enums.DiggingAction;
|
||||
|
||||
@CheckData(name = "FarBreak", description = "Breaking blocks too far away", experimental = true)
|
||||
public class FarBreak extends Check implements BlockBreakCheck {
|
||||
public FarBreak(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (player.gamemode == GameMode.SPECTATOR || player.inVehicle() || blockBreak.action == DiggingAction.CANCELLED_DIGGING)
|
||||
return; // falses
|
||||
|
||||
double min = Double.MAX_VALUE;
|
||||
for (double d : player.getPossibleEyeHeights()) {
|
||||
SimpleCollisionBox box = new SimpleCollisionBox(blockBreak.position);
|
||||
Vector3dm eyes = new Vector3dm(player.x, player.y + d, player.z);
|
||||
Vector3dm best = VectorUtils.cutBoxToVector(eyes, box);
|
||||
min = Math.min(min, eyes.distanceSquared(best));
|
||||
}
|
||||
|
||||
// getPickRange() determines this?
|
||||
// With 1.20.5+ the new attribute determines creative mode reach using a modifier
|
||||
double maxReach = player.compensatedEntities.self.getAttributeValue(Attributes.BLOCK_INTERACTION_RANGE);
|
||||
if (player.packetStateData.didLastMovementIncludePosition || player.canSkipTicks()) {
|
||||
double threshold = player.getMovementThreshold();
|
||||
maxReach += Math.hypot(threshold, threshold);
|
||||
}
|
||||
|
||||
if (min > maxReach * maxReach && flagAndAlert(String.format("distance=%.2f", Math.sqrt(min))) && shouldModifyPackets()) {
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
import ac.grim.grimac.api.packet.block.PacketBlockState;
|
||||
import ac.grim.grimac.api.packet.item.PacketStateType;
|
||||
import ac.grim.grimac.api.packet.player.enums.DiggingAction;
|
||||
import ac.grim.grimac.api.packet.protocol.PacketClientVersions;
|
||||
import ac.grim.grimac.api.packet.protocol.version.server.ServerVersions;
|
||||
import ac.grim.grimac.api.packet.types.event.PacketReceiveEvent;
|
||||
import ac.grim.grimac.api.packet.util.vec.ImmutableVector3i;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.BlockBreakCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
|
||||
import ac.grim.grimac.utils.math.GrimMath;
|
||||
import ac.grim.grimac.utils.nmsutil.BlockBreakSpeed;
|
||||
import ac.grim.grimac.utils.reflection.ViaVersionUtil;
|
||||
import ac.grim.grimac.api.packet.types.PacketTypes;
|
||||
import ac.grim.grimac.api.packet.world.PacketStateTypes;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
// Based loosely off of Hawk BlockBreakSpeedSurvival
|
||||
// Also based loosely off of NoCheatPlus FastBreak
|
||||
// Also based off minecraft wiki: https://minecraft.wiki/w/Breaking#Instant_breaking
|
||||
@CheckData(name = "FastBreak", description = "Breaking blocks too quickly")
|
||||
public class FastBreak extends Check implements BlockBreakCheck {
|
||||
|
||||
// For some reason these states flag and I don't know why.
|
||||
// Better to just exempt to not annoy legit players.
|
||||
private static final Set<PacketStateType> EXEMPT_STATES = Set.of();
|
||||
private final boolean clientOlderThanServer = ServerVersions.getServerVersion().getProtocolVersion() > player.getClientVersion().getProtocolVersion();
|
||||
|
||||
public FastBreak(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
// The block the player is currently breaking
|
||||
ImmutableVector3i targetBlockPosition = null;
|
||||
// The maximum amount of damage the player deals to the block
|
||||
//
|
||||
double maximumBlockDamage = 0;
|
||||
// The last time a finish digging packet was sent, to enforce 0.3-second delay after non-instabreak
|
||||
long lastFinishBreak = 0;
|
||||
// The time the player started to break the block, to know how long the player waited until they finished breaking the block
|
||||
long startBreak = 0;
|
||||
|
||||
// The buffer to this check
|
||||
double blockBreakBalance = 0;
|
||||
double blockDelayBalance = 0;
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.action == DiggingAction.START_DIGGING) {
|
||||
if (!ViaVersionUtil.isAvailable()) {
|
||||
// Exempt all blocks that do not exist in the player version
|
||||
final PacketBlockState defaultState = PacketBlockState.getDefaultState(player.getClientVersion(), blockBreak.block.getType());
|
||||
if (defaultState.getType() == PacketStateTypes.AIR || EXEMPT_STATES.contains(defaultState.getType())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If client is older than the server, fetch block client actually sees from via
|
||||
// otherwise just return the server-side block (since if client is >= server version the block is guaranteed to exist in client version)
|
||||
// TODO this lazy loads PacketEvents mappings for older versions for clients on versions older than the servers, increasing memory usage
|
||||
// * its the only thing we use non-native mappings for behind ViaVersion
|
||||
// * can we translate back "up" to server version and run check against server version to avoid loading older registries?
|
||||
PacketBlockState block = clientOlderThanServer ? PacketBlockState.getByGlobalId(player.getClientVersion(), player.getViaTranslatedClientBlockID(blockBreak.block.getGlobalId())) : blockBreak.block;
|
||||
|
||||
startBreak = System.currentTimeMillis() - (targetBlockPosition == null ? 50 : 0); // ???
|
||||
targetBlockPosition = blockBreak.position;
|
||||
|
||||
maximumBlockDamage = BlockBreakSpeed.getBlockDamage(player, block);
|
||||
|
||||
double breakDelay = System.currentTimeMillis() - lastFinishBreak;
|
||||
|
||||
if (breakDelay >= 275) { // Reduce buffer if "close enough"
|
||||
blockDelayBalance *= 0.9;
|
||||
} else { // Otherwise, increase buffer
|
||||
blockDelayBalance += 300 - breakDelay;
|
||||
}
|
||||
|
||||
if (blockDelayBalance > 1000) { // If more than a second of advantage
|
||||
if (flagAndAlert("delay=" + breakDelay + "ms, type=" + blockBreak.block.getType()) && shouldModifyPackets()) {
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
clampBalance();
|
||||
}
|
||||
|
||||
if (blockBreak.action == DiggingAction.FINISHED_DIGGING && targetBlockPosition != null) {
|
||||
double predictedTime = Math.ceil(1 / maximumBlockDamage) * 50;
|
||||
double realTime = System.currentTimeMillis() - startBreak;
|
||||
double diff = predictedTime - realTime;
|
||||
|
||||
clampBalance();
|
||||
|
||||
if (diff < 25) { // Reduce buffer if "close enough"
|
||||
blockBreakBalance *= 0.9;
|
||||
} else { // Otherwise, increase buffer
|
||||
blockBreakBalance += diff;
|
||||
}
|
||||
|
||||
if (blockBreakBalance > 1000) { // If more than a second of advantage
|
||||
if (flagAndAlert("diff=" + diff + "ms, balance=" + blockBreakBalance + "ms, type=" + blockBreak.block.getType()) && shouldModifyPackets()) {
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
// also set start time because the breaking netcode is fucked on 1.14.4+
|
||||
lastFinishBreak = startBreak = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
// Find the most optimal block damage using the animation packet, which is sent at least once a tick when breaking blocks
|
||||
// On 1.8 clients, via screws with this packet meaning we must fall back to the 1.8 idle flying packet
|
||||
if ((player.getClientVersion().isNewerThanOrEquals(PacketClientVersions.V_1_9) ? event.getPacketType() == PacketTypes.Play.Client.ANIMATION : isFlying(event.getPacketType())) && targetBlockPosition != null) {
|
||||
maximumBlockDamage = Math.max(maximumBlockDamage, BlockBreakSpeed.getBlockDamage(player, player.compensatedWorld.getBlock(targetBlockPosition)));
|
||||
}
|
||||
}
|
||||
|
||||
private void clampBalance() {
|
||||
double balance = Math.max(1000, (player.getTransactionPing()));
|
||||
blockBreakBalance = GrimMath.clamp(blockBreakBalance, -balance, balance); // Clamp not Math.max in case other logic changes
|
||||
blockDelayBalance = GrimMath.clamp(blockDelayBalance, -balance, balance);
|
||||
}
|
||||
}
|
||||
Loaded 100 of 732 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user