Compare commits
1086
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17f01fb067 | ||
|
|
52f3c6a998 | ||
|
|
45766c5265 | ||
|
|
4d8f6b5f50 | ||
|
|
8acf512c80 | ||
|
|
deff13deb6 | ||
|
|
32c75c78b0 | ||
|
|
b71c11882a | ||
|
|
990efdd6d2 | ||
|
|
3c89193fff | ||
|
|
aff9dc3c25 | ||
|
|
6b17d5fd0e | ||
|
|
319dca27ae | ||
|
|
5d20372645 | ||
|
|
74108a2088 | ||
|
|
aab710dd8b | ||
|
|
39a034d92c | ||
|
|
4a65251817 | ||
|
|
80b196cac0 | ||
|
|
1fb1a73060 | ||
|
|
6811bc71fc | ||
|
|
6205a23edd | ||
|
|
2f844bc56e | ||
|
|
5ca4082675 | ||
|
|
078bc139f7 | ||
|
|
37d07d3b03 | ||
|
|
5bccfe831d | ||
|
|
42576f10ce | ||
|
|
328e031c1b | ||
|
|
0bc781f390 | ||
|
|
3fbaa0a0e6 | ||
|
|
931d26569c | ||
|
|
b207fe233e | ||
|
|
0cc0910455 | ||
|
|
b5acee4911 | ||
|
|
ccada109b1 | ||
|
|
16c0d37b54 | ||
|
|
f6c16ea567 | ||
|
|
b9934f5130 | ||
|
|
3c48b6edab | ||
|
|
fdf8bc26a5 | ||
|
|
900cbed5fa | ||
|
|
ab6920c300 | ||
|
|
c7f4bd15d2 | ||
|
|
233cd2a7d7 | ||
|
|
0c8b60018a | ||
|
|
a54787152d | ||
|
|
2932f0a40c | ||
|
|
94d47391af | ||
|
|
9964478ce1 | ||
|
|
d3667e1add | ||
|
|
9af7a7267e | ||
|
|
04e1459d9e | ||
|
|
3ff9e774cd | ||
|
|
36e5eb9304 | ||
|
|
e99855bdc5 | ||
|
|
b7c9deef83 | ||
|
|
0d2940c34a | ||
|
|
a793912337 | ||
|
|
d1194223ab | ||
|
|
0624b117b5 | ||
|
|
028a526c51 | ||
|
|
9650cdb4f2 | ||
|
|
5326845c7a | ||
|
|
7fed456871 | ||
|
|
5f4ec6a1a7 | ||
|
|
3c400f1eeb | ||
|
|
f6dba5ee8e | ||
|
|
8b3cbab3ad | ||
|
|
c0e6ae7ec6 | ||
|
|
6a5772b26b | ||
|
|
71d6d9e33f | ||
|
|
0508bd98ba | ||
|
|
5b9efc0ea5 | ||
|
|
a3812b2546 | ||
|
|
05fb233f0e | ||
|
|
e15277d58d | ||
|
|
177ae4cbfa | ||
|
|
c1db1479b6 | ||
|
|
7646df0563 | ||
|
|
23369cf1d6 | ||
|
|
86f89c010d | ||
|
|
5de92f28de | ||
|
|
864e9de3e8 | ||
|
|
68b4fa7805 | ||
|
|
c7e1fda7bb | ||
|
|
6c42bdcd4e | ||
|
|
96ab0c3bdf | ||
|
|
a4a1397b87 | ||
|
|
4b5cf2a9a1 | ||
|
|
fa86c87693 | ||
|
|
439cbc6db3 | ||
|
|
652b66202d | ||
|
|
9f031e638a | ||
|
|
45da02e7c0 | ||
|
|
68a04d05f8 | ||
|
|
e329171b11 | ||
|
|
b8121543ee | ||
|
|
70cf56fad6 | ||
|
|
6b639048b9 | ||
|
|
5413484c2a | ||
|
|
6d6b27dfe2 | ||
|
|
f88a114e0e | ||
|
|
fde5efa31f | ||
|
|
cccc0194d6 | ||
|
|
d8e7bc8f3e | ||
|
|
dd37d3407b | ||
|
|
c0c19d1a2d | ||
|
|
ff888f8c73 | ||
|
|
66a250eb9e | ||
|
|
3c56ba9880 | ||
|
|
514a48e508 | ||
|
|
32b66cb4ff | ||
|
|
057de4d4e2 | ||
|
|
081e2d3b2b | ||
|
|
856a51e574 | ||
|
|
a4786a16c0 | ||
|
|
c904f14c7b | ||
|
|
59eb669c17 | ||
|
|
86cb4af960 | ||
|
|
056b9f0486 | ||
|
|
afe483c0ad | ||
|
|
5d4c8f6f85 | ||
|
|
896cf12b71 | ||
|
|
1506c97ffc | ||
|
|
a08963e1dc | ||
|
|
50a2b3af95 | ||
|
|
9107586fc1 | ||
|
|
bc96460eb3 | ||
|
|
94705fcd09 | ||
|
|
01cd47a6b6 | ||
|
|
7ae935f5e3 | ||
|
|
6d06b9b559 | ||
|
|
7494b995bc | ||
|
|
bae421ff27 | ||
|
|
f81743e07f | ||
|
|
b0e4693f2b | ||
|
|
e569483f63 | ||
|
|
164d16dce9 | ||
|
|
a504b8f595 | ||
|
|
e4ef877188 | ||
|
|
efa8b750e7 | ||
|
|
21d21d2509 | ||
|
|
44011acca2 | ||
|
|
0a9ea97aa6 | ||
|
|
91e281514b | ||
|
|
a03c8bbdbd | ||
|
|
22074dc228 | ||
|
|
3a40ba8b29 | ||
|
|
71791a1020 | ||
|
|
665a43bd4c | ||
|
|
5ce81e0fe4 | ||
|
|
29b6e12cb8 | ||
|
|
014c5f7670 | ||
|
|
0d84b4e958 | ||
|
|
098399f754 | ||
|
|
334a356446 | ||
|
|
acac69e750 | ||
|
|
f8aa54855d | ||
|
|
7d928d581f | ||
|
|
9c9316e224 | ||
|
|
31394f472f | ||
|
|
f721b1850c | ||
|
|
4419646f11 | ||
|
|
9e296cbf5a | ||
|
|
40bbd2eb2e | ||
|
|
0af47a1266 | ||
|
|
6cfe71da9b | ||
|
|
393357d9f6 | ||
|
|
dcf0c73005 | ||
|
|
856ec6c655 | ||
|
|
54a10f77db | ||
|
|
0f50bde4db | ||
|
|
d7368ceba6 | ||
|
|
1e8fc587af | ||
|
|
8e6219c597 | ||
|
|
9aa555ff78 | ||
|
|
21c0833769 | ||
|
|
450642d888 | ||
|
|
75bcac7a49 | ||
|
|
111cc7aafd | ||
|
|
924dcf9014 | ||
|
|
63aa1ed632 | ||
|
|
eda4dc7236 | ||
|
|
85e1e20e41 | ||
|
|
b6a79b74b6 | ||
|
|
783240c06f | ||
|
|
fbcad3e605 | ||
|
|
10c1a1350c | ||
|
|
69875008c3 | ||
|
|
e39eb89f59 | ||
|
|
71015ec3c7 | ||
|
|
09b8071f5b | ||
|
|
e011b2dbbd | ||
|
|
7208842b0c | ||
|
|
2830856812 | ||
|
|
50f9b6ecbd | ||
|
|
4fa3ef68e2 | ||
|
|
f477ba4c62 | ||
|
|
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 | ||
|
|
4ac58782ac | ||
|
|
2f6242027b | ||
|
|
d8c0aef8cc | ||
|
|
c1225cb920 | ||
|
|
17927c11bf | ||
|
|
66f6bd72d0 | ||
|
|
6816df7a93 | ||
|
|
7e0699d1bb | ||
|
|
3f1b4d8472 | ||
|
|
1ce5a530ff | ||
|
|
61e506437b | ||
|
|
a23e1a10f4 | ||
|
|
d1f6a47519 | ||
|
|
4cb6de2cb1 | ||
|
|
000758e7f1 | ||
|
|
57157d068e | ||
|
|
368db15026 | ||
|
|
a0b1d290b5 | ||
|
|
e75b987a6e | ||
|
|
7955563931 | ||
|
|
cd9e22aad4 | ||
|
|
cf66554afe | ||
|
|
0adc332d14 | ||
|
|
a179f3e625 | ||
|
|
fe96f848ad | ||
|
|
37b12ac56b | ||
|
|
6846e2d6a3 | ||
|
|
5da77e2aa5 | ||
|
|
7ac3d4104f | ||
|
|
1c1f1d7031 | ||
|
|
47a26f86dc | ||
|
|
9e054c2b6c | ||
|
|
cda6af1f34 | ||
|
|
237f3744d4 | ||
|
|
c685c47d16 | ||
|
|
b968bd98f3 | ||
|
|
5902fec4a8 | ||
|
|
2171a57757 | ||
|
|
882990fe84 | ||
|
|
99b309a0b3 | ||
|
|
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 | ||
|
|
ad68a43b83 | ||
|
|
e7abaf8523 | ||
|
|
a508002c48 | ||
|
|
259696710f | ||
|
|
069c503bda | ||
|
|
b7c8ca1683 | ||
|
|
a47a34e9f9 | ||
|
|
27f4f34b16 | ||
|
|
4eb5ad4e87 | ||
|
|
d388d3f5db | ||
|
|
46e616107e | ||
|
|
744be32389 | ||
|
|
dcb72a9efd | ||
|
|
8c97274929 | ||
|
|
b939ba5921 | ||
|
|
786611aeec | ||
|
|
44eba3b446 | ||
|
|
0f11cb74b8 | ||
|
|
1cff3e526f | ||
|
|
a09093ee5b | ||
|
|
c1db9edd7d | ||
|
|
9ac2b4fbb6 | ||
|
|
0b9ba69afc | ||
|
|
b326c7b961 | ||
|
|
f1243073f2 | ||
|
|
4e4f23479a | ||
|
|
c7a4eeec94 | ||
|
|
d1a2dbf6aa | ||
|
|
c67258ac13 | ||
|
|
ca7da355f7 | ||
|
|
2a452c7d85 | ||
|
|
66776e8163 | ||
|
|
3089036d43 | ||
|
|
447ce3466d | ||
|
|
244113714e | ||
|
|
ae1c47d21f | ||
|
|
241525c2c2 | ||
|
|
d2b529aceb | ||
|
|
89f0aefe22 | ||
|
|
8d8499d6fc | ||
|
|
3bd1673e67 | ||
|
|
2ee47a23ea | ||
|
|
734d227175 | ||
|
|
1377747bec | ||
|
|
210a9266a4 | ||
|
|
616c46d97e | ||
|
|
aa69b6f69f | ||
|
|
fae66e9039 | ||
|
|
fb05fcb1fa | ||
|
|
acdcfe8f71 | ||
|
|
e3f5db6f19 | ||
|
|
be48c35eda | ||
|
|
2ea1d29da5 | ||
|
|
c49e531853 | ||
|
|
2eebcfd056 | ||
|
|
f1988e66be | ||
|
|
d7474db60d | ||
|
|
97b3781f49 | ||
|
|
a99e0e4947 | ||
|
|
ec88893d52 | ||
|
|
c1670a7f4e | ||
|
|
a630dbe028 | ||
|
|
3e42fe9d5e | ||
|
|
06fad2ecaf | ||
|
|
3e185b6e1e | ||
|
|
3ddc1e846a | ||
|
|
d714211fe6 | ||
|
|
71d524aad0 | ||
|
|
9bf8eed3d1 | ||
|
|
74c8c5ff01 | ||
|
|
935b26ca0c | ||
|
|
5e2f889550 | ||
|
|
af6c859b16 | ||
|
|
d138d0d602 | ||
|
|
70d0fa96c2 | ||
|
|
133e7dc490 | ||
|
|
4cb0a46797 | ||
|
|
4298031d3f | ||
|
|
f4c43735f7 | ||
|
|
61f90fe721 | ||
|
|
431200c855 | ||
|
|
481a115ba1 | ||
|
|
b0f6e49109 | ||
|
|
122ad4a93c | ||
|
|
464e61b6b0 | ||
|
|
1405faa391 | ||
|
|
b003ec799b | ||
|
|
11037cdc85 | ||
|
|
fffae61f8a | ||
|
|
6a56b9bbf0 | ||
|
|
4c13a0adec | ||
|
|
0932b7062d | ||
|
|
7f61d19f55 | ||
|
|
1f93dff26c | ||
|
|
002b027e2b | ||
|
|
31396cdd73 | ||
|
|
2a5b25e927 | ||
|
|
ceb6e7932b | ||
|
|
82a755d739 | ||
|
|
597e3ba820 | ||
|
|
20234319e6 | ||
|
|
631217a7f4 | ||
|
|
8b76fd36d7 | ||
|
|
6ca375ff61 | ||
|
|
1836b14d5d | ||
|
|
618b6aca24 | ||
|
|
4a45918971 | ||
|
|
f8af107a1a | ||
|
|
94491d293b | ||
|
|
49debf6cd0 | ||
|
|
c87ae3af8b | ||
|
|
423f2d0711 | ||
|
|
9a0ec5d010 | ||
|
|
60ed674228 | ||
|
|
8bec79abc6 | ||
|
|
0ee4b2551f | ||
|
|
ad3cbd739a | ||
|
|
d9718b308f | ||
|
|
b880f51fbc | ||
|
|
2a86ff4e5f | ||
|
|
3d3a17eea9 | ||
|
|
ac2607d6cd | ||
|
|
4b03892c86 | ||
|
|
b4820b5f19 | ||
|
|
79c70572a8 | ||
|
|
ced56218d9 | ||
|
|
6243fdf605 | ||
|
|
7668ddb6d6 | ||
|
|
33582cd417 | ||
|
|
2474c550cc | ||
|
|
4f8357f5a1 | ||
|
|
b40deaa620 | ||
|
|
b4ac002779 | ||
|
|
f04cadb38d | ||
|
|
79ec178845 | ||
|
|
a8da7dde72 | ||
|
|
576a67502b | ||
|
|
eb72a7c86d | ||
|
|
5d486a5707 | ||
|
|
9975d1a6bf | ||
|
|
dd74dc9737 | ||
|
|
571ae73fc5 | ||
|
|
8d2d33f1ea | ||
|
|
738cd44ab9 | ||
|
|
b800699cbf | ||
|
|
bf37add382 | ||
|
|
432a0aed02 | ||
|
|
d3c82a326a | ||
|
|
e40ba62e5a | ||
|
|
6a1a5f81ed | ||
|
|
bcc9e9be13 | ||
|
|
40918c9988 | ||
|
|
a620149a93 | ||
|
|
f493fe3005 | ||
|
|
c5dc6d4050 | ||
|
|
db8aad3c00 | ||
|
|
12cdd2f380 | ||
|
|
6c3657ae40 | ||
|
|
ffa21f6f3e | ||
|
|
7ce0e2f9ec | ||
|
|
1c3c6a8879 | ||
|
|
75aa7d8f71 | ||
|
|
33c96893d7 | ||
|
|
c3f6fd5c65 | ||
|
|
616f3076c9 | ||
|
|
0898a94104 | ||
|
|
48a371dc66 | ||
|
|
5e7fef1572 | ||
|
|
8701f12f6a | ||
|
|
cbdd5a7a14 | ||
|
|
48ba546a40 | ||
|
|
cdbe983d22 | ||
|
|
e2ad24e604 | ||
|
|
d954784e74 | ||
|
|
dd0e338588 | ||
|
|
73d591907d | ||
|
|
806a13ea25 | ||
|
|
38d64e2cff | ||
|
|
c666d98a9e | ||
|
|
c270105c09 | ||
|
|
36776a488b | ||
|
|
5d6c77851a | ||
|
|
8bb5be493d | ||
|
|
c681a12176 | ||
|
|
ea614f7336 | ||
|
|
fa985fe4fa | ||
|
|
f485b70cbf | ||
|
|
36e0974fcf | ||
|
|
a4ee272641 | ||
|
|
fd8507610b | ||
|
|
4428af4acc | ||
|
|
a4031c4862 | ||
|
|
7abb8d61b0 | ||
|
|
0b76452fbb | ||
|
|
4c21c11484 | ||
|
|
ca72cd5997 | ||
|
|
3952600032 | ||
|
|
d42bc4bec7 | ||
|
|
30a6e7c336 | ||
|
|
d82b168cd6 | ||
|
|
284effc237 | ||
|
|
e97566cd5f | ||
|
|
8c2b87f472 | ||
|
|
f3433f3011 | ||
|
|
587b317cb6 | ||
|
|
febe00e950 | ||
|
|
c7445019f9 | ||
|
|
ff1c3043b3 | ||
|
|
0b038d38e9 | ||
|
|
b0790af3e1 | ||
|
|
912939a5f4 | ||
|
|
0c8b4c2f3a | ||
|
|
42af76a9ea | ||
|
|
7d30183af3 | ||
|
|
2ac8a86d4f | ||
|
|
d598ae0057 | ||
|
|
d3fde8025a | ||
|
|
7a0f2b1227 | ||
|
|
1789912e14 | ||
|
|
6cbedf1f26 | ||
|
|
7fe146db05 | ||
|
|
227458a633 | ||
|
|
e61fb9b3e4 | ||
|
|
97abaaf8ad | ||
|
|
1f3ac2a174 | ||
|
|
ff0629d0b7 | ||
|
|
9936984534 | ||
|
|
ca56975136 | ||
|
|
348daf6a52 | ||
|
|
d67b470ff6 | ||
|
|
2c42a96c3c | ||
|
|
130f9e1023 | ||
|
|
eaac8ad908 | ||
|
|
89f8696d88 | ||
|
|
940a1f819f | ||
|
|
3f01edba9d | ||
|
|
24409a5771 | ||
|
|
88e0f98241 | ||
|
|
fde99a7cbf | ||
|
|
1c3929834a | ||
|
|
3a839d7240 | ||
|
|
7737337a86 | ||
|
|
88dc6a42a9 | ||
|
|
bcc93aab4a | ||
|
|
b88561284c | ||
|
|
5fd8230884 | ||
|
|
ca0fa88a77 | ||
|
|
cbb3c1cc0f | ||
|
|
519968b85a | ||
|
|
6314b78e47 | ||
|
|
b791897dbc | ||
|
|
61af1d1e72 | ||
|
|
bf3fc94d92 | ||
|
|
bc1ab00c3f | ||
|
|
34fde514fd | ||
|
|
26d5d9d9d2 | ||
|
|
4887415912 | ||
|
|
f755f2d670 | ||
|
|
7f0838832d | ||
|
|
336efafbd3 | ||
|
|
782f8f8a09 | ||
|
|
c1858e49d8 | ||
|
|
7dce3a7a12 | ||
|
|
3004390528 | ||
|
|
af141e35d3 | ||
|
|
3a33be168f | ||
|
|
30994d1279 | ||
|
|
9b716b5c58 | ||
|
|
714549f79c | ||
|
|
d0fcf33255 | ||
|
|
02553f332f | ||
|
|
7786da7296 | ||
|
|
1eb12bafd4 | ||
|
|
bc365176b1 | ||
|
|
7fe224c206 | ||
|
|
48e5f54341 | ||
|
|
88883caca8 | ||
|
|
5edf92f124 | ||
|
|
1c3e938f0f | ||
|
|
ec71581eae | ||
|
|
5a8e8b320a | ||
|
|
0904b61df0 | ||
|
|
c9e082257c | ||
|
|
53dd27e95d | ||
|
|
3723581dc2 | ||
|
|
7ea0d4d24c | ||
|
|
8875bbf991 | ||
|
|
e933186d2e | ||
|
|
89bec80b34 | ||
|
|
cc78eca02f | ||
|
|
77a91ec627 | ||
|
|
dff5361934 | ||
|
|
1036563b24 | ||
|
|
dd5ea74ae4 | ||
|
|
cd032a51ab | ||
|
|
aa7a4dc155 | ||
|
|
3387365732 | ||
|
|
411aa4f2b2 | ||
|
|
63a8e394a9 | ||
|
|
9804b8b62f | ||
|
|
f59279ad51 | ||
|
|
f82cce32f6 | ||
|
|
474ae7dd27 | ||
|
|
d85c1d267b | ||
|
|
6ce2bcb9e9 | ||
|
|
379fc6601d | ||
|
|
dd490aa8c2 | ||
|
|
48eff610c3 | ||
|
|
677dd044ff | ||
|
|
87f30eea37 | ||
|
|
370da407ce | ||
|
|
43e4c29f2c | ||
|
|
7924107b00 | ||
|
|
42094cbddc | ||
|
|
d0562de1e1 | ||
|
|
d85979d3ab | ||
|
|
3809aed146 | ||
|
|
06210f03ba | ||
|
|
97afbd8d77 | ||
|
|
df89d15aa6 | ||
|
|
12864dccc5 | ||
|
|
4c9b07612d | ||
|
|
026c2417c9 | ||
|
|
1ef4b4eec9 | ||
|
|
954eb8b51c | ||
|
|
84ceaa29dc | ||
|
|
6974d61b9d | ||
|
|
d9a3a890c8 | ||
|
|
c4495d995a | ||
|
|
9621add16e | ||
|
|
9bd5c2db0b | ||
|
|
2518b23f8b | ||
|
|
7bd3af3eca | ||
|
|
dd9d14e195 | ||
|
|
bd2ceeeed4 | ||
|
|
8d01e90f11 | ||
|
|
a6d082b355 | ||
|
|
8af0dbc46d | ||
|
|
3fedd558d6 | ||
|
|
6ed64d3730 | ||
|
|
8660ff0f60 | ||
|
|
547a2965dd | ||
|
|
c19914e83f | ||
|
|
6c14faa51d | ||
|
|
6b4060e0c4 | ||
|
|
483706151b | ||
|
|
9dc128cc1d | ||
|
|
50b7e84f58 | ||
|
|
a77067ffe5 | ||
|
|
2a49635497 | ||
|
|
a158019d66 | ||
|
|
5f7d296b4d | ||
|
|
fd889bd26a | ||
|
|
c4cd8136bf | ||
|
|
dbc0c11795 | ||
|
|
1a7949a477 | ||
|
|
0a26d37728 | ||
|
|
73597d9524 | ||
|
|
d30b024bd3 | ||
|
|
a3e979abc8 | ||
|
|
1799a56072 | ||
|
|
56e4fa75bf | ||
|
|
b535b28661 | ||
|
|
43634772c7 | ||
|
|
aea66feb33 | ||
|
|
11d856ce08 | ||
|
|
30a346bd3f | ||
|
|
5254a376c4 | ||
|
|
f79e8c12a5 | ||
|
|
af580c4d48 | ||
|
|
be65dc5e51 | ||
|
|
93c1c7b480 | ||
|
|
b0a5dbd07f | ||
|
|
74cca86bb6 | ||
|
|
fe4e60c80c | ||
|
|
22dd134196 | ||
|
|
e971604565 | ||
|
|
90c59ad4df | ||
|
|
c888256b38 | ||
|
|
72a0ad53dd | ||
|
|
2fc13af09d | ||
|
|
57ccbe753e | ||
|
|
d14916c590 | ||
|
|
5b8741ca46 | ||
|
|
cfcf52f337 | ||
|
|
ab32f24dc1 | ||
|
|
a653e17f3c | ||
|
|
809d26307f | ||
|
|
d35d326595 | ||
|
|
81c550e834 | ||
|
|
b27cea2385 | ||
|
|
79f1d65713 | ||
|
|
737e6c4cfb | ||
|
|
44f68a3266 | ||
|
|
4e69adc548 | ||
|
|
93d0c38393 | ||
|
|
81aa8b8d31 | ||
|
|
ce28bb689a | ||
|
|
487ce68ef6 | ||
|
|
a29f7a2807 | ||
|
|
80d33f0f11 | ||
|
|
0bd57102d5 | ||
|
|
c701b22098 | ||
|
|
0ad3c58496 | ||
|
|
99e06d6b3b | ||
|
|
4785482543 | ||
|
|
c06beba53b | ||
|
|
4b989a15b6 | ||
|
|
0f10d48519 | ||
|
|
2e7454de84 | ||
|
|
5faad6b3ba | ||
|
|
75b0f5c344 | ||
|
|
d0b94bbda5 | ||
|
|
6f18622643 | ||
|
|
2b5016442b | ||
|
|
e389e4b5e1 | ||
|
|
7d9cdb91b0 | ||
|
|
fad1eb5736 | ||
|
|
d01805ad13 | ||
|
|
f638772c5f | ||
|
|
b84b21a68f | ||
|
|
da230781e3 | ||
|
|
c91ef45062 | ||
|
|
9a87329618 | ||
|
|
24ee315c0b | ||
|
|
a4decb57f8 | ||
|
|
81feb5be3f | ||
|
|
2253fd0ec3 | ||
|
|
db4ad8e16d | ||
|
|
11571a2b8a | ||
|
|
c615c98d09 | ||
|
|
922b134467 | ||
|
|
6650e0cece | ||
|
|
8714e0e5a9 | ||
|
|
24570aa658 | ||
|
|
4b28aa7604 | ||
|
|
50425ada16 | ||
|
|
93f14a5b40 | ||
|
|
6d4f3650cc | ||
|
|
de7a5358d2 | ||
|
|
9a0f3a4dd1 | ||
|
|
bfbde9d8fc | ||
|
|
a5ced59a35 | ||
|
|
e9c6fac17a | ||
|
|
2bc467ac82 | ||
|
|
c68f7bd5f8 | ||
|
|
7015a9efa2 | ||
|
|
06bd96fcae | ||
|
|
db7bbef9b5 | ||
|
|
fa0d147e04 | ||
|
|
39e7cbe9ca | ||
|
|
84a1641968 | ||
|
|
26acd7b3a5 | ||
|
|
f51e5e4eae | ||
|
|
636eaf3d5d | ||
|
|
5b9fdd00c8 | ||
|
|
bc42035866 | ||
|
|
917eb371c8 | ||
|
|
ef45df9ea3 | ||
|
|
24965108b2 | ||
|
|
9f09fcd103 | ||
|
|
e1baecd32e | ||
|
|
44d66e0e5b | ||
|
|
0368f930b8 | ||
|
|
a83a0c8579 | ||
|
|
92b1ad28c2 | ||
|
|
5302f15b9d | ||
|
|
6a3eec1960 | ||
|
|
11425840ad | ||
|
|
8515df8224 | ||
|
|
fe5d6e34f2 | ||
|
|
e3e797e19a | ||
|
|
2293092048 | ||
|
|
147081ccc5 | ||
|
|
b924f65f91 | ||
|
|
259dd72f87 | ||
|
|
ab726bda78 | ||
|
|
163bbd7b0e | ||
|
|
205e169754 | ||
|
|
35f7914249 | ||
|
|
31b7fd462f | ||
|
|
b9812ba2b6 | ||
|
|
fc1d5ff3ae | ||
|
|
2de0f49af9 | ||
|
|
2f983ad316 | ||
|
|
db23910195 | ||
|
|
968e166bde | ||
|
|
efe729c4d1 | ||
|
|
d40d19d6e3 | ||
|
|
b476b143f4 | ||
|
|
bb54697d9c | ||
|
|
24102c15e6 | ||
|
|
5100ef06c8 | ||
|
|
9b892eab85 | ||
|
|
eab5ca7f6d | ||
|
|
fd055c163e | ||
|
|
ea78d2ff40 | ||
|
|
6f074513f2 | ||
|
|
0719c5bdc6 | ||
|
|
36a394d142 | ||
|
|
0e08dbc6f2 | ||
|
|
003aa67a41 | ||
|
|
be45a43524 | ||
|
|
0d700848f8 | ||
|
|
1ff402036d | ||
|
|
9d36dbd2b8 | ||
|
|
c53c4378d8 | ||
|
|
eacf176f88 | ||
|
|
13afb067bb | ||
|
|
7af2f4b2e2 | ||
|
|
a1d8bfa6a1 | ||
|
|
47b3fe9ca2 | ||
|
|
0ce52ea107 | ||
|
|
d98fe31412 | ||
|
|
d8f338aada | ||
|
|
f5965c48b3 | ||
|
|
0df7077ddb | ||
|
|
222a9341bf | ||
|
|
35f6f7870a | ||
|
|
15b6e0ba27 | ||
|
|
968754efe0 | ||
|
|
a03c9e0194 | ||
|
|
734e7cbae8 | ||
|
|
52fe6691ac | ||
|
|
acd8d1192c | ||
|
|
8fc309cb76 | ||
|
|
45f16ec10f | ||
|
|
5ff8cb21c8 | ||
|
|
f8997b8739 | ||
|
|
ed21464c3a | ||
|
|
7954575216 | ||
|
|
1a11d3e733 | ||
|
|
487aa45a27 | ||
|
|
b7f9aeab06 | ||
|
|
6aaee382a6 | ||
|
|
8c84c506bf | ||
|
|
39a53db067 | ||
|
|
0622f92cf1 | ||
|
|
a8f81c141a | ||
|
|
efffceb9f2 | ||
|
|
75d1fc32c8 | ||
|
|
e087e93e2a | ||
|
|
e83c9967b4 | ||
|
|
2b1896020d | ||
|
|
61b17907ee | ||
|
|
339fb42f37 | ||
|
|
7985275697 | ||
|
|
661b60d07c | ||
|
|
d4f647e18b | ||
|
|
1761d853de | ||
|
|
42a6543f9b | ||
|
|
9356c6c323 | ||
|
|
a7a92f7e10 | ||
|
|
e149ca6be8 | ||
|
|
d44493743d | ||
|
|
7eb030de7d | ||
|
|
8fd4a4a87d | ||
|
|
9bfc7d7d9b | ||
|
|
8f71a427fd | ||
|
|
7c93eda985 | ||
|
|
1e7a858aa0 | ||
|
|
11fba1b6bd | ||
|
|
8b9bc356f2 | ||
|
|
89b6c8306e | ||
|
|
ce9d66c199 | ||
|
|
32a09aa36b | ||
|
|
3ea716c580 | ||
|
|
328d347845 | ||
|
|
d394c3d67c | ||
|
|
17b6b8a4e7 | ||
|
|
980226fab9 | ||
|
|
0f726a0f34 | ||
|
|
91ee057f4a | ||
|
|
c26afbc0af | ||
|
|
be56e28009 | ||
|
|
0697c425ca | ||
|
|
ca0ca471fb | ||
|
|
7b2aac3874 | ||
|
|
fbe8376ca0 | ||
|
|
22bc18859b | ||
|
|
25f9608d58 | ||
|
|
428f213e15 | ||
|
|
593d48a6e6 | ||
|
|
3dcf3c931a | ||
|
|
8cc45ddba3 | ||
|
|
6f23122657 | ||
|
|
c0b0759ed0 | ||
|
|
00252f3b97 | ||
|
|
531c49011b | ||
|
|
dea22454f7 | ||
|
|
12bda63785 | ||
|
|
c65e17cf0c | ||
|
|
753ca0e6ad | ||
|
|
8b85e1711d | ||
|
|
12b0dfd19d | ||
|
|
8c05d41423 | ||
|
|
c5ab0f5440 | ||
|
|
d92f5ef375 | ||
|
|
c313d6203a | ||
|
|
070f92aea2 | ||
|
|
4e3c5894b5 | ||
|
|
8cfb9f0f17 | ||
|
|
4e135e3f92 | ||
|
|
938522974b | ||
|
|
6994975387 | ||
|
|
6d3a172466 | ||
|
|
3aaa185617 | ||
|
|
980cd92333 | ||
|
|
89da2942c7 | ||
|
|
8ea905e053 | ||
|
|
885e959cdb | ||
|
|
02904a3dce | ||
|
|
e8d4bb2376 | ||
|
|
7695167578 | ||
|
|
94e5f63a65 | ||
|
|
9fa0f773d5 | ||
|
|
88111e6f7e | ||
|
|
9a5c16fe6a | ||
|
|
4efaf8d497 | ||
|
|
07881da451 | ||
|
|
bd6c2524e7 | ||
|
|
b096e02b9b | ||
|
|
ad6b24345b | ||
|
|
9694b756b5 | ||
|
|
6b5786be9d | ||
|
|
1f49ab2551 | ||
|
|
b18a5bec8e | ||
|
|
d741459e2f | ||
|
|
7007722aca | ||
|
|
05e7b3c1e5 | ||
|
|
13554546eb | ||
|
|
e2f3722b52 | ||
|
|
1b75734046 | ||
|
|
330a9782bc | ||
|
|
61d9609328 | ||
|
|
4cff51c89f | ||
|
|
ace5178e99 | ||
|
|
4a9d8627d3 | ||
|
|
fc89b932dd | ||
|
|
0852ac8326 | ||
|
|
87194d7f1b | ||
|
|
31fa689a98 | ||
|
|
5d366e742c | ||
|
|
7cc3c8f5ef | ||
|
|
7215dfcf60 | ||
|
|
5c709c1c54 | ||
|
|
1e5ad65c9f | ||
|
|
f6aeffb264 | ||
|
|
4593f3077c | ||
|
|
b92c8726de | ||
|
|
c560539a16 | ||
|
|
9cba7a95f7 | ||
|
|
d6d86ef04d | ||
|
|
ed643f3481 | ||
|
|
d8c2f77a0b | ||
|
|
6cfda647f7 | ||
|
|
fc58fcc721 | ||
|
|
5f0707956a | ||
|
|
528712e931 | ||
|
|
8fe609452b | ||
|
|
3afd2c4ac9 | ||
|
|
5793d7b678 | ||
|
|
569a8b4c4d | ||
|
|
9cab8f7469 | ||
|
|
1ac0b2efbe | ||
|
|
b78a36f1c2 | ||
|
|
e23d191cb8 | ||
|
|
8854b00b46 | ||
|
|
4be835de07 | ||
|
|
b8f59fa99c | ||
|
|
2236efea4f | ||
|
|
344ba4138d | ||
|
|
ba0fa7a869 | ||
|
|
21668a63fd | ||
|
|
2f6f9bcbc5 | ||
|
|
86d19de452 | ||
|
|
d4986449f1 | ||
|
|
3fc366bf1a | ||
|
|
9d192b215e | ||
|
|
b4ea4517e9 | ||
|
|
07ad12a16f | ||
|
|
f7529a18df | ||
|
|
c66522cb47 | ||
|
|
94a31f77ff | ||
|
|
c0630f9f6d | ||
|
|
3a145cb615 | ||
|
|
837516ea86 | ||
|
|
66228f59be | ||
|
|
800c79a898 | ||
|
|
2177b12bcf | ||
|
|
050c22ce27 | ||
|
|
ded614f30f | ||
|
|
88e439ebfd | ||
|
|
a027355c7d | ||
|
|
8a351ec928 | ||
|
|
b2fa4974ef | ||
|
|
9c2a034b43 | ||
|
|
45ba746300 | ||
|
|
483f317f83 | ||
|
|
dee3268bce | ||
|
|
2a88d3eef4 | ||
|
|
2898fed15a | ||
|
|
d2721077c9 | ||
|
|
dd7bb81b46 | ||
|
|
4515d21023 | ||
|
|
3315e3c148 | ||
|
|
2b552680a7 | ||
|
|
f78c80f04d | ||
|
|
bc239a7994 | ||
|
|
a508ec2279 | ||
|
|
cccecbacbc | ||
|
|
177a8b0527 | ||
|
|
d869ff959f | ||
|
|
772ba562e6 | ||
|
|
1786360d7c | ||
|
|
328596f01f | ||
|
|
6a13c9f822 | ||
|
|
3c78a63719 | ||
|
|
8b645b75df | ||
|
|
ae3ea30c92 | ||
|
|
01bd2c0c11 | ||
|
|
e91721299a | ||
|
|
4e08ec9fca | ||
|
|
b599008040 | ||
|
|
831f68b00c | ||
|
|
bccda6cb9e | ||
|
|
d0e77d2959 | ||
|
|
441ff72e1e | ||
|
|
aff131394e | ||
|
|
7a6f758853 | ||
|
|
eef8f538bc | ||
|
|
42d79ea01f | ||
|
|
df2c92555f | ||
|
|
380f6b5581 | ||
|
|
fb6450fb72 | ||
|
|
bb01c25605 | ||
|
|
d812e7dd8b | ||
|
|
60f3a765f3 | ||
|
|
31d6bd3664 | ||
|
|
4c0018b04c | ||
|
|
4b0b3df9d2 | ||
|
|
f699be1a65 | ||
|
|
b6496b31f0 | ||
|
|
1e601c3de9 | ||
|
|
00b39fec38 | ||
|
|
9224ab8a76 | ||
|
|
5307aebbf5 | ||
|
|
e7d8d613aa | ||
|
|
f469b08505 | ||
|
|
60b2a07659 | ||
|
|
8d6d448073 | ||
|
|
798156fedc | ||
|
|
e18510fc6b | ||
|
|
0fe96bf32d | ||
|
|
6d1f491b80 | ||
|
|
07ac8b99f0 | ||
|
|
622c35e935 | ||
|
|
c6adad5992 | ||
|
|
211722a8a7 | ||
|
|
a0082a4ce7 | ||
|
|
a4eb540d23 | ||
|
|
2d427d6c47 | ||
|
|
0d00168aaf |
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
|
||||
@@ -15,24 +15,98 @@ jobs:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
contents: write # Allows the workflow to create or update references (tags)
|
||||
packages: write
|
||||
actions: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
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
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
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/actions/setup-gradle@v3
|
||||
with:
|
||||
arguments: build
|
||||
- name: Upload a Build Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: /home/runner/work/Grim/Grim/build/libs/**.jar
|
||||
# Temporary tasks so built jar works because PacketEvents won't merge my fixes for their bugs yet
|
||||
- name: Clone Axionize's PacketEvents Repository
|
||||
run: |
|
||||
git clone -b fix/fabric-events https://github.com/Axionize/packetevents.git packetevents
|
||||
cd packetevents
|
||||
echo "Cloned PacketEvents repository"
|
||||
|
||||
- name: Build and Publish PacketEvents to Maven Local
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
build-root-directory: packetevents
|
||||
arguments: publishToMavenLocal
|
||||
|
||||
- name: Extract Version from build.gradle.kts
|
||||
id: extract-version
|
||||
run: |
|
||||
# Extract the version from build.gradle.kts using grep and sed
|
||||
VERSION=$(grep "^version\s*=" build.gradle.kts | sed 's/version\s*=\s*"\(.*\)"/\1/')
|
||||
echo "VERSION: $VERSION"
|
||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build Lite Jar with Gradle
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
arguments: build -PshadePE=false
|
||||
|
||||
- name: Upload Lite Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: grimac-lite
|
||||
path: ${{ github.workspace }}/build/libs/grimac-${{ env.VERSION }}-lite.jar
|
||||
|
||||
- name: Build Main Jar with Gradle
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
arguments: build
|
||||
|
||||
- name: Upload Main Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: grimac-main
|
||||
path: ${{ github.workspace }}/build/libs/grimac-${{ env.VERSION }}.jar
|
||||
|
||||
- name: Generate build number
|
||||
if: contains(fromJSON('["merge", "release", "main"]'), github.ref_name)
|
||||
id: buildnumber
|
||||
uses: onyxmueller/build-tag-number@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Publish to Modrinth
|
||||
if: contains(fromJSON('["merge", "release", "main"]'), github.ref_name)
|
||||
uses: Kir-Antipov/mc-publish@v3.3
|
||||
with:
|
||||
modrinth-id: ${{ vars.MODRINTH_ID }}
|
||||
modrinth-featured: true
|
||||
modrinth-unfeature-mode: subset
|
||||
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
|
||||
|
||||
files: |
|
||||
${{ github.workspace }}/build/libs/grimac-${{ env.VERSION }}.jar
|
||||
${{ github.workspace }}/build/libs/grimac-${{ env.VERSION }}-lite.jar
|
||||
|
||||
name: Lightning Grim Anticheat ${{ env.VERSION }}-b${{ steps.buildnumber.outputs.build_number }}
|
||||
version: ${{ env.VERSION }}-b${{ steps.buildnumber.outputs.build_number }}
|
||||
version-type: release
|
||||
|
||||
loaders: |
|
||||
bukkit
|
||||
spigot
|
||||
paper
|
||||
folia
|
||||
purpur
|
||||
|
||||
game-versions: |
|
||||
>=1.7
|
||||
|
||||
retry-attempts: 2
|
||||
retry-delay: 10000
|
||||
fail-mode: fail
|
||||
@@ -1,27 +1,47 @@
|
||||
# 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](https://nightly.link/GrimAnticheat/Grim/workflows/gradle-publish/2.0/artifact.zip)
|
||||
|
||||
## Installation notes
|
||||
- Java 8 is fully supported.
|
||||
- Paper, Spigot, and Folia 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 jar will compile into the build/libs folder
|
||||
|
||||
## 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
|
||||
|
||||
+81
-19
@@ -3,7 +3,7 @@ import net.minecrell.pluginyml.bukkit.BukkitPluginDescription.Permission
|
||||
plugins {
|
||||
id("java")
|
||||
id("maven-publish")
|
||||
id("com.github.johnrengelman.shadow") version "8.1.1"
|
||||
id("com.gradleup.shadow") version "9.0.0-beta6"
|
||||
id("io.freefair.lombok") version "8.6"
|
||||
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
|
||||
id("com.diffplug.spotless") version "6.25.0"
|
||||
@@ -26,25 +26,40 @@ spotless {
|
||||
}
|
||||
|
||||
group = "ac.grim.grimac"
|
||||
version = "2.3.68"
|
||||
version = "2.3.72"
|
||||
description = "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0."
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
|
||||
}
|
||||
java.sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
java.targetCompatibility = JavaVersion.VERSION_1_8
|
||||
|
||||
// Set to false for debug builds
|
||||
// You cannot live reload classes if the jar relocates dependencies
|
||||
var relocate = true;
|
||||
// Checks Project properties -> environment variable -> defaults true
|
||||
val relocate: Boolean = project.findProperty("relocate")?.toString()?.toBoolean()
|
||||
?: System.getenv("RELOCATE_JAR")?.toBoolean()
|
||||
?: true
|
||||
|
||||
// Whether or not to shade PE into the jar, some servers may not want this if they use other plugins
|
||||
// With PE; this prevents duplicate listening and reduces RAM usage by ~80-100 MB
|
||||
val shadePE: Boolean = project.findProperty("shadePE")?.toString()?.toBoolean()
|
||||
?: System.getenv("SHADE_PE")?.toBoolean()
|
||||
?: true
|
||||
|
||||
repositories {
|
||||
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://jitpack.io/") { // Grim API
|
||||
content {
|
||||
includeGroup("com.github.grimanticheat")
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = "grimacSnapshots"
|
||||
url = uri("https://repo.grim.ac/snapshots")
|
||||
}
|
||||
maven("https://repo.viaversion.com") // ViaVersion
|
||||
maven("https://repo.aikar.co/content/groups/aikar/") // ACF
|
||||
maven("https://nexus.scarsz.me/content/repositories/releases") // Configuralize
|
||||
@@ -52,26 +67,38 @@ repositories {
|
||||
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/")
|
||||
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
|
||||
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // placeholderapi
|
||||
mavenCentral()
|
||||
// FastUtil, Discord-Webhooks
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.github.retrooper:packetevents-spigot:2.5.1-SNAPSHOT")
|
||||
compileOnly("io.papermc.paper:paper-api:1.20.6-R0.1-SNAPSHOT")
|
||||
// PE dependency is now conditional
|
||||
if (shadePE) {
|
||||
implementation("com.github.retrooper:packetevents-spigot:2.8.0-SNAPSHOT")
|
||||
} else {
|
||||
compileOnly("com.github.retrooper:packetevents-spigot:2.8.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("it.unimi.dsi:fastutil:8.5.15")
|
||||
implementation("github.scarsz:configuralize:1.4.0")
|
||||
implementation("com.zaxxer:HikariCP:4.0.3")
|
||||
|
||||
//implementation("com.github.grimanticheat:grimapi:1193c4fa41")
|
||||
// Used for local testing: implementation("ac.grim.grimac:GRIMAPI:1.0")
|
||||
implementation("com.github.grimanticheat:grimapi:fc5634e444")
|
||||
|
||||
// Used for local testing:
|
||||
//implementation("ac.grim.grimac:GrimAPI:1.0")
|
||||
implementation("ac.grim.grimac:GrimAPI:05e31d62f2")
|
||||
|
||||
implementation("net.kyori:adventure-text-minimessage:4.20.0")
|
||||
implementation("net.kyori:adventure-platform-bukkit:4.3.4")
|
||||
|
||||
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:5.0.4-SNAPSHOT")
|
||||
//
|
||||
compileOnly("me.clip:placeholderapi:2.11.6")
|
||||
compileOnly("io.netty:netty-all:4.1.85.Final")
|
||||
}
|
||||
|
||||
@@ -83,6 +110,10 @@ bukkit {
|
||||
apiVersion = "1.13"
|
||||
foliaSupported = true
|
||||
|
||||
if (!shadePE) {
|
||||
depend = listOf("packetevents") + (depend ?: emptyList())
|
||||
}
|
||||
|
||||
softDepend = listOf(
|
||||
"ProtocolLib",
|
||||
"ProtocolSupport",
|
||||
@@ -92,7 +123,8 @@ bukkit {
|
||||
"ViaRewind",
|
||||
"Geyser-Spigot",
|
||||
"floodgate",
|
||||
"FastLogin"
|
||||
"FastLogin",
|
||||
"PlaceholderAPI",
|
||||
)
|
||||
|
||||
permissions {
|
||||
@@ -121,6 +153,11 @@ bukkit {
|
||||
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
|
||||
@@ -140,6 +177,16 @@ bukkit {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,16 +199,30 @@ tasks.withType<JavaCompile> {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
||||
disableAutoTargetJvm()
|
||||
}
|
||||
|
||||
publishing.publications.create<MavenPublication>("maven") {
|
||||
artifact(tasks["shadowJar"])
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
manifest {
|
||||
attributes["paperweight-mappings-namespace"] = "mojang"
|
||||
}
|
||||
|
||||
minimize()
|
||||
archiveFileName.set("${project.name}-${project.version}.jar")
|
||||
archiveFileName.set("${project.name}-${project.version}${if (shadePE) "" else "-lite"}.jar")
|
||||
if (relocate) {
|
||||
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")
|
||||
// Only relocate PE if we're shading it
|
||||
if (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")
|
||||
exclude("assets/mappings") // Exclude new PE mappings folder
|
||||
relocate("net.kyori", "ac.grim.grimac.shaded.kyori") // use PE's built-in adventure instead when not shading
|
||||
}
|
||||
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")
|
||||
@@ -170,12 +231,13 @@ tasks.shadowJar {
|
||||
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")
|
||||
relocate("com.zaxxer", "ac.grim.grimac.shaded.zaxxer")
|
||||
relocate("org.slf4j", "ac.grim.grimac.shaded.slf4j")
|
||||
}
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -86,8 +86,7 @@ done
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -206,7 +205,7 @@ fi
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
@@ -2,8 +2,11 @@ package ac.grim.grimac;
|
||||
|
||||
import ac.grim.grimac.manager.*;
|
||||
import ac.grim.grimac.manager.config.BaseConfigManager;
|
||||
import ac.grim.grimac.manager.violationdatabase.ViolationDatabaseManager;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import ac.grim.grimac.utils.anticheat.PlayerDataManager;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
@Getter
|
||||
@@ -17,22 +20,39 @@ public enum GrimAPI {
|
||||
private final PlayerDataManager playerDataManager = new PlayerDataManager();
|
||||
private final TickManager tickManager = new TickManager();
|
||||
private final GrimExternalAPI externalAPI = new GrimExternalAPI(this);
|
||||
private ViolationDatabaseManager violationDatabaseManager;
|
||||
private InitManager initManager;
|
||||
private JavaPlugin plugin;
|
||||
private boolean criticalLoadFailure = false; // Track critical failures
|
||||
|
||||
public void load(final JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.violationDatabaseManager = new ViolationDatabaseManager(plugin);
|
||||
initManager = new InitManager();
|
||||
initManager.load();
|
||||
initManager.load(); // Load all initializers
|
||||
}
|
||||
|
||||
public void start(final JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
initManager.start();
|
||||
if (initManager != null) {
|
||||
initManager.start();
|
||||
}
|
||||
|
||||
if (criticalLoadFailure) {
|
||||
LogUtil.error("GrimAC encountered one or more critical error(s) during initialization.");
|
||||
Bukkit.getPluginManager().disablePlugin(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop(final JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
initManager.stop();
|
||||
if (initManager != null) {
|
||||
initManager.stop();
|
||||
}
|
||||
}
|
||||
|
||||
// Method to signal a critical failure
|
||||
public void signalCriticalFailure() {
|
||||
criticalLoadFailure = true;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import org.bukkit.plugin.ServicePriority;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
@@ -43,8 +44,10 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, I
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServerName(String name) {
|
||||
variableReplacements.put("%server%", user -> name);
|
||||
public @Nullable GrimUser getGrimUser(UUID uuid) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player == null) return null;
|
||||
return getGrimUser(player);
|
||||
}
|
||||
|
||||
@Getter
|
||||
@@ -53,8 +56,7 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, I
|
||||
@Getter
|
||||
private final Map<String, String> staticReplacements = new ConcurrentHashMap<>();
|
||||
|
||||
public String replaceVariables(GrimUser user, String content, boolean colors) {
|
||||
if (colors) content = ChatColor.translateAlternateColorCodes('&', content);
|
||||
public String replaceVariables(GrimUser user, String content) {
|
||||
for (Map.Entry<String, String> entry : staticReplacements.entrySet()) {
|
||||
content = content.replace(entry.getKey(), entry.getValue());
|
||||
}
|
||||
@@ -114,6 +116,16 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, I
|
||||
return configManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStarted() {
|
||||
return started;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentTick() {
|
||||
return GrimAPI.INSTANCE.getTickManager().currentTick;
|
||||
}
|
||||
|
||||
private ConfigManager configManager = null;
|
||||
private final ConfigManagerFileImpl configManagerFile = new ConfigManagerFileImpl();
|
||||
private boolean started = false;
|
||||
@@ -208,7 +220,7 @@ public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, I
|
||||
variableReplacements.putIfAbsent("%tps%", user -> String.format("%.2f", SpigotReflectionUtil.getTPS()));
|
||||
variableReplacements.putIfAbsent("%version%", GrimUser::getVersionName);
|
||||
// static variables
|
||||
staticReplacements.putIfAbsent("%prefix%", ChatColor.translateAlternateColorCodes('&', GrimAPI.INSTANCE.getConfigManager().getPrefix()));
|
||||
staticReplacements.put("%prefix%", ChatColor.translateAlternateColorCodes('&', GrimAPI.INSTANCE.getConfigManager().getPrefix()));
|
||||
staticReplacements.putIfAbsent("%grim_version%", getGrimVersion());
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@ import ac.grim.grimac.api.AbstractCheck;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.api.events.FlagEvent;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.common.ConfigReloadObserver;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -15,7 +16,7 @@ import org.bukkit.Bukkit;
|
||||
|
||||
// Class from https://github.com/Tecnio/AntiCheatBase/blob/master/src/main/java/me/tecnio/anticheat/check/Check.java
|
||||
@Getter
|
||||
public class Check implements AbstractCheck, ConfigReloadObserver {
|
||||
public class Check extends GrimProcessor implements AbstractCheck {
|
||||
protected final GrimPlayer player;
|
||||
|
||||
public double violations;
|
||||
@@ -31,20 +32,16 @@ public class Check implements AbstractCheck, ConfigReloadObserver {
|
||||
private boolean experimental;
|
||||
@Setter
|
||||
private boolean isEnabled;
|
||||
private boolean exempted;
|
||||
|
||||
@Override
|
||||
public boolean isExperimental() {
|
||||
return experimental;
|
||||
}
|
||||
private boolean exemptPermission;
|
||||
private boolean noSetbackPermission;
|
||||
private boolean noModifyPacketPermission;
|
||||
|
||||
public Check(final GrimPlayer player) {
|
||||
this.player = player;
|
||||
|
||||
final Class<?> checkClass = this.getClass();
|
||||
|
||||
if (checkClass.isAnnotationPresent(CheckData.class)) {
|
||||
final CheckData checkData = checkClass.getAnnotation(CheckData.class);
|
||||
final CheckData checkData = this.getClass().getAnnotation(CheckData.class);
|
||||
if (checkData != null) {
|
||||
this.checkName = checkData.name();
|
||||
this.configName = checkData.configName();
|
||||
// Fall back to check name
|
||||
@@ -56,23 +53,31 @@ public class Check implements AbstractCheck, ConfigReloadObserver {
|
||||
this.description = checkData.description();
|
||||
this.displayName = this.checkName;
|
||||
}
|
||||
//
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
public boolean shouldModifyPackets() {
|
||||
return isEnabled && !player.disableGrim && !player.noModifyPacketPermission && !exempted;
|
||||
return isEnabled && !player.disableGrim && !player.noModifyPacketPermission && !exemptPermission;
|
||||
}
|
||||
|
||||
public void updateExempted() {
|
||||
public void updatePermissions() {
|
||||
if (player.bukkitPlayer == null || checkName == null) return;
|
||||
FoliaScheduler.getEntityScheduler().run(player.bukkitPlayer, GrimAPI.INSTANCE.getPlugin(),
|
||||
t -> exempted = player.bukkitPlayer.hasPermission("grim.exempt." + checkName.toLowerCase()),
|
||||
() -> {});
|
||||
FoliaScheduler.getEntityScheduler().run(
|
||||
player.bukkitPlayer,
|
||||
GrimAPI.INSTANCE.getPlugin(),
|
||||
t -> {
|
||||
final String id = checkName.toLowerCase();
|
||||
exemptPermission = player.bukkitPlayer.hasPermission("grim.exempt." + id);
|
||||
noSetbackPermission = player.bukkitPlayer.hasPermission("grim.nosetback." + id);
|
||||
noModifyPacketPermission = player.bukkitPlayer.hasPermission("grim.nomodifypacket." + id);
|
||||
},
|
||||
() -> {}
|
||||
);
|
||||
}
|
||||
|
||||
public final boolean flagAndAlert(String verbose) {
|
||||
if (flag()) {
|
||||
if (flag(verbose)) {
|
||||
alert(verbose);
|
||||
return true;
|
||||
}
|
||||
@@ -84,16 +89,21 @@ public class Check implements AbstractCheck, ConfigReloadObserver {
|
||||
}
|
||||
|
||||
public final boolean flag() {
|
||||
if (player.disableGrim || (experimental && !player.isExperimentalChecks()) || exempted)
|
||||
return flag("");
|
||||
}
|
||||
|
||||
private long lastViolationTime;
|
||||
|
||||
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);
|
||||
FlagEvent event = new FlagEvent(player, this, verbose);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) return false;
|
||||
|
||||
|
||||
player.punishmentManager.handleViolation(this);
|
||||
|
||||
lastViolationTime = System.currentTimeMillis();
|
||||
violations++;
|
||||
return true;
|
||||
}
|
||||
@@ -106,6 +116,18 @@ public class Check implements AbstractCheck, ConfigReloadObserver {
|
||||
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);
|
||||
}
|
||||
@@ -115,9 +137,10 @@ public class Check implements AbstractCheck, ConfigReloadObserver {
|
||||
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;
|
||||
updateExempted();
|
||||
updatePermissions();
|
||||
onReload(configuration);
|
||||
}
|
||||
|
||||
@@ -131,14 +154,14 @@ public class Check implements AbstractCheck, ConfigReloadObserver {
|
||||
}
|
||||
|
||||
public boolean setbackIfAboveSetbackVL() {
|
||||
if (getViolations() > setbackVL) {
|
||||
if (shouldSetback()) {
|
||||
return player.getSetbackTeleportUtil().executeViolationSetback();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAboveSetbackVl() {
|
||||
return getViolations() > setbackVL;
|
||||
public boolean shouldSetback() {
|
||||
return !noSetbackPermission && violations > setbackVL;
|
||||
}
|
||||
|
||||
public String formatOffset(double offset) {
|
||||
@@ -150,9 +173,37 @@ public class Check implements AbstractCheck, ConfigReloadObserver {
|
||||
packetType == PacketType.Play.Client.WINDOW_CONFIRMATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
reload(GrimAPI.INSTANCE.getConfigManager().getConfig());
|
||||
public boolean isFlying(PacketTypeCommon packetType) {
|
||||
return WrapperPlayClientPlayerFlying.isFlying(packetType);
|
||||
}
|
||||
|
||||
public boolean isUpdate(PacketTypeCommon packetType) {
|
||||
return isFlying(packetType)
|
||||
|| packetType == PacketType.Play.Client.CLIENT_TICK_END
|
||||
|| isTransaction(packetType);
|
||||
}
|
||||
|
||||
public boolean isTickPacket(PacketTypeCommon packetType) {
|
||||
if (isTickPacketIncludingNonMovement(packetType)) {
|
||||
if (isFlying(packetType)) {
|
||||
return !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTickPacketIncludingNonMovement(PacketTypeCommon 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(ClientVersion.V_1_21_2)
|
||||
&& !player.packetStateData.didSendMovementBeforeTickEnd) {
|
||||
if (packetType == PacketType.Play.Client.CLIENT_TICK_END) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return isFlying(packetType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,23 @@
|
||||
package ac.grim.grimac.checks.debug;
|
||||
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
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(Player player);
|
||||
|
||||
public abstract boolean toggleConsoleOutput();
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package ac.grim.grimac.checks.debug;
|
||||
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.NoCollisionBox;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.Pair;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPluginMessage;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* Handles debug visualization of hitboxes and reach calculations for GrimAC.
|
||||
* Sends debug data to clients through plugin messages that can be visualized by compatible clients.
|
||||
*/
|
||||
public class HitboxDebugHandler extends AbstractDebugHandler {
|
||||
|
||||
/**
|
||||
* Set of players currently listening to hitbox debug data
|
||||
*/
|
||||
private final Set<Player> listeners = new CopyOnWriteArraySet<>(new HashSet<>());
|
||||
|
||||
/**
|
||||
* Creates a new HitboxDebugHandler for the specified player
|
||||
*
|
||||
* @param grimPlayer The GrimAC player instance to debug
|
||||
*/
|
||||
public HitboxDebugHandler(GrimPlayer grimPlayer) {
|
||||
super(grimPlayer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles whether a player receives hitbox debug visualization data.
|
||||
* If the player is already listening, they will be removed. If not, they will be added.
|
||||
*
|
||||
* @param player The player to toggle debug visualization for
|
||||
*/
|
||||
@Override
|
||||
public void toggleListener(Player player) {
|
||||
if (!listeners.remove(player)) listeners.add(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean toggleConsoleOutput() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends debug visualization data for reach calculations to all listening players.
|
||||
* The data includes hitboxes, target entities, look vectors, and eye heights used in reach calculations.
|
||||
*
|
||||
* @param hitboxes Map of entity IDs to their collision boxes
|
||||
* @param targetEntities Set of entity IDs that are considered targets
|
||||
* @param lookVecsAndEyeHeights List of pairs containing look vectors and their corresponding eye heights
|
||||
* @param basePos Base position before eye height adjustments
|
||||
* @param isPrediction Whether these hitboxes are from a prediction calculation
|
||||
*
|
||||
* Packet Format (Version 1):
|
||||
* - Byte: Version (0)
|
||||
* - Byte: Global flags
|
||||
* - Bit 0: isPrediction
|
||||
* - Bits 1-7: Reserved
|
||||
* - Double: Player reach/interact distance
|
||||
* - Vector3d: Base position (3 doubles)
|
||||
* - VarInt: Number of ray traces
|
||||
* - For each ray trace:
|
||||
* - Double: Eye height delta
|
||||
* - Vector3d: Look vector (3 doubles)
|
||||
* - VarInt: Number of hitboxes
|
||||
* - For each hitbox:
|
||||
* - VarInt: Entity ID
|
||||
* - Byte: Flags
|
||||
* - Bit 0: Is target entity
|
||||
* - Bit 1: Is no collision
|
||||
* - Bits 2-7: Reserved
|
||||
* - If not NoCollisionBox:
|
||||
* - Double: minX
|
||||
* - Double: minY
|
||||
* - Double: minZ
|
||||
* - Double: maxX
|
||||
* - Double: maxY
|
||||
* - Double: maxZ
|
||||
*/
|
||||
public void sendHitboxData(Map<Integer, CollisionBox> hitboxes, Set<Integer> targetEntities,
|
||||
List<Pair<Vector, Double>> lookVecsAndEyeHeights, Vector basePos,
|
||||
boolean isPrediction, double reachDistance) {
|
||||
if (!isEnabled()) return;
|
||||
|
||||
ByteBuf buffer = Unpooled.buffer();
|
||||
try {
|
||||
// Version Header
|
||||
buffer.writeByte(1);
|
||||
|
||||
// Global Flags Header
|
||||
// Pack boolean flags into a single byte
|
||||
byte global_flags = 0;
|
||||
global_flags |= (isPrediction ? 1 : 0); // Bit 0: are the hitboxes from a prediction?
|
||||
// Bits 2-7 reserved for future use
|
||||
buffer.writeByte(global_flags);
|
||||
|
||||
// Write reach distance
|
||||
buffer.writeDouble(reachDistance);
|
||||
|
||||
// Write base position
|
||||
writeVector(buffer, basePos);
|
||||
|
||||
// Write number of ray traces
|
||||
ByteBufHelper.writeVarInt(buffer, lookVecsAndEyeHeights.size());
|
||||
|
||||
// Write all possible ray traces
|
||||
for (Pair<Vector, Double> pair : lookVecsAndEyeHeights) {
|
||||
Vector lookVec = pair.first();
|
||||
double eyeHeight = pair.second();
|
||||
|
||||
// Write eye height delta and look vector
|
||||
// we make them 3 meters shorter because all of the vectors passed into here are made 3 meters longer
|
||||
// then they need to be so grim can report correct reach distance for too far away hits
|
||||
buffer.writeDouble(eyeHeight);
|
||||
writeVector(buffer, lookVec);
|
||||
}
|
||||
|
||||
// Write number of hitboxes
|
||||
ByteBufHelper.writeVarInt(buffer, hitboxes.size());
|
||||
|
||||
// Write hitbox data
|
||||
for (Map.Entry<Integer, CollisionBox> entry : hitboxes.entrySet()) {
|
||||
int entityId = entry.getKey();
|
||||
CollisionBox box = entry.getValue();
|
||||
|
||||
// Write entity ID
|
||||
ByteBufHelper.writeVarInt(buffer, entityId);
|
||||
|
||||
// Pack boolean flags into a single byte
|
||||
byte flags = 0;
|
||||
flags |= (targetEntities.contains(entityId) ? 1 : 0); // Bit 0: Is target
|
||||
flags |= (box == NoCollisionBox.INSTANCE ? 2 : 0); // Bit 1: Is no collision
|
||||
// Bits 2-7 reserved for future use
|
||||
buffer.writeByte(flags);
|
||||
|
||||
// Write box coordinates if it's not a NoCollisionBox
|
||||
if ((flags & 2) == 0) {
|
||||
SimpleCollisionBox simpleCollisionBox = (SimpleCollisionBox) box;
|
||||
buffer.writeDouble(simpleCollisionBox.minX);
|
||||
buffer.writeDouble(simpleCollisionBox.minY);
|
||||
buffer.writeDouble(simpleCollisionBox.minZ);
|
||||
buffer.writeDouble(simpleCollisionBox.maxX);
|
||||
buffer.writeDouble(simpleCollisionBox.maxY);
|
||||
buffer.writeDouble(simpleCollisionBox.maxZ);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert buffer to byte array
|
||||
byte[] data = new byte[buffer.readableBytes()];
|
||||
buffer.readBytes(data);
|
||||
|
||||
// Create and send packet
|
||||
WrapperPlayServerPluginMessage packet = new WrapperPlayServerPluginMessage(
|
||||
"grim:debug_hitbox",
|
||||
data
|
||||
);
|
||||
|
||||
// Send to all listeners
|
||||
for (Player listener : listeners) {
|
||||
if (listener != null) {
|
||||
PacketEvents.getAPI().getPlayerManager().sendPacket(listener, packet);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Release buffer to prevent memory leaks
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return !listeners.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to write a Vector to the ByteBuf
|
||||
* @param buffer The buffer to write to
|
||||
* @param vector The vector to write
|
||||
*/
|
||||
private void writeVector(ByteBuf buffer, Vector vector) {
|
||||
buffer.writeDouble(vector.getX());
|
||||
buffer.writeDouble(vector.getY());
|
||||
buffer.writeDouble(vector.getZ());
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ public class AimDuplicateLook extends Check implements RotationCheck {
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,10 @@ public class AimModulo360 extends Check implements RotationCheck {
|
||||
|
||||
@Override
|
||||
public void process(final RotationUpdate rotationUpdate) {
|
||||
if (player.packetStateData.lastPacketWasTeleport) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ 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;
|
||||
|
||||
|
||||
@@ -5,10 +5,11 @@ 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.player.GameMode;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
|
||||
@CheckData(name = "BadPacketsC")
|
||||
@CheckData(name = "BadPacketsC", description = "Interacted with self")
|
||||
public class BadPacketsC extends Check implements PacketCheck {
|
||||
public BadPacketsC(GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -17,6 +18,7 @@ public class BadPacketsC extends Check implements PacketCheck {
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
if (player.gamemode == GameMode.SPECTATOR) return;
|
||||
if (new WrapperPlayClientInteractEntity(event).getEntityId() == player.entityID) {
|
||||
// Instant ban
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
@CheckData(name = "BadPacketsD")
|
||||
@CheckData(name = "BadPacketsD", description = "Impossible pitch")
|
||||
public class BadPacketsD extends Check implements PacketCheck {
|
||||
public BadPacketsD(GrimPlayer player) {
|
||||
super(player);
|
||||
|
||||
@@ -4,8 +4,11 @@ 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.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
@CheckData(name = "BadPacketsE")
|
||||
@@ -18,12 +21,14 @@ public class BadPacketsE extends Check implements PacketCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
final boolean isViaPleaseStopUsingProtocolHacksOnYourServer = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_2) || PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2);
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION ||
|
||||
event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION) {
|
||||
noReminderTicks = 0;
|
||||
} else if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
|
||||
noReminderTicks++;
|
||||
} else if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE) {
|
||||
} else if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE
|
||||
|| (isViaPleaseStopUsingProtocolHacksOnYourServer && player.inVehicle())) {
|
||||
noReminderTicks = 0; // Exempt vehicles
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@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
|
||||
|
||||
@@ -8,10 +8,9 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "BadPacketsG")
|
||||
@CheckData(name = "BadPacketsG", description = "Sent duplicate sneaking status")
|
||||
public class BadPacketsG extends Check implements PacketCheck {
|
||||
boolean wasTeleport;
|
||||
boolean lastSneaking;
|
||||
private boolean lastSneaking, respawn;
|
||||
|
||||
public BadPacketsG(GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -19,13 +18,12 @@ public class BadPacketsG extends Check implements PacketCheck {
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
wasTeleport = player.packetStateData.lastPacketWasTeleport || wasTeleport;
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
|
||||
WrapperPlayClientEntityAction packet = new WrapperPlayClientEntityAction(event);
|
||||
|
||||
if (packet.getAction() == WrapperPlayClientEntityAction.Action.START_SNEAKING) {
|
||||
if (lastSneaking && !wasTeleport) {
|
||||
// The player may send two START_SNEAKING packets if they respawned
|
||||
if (lastSneaking && !respawn) {
|
||||
if (flagAndAlert("state=true") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
@@ -33,8 +31,9 @@ public class BadPacketsG extends Check implements PacketCheck {
|
||||
} else {
|
||||
lastSneaking = true;
|
||||
}
|
||||
respawn = false;
|
||||
} else if (packet.getAction() == WrapperPlayClientEntityAction.Action.STOP_SNEAKING) {
|
||||
if (!lastSneaking && !wasTeleport) {
|
||||
if (!lastSneaking && !respawn) {
|
||||
if (flagAndAlert("state=false") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
@@ -42,7 +41,13 @@ public class BadPacketsG extends Check implements PacketCheck {
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ 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;
|
||||
|
||||
@CheckData(name = "BadPacketsH")
|
||||
@CheckData(name = "BadPacketsH", description = "Did not swing for attack")
|
||||
public class BadPacketsH extends Check implements PacketCheck {
|
||||
|
||||
// 1.9 packet order: INTERACT -> ANIMATION
|
||||
@@ -41,9 +41,9 @@ public class BadPacketsH extends Check implements PacketCheck {
|
||||
// I will simply disable this check for 1.8- clients on 1.9+ servers as I can't be bothered to find a way around this.
|
||||
// Stop supporting such old clients on modern servers!
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_9)
|
||||
&& PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_8)) return;
|
||||
&& PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) return;
|
||||
|
||||
if (!sentAnimation && flagAndAlert()) {
|
||||
if (!sentAnimation && flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ 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);
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
|
||||
@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);
|
||||
|
||||
@@ -8,13 +8,11 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
// checks for impossible dig packets
|
||||
@CheckData(name = "BadPacketsL")
|
||||
@CheckData(name = "BadPacketsL", description = "Sent impossible dig packet")
|
||||
public class BadPacketsL extends Check implements PacketCheck {
|
||||
|
||||
public BadPacketsL(GrimPlayer player) {
|
||||
@@ -30,19 +28,20 @@ public class BadPacketsL extends Check implements PacketCheck {
|
||||
|
||||
// 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 BlockFace expectedFace = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10) && packet.getAction() == DiggingAction.RELEASE_USE_ITEM
|
||||
? BlockFace.SOUTH : BlockFace.DOWN;
|
||||
final int expectedFace = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10) && packet.getAction() == DiggingAction.RELEASE_USE_ITEM
|
||||
? 255 : 0;
|
||||
|
||||
if (packet.getBlockFace() != expectedFace
|
||||
if (packet.getBlockFaceId() != expectedFace
|
||||
|| packet.getBlockPosition().getX() != 0
|
||||
|| packet.getBlockPosition().getY() != 0
|
||||
|| packet.getBlockPosition().getZ() != 0
|
||||
|| packet.getSequence() != 0
|
||||
) {
|
||||
if (flagAndAlert("xyzF="
|
||||
+ packet.getBlockPosition().getX() + ", " + packet.getBlockPosition().getY() + ", " + packet.getBlockPosition().getZ() + ", " + packet.getBlockFace()
|
||||
if (flagAndAlert("pos="
|
||||
+ packet.getBlockPosition().getX() + ", " + packet.getBlockPosition().getY() + ", " + packet.getBlockPosition().getZ()
|
||||
+ ", face=" + packet.getBlockFace()
|
||||
+ ", sequence=" + packet.getSequence()
|
||||
+ ", action=" + packet.getAction().toString().toLowerCase(Locale.ROOT).replace("_", " ") + " v" + player.getVersionName()
|
||||
+ ", action=" + packet.getAction().toString().toLowerCase(Locale.ROOT)
|
||||
) && shouldModifyPackets() && packet.getAction() != DiggingAction.RELEASE_USE_ITEM) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -8,6 +8,7 @@ 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.WrapperPlayClientClickWindow;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClickWindow.WindowClickType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerOpenWindow;
|
||||
|
||||
@CheckData(name = "BadPacketsP", experimental = true)
|
||||
@@ -33,35 +34,39 @@ public class BadPacketsP extends Check implements PacketCheck {
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
|
||||
WrapperPlayClientClickWindow wrapper = new WrapperPlayClientClickWindow(event);
|
||||
int clickType = wrapper.getWindowClickType().ordinal();
|
||||
WindowClickType clickType = wrapper.getWindowClickType();
|
||||
int button = wrapper.getButton();
|
||||
|
||||
boolean flag = false;
|
||||
|
||||
//TODO: Adjust for containers
|
||||
// TODO: Adjust for containers
|
||||
boolean flag;
|
||||
switch (clickType) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 4:
|
||||
if (button != 0 && button != 1) flag = true;
|
||||
case PICKUP:
|
||||
case QUICK_MOVE:
|
||||
case CLONE:
|
||||
flag = button > 2 || button < 0;
|
||||
break;
|
||||
case 2:
|
||||
if ((button > 8 || button < 0) && button != 40) flag = true;
|
||||
case SWAP:
|
||||
flag = (button > 8 || button < 0) && button != 40;
|
||||
break;
|
||||
case 3:
|
||||
if (button != 2) flag = true;
|
||||
case THROW:
|
||||
flag = button != 0 && button != 1;
|
||||
break;
|
||||
case 5:
|
||||
if (button == 3 || button == 7 || button > 10 || button < 0) flag = true;
|
||||
case QUICK_CRAFT:
|
||||
flag = button == 3 || button == 7 || button > 10 || button < 0;
|
||||
break;
|
||||
case 6:
|
||||
if (button != 0) flag = true;
|
||||
case PICKUP_ALL:
|
||||
flag = button != 0;
|
||||
break;
|
||||
case UNKNOWN:
|
||||
flag = true;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Impossible clickType; Compiler does not know this is unreachable!");
|
||||
}
|
||||
|
||||
//Allowing this to false flag to debug and find issues faster
|
||||
// Allowing this to false flag to debug and find issues faster
|
||||
if (flag) {
|
||||
if (flagAndAlert("clickType=" + clickType + " button=" + button + (wrapper.getWindowId() == containerId ? " container=" + containerType : "")) && shouldModifyPackets()) {
|
||||
if (flagAndAlert("clickType=" + clickType.toString().toLowerCase() + ", button=" + button + (wrapper.getWindowId() == containerId ? ", container=" + containerType : "")) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
|
||||
@@ -19,8 +19,10 @@ public class BadPacketsQ extends Check implements PacketCheck {
|
||||
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)) {
|
||||
// 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();
|
||||
|
||||
@@ -25,8 +25,8 @@ public class BadPacketsR extends Check implements PacketCheck {
|
||||
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();
|
||||
}
|
||||
@@ -39,9 +39,10 @@ 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()) {
|
||||
event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION) && !player.inVehicle()) {
|
||||
positions++;
|
||||
} else if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE && player.compensatedEntities.getSelf().inVehicle()) {
|
||||
} else if ((event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE || event.getPacketType() == PacketType.Play.Client.VEHICLE_MOVE)
|
||||
&& player.inVehicle()) {
|
||||
positions++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ 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);
|
||||
final float scale = (float) packetEntity.getAttributeValue(Attributes.SCALE);
|
||||
if (targetVector.y > (minVerticalDisplacement * scale) && targetVector.y < (maxVerticalDisplacement * scale)
|
||||
&& Math.abs(targetVector.x) < (maxHorizontalDisplacement * scale)
|
||||
&& Math.abs(targetVector.z) < (maxHorizontalDisplacement * scale)) {
|
||||
|
||||
@@ -14,7 +14,7 @@ import com.github.retrooper.packetevents.util.Vector3f;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerBlockPlacement;
|
||||
|
||||
@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);
|
||||
|
||||
@@ -5,26 +5,36 @@ 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.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
@CheckData(name = "BadPacketsV", experimental = true)
|
||||
@CheckData(name = "BadPacketsV", description = "Did not move far enough", experimental = true)
|
||||
public class BadPacketsV extends Check implements PacketCheck {
|
||||
public BadPacketsV(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int noReminderTicks;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
WrapperPlayClientInteractEntity interactEntity = new WrapperPlayClientInteractEntity(event);
|
||||
if (interactEntity.getAction() != WrapperPlayClientInteractEntity.InteractAction.ATTACK) return;
|
||||
if (!player.packetStateData.isSlowedByUsingItem()) return;
|
||||
ItemStack itemInUse = player.getInventory().getItemInHand(player.packetStateData.eatingHand);
|
||||
if (flagAndAlert("UseItem=" + itemInUse.getType().getName().getKey()) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
if (!player.canSkipTicks() && isTickPacket(event.getPacketType())) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION || event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION) {
|
||||
int positionAtLeastEveryNTicks = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) ? 20 : 19;
|
||||
|
||||
if (noReminderTicks < positionAtLeastEveryNTicks && !player.uncertaintyHandler.lastTeleportTicks.hasOccurredSince(1)) {
|
||||
final double deltaSq = new WrapperPlayClientPlayerFlying(event).getLocation().getPosition()
|
||||
.distanceSquared(new Vector3d(player.lastX, player.lastY, player.lastZ));
|
||||
if (deltaSq <= player.getMovementThreshold() * player.getMovementThreshold()) {
|
||||
flagAndAlert("delta=" + Math.sqrt(deltaSq));
|
||||
}
|
||||
}
|
||||
|
||||
noReminderTicks = 0;
|
||||
} else {
|
||||
noReminderTicks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -2,42 +2,82 @@ package ac.grim.grimac.checks.impl.badpackets;
|
||||
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.checks.type.PostPredictionCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "BadPacketsX", experimental = true)
|
||||
public class BadPacketsX extends Check implements PacketCheck {
|
||||
public class BadPacketsX extends Check implements PostPredictionCheck {
|
||||
public BadPacketsX(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
public final boolean noFireHitbox = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_15_2);
|
||||
private boolean sprint;
|
||||
private boolean sneak;
|
||||
private int flags;
|
||||
|
||||
public final void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging dig, StateType block) {
|
||||
if (dig.getAction() != DiggingAction.START_DIGGING && dig.getAction() != DiggingAction.FINISHED_DIGGING)
|
||||
@Override
|
||||
public void onPredictionComplete(final PredictionComplete predictionComplete) {
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flags > 0) {
|
||||
setbackIfAboveSetbackVL();
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// the block does not have a hitbox
|
||||
boolean invalid = (block == StateTypes.LIGHT && !(player.getInventory().getHeldItem().is(ItemTypes.LIGHT) || player.getInventory().getOffHand().is(ItemTypes.LIGHT)))
|
||||
|| block.isAir()
|
||||
|| block == StateTypes.WATER
|
||||
|| block == StateTypes.LAVA
|
||||
|| block == StateTypes.BUBBLE_COLUMN
|
||||
|| block == StateTypes.MOVING_PISTON
|
||||
|| (block == StateTypes.FIRE && noFireHitbox)
|
||||
// or the client claims to have broken an unbreakable block
|
||||
|| block.getHardness() == -1.0f && dig.getAction() == DiggingAction.FINISHED_DIGGING;
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; flags > 0; flags--) {
|
||||
flagAndAlertWithSetback();
|
||||
}
|
||||
}
|
||||
|
||||
if (invalid && flagAndAlert("block=" + block.getName() + ", type=" + dig.getAction()) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.gamemode == GameMode.SPECTATOR || isTickPacket(event.getPacketType())) {
|
||||
sprint = sneak = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
|
||||
WrapperPlayClientEntityAction wrapper = new WrapperPlayClientEntityAction(event);
|
||||
switch (wrapper.getAction()) {
|
||||
case START_SNEAKING:
|
||||
case STOP_SNEAKING:
|
||||
if (sneak) {
|
||||
if (player.canSkipTicks() || flagAndAlert()) {
|
||||
flags++;
|
||||
}
|
||||
}
|
||||
sneak = true;
|
||||
break;
|
||||
|
||||
case START_SPRINTING:
|
||||
case STOP_SPRINTING:
|
||||
if (player.inVehicle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sprint) {
|
||||
if (player.canSkipTicks() || flagAndAlert()) {
|
||||
flags++;
|
||||
}
|
||||
}
|
||||
sprint = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Handle other cases if necessary
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientHeldItemChange;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
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 com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
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 AirLiquidBreak(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
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 Vector3i lastBreakLoc = new Vector3i();
|
||||
private @NonNull StateType lastBlockType = StateTypes.AIR;
|
||||
|
||||
public final boolean noFireHitbox = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_15_2);
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.action != DiggingAction.START_DIGGING && blockBreak.action != DiggingAction.FINISHED_DIGGING)
|
||||
return;
|
||||
|
||||
final StateType 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 == StateTypes.WATER
|
||||
) return;
|
||||
lastTick = newTick;
|
||||
lastBreakLoc = blockBreak.position;
|
||||
lastBlockType = block;
|
||||
|
||||
// the block does not have a hitbox
|
||||
boolean invalid = (block == StateTypes.LIGHT && !(player.getInventory().getHeldItem().is(ItemTypes.LIGHT) || player.getInventory().getOffHand().is(ItemTypes.LIGHT)))
|
||||
|| block.isAir()
|
||||
|| block == StateTypes.WATER
|
||||
|| block == StateTypes.LAVA
|
||||
|| block == StateTypes.BUBBLE_COLUMN
|
||||
|| block == StateTypes.MOVING_PISTON
|
||||
|| block == StateTypes.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,45 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
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.utils.math.VectorUtils;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
@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);
|
||||
Vector eyes = new Vector(player.x, player.y + d, player.z);
|
||||
Vector 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,122 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
import java.util.Collections;
|
||||
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<StateType> EXEMPT_STATES = Collections.emptySet();
|
||||
|
||||
public FastBreak(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
// The block the player is currently breaking
|
||||
Vector3i targetBlock = 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) {
|
||||
WrappedBlockState block = blockBreak.block;
|
||||
|
||||
// Exempt all blocks that do not exist in the player version
|
||||
final WrappedBlockState defaultState = WrappedBlockState.getDefaultState(player.getClientVersion(), block.getType());
|
||||
if (defaultState.getType() == StateTypes.AIR || EXEMPT_STATES.contains(defaultState.getType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
startBreak = System.currentTimeMillis() - (targetBlock == null ? 50 : 0); // ???
|
||||
targetBlock = blockBreak.position;
|
||||
|
||||
maximumBlockDamage = BlockBreakSpeed.getBlockDamage(player, targetBlock);
|
||||
|
||||
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 && targetBlock != 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(ClientVersion.V_1_9) ? event.getPacketType() == PacketType.Play.Client.ANIMATION : WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) && targetBlock != null) {
|
||||
maximumBlockDamage = Math.max(maximumBlockDamage, BlockBreakSpeed.getBlockDamage(player, targetBlock));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
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 com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
|
||||
@CheckData(name = "InvalidBreak", description = "Sent impossible block face id")
|
||||
public class InvalidBreak extends Check implements BlockBreakCheck {
|
||||
public InvalidBreak(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.faceId == 255 && blockBreak.action == DiggingAction.CANCELLED_DIGGING && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (blockBreak.faceId < 0 || blockBreak.faceId > 5) {
|
||||
// ban
|
||||
if (flagAndAlert("face=" + blockBreak.faceId + ", action=" + blockBreak.action) && shouldModifyPackets()) {
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
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.MessageUtil;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
|
||||
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@CheckData(name = "MultiBreak", experimental = true)
|
||||
public class MultiBreak extends Check implements BlockBreakCheck {
|
||||
public MultiBreak(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private final List<String> flags = new ArrayList<>();
|
||||
|
||||
private boolean hasBroken;
|
||||
private BlockFace lastFace;
|
||||
private Vector3i lastPos;
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasBroken && (blockBreak.face != lastFace || !blockBreak.position.equals(lastPos))) {
|
||||
final String verbose = "face=" + blockBreak.face + ", lastFace=" + lastFace
|
||||
+ ", pos=" + MessageUtil.toUnlabledString(blockBreak.position)
|
||||
+ ", lastPos=" + MessageUtil.toUnlabledString(lastPos);
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets()) {
|
||||
blockBreak.cancel();
|
||||
}
|
||||
} else {
|
||||
flags.add(verbose);
|
||||
}
|
||||
}
|
||||
|
||||
lastFace = blockBreak.face;
|
||||
lastPos = blockBreak.position;
|
||||
hasBroken = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.gamemode == GameMode.SPECTATOR || isTickPacket(event.getPacketType())) {
|
||||
hasBroken = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (!player.canSkipTicks()) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (String verbose : flags) {
|
||||
flagAndAlert(verbose);
|
||||
}
|
||||
}
|
||||
|
||||
flags.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
|
||||
@CheckData(name = "NoSwingBreak", description = "Did not swing while breaking block", experimental = true)
|
||||
public class NoSwingBreak extends Check implements BlockBreakCheck {
|
||||
public NoSwingBreak(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
private boolean sentAnimation;
|
||||
private boolean sentBreak;
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.action != DiggingAction.CANCELLED_DIGGING) {
|
||||
sentBreak = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.ANIMATION) {
|
||||
sentAnimation = true;
|
||||
}
|
||||
|
||||
if (isTickPacket(event.getPacketType())) {
|
||||
if (sentBreak && !sentAnimation) {
|
||||
flagAndAlert();
|
||||
}
|
||||
|
||||
sentAnimation = sentBreak = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
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 com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
|
||||
@CheckData(name = "PositionBreakA")
|
||||
public class PositionBreakA extends Check implements BlockBreakCheck {
|
||||
public PositionBreakA(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (player.inVehicle()
|
||||
|| blockBreak.action == DiggingAction.CANCELLED_DIGGING
|
||||
|| blockBreak.block.getType() == StateTypes.REDSTONE_WIRE
|
||||
) return;
|
||||
|
||||
SimpleCollisionBox combined = blockBreak.getCombinedBox();
|
||||
|
||||
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
|
||||
double minEyeHeight = Double.MAX_VALUE;
|
||||
double maxEyeHeight = Double.MIN_VALUE;
|
||||
for (double height : possibleEyeHeights) {
|
||||
minEyeHeight = Math.min(minEyeHeight, height);
|
||||
maxEyeHeight = Math.max(maxEyeHeight, height);
|
||||
}
|
||||
|
||||
SimpleCollisionBox eyePositions = new SimpleCollisionBox(player.x, player.y + minEyeHeight, player.z, player.x, player.y + maxEyeHeight, player.z);
|
||||
if (!player.packetStateData.didLastMovementIncludePosition || player.canSkipTicks()) {
|
||||
eyePositions.expand(player.getMovementThreshold());
|
||||
}
|
||||
|
||||
// If the player is inside a block, then they can ray trace through the block and hit the other side of the block
|
||||
if (eyePositions.isIntersected(combined)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// So now we have the player's possible eye positions
|
||||
// So then look at the face that the player has clicked
|
||||
boolean flag;
|
||||
switch (blockBreak.face) {
|
||||
case NORTH:
|
||||
flag = eyePositions.minZ > combined.minZ; // Z- face
|
||||
break;
|
||||
case SOUTH:
|
||||
flag = eyePositions.maxZ < combined.maxZ; // Z+ face
|
||||
break;
|
||||
case EAST:
|
||||
flag = eyePositions.maxX < combined.maxX; // X+ face
|
||||
break;
|
||||
case WEST:
|
||||
flag = eyePositions.minX > combined.minX; // X- face
|
||||
break;
|
||||
case UP:
|
||||
flag = eyePositions.maxY < combined.maxY; // Y+ face
|
||||
break;
|
||||
case DOWN:
|
||||
flag = eyePositions.minY > combined.minY; // Y- face
|
||||
break;
|
||||
default:
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flag && flagAndAlert("action=" + blockBreak.action + ", face=" + blockBreak.face) && shouldModifyPackets()) {
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
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 com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
|
||||
@CheckData(name = "PositionBreakB", experimental = true)
|
||||
public class PositionBreakB extends Check implements BlockBreakCheck {
|
||||
public PositionBreakB(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private BlockFace lastFace;
|
||||
private final int releaseFace = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) ? 0 : 255;
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.action == DiggingAction.START_DIGGING) {
|
||||
if (blockBreak.face == lastFace) {
|
||||
lastFace = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastFace != null) {
|
||||
flagAndAlert("lastFace=" + lastFace + ", action=" + blockBreak.action);
|
||||
}
|
||||
|
||||
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
|
||||
lastFace = blockBreak.faceId == releaseFace ? null : blockBreak.face;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
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.utils.data.Pair;
|
||||
import ac.grim.grimac.utils.nmsutil.Ray;
|
||||
import ac.grim.grimac.utils.nmsutil.ReachUtils;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.util.Vector3f;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@CheckData(name = "RotationBreak", experimental = true)
|
||||
public class RotationBreak extends Check implements BlockBreakCheck {
|
||||
public RotationBreak(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private double flagBuffer = 0; // If the player flags once, force them to play legit, or we will cancel the tick before.
|
||||
private boolean ignorePost = false;
|
||||
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (player.gamemode == GameMode.SPECTATOR) return; // you don't send flying packets when spectating entities
|
||||
if (player.inVehicle()) return; // falses
|
||||
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) return; // falses
|
||||
|
||||
if (flagBuffer > 0 && !didRayTraceHit(blockBreak)) {
|
||||
ignorePost = true;
|
||||
// If the player hit and has flagged this check recently
|
||||
if (flagAndAlert("pre-flying, action=" + blockBreak.action) && shouldModifyPackets()) {
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostFlyingBlockBreak(BlockBreak blockBreak) {
|
||||
if (player.gamemode == GameMode.SPECTATOR) return; // you don't send flying packets when spectating entities
|
||||
if (player.inVehicle()) return; // falses
|
||||
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) return; // falses
|
||||
|
||||
// Don't flag twice
|
||||
if (ignorePost) {
|
||||
ignorePost = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (didRayTraceHit(blockBreak)) {
|
||||
flagBuffer = Math.max(0, flagBuffer - 0.1);
|
||||
} else {
|
||||
flagBuffer = 1;
|
||||
flagAndAlert("post-flying, action=" + blockBreak.action);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean didRayTraceHit(BlockBreak blockBreak) {
|
||||
SimpleCollisionBox box = new SimpleCollisionBox(blockBreak.position);
|
||||
|
||||
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
|
||||
|
||||
// Start checking if player is in the block
|
||||
double minEyeHeight = Double.MAX_VALUE;
|
||||
double maxEyeHeight = Double.MIN_VALUE;
|
||||
for (double height : possibleEyeHeights) {
|
||||
minEyeHeight = Math.min(minEyeHeight, height);
|
||||
maxEyeHeight = Math.max(maxEyeHeight, height);
|
||||
}
|
||||
|
||||
SimpleCollisionBox eyePositions = new SimpleCollisionBox(player.x, player.y + minEyeHeight, player.z, player.x, player.y + maxEyeHeight, player.z);
|
||||
eyePositions.expand(player.getMovementThreshold());
|
||||
|
||||
// If the player is inside a block, then they can ray trace through the block and hit the other side of the block
|
||||
if (eyePositions.isIntersected(box)) {
|
||||
return true;
|
||||
}
|
||||
// End checking if the player is in the block
|
||||
|
||||
List<Vector3f> possibleLookDirs = new ArrayList<>(Arrays.asList(
|
||||
new Vector3f(player.lastXRot, player.yRot, 0),
|
||||
new Vector3f(player.xRot, player.yRot, 0)
|
||||
));
|
||||
|
||||
// 1.9+ players could be a tick behind because we don't get skipped ticks
|
||||
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
|
||||
possibleLookDirs.add(new Vector3f(player.lastXRot, player.lastYRot, 0));
|
||||
}
|
||||
|
||||
// 1.7 players do not have any of these issues! They are always on the latest look vector
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
|
||||
possibleLookDirs = Collections.singletonList(new Vector3f(player.xRot, player.yRot, 0));
|
||||
}
|
||||
|
||||
final double distance = player.compensatedEntities.self.getAttributeValue(Attributes.BLOCK_INTERACTION_RANGE);
|
||||
for (double d : possibleEyeHeights) {
|
||||
for (Vector3f lookDir : possibleLookDirs) {
|
||||
Vector3d starting = new Vector3d(player.x, player.y + d, player.z);
|
||||
Ray trace = new Ray(player, starting.getX(), starting.getY(), starting.getZ(), lookDir.getX(), lookDir.getY());
|
||||
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
|
||||
|
||||
if (intercept.first() != null) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+18
-31
@@ -1,24 +1,22 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
package ac.grim.grimac.checks.impl.breaking;
|
||||
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.checks.type.BlockBreakCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.MessageUtil;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
import static ac.grim.grimac.events.packets.patch.ResyncWorldUtil.resyncPosition;
|
||||
import static ac.grim.grimac.utils.nmsutil.BlockBreakSpeed.getBlockDamage;
|
||||
|
||||
@CheckData(name = "BadPacketsZ", experimental = true)
|
||||
public class BadPacketsZ extends Check implements PacketCheck {
|
||||
public BadPacketsZ(final GrimPlayer player) {
|
||||
@CheckData(name = "WrongBreak")
|
||||
public class WrongBreak extends Check implements BlockBreakCheck {
|
||||
public WrongBreak(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@@ -40,9 +38,10 @@ public class BadPacketsZ extends Check implements PacketCheck {
|
||||
return player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || getBlockDamage(player, pos) < 1;
|
||||
}
|
||||
|
||||
public void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging dig) {
|
||||
if (dig.getAction() == DiggingAction.START_DIGGING) {
|
||||
final Vector3i pos = dig.getBlockPosition();
|
||||
@Override
|
||||
public void onBlockBreak(BlockBreak blockBreak) {
|
||||
if (blockBreak.action == DiggingAction.START_DIGGING) {
|
||||
final Vector3i pos = blockBreak.position;
|
||||
|
||||
lastBlockWasInstantBreak = getBlockDamage(player, pos) >= 1;
|
||||
lastCancelledBlock = null;
|
||||
@@ -50,24 +49,15 @@ public class BadPacketsZ extends Check implements PacketCheck {
|
||||
lastBlock = pos;
|
||||
}
|
||||
|
||||
if (dig.getAction() == DiggingAction.CANCELLED_DIGGING) {
|
||||
final Vector3i pos = dig.getBlockPosition();
|
||||
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
|
||||
final Vector3i pos = blockBreak.position;
|
||||
|
||||
if (shouldExempt(pos)) {
|
||||
lastCancelledBlock = pos;
|
||||
lastLastBlock = null;
|
||||
lastBlock = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pos.equals(lastBlock)) {
|
||||
if (!shouldExempt(pos) && !pos.equals(lastBlock)) {
|
||||
// https://github.com/GrimAnticheat/Grim/issues/1512
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || (!lastBlockWasInstantBreak && pos.equals(lastCancelledBlock))) {
|
||||
if (flagAndAlert("action=CANCELLED_DIGGING" + ", last=" + MessageUtil.toUnlabledString(lastBlock) + ", pos=" + MessageUtil.toUnlabledString(pos))) {
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
resyncPosition(player, pos);
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,24 +69,21 @@ public class BadPacketsZ extends Check implements PacketCheck {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dig.getAction() == DiggingAction.FINISHED_DIGGING) {
|
||||
final Vector3i pos = dig.getBlockPosition();
|
||||
if (blockBreak.action == DiggingAction.FINISHED_DIGGING) {
|
||||
final Vector3i pos = blockBreak.position;
|
||||
|
||||
// when a player looks away from the mined block, they send a cancel, and if they look at it again, they don't send another start. (thanks mojang!)
|
||||
if (!pos.equals(lastCancelledBlock) && (!lastBlockWasInstantBreak || player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4)) && !pos.equals(lastBlock)) {
|
||||
if (flagAndAlert("action=FINISHED_DIGGING" + ", last=" + MessageUtil.toUnlabledString(lastBlock) + ", pos=" + MessageUtil.toUnlabledString(pos))) {
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
resyncPosition(player, pos);
|
||||
blockBreak.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastCancelledBlock = null;
|
||||
|
||||
// 1.14.4+ clients don't send another start break in protected regions
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4)) {
|
||||
lastCancelledBlock = null;
|
||||
lastLastBlock = null;
|
||||
lastBlock = null;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package ac.grim.grimac.checks.impl.combat;
|
||||
|
||||
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 = "HitboxBlock", configName = "HitboxBlock", setback = 20)
|
||||
public class HitboxBlock extends Check implements PacketCheck {
|
||||
public HitboxBlock(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package ac.grim.grimac.checks.impl.combat;
|
||||
|
||||
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 = "HitboxEntity", configName = "HitboxEntity", setback = 30)
|
||||
public class HitboxEntity extends Check implements PacketCheck {
|
||||
public HitboxEntity(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package ac.grim.grimac.checks.impl.combat;
|
||||
|
||||
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 = "HitboxMiss", configName = "HitboxMiss", setback = 10)
|
||||
public class HitboxMiss extends Check implements PacketCheck {
|
||||
public HitboxMiss(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,12 @@ import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@CheckData(name = "MultiInteractA", experimental = true)
|
||||
@CheckData(name = "MultiInteractA", description = "Interacted with multiple entities in the same tick", experimental = true)
|
||||
public class MultiInteractA extends Check implements PostPredictionCheck {
|
||||
public MultiInteractA(final GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -34,7 +33,7 @@ public class MultiInteractA extends Check implements PostPredictionCheck {
|
||||
if (hasInteracted && entity != lastEntity) {
|
||||
String verbose = "lastEntity=" + lastEntity + ", entity=" + entity
|
||||
+ ", lastSneaking=" + lastSneaking + ", sneaking=" + sneaking;
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
@@ -49,15 +48,14 @@ public class MultiInteractA extends Check implements PostPredictionCheck {
|
||||
hasInteracted = true;
|
||||
}
|
||||
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) && !player.packetStateData.lastPacketWasTeleport) {
|
||||
if (player.gamemode == GameMode.SPECTATOR || isTickPacket(event.getPacketType())) {
|
||||
hasInteracted = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
if (!player.canSkipTicks()) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (String verbose : flags) {
|
||||
@@ -66,6 +64,5 @@ public class MultiInteractA extends Check implements PostPredictionCheck {
|
||||
}
|
||||
|
||||
flags.clear();
|
||||
hasInteracted = false;
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,9 @@ import ac.grim.grimac.utils.anticheat.MessageUtil;
|
||||
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.util.Vector3f;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -36,7 +35,7 @@ public class MultiInteractB extends Check implements PostPredictionCheck {
|
||||
|
||||
if (hasInteracted && !pos.equals(lastPos)) {
|
||||
String verbose = "pos=" + MessageUtil.toUnlabledString(pos) + ", lastPos=" + MessageUtil.toUnlabledString(lastPos);
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
@@ -50,15 +49,14 @@ public class MultiInteractB extends Check implements PostPredictionCheck {
|
||||
hasInteracted = true;
|
||||
}
|
||||
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) && !player.packetStateData.lastPacketWasTeleport) {
|
||||
if (player.gamemode == GameMode.SPECTATOR || isTickPacket(event.getPacketType())) {
|
||||
hasInteracted = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
// we don't need to check pre-1.9 players here (no tick skipping)
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
|
||||
if (!player.canSkipTicks()) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (String verbose : flags) {
|
||||
@@ -67,6 +65,5 @@ public class MultiInteractB extends Check implements PostPredictionCheck {
|
||||
}
|
||||
|
||||
flags.clear();
|
||||
hasInteracted = false;
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,18 @@ package ac.grim.grimac.checks.impl.combat;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.debug.HitboxDebugHandler;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.NoCollisionBox;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import ac.grim.grimac.utils.data.BlockHitData;
|
||||
import ac.grim.grimac.utils.data.EntityHitData;
|
||||
import ac.grim.grimac.utils.data.HitData;
|
||||
import ac.grim.grimac.utils.data.Pair;
|
||||
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
|
||||
import ac.grim.grimac.utils.nmsutil.BlockRayTrace;
|
||||
import ac.grim.grimac.utils.data.packetentity.dragon.PacketEntityEnderDragonPart;
|
||||
import ac.grim.grimac.utils.nmsutil.ReachUtils;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
@@ -31,28 +39,39 @@ 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.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
// You may not copy the check unless you are licensed under GPL
|
||||
@CheckData(name = "Reach", configName = "Reach", setback = 10)
|
||||
@CheckData(name = "Reach", setback = 10)
|
||||
public class Reach extends Check implements PacketCheck {
|
||||
|
||||
// Only one flag per reach attack, per entity, per tick.
|
||||
// We store position because lastX isn't reliable on teleports.
|
||||
private final Int2ObjectMap<Vector3d> playerAttackQueue = new Int2ObjectOpenHashMap<>();
|
||||
// Used to prevent falses in the wall hit check
|
||||
private final Set<Vector3i> blocksChangedThisTick = new HashSet<>();
|
||||
|
||||
public static final double extraSearchDistance = 3; // extra distance to raytrace beyond reach distance so we know far beyond the legit distance a cheater hit
|
||||
|
||||
private static final List<EntityType> blacklisted = Arrays.asList(
|
||||
EntityTypes.BOAT,
|
||||
EntityTypes.CHEST_BOAT,
|
||||
EntityTypes.SHULKER);
|
||||
|
||||
private boolean ignoreNonPlayerTargets;
|
||||
private boolean cancelImpossibleHits;
|
||||
private double threshold;
|
||||
public double reachThreshold;
|
||||
private double cancelBuffer; // For the next 4 hits after using reach, we aggressively cancel reach
|
||||
|
||||
public Reach(GrimPlayer player) {
|
||||
@@ -84,6 +103,10 @@ public class Reach extends Check implements PacketCheck {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ignoreNonPlayerTargets && !entity.getType().equals(EntityTypes.PLAYER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dead entities cause false flags (https://github.com/GrimAnticheat/Grim/issues/546)
|
||||
if (entity.isDead) return;
|
||||
|
||||
@@ -91,7 +114,7 @@ public class Reach extends Check implements PacketCheck {
|
||||
if (entity.getType() == EntityTypes.ARMOR_STAND && player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) return;
|
||||
|
||||
if (player.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR) return;
|
||||
if (player.compensatedEntities.getSelf().inVehicle()) return;
|
||||
if (player.inVehicle()) return;
|
||||
if (entity.riding != null) return;
|
||||
|
||||
boolean tooManyAttacks = playerAttackQueue.size() > 10;
|
||||
@@ -108,10 +131,9 @@ public class Reach extends Check implements PacketCheck {
|
||||
}
|
||||
|
||||
// If the player set their look, or we know they have a new tick
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) ||
|
||||
event.getPacketType() == PacketType.Play.Client.PONG ||
|
||||
event.getPacketType() == PacketType.Play.Client.WINDOW_CONFIRMATION) {
|
||||
tickBetterReachCheckWithAngle();
|
||||
final boolean isFlying = WrapperPlayClientPlayerFlying.isFlying(event.getPacketType());
|
||||
if (isUpdate(event.getPacketType())) {
|
||||
tickBetterReachCheckWithAngle(isFlying);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,38 +151,55 @@ public class Reach extends Check implements PacketCheck {
|
||||
return false; // exempt
|
||||
|
||||
if (player.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR) return false;
|
||||
if (player.compensatedEntities.getSelf().inVehicle()) return false;
|
||||
if (player.inVehicle()) return false;
|
||||
|
||||
// Filter out what we assume to be cheats
|
||||
if (cancelBuffer != 0) {
|
||||
return checkReach(reachEntity, new Vector3d(player.x, player.y, player.z), true) != null; // If they flagged
|
||||
return checkReach(reachEntity, new Vector3d(player.x, player.y, player.z), true) != NONE; // If they flagged
|
||||
} else {
|
||||
SimpleCollisionBox targetBox = reachEntity.getPossibleCollisionBoxes();
|
||||
if (reachEntity.getType() == EntityTypes.END_CRYSTAL) {
|
||||
targetBox = new SimpleCollisionBox(reachEntity.trackedServerPosition.getPos().subtract(1, 0, 1), reachEntity.trackedServerPosition.getPos().add(1, 2, 1));
|
||||
}
|
||||
return ReachUtils.getMinReachToBox(player, targetBox) > player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE);
|
||||
return ReachUtils.getMinReachToBox(player, targetBox) > player.compensatedEntities.self.getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE);
|
||||
}
|
||||
}
|
||||
|
||||
private void tickBetterReachCheckWithAngle() {
|
||||
private void tickBetterReachCheckWithAngle(boolean isFlying) {
|
||||
for (Int2ObjectMap.Entry<Vector3d> attack : playerAttackQueue.int2ObjectEntrySet()) {
|
||||
PacketEntity reachEntity = player.compensatedEntities.entityMap.get(attack.getIntKey());
|
||||
if (reachEntity != null) {
|
||||
String result = checkReach(reachEntity, attack.getValue(), false);
|
||||
if (result != null) {
|
||||
if (reachEntity.getType() == EntityTypes.PLAYER) {
|
||||
flagAndAlert(result);
|
||||
} else {
|
||||
flagAndAlert(result + " type=" + reachEntity.getType().getName().getKey());
|
||||
}
|
||||
}
|
||||
if (reachEntity == null) continue;
|
||||
|
||||
CheckResult result = checkReach(reachEntity, attack.getValue(), false);
|
||||
String added;
|
||||
switch (result.type()) {
|
||||
case REACH:
|
||||
added = reachEntity.getType() == EntityTypes.PLAYER ? "" : ", type=" + reachEntity.getType().getName().getKey();
|
||||
flagAndAlert(result.verbose() + added);
|
||||
break;
|
||||
case HITBOX:
|
||||
added = reachEntity.getType() == EntityTypes.PLAYER ? "" : "type=" + reachEntity.getType().getName().getKey();
|
||||
player.checkManager.getPacketCheck(HitboxMiss.class).flagAndAlert(result.verbose() + added);
|
||||
break;
|
||||
case BLOCK:
|
||||
added = reachEntity.getType() == EntityTypes.PLAYER ? "" : "type=" + reachEntity.getType().getName().getKey();
|
||||
player.checkManager.getPacketCheck(HitboxBlock.class).flagAndAlert(result.verbose() + added);
|
||||
break;
|
||||
case ENTITY:
|
||||
added = reachEntity.getType() == EntityTypes.PLAYER ? "" : "type=" + reachEntity.getType().getName().getKey();
|
||||
player.checkManager.getPacketCheck(HitboxEntity.class).flagAndAlert(result.verbose() + added);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
playerAttackQueue.clear();
|
||||
// We can't use transactions for this because of this problem:
|
||||
// transaction -> block changed applied -> 2nd transaction -> list cleared -> attack packet -> flying -> reach block hit checked, falses
|
||||
if (isFlying) blocksChangedThisTick.clear();
|
||||
}
|
||||
|
||||
private String checkReach(PacketEntity reachEntity, Vector3d from, boolean isPrediction) {
|
||||
@NotNull
|
||||
private CheckResult checkReach(PacketEntity reachEntity, Vector3d from, boolean isPrediction) {
|
||||
SimpleCollisionBox targetBox = reachEntity.getPossibleCollisionBoxes();
|
||||
|
||||
if (reachEntity.getType() == EntityTypes.END_CRYSTAL) { // Hardcode end crystal box
|
||||
@@ -173,41 +212,33 @@ public class Reach extends Check implements PacketCheck {
|
||||
targetBox.expand(0.1f);
|
||||
}
|
||||
|
||||
targetBox.expand(threshold);
|
||||
targetBox.expand(reachThreshold);
|
||||
|
||||
// This is better than adding to the reach, as 0.03 can cause a player to miss their target
|
||||
// Adds some more than 0.03 uncertainty in some cases, but a good trade off for simplicity
|
||||
//
|
||||
// Just give the uncertainty on 1.9+ clients as we have no way of knowing whether they had 0.03 movement
|
||||
if (!player.packetStateData.didLastLastMovementIncludePosition || player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9))
|
||||
// However, on 1.21.2+ we do know if they had 0.03 movement
|
||||
if (!player.packetStateData.didLastLastMovementIncludePosition || player.canSkipTicks())
|
||||
targetBox.expand(player.getMovementThreshold());
|
||||
|
||||
double minDistance = Double.MAX_VALUE;
|
||||
|
||||
// https://bugs.mojang.com/browse/MC-67665
|
||||
List<Vector> possibleLookDirs = new ArrayList<>(Collections.singletonList(ReachUtils.getLook(player, player.xRot, player.yRot)));
|
||||
// will store all lookVecsAndEyeHeight pairs that landed a hit on the target entity
|
||||
// We only need to check for blocking intersections for these
|
||||
List<Pair<Vector, Double>> lookVecsAndEyeHeights = new ArrayList<>();
|
||||
|
||||
// If we are a tick behind, we don't know their next look so don't bother doing this
|
||||
if (!isPrediction) {
|
||||
possibleLookDirs.add(ReachUtils.getLook(player, player.lastXRot, player.yRot));
|
||||
|
||||
// 1.9+ players could be a tick behind because we don't get skipped ticks
|
||||
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
|
||||
possibleLookDirs.add(ReachUtils.getLook(player, player.lastXRot, player.lastYRot));
|
||||
}
|
||||
|
||||
// 1.7 players do not have any of these issues! They are always on the latest look vector
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
|
||||
possibleLookDirs = Collections.singletonList(ReachUtils.getLook(player, player.xRot, player.yRot));
|
||||
}
|
||||
}
|
||||
|
||||
// +3 would be 3 + 3 = 6, which is the pre-1.20.5 behaviour, preventing "Missed Hitbox"
|
||||
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE) + 3;
|
||||
final double maxReach = player.compensatedEntities.self.getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE);
|
||||
// We raytrace for > the player's reach distance so in the case a player is hacking
|
||||
// We can return in the flag the distance of the reach hit instead of a generic "player failed reach check"
|
||||
// +3 would be 3 + extraSearchDistance = 6, which is the pre-1.20.5 behaviour, preventing "Missed Hitbox"
|
||||
final double distance = maxReach + extraSearchDistance;
|
||||
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
|
||||
final Vector[] possibleLookDirs = player.getPossibleLookVectors(isPrediction);
|
||||
final Vector eyePos = new Vector(from.getX(), 0, from.getZ());
|
||||
for (Vector lookVec : possibleLookDirs) {
|
||||
for (double eye : possibleEyeHeights) {
|
||||
Vector eyePos = new Vector(from.getX(), from.getY() + eye, from.getZ());
|
||||
eyePos.setY(from.getY() + eye);
|
||||
Vector endReachPos = eyePos.clone().add(new Vector(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance));
|
||||
|
||||
Vector intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).first();
|
||||
@@ -219,29 +250,191 @@ public class Reach extends Check implements PacketCheck {
|
||||
|
||||
if (intercept != null) {
|
||||
minDistance = Math.min(eyePos.distance(intercept), minDistance);
|
||||
lookVecsAndEyeHeights.add(new Pair<>(lookVec, eye));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hitboxDebuggingEnabled())
|
||||
sendHitboxDebugData(reachEntity, from, lookVecsAndEyeHeights, isPrediction);
|
||||
|
||||
HitData foundHitData = null;
|
||||
// If the entity is within range of the player (we'll flag anyway if not, so no point checking blocks in this case)
|
||||
// Ignore when could be hitting through a moving shulker, piston blocks. They are just too glitchy/uncertain to check.
|
||||
if (minDistance <= distance - extraSearchDistance && !player.compensatedWorld.isNearHardEntity(player.boundingBox.copy().expand(4))) {
|
||||
// we can optimize didRayTraceHit more to only rayTrace up to the maximize distance of all rays that hit to the target...
|
||||
// I'm too lazy to do that and we don't need to optimize that much yet so...
|
||||
final @Nullable Pair<Double, HitData> hitResult = didRayTraceHit(reachEntity, lookVecsAndEyeHeights, from);
|
||||
HitData hitData = hitResult.second();
|
||||
// If the returned hit result was NOT the target entity we flag the check
|
||||
if (hitData instanceof EntityHitData &&
|
||||
player.compensatedEntities.getPacketEntityID(((EntityHitData) hitData).getEntity()) != player.compensatedEntities.getPacketEntityID(reachEntity)) {
|
||||
minDistance = Double.MIN_VALUE;
|
||||
foundHitData = hitData;
|
||||
// until I fix block modeling exempt any blocks changed this tick
|
||||
} else if (hitData instanceof BlockHitData && !blocksChangedThisTick.contains(((BlockHitData) hitData).getPosition())) {
|
||||
minDistance = Double.MIN_VALUE;
|
||||
foundHitData = hitData;
|
||||
}
|
||||
}
|
||||
|
||||
// if the entity is not exempt and the entity is alive
|
||||
if ((!blacklisted.contains(reachEntity.getType()) && reachEntity.isLivingEntity()) || reachEntity.getType() == EntityTypes.END_CRYSTAL) {
|
||||
if (minDistance == Double.MAX_VALUE) {
|
||||
if (minDistance == Double.MIN_VALUE && foundHitData != null) {
|
||||
cancelBuffer = 1;
|
||||
return "Missed hitbox";
|
||||
} else if (minDistance > player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE)) {
|
||||
if (foundHitData instanceof BlockHitData) {
|
||||
return new CheckResult(ResultType.BLOCK, "Hit block=" + ((BlockHitData) foundHitData).getState().getType().getName() + " ");
|
||||
} else { // entity hit data
|
||||
return new CheckResult(ResultType.ENTITY, "Hit entity=" + ((EntityHitData) foundHitData).getEntity().getType().getName() + " ");
|
||||
}
|
||||
} else if (minDistance == Double.MAX_VALUE) {
|
||||
cancelBuffer = 1;
|
||||
return String.format("%.5f", minDistance) + " blocks";
|
||||
return new CheckResult(ResultType.HITBOX, "");
|
||||
} else if (minDistance > player.compensatedEntities.self.getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE)) {
|
||||
cancelBuffer = 1;
|
||||
return new CheckResult(ResultType.REACH, String.format("%.5f", minDistance) + " blocks");
|
||||
} else {
|
||||
cancelBuffer = Math.max(0, cancelBuffer - 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return NONE;
|
||||
}
|
||||
|
||||
private static final CheckResult NONE = new CheckResult(ResultType.NONE, "");
|
||||
|
||||
private static class CheckResult {
|
||||
private final ResultType type;
|
||||
private final String verbose;
|
||||
|
||||
public CheckResult(ResultType type, String verbose) {
|
||||
this.type = type;
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
public ResultType type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String verbose() {
|
||||
return verbose;
|
||||
}
|
||||
|
||||
public boolean isFlag() {
|
||||
return type != ResultType.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
private enum ResultType {
|
||||
REACH, HITBOX, BLOCK, ENTITY, NONE
|
||||
}
|
||||
|
||||
public void handleBlockChange(Vector3i vector3i, WrappedBlockState state) {
|
||||
if (blocksChangedThisTick.size() >= 40) return; // Don't let players freeze movement packets to grow this
|
||||
// Only do this for nearby blocks
|
||||
if (new Vector(vector3i.x, vector3i.y, vector3i.z).distanceSquared(new Vector(player.x, player.y, player.z)) > 6) return;
|
||||
// Only do this if the state really had any world impact
|
||||
if (state.equals(player.compensatedWorld.getBlock(vector3i))) return;
|
||||
blocksChangedThisTick.add(vector3i);
|
||||
}
|
||||
|
||||
// Checks if it was possible to hit a target entity
|
||||
// TODO refactor to return list of rays and why each of them didn't hit instead of closest obstruction
|
||||
// NOTE: It should be impossible for the returned Pair to be null
|
||||
// because all of the possibleLookVecsAndEyeHeights passed in should be ones that hit the target entity
|
||||
// in previous parts of this check when we didn't check for any obstructions like blocks/entities
|
||||
private @NotNull Pair<@NotNull Double, @NotNull HitData> didRayTraceHit(PacketEntity targetEntity,
|
||||
List<Pair<Vector, Double>> possibleLookVecsAndEyeHeights,
|
||||
Vector3d from) {
|
||||
HitData firstObstruction = null;
|
||||
double firstObstructionDistanceSq = 0;
|
||||
|
||||
// Check every possible look direction and every possible eye height
|
||||
for (Pair<Vector, Double> vectorDoublePair : possibleLookVecsAndEyeHeights) {
|
||||
Vector lookVec = vectorDoublePair.first();
|
||||
double eye = vectorDoublePair.second();
|
||||
|
||||
Vector eyes = new Vector(from.getX(), from.getY() + eye, from.getZ());
|
||||
// this function is completely 0.03 aware
|
||||
final HitData hitResult = BlockRayTrace.getNearestHitResult(player, targetEntity, eyes, lookVec);
|
||||
|
||||
// If we hit the target entity, it's a valid hit
|
||||
if (hitResult instanceof EntityHitData && ((EntityHitData) hitResult).getEntity().equals(targetEntity)) {
|
||||
double distanceSquared = eyes.distanceSquared(hitResult.getBlockHitLocation());
|
||||
return new Pair<>(distanceSquared, hitResult); // Legitimate hit
|
||||
} else if (hitResult != null && firstObstruction == null) {
|
||||
// Store the first obstruction only
|
||||
firstObstruction = hitResult;
|
||||
firstObstructionDistanceSq = eyes.distanceSquared(hitResult.getBlockHitLocation());
|
||||
}
|
||||
}
|
||||
|
||||
// Return the first obstruction if no valid hit found
|
||||
// Since we sort eye heights by likeniness, we should in effect return the most likely (first) obstruction
|
||||
assert firstObstruction != null;
|
||||
return new Pair<>(firstObstructionDistanceSq, firstObstruction);
|
||||
}
|
||||
|
||||
private boolean hitboxDebuggingEnabled() {
|
||||
return player.checkManager.getCheck(HitboxDebugHandler.class).isEnabled();
|
||||
}
|
||||
|
||||
private void sendHitboxDebugData(PacketEntity reachEntity, Vector3d from, List<Pair<Vector, Double>> lookVecsAndEyeHeights, boolean isPrediction) {
|
||||
Map<Integer, CollisionBox> hitboxes = new HashMap<>();
|
||||
for (Int2ObjectMap.Entry<PacketEntity> entry : player.compensatedEntities.entityMap.int2ObjectEntrySet()) {
|
||||
PacketEntity entity = entry.getValue();
|
||||
if (!entity.canHit()) continue;
|
||||
|
||||
CollisionBox box;
|
||||
|
||||
if (entity.equals(reachEntity)) {
|
||||
// Target entity gets expanded hitbox
|
||||
box = entity.getPossibleCollisionBoxes();
|
||||
SimpleCollisionBox sBox = (SimpleCollisionBox) box;
|
||||
sBox.expand(player.checkManager.getPacketCheck(Reach.class).reachThreshold);
|
||||
|
||||
// Add movement threshold uncertainty for 1.9+ or non-position updates
|
||||
if (!player.packetStateData.didLastLastMovementIncludePosition
|
||||
|| player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
|
||||
sBox.expand(player.getMovementThreshold());
|
||||
}
|
||||
} else {
|
||||
// Non-target entities
|
||||
box = entity.getMinimumPossibleCollisionBoxes();
|
||||
if (box instanceof NoCollisionBox) {
|
||||
hitboxes.put(entry.getIntKey(), NoCollisionBox.INSTANCE);
|
||||
continue;
|
||||
} else if (box instanceof SimpleCollisionBox) {
|
||||
SimpleCollisionBox sBox = (SimpleCollisionBox) box;
|
||||
sBox.expand(-player.checkManager.getPacketCheck(Reach.class).reachThreshold);
|
||||
// Shrink non-target entities by movement threshold when applicable
|
||||
if (!player.packetStateData.didLastLastMovementIncludePosition
|
||||
|| player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
|
||||
sBox.expand(-player.getMovementThreshold());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add 1.8 and below extra hitbox size
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_9)
|
||||
&& box instanceof SimpleCollisionBox) {
|
||||
((SimpleCollisionBox) box).expand(0.1f);
|
||||
}
|
||||
|
||||
hitboxes.put(entry.getIntKey(), box);
|
||||
}
|
||||
|
||||
player.checkManager.getCheck(HitboxDebugHandler.class).sendHitboxData(hitboxes,
|
||||
Collections.singleton(player.compensatedEntities.getPacketEntityID(reachEntity)),
|
||||
lookVecsAndEyeHeights,
|
||||
new Vector(from.getX(), from.getY(), from.getZ()),
|
||||
isPrediction, player.compensatedEntities.self.getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
this.ignoreNonPlayerTargets = config.getBooleanElse("Reach.ignore-non-player-targets", false);
|
||||
this.cancelImpossibleHits = config.getBooleanElse("Reach.block-impossible-hits", true);
|
||||
this.threshold = config.getDoubleElse("Reach.threshold", 0.0005);
|
||||
this.reachThreshold = config.getDoubleElse("Reach.threshold", 0.0005);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
|
||||
@CheckData(name = "CrashB")
|
||||
@CheckData(name = "CrashB", description = "Sent creative mode inventory click packets while not in creative mode")
|
||||
public class CrashB extends Check implements PacketCheck {
|
||||
public CrashB(GrimPlayer player) {
|
||||
super(player);
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.world.Location;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
@CheckData(name = "CrashC")
|
||||
@CheckData(name = "CrashC", description = "Sent non-finite position or rotation")
|
||||
public class CrashC extends Check implements PacketCheck {
|
||||
public CrashC(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClickWindow;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerOpenWindow;
|
||||
|
||||
@CheckData(name = "CrashD", experimental = false)
|
||||
@CheckData(name = "CrashD", description = "Clicking slots in lectern window")
|
||||
public class CrashD extends Check implements PacketCheck {
|
||||
|
||||
public CrashD(GrimPlayer playerData) {
|
||||
|
||||
@@ -2,14 +2,13 @@ package ac.grim.grimac.checks.impl.crash;
|
||||
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.impl.exploit.ExploitA;
|
||||
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.WrapperPlayClientSettings;
|
||||
|
||||
@CheckData(name = "CrashE", experimental = false)
|
||||
@CheckData(name = "CrashE")
|
||||
public class CrashE extends Check implements PacketCheck {
|
||||
|
||||
public CrashE(GrimPlayer playerData) {
|
||||
@@ -21,12 +20,10 @@ public class CrashE extends Check implements PacketCheck {
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLIENT_SETTINGS) {
|
||||
WrapperPlayClientSettings wrapper = new WrapperPlayClientSettings(event);
|
||||
int viewDistance = wrapper.getViewDistance();
|
||||
boolean invalidLocale = player.checkManager.getPrePredictionCheck(ExploitA.class).checkString(wrapper.getLocale());
|
||||
if (viewDistance < 2) {
|
||||
flagAndAlert("distance=" + viewDistance);
|
||||
wrapper.setViewDistance(2);
|
||||
}
|
||||
if (invalidLocale) wrapper.setLocale("en_us");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPl
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientUseItem;
|
||||
|
||||
@CheckData(name = "CrashG")
|
||||
@CheckData(name = "CrashG", description = "Sent negative sequence id")
|
||||
public class CrashG extends Check implements PacketCheck {
|
||||
|
||||
public CrashG(GrimPlayer player) {
|
||||
|
||||
@@ -32,13 +32,12 @@ public class CrashH extends Check implements PacketCheck {
|
||||
}
|
||||
// paper's patch
|
||||
final int index;
|
||||
if (text.length() > 64 && ((index = text.indexOf(' ')) == -1 || index >= 64)) {
|
||||
if (length > 64 && ((index = text.indexOf(' ')) == -1 || index >= 64)) {
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
flagAndAlert("(invalid) length=" + length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package ac.grim.grimac.checks.impl.elytra;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "ElytraA", description = "Started gliding while already gliding", experimental = true)
|
||||
public class ElytraA extends Check implements PostPredictionCheck {
|
||||
private boolean setback;
|
||||
|
||||
public ElytraA(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
public void onStartGliding(PacketReceiveEvent event) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isGliding && flagAndAlert()) {
|
||||
setback = true;
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
player.resyncPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_15) && event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION
|
||||
&& new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_FLYING_WITH_ELYTRA
|
||||
) onStartGliding(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (setback) {
|
||||
setbackIfAboveSetbackVL();
|
||||
setback = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package ac.grim.grimac.checks.impl.elytra;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "ElytraB", description = "Started gliding without jumping", experimental = true)
|
||||
public class ElytraB extends Check implements PostPredictionCheck {
|
||||
private boolean glide;
|
||||
private boolean setback;
|
||||
|
||||
public ElytraB(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION
|
||||
&& new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_FLYING_WITH_ELYTRA
|
||||
&& player.supportsEndTick()
|
||||
) {
|
||||
if (player.packetStateData.knownInput.jump()) {
|
||||
if (flagAndAlert("no release")) {
|
||||
setback = true;
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
player.resyncPose();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
glide = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isUpdate(event.getPacketType())) {
|
||||
if (glide && !player.packetStateData.knownInput.jump() && flagAndAlert("no jump")) {
|
||||
setback = true;
|
||||
}
|
||||
|
||||
glide = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (setback) {
|
||||
setback = false;
|
||||
setbackIfAboveSetbackVL();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package ac.grim.grimac.checks.impl.elytra;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "ElytraC", description = "Started gliding too frequently", experimental = true)
|
||||
public class ElytraC extends Check implements PostPredictionCheck {
|
||||
private boolean glideThisTick, glideLastTick, setback;
|
||||
private int flags;
|
||||
|
||||
public ElytraC(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.gamemode == GameMode.SPECTATOR) {
|
||||
glideThisTick = glideLastTick = false;
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION && new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_FLYING_WITH_ELYTRA) {
|
||||
if (glideThisTick || glideLastTick) {
|
||||
if (player.canSkipTicks()) {
|
||||
flags++;
|
||||
} else {
|
||||
if (flagAndAlert()) {
|
||||
setback = true;
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
player.resyncPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glideThisTick = true;
|
||||
}
|
||||
|
||||
if (isTickPacket(event.getPacketType())) {
|
||||
glideLastTick = glideThisTick;
|
||||
glideThisTick = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (player.canSkipTicks()) {
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; flags > 0; flags--) {
|
||||
flagAndAlert();
|
||||
}
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
setback = false;
|
||||
}
|
||||
|
||||
if (setback) {
|
||||
setback = false;
|
||||
setbackIfAboveSetbackVL();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package ac.grim.grimac.checks.impl.elytra;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "ElytraD", description = "Started gliding without an elytra", experimental = true)
|
||||
public class ElytraD extends Check implements PostPredictionCheck {
|
||||
private boolean setback;
|
||||
|
||||
public ElytraD(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION
|
||||
&& new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_FLYING_WITH_ELYTRA
|
||||
&& !player.canGlide()
|
||||
&& flagAndAlert()
|
||||
) {
|
||||
setback = true;
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
player.resyncPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (setback) {
|
||||
setbackIfAboveSetbackVL();
|
||||
setback = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package ac.grim.grimac.checks.impl.elytra;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "ElytraE", description = "Started gliding while flying", experimental = true)
|
||||
public class ElytraE extends Check implements PostPredictionCheck {
|
||||
private boolean setback;
|
||||
|
||||
public ElytraE(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION
|
||||
&& new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_FLYING_WITH_ELYTRA
|
||||
&& player.isFlying
|
||||
&& flagAndAlert()
|
||||
) {
|
||||
setback = true;
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
player.resyncPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (setback) {
|
||||
setbackIfAboveSetbackVL();
|
||||
setback = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package ac.grim.grimac.checks.impl.elytra;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "ElytraF", description = "Started gliding while on ground", experimental = true)
|
||||
public class ElytraF extends Check implements PostPredictionCheck {
|
||||
private boolean setback;
|
||||
|
||||
public ElytraF(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION
|
||||
&& new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_FLYING_WITH_ELYTRA
|
||||
&& player.clientClaimsLastOnGround
|
||||
&& flagAndAlert()
|
||||
) {
|
||||
setback = true;
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
player.resyncPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (setback) {
|
||||
setbackIfAboveSetbackVL();
|
||||
setback = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package ac.grim.grimac.checks.impl.elytra;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "ElytraG", description = "Started gliding with levitation", experimental = true)
|
||||
public class ElytraG extends Check implements PostPredictionCheck {
|
||||
private boolean setback;
|
||||
|
||||
public ElytraG(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION
|
||||
&& new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_FLYING_WITH_ELYTRA
|
||||
&& player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_16)
|
||||
&& player.compensatedEntities.self.hasPotionEffect(PotionTypes.LEVITATION)
|
||||
&& flagAndAlert()
|
||||
) {
|
||||
setback = true;
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
player.resyncPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (setback) {
|
||||
setbackIfAboveSetbackVL();
|
||||
setback = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package ac.grim.grimac.checks.impl.elytra;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "ElytraH", description = "Started gliding in vehicle", experimental = true)
|
||||
public class ElytraH extends Check implements PostPredictionCheck {
|
||||
private boolean setback;
|
||||
|
||||
public ElytraH(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION
|
||||
&& new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_FLYING_WITH_ELYTRA
|
||||
&& player.inVehicle()
|
||||
&& flagAndAlert()
|
||||
) {
|
||||
setback = true;
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
player.resyncPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (setback) {
|
||||
setbackIfAboveSetbackVL();
|
||||
setback = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package ac.grim.grimac.checks.impl.elytra;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "ElytraI", description = "Started gliding in water", experimental = true)
|
||||
public class ElytraI extends Check implements PostPredictionCheck {
|
||||
private boolean setback;
|
||||
|
||||
public ElytraI(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION
|
||||
&& new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_FLYING_WITH_ELYTRA
|
||||
&& player.wasTouchingWater
|
||||
&& player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_15)
|
||||
&& flagAndAlert()
|
||||
) {
|
||||
setback = true;
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
player.resyncPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (setback) {
|
||||
setbackIfAboveSetbackVL();
|
||||
setback = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,11 @@ 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.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientChatMessage;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientNameItem;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientTabComplete;
|
||||
|
||||
@CheckData(name = "ExploitA", experimental = true)
|
||||
public class ExploitA extends Check implements PacketCheck {
|
||||
@@ -18,35 +17,18 @@ public class ExploitA extends Check implements PacketCheck {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
private static final Pattern EXPLOIT_PATTERN = Pattern.compile("\\$\\{.+}");
|
||||
|
||||
/*
|
||||
WARNING: This doesn't fully patch Log4J! It is highly recommended you update your server
|
||||
jar to a version that has true Log4J migrations instead of using a plugin. However, this
|
||||
patch is better than nothing and will still be useful for punishing players who attempt
|
||||
to abuse this exploit.
|
||||
*/
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.CHAT_MESSAGE) {
|
||||
if (true) return; // TODO: Fix PacketEvents pls retrooper
|
||||
WrapperPlayClientChatMessage wrapper = new WrapperPlayClientChatMessage(event);
|
||||
String message = wrapper.getMessage();
|
||||
if (checkString(message)) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else if (event.getPacketType() == PacketType.Play.Client.NAME_ITEM) {
|
||||
WrapperPlayClientNameItem wrapper = new WrapperPlayClientNameItem(event);
|
||||
String name = wrapper.getItemName();
|
||||
if (checkString(name)) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
if (event.getPacketType() == PacketType.Play.Client.TAB_COMPLETE && PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13)) {
|
||||
WrapperPlayClientTabComplete wrapper = new WrapperPlayClientTabComplete(event);
|
||||
String text = wrapper.getText();
|
||||
if (text.equals("/") || text.trim().isEmpty()) {
|
||||
if (flagAndAlert("")) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkString(String message) {
|
||||
return EXPLOIT_PATTERN.matcher(message).matches() && flagAndAlert();
|
||||
}
|
||||
}
|
||||
@@ -4,31 +4,29 @@ 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.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientTabComplete;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEditBook;
|
||||
|
||||
@CheckData(name = "ExploitB", experimental = true)
|
||||
@CheckData(name = "ExploitB", description = "Too long book title")
|
||||
public class ExploitB extends Check implements PacketCheck {
|
||||
|
||||
public ExploitB(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.TAB_COMPLETE && PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13)) {
|
||||
WrapperPlayClientTabComplete wrapper = new WrapperPlayClientTabComplete(event);
|
||||
String text = wrapper.getText();
|
||||
if (text.equals("/") || text.trim().length() == 0) {
|
||||
if (flagAndAlert("")) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.EDIT_BOOK) {
|
||||
final String title = new WrapperPlayClientEditBook(event).getTitle();
|
||||
|
||||
if (title == null) return; // book was not signed
|
||||
|
||||
if (title.length() > 15) {
|
||||
if (flagAndAlert("title=" + title) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package ac.grim.grimac.checks.impl.exploit;
|
||||
|
||||
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.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientChatCommand;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientChatCommandUnsigned;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientChatMessage;
|
||||
|
||||
// this can false from click events, but I doubt this would actually
|
||||
// happen unless they're trying to flag, or if the server is set up badly
|
||||
@CheckData(name = "ExploitC", description = "Invalid chat message")
|
||||
public class ExploitC extends Check implements PacketCheck {
|
||||
public ExploitC(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.CHAT_MESSAGE) {
|
||||
String message = new WrapperPlayClientChatMessage(event).getMessage();
|
||||
if (message.isEmpty() || !message.trim().equals(message) || message.startsWith("/") && PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_19)) {
|
||||
if (flagAndAlert("message=" + message)) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.CHAT_COMMAND_UNSIGNED) {
|
||||
String command = "/" + new WrapperPlayClientChatCommandUnsigned(event).getCommand();
|
||||
String strippedCommand = command.replaceAll("\\s+$", ""); // Remove trailing whitespace
|
||||
if (!strippedCommand.equals(command)) {
|
||||
if (flagAndAlert("command=" + command)) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.CHAT_COMMAND) {
|
||||
String command = "/" + new WrapperPlayClientChatCommand(event).getCommand();
|
||||
if (!command.trim().equals(command)) {
|
||||
if (flagAndAlert("command=" + command)) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -17,12 +17,12 @@ import java.util.List;
|
||||
|
||||
// Catches NoFalls for LOOK and GROUND packets
|
||||
// This check runs AFTER the predictions
|
||||
@CheckData(name = "NoFall", configName = "nofall", setback = 10)
|
||||
public class NoFallA extends Check implements PacketCheck {
|
||||
@CheckData(name = "NoFall", setback = 10)
|
||||
public class NoFall extends Check implements PacketCheck {
|
||||
|
||||
public boolean flipPlayerGroundStatus = false;
|
||||
|
||||
public NoFallA(GrimPlayer player) {
|
||||
public NoFall(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class NoFallA extends Check implements PacketCheck {
|
||||
if (wrapper.isOnGround() && !hasPosition) {
|
||||
if (!isNearGround(wrapper.isOnGround())) { // If player isn't near ground
|
||||
// 1.8 boats have a mind on their own... only flag if they're not near a boat or are on 1.9+
|
||||
if (!GhostBlockDetector.isGhostBlock(player) && flagWithSetback()) alert("");
|
||||
if (!GhostBlockDetector.isGhostBlock(player)) flagAndAlertWithSetback();
|
||||
if (shouldModifyPackets()) {
|
||||
wrapper.setOnGround(false);
|
||||
event.markForReEncode(true);
|
||||
@@ -0,0 +1,42 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
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 com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity.InteractAction;
|
||||
|
||||
@CheckData(name = "InventoryA", setback = 3, description = "Attacked an entity while inventory is open")
|
||||
public class InventoryA extends InventoryCheck {
|
||||
public InventoryA(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
super.onPacketReceive(event);
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
WrapperPlayClientInteractEntity wrapper = new WrapperPlayClientInteractEntity(event);
|
||||
|
||||
if (wrapper.getAction() != InteractAction.ATTACK) return;
|
||||
|
||||
// Is not possible to attack while the inventory is open.
|
||||
if (player.hasInventoryOpen) {
|
||||
if (flagAndAlert()) {
|
||||
// Cancel the packet
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
if (!isNoSetbackPermission())
|
||||
closeInventory();
|
||||
}
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
@CheckData(name = "InventoryB", setback = 3, description = "Started digging blocks while inventory is open")
|
||||
public class InventoryB extends InventoryCheck {
|
||||
public InventoryB(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
public void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging wrapper) {
|
||||
if (wrapper.getAction() != DiggingAction.START_DIGGING) return;
|
||||
|
||||
// Is not possible to start digging a block while the inventory is open.
|
||||
if (player.hasInventoryOpen) {
|
||||
if (flagAndAlert()) {
|
||||
// Cancel the packet
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
if (!isNoSetbackPermission()) {
|
||||
closeInventory();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
|
||||
|
||||
@CheckData(name = "InventoryC", setback = 3, description = "Placed a block while inventory is open")
|
||||
public class InventoryC extends InventoryCheck {
|
||||
|
||||
public InventoryC(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
public void onBlockPlace(final BlockPlace place) {
|
||||
// It is not possible to place a block while the inventory is open
|
||||
if (player.hasInventoryOpen) {
|
||||
if (flagAndAlert()) {
|
||||
if (shouldModifyPackets()) {
|
||||
place.resync();
|
||||
}
|
||||
if (!isNoSetbackPermission()) {
|
||||
closeInventory();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
|
||||
import ac.grim.grimac.utils.data.VectorData;
|
||||
import ac.grim.grimac.utils.data.VectorData.MoveVectorData;
|
||||
import ac.grim.grimac.utils.data.VehicleData;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
@CheckData(name = "InventoryD", setback = 1, decay = 0.25)
|
||||
public class InventoryD extends InventoryCheck {
|
||||
private int horseJumpVerbose;
|
||||
|
||||
public InventoryD(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(final PredictionComplete predictionComplete) {
|
||||
if (!predictionComplete.isChecked() ||
|
||||
predictionComplete.getData().isTeleport() ||
|
||||
player.getSetbackTeleportUtil().blockOffsets ||
|
||||
player.packetStateData.lastPacketWasTeleport ||
|
||||
player.packetStateData.isSlowedByUsingItem() ||
|
||||
System.currentTimeMillis() - player.lastBlockPlaceUseItem < 50L) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.hasInventoryOpen) {
|
||||
boolean inVehicle = player.inVehicle();
|
||||
boolean isJumping, isMoving;
|
||||
|
||||
if (inVehicle) {
|
||||
VehicleData vehicle = player.vehicleData;
|
||||
|
||||
// Will flag once if player open anything with pressed space bar
|
||||
isJumping = vehicle.nextHorseJump > 0 && horseJumpVerbose++ >= 1;
|
||||
isMoving = vehicle.nextVehicleForward != 0 || vehicle.nextVehicleHorizontal != 0;
|
||||
} else {
|
||||
MoveVectorData move = findMovement(player.predictedVelocity);
|
||||
|
||||
isJumping = player.predictedVelocity.isJump();
|
||||
isMoving = move != null && (move.x != 0 || move.z != 0);
|
||||
}
|
||||
|
||||
if (!isMoving && !isJumping) {
|
||||
reward();
|
||||
return;
|
||||
}
|
||||
|
||||
if (flag()) {
|
||||
if (!isNoSetbackPermission())
|
||||
closeInventory();
|
||||
|
||||
StringJoiner joiner = new StringJoiner(" ");
|
||||
|
||||
if (isMoving) joiner.add("moving");
|
||||
if (isJumping) joiner.add("jumping");
|
||||
if (inVehicle) joiner.add("inVehicle");
|
||||
|
||||
alert(joiner.toString());
|
||||
}
|
||||
} else {
|
||||
horseJumpVerbose = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private MoveVectorData findMovement(VectorData vectorData) {
|
||||
if (vectorData instanceof MoveVectorData) {
|
||||
return (MoveVectorData) vectorData;
|
||||
}
|
||||
|
||||
while (vectorData != null) {
|
||||
vectorData = vectorData.lastVector;
|
||||
if (vectorData instanceof MoveVectorData) {
|
||||
return (MoveVectorData) vectorData;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.event.PacketSendEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
|
||||
@CheckData(name = "InventoryE", setback = 3, description = "Sent a held item change packet while inventory is open")
|
||||
public class InventoryE extends InventoryCheck {
|
||||
private long lastTransaction = Long.MAX_VALUE; // Impossible transaction ID
|
||||
|
||||
public InventoryE(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
super.onPacketReceive(event);
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.HELD_ITEM_CHANGE) {
|
||||
// It is not possible to change hotbar slots with held item change while the inventory is open
|
||||
// A container click packet would be sent instead
|
||||
if (player.hasInventoryOpen) {
|
||||
if (this.lastTransaction < player.lastTransactionReceived.get()
|
||||
&& flagAndAlert()) {
|
||||
// Cancel the packet
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
player.getInventory().needResend = true;
|
||||
}
|
||||
if (!isNoSetbackPermission()) {
|
||||
closeInventory();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(PacketSendEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Server.HELD_ITEM_CHANGE) {
|
||||
this.lastTransaction = player.lastTransactionSent.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.inventory.InventoryDesyncStatus;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
|
||||
@CheckData(name = "InventoryF", setback = 3, description = "Sent a click window packet without a open inventory", experimental = true)
|
||||
public class InventoryF extends InventoryCheck {
|
||||
|
||||
public InventoryF(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
// Exempt on 1.9+ server version due to the Via hack done in PacketPlayerWindow, the exemption can be deleted
|
||||
// once we are ahead of ViaVersion
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)
|
||||
|| player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) return;
|
||||
|
||||
super.onPacketReceive(event);
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
|
||||
if (!player.hasInventoryOpen && player.inventoryDesyncStatus == InventoryDesyncStatus.NOT_DESYNCED) {
|
||||
if (flagAndAlert()) {
|
||||
// Cancel the packet
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
if (!isNoSetbackPermission()) {
|
||||
closeInventory();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package ac.grim.grimac.checks.impl.inventory;
|
||||
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.InventoryCheck;
|
||||
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;
|
||||
|
||||
@CheckData(name = "InventoryG", setback = 3, description = "Sent a entity action packet while inventory is open", experimental = true)
|
||||
public class InventoryG extends InventoryCheck {
|
||||
|
||||
public InventoryG(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.packetStateData.lastPacketWasTeleport) return;
|
||||
super.onPacketReceive(event);
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
|
||||
WrapperPlayClientEntityAction wrapper = new WrapperPlayClientEntityAction(event);
|
||||
WrapperPlayClientEntityAction.Action action = wrapper.getAction();
|
||||
|
||||
if (action == WrapperPlayClientEntityAction.Action.STOP_SNEAKING
|
||||
|| action == WrapperPlayClientEntityAction.Action.STOP_SPRINTING) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.hasInventoryOpen) {
|
||||
if (flagAndAlert() && !isNoSetbackPermission()) {
|
||||
closeInventory();
|
||||
}
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,27 @@ package ac.grim.grimac.checks.impl.misc;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.impl.exploit.ExploitA;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.MessageUtil;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.configuration.client.WrapperConfigClientPluginMessage;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPluginMessage;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class ClientBrand extends Check implements PacketCheck {
|
||||
String brand = "vanilla";
|
||||
boolean hasBrand = false;
|
||||
public static final String channel = PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13) ? "minecraft:brand" : "MC|Brand";
|
||||
|
||||
@Getter
|
||||
private String brand = "vanilla";
|
||||
private boolean hasBrand = false;
|
||||
|
||||
public ClientBrand(GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -24,40 +32,37 @@ public class ClientBrand extends Check implements PacketCheck {
|
||||
public void onPacketReceive(final PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLUGIN_MESSAGE) {
|
||||
WrapperPlayClientPluginMessage packet = new WrapperPlayClientPluginMessage(event);
|
||||
String channelName = packet.getChannelName();
|
||||
handle(channelName, packet.getData());
|
||||
handle(packet.getChannelName(), packet.getData());
|
||||
} else if (event.getPacketType() == PacketType.Configuration.Client.PLUGIN_MESSAGE) {
|
||||
WrapperConfigClientPluginMessage packet = new WrapperConfigClientPluginMessage(event);
|
||||
handle(packet.getChannelName(), packet.getData());
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(String channel, byte[] data) {
|
||||
if (channel.equalsIgnoreCase("minecraft:brand") || // 1.13+
|
||||
channel.equals("MC|Brand")) { // 1.12
|
||||
if (data.length > 64 || data.length == 0) {
|
||||
brand = "sent " + data.length + " bytes as brand";
|
||||
} else if (!hasBrand) {
|
||||
byte[] minusLength = new byte[data.length - 1];
|
||||
System.arraycopy(data, 1, minusLength, 0, minusLength.length);
|
||||
|
||||
brand = new String(minusLength).replace(" (Velocity)", ""); //removes velocity's brand suffix
|
||||
brand = ChatColor.stripColor(brand); //strip color codes from client brand
|
||||
if (player.checkManager.getPrePredictionCheck(ExploitA.class).checkString(brand)) brand = "sent log4j";
|
||||
if (!GrimAPI.INSTANCE.getConfigManager().isIgnoredClient(brand)) {
|
||||
String message = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("client-brand-format", "%prefix% &f%player% joined using %brand%");
|
||||
message = GrimAPI.INSTANCE.getExternalAPI().replaceVariables(getPlayer(), message, true);
|
||||
// sendMessage is async safe while broadcast isn't due to adventure
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (player.hasPermission("grim.brand")) {
|
||||
player.sendMessage(message);
|
||||
}
|
||||
private void handle(String channel, byte[] data) {
|
||||
if (!channel.equals(ClientBrand.channel)) return;
|
||||
|
||||
if (data.length > 64 || data.length == 0) {
|
||||
brand = "sent " + data.length + " bytes as brand";
|
||||
} else if (!hasBrand) {
|
||||
byte[] minusLength = new byte[data.length - 1];
|
||||
System.arraycopy(data, 1, minusLength, 0, minusLength.length);
|
||||
|
||||
brand = new String(minusLength).replace(" (Velocity)", ""); //removes velocity's brand suffix
|
||||
brand = ChatColor.stripColor(brand); //strip color codes from client brand
|
||||
if (!GrimAPI.INSTANCE.getConfigManager().isIgnoredClient(brand)) {
|
||||
String message = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("client-brand-format", "%prefix% &f%player% joined using %brand%");
|
||||
Component component = MessageUtil.replacePlaceholders(player, MessageUtil.miniMessage(message));
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (GrimAPI.INSTANCE.getAlertManager().hasBrandsEnabled(player)) {
|
||||
MessageUtil.sendMessage(player, component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hasBrand = true;
|
||||
}
|
||||
}
|
||||
|
||||
public String getBrand() {
|
||||
return brand;
|
||||
hasBrand = true;
|
||||
}
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.misc;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
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.math.GrimMath;
|
||||
import ac.grim.grimac.utils.nmsutil.BlockBreakSpeed;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerAcknowledgeBlockChanges;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerBlockChange;
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
// 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", experimental = false)
|
||||
public class FastBreak extends Check implements PacketCheck {
|
||||
public FastBreak(GrimPlayer playerData) {
|
||||
super(playerData);
|
||||
}
|
||||
|
||||
// The block the player is currently breaking
|
||||
Vector3i targetBlock = 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 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(ClientVersion.V_1_9) ? event.getPacketType() == PacketType.Play.Client.ANIMATION : WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) && targetBlock != null) {
|
||||
maximumBlockDamage = Math.max(maximumBlockDamage, BlockBreakSpeed.getBlockDamage(player, targetBlock));
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
|
||||
WrapperPlayClientPlayerDigging digging = new WrapperPlayClientPlayerDigging(event);
|
||||
final Vector3i blockPosition = digging.getBlockPosition();
|
||||
|
||||
if (digging.getAction() == DiggingAction.START_DIGGING) {
|
||||
WrappedBlockState block = player.compensatedWorld.getWrappedBlockStateAt(blockPosition);
|
||||
|
||||
// Exempt all blocks that do not exist in the player version
|
||||
if (WrappedBlockState.getDefaultState(player.getClientVersion(), block.getType()).getType() == StateTypes.AIR) {
|
||||
return;
|
||||
}
|
||||
|
||||
startBreak = System.currentTimeMillis() - (targetBlock == null ? 50 : 0); // ???
|
||||
targetBlock = blockPosition;
|
||||
|
||||
maximumBlockDamage = BlockBreakSpeed.getBlockDamage(player, targetBlock);
|
||||
|
||||
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
|
||||
flagAndAlert("Delay=" + breakDelay);
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true); // Cancelling start digging will cause server to reject block break
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
|
||||
clampBalance();
|
||||
}
|
||||
|
||||
if (digging.getAction() == DiggingAction.FINISHED_DIGGING && targetBlock != 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
|
||||
FoliaScheduler.getEntityScheduler().execute(player.bukkitPlayer, GrimAPI.INSTANCE.getPlugin(), () -> {
|
||||
Player bukkitPlayer = player.bukkitPlayer;
|
||||
if (bukkitPlayer == null || !bukkitPlayer.isOnline()) return;
|
||||
|
||||
if (bukkitPlayer.getLocation().distance(new Location(bukkitPlayer.getWorld(), blockPosition.getX(), blockPosition.getY(), blockPosition.getZ())) < 64) {
|
||||
final int chunkX = blockPosition.getX() >> 4;
|
||||
final int chunkZ = blockPosition.getZ() >> 4;
|
||||
if (!bukkitPlayer.getWorld().isChunkLoaded(chunkX, chunkZ)) return; // Don't load chunks sync
|
||||
|
||||
Chunk chunk = bukkitPlayer.getWorld().getChunkAt(chunkX, chunkZ);
|
||||
Block block = chunk.getBlock(blockPosition.getX() & 15, blockPosition.getY(), blockPosition.getZ() & 15);
|
||||
|
||||
int blockId;
|
||||
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13)) {
|
||||
// Cache this because strings are expensive
|
||||
blockId = WrappedBlockState.getByString(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), block.getBlockData().getAsString(false)).getGlobalId();
|
||||
} else {
|
||||
blockId = (block.getType().getId() << 4) | block.getData();
|
||||
}
|
||||
|
||||
player.user.sendPacket(new WrapperPlayServerBlockChange(blockPosition, blockId));
|
||||
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_19)) { // Via will handle this for us pre-1.19
|
||||
player.user.sendPacket(new WrapperPlayServerAcknowledgeBlockChanges(digging.getSequence())); // Make 1.19 clients apply the changes
|
||||
}
|
||||
}
|
||||
}, null, 0);
|
||||
|
||||
if (flagAndAlert("Diff=" + diff + ",Balance=" + blockBreakBalance) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
|
||||
lastFinishBreak = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,9 @@ import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
|
||||
|
||||
@CheckData(name = "TransactionOrder", experimental = false)
|
||||
@CheckData(name = "TransactionOrder")
|
||||
public class TransactionOrder extends Check implements PacketCheck {
|
||||
|
||||
public TransactionOrder(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.movement;
|
||||
|
||||
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;
|
||||
|
||||
@CheckData(name = "Entity control", configName = "EntityControl")
|
||||
public class EntityControl extends Check implements PostPredictionCheck {
|
||||
public EntityControl(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
public void rewardPlayer() {
|
||||
reward();
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -8,8 +8,8 @@ import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
|
||||
@CheckData(name = "NoSlowA (Prediction)", configName = "NoSlowA", setback = 5)
|
||||
public class NoSlowA extends Check implements PostPredictionCheck {
|
||||
@CheckData(name = "NoSlow", description = "Was not slowed while using an item", setback = 5)
|
||||
public class NoSlow extends Check implements PostPredictionCheck {
|
||||
double offsetToFlag;
|
||||
double bestOffset = 1;
|
||||
// The player sends that they switched items the next tick if they switch from an item that can be used
|
||||
@@ -17,7 +17,7 @@ public class NoSlowA extends Check implements PostPredictionCheck {
|
||||
public boolean didSlotChangeLastTick = false;
|
||||
public boolean flaggedLastTick = false;
|
||||
|
||||
public NoSlowA(GrimPlayer player) {
|
||||
public NoSlow(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ public class NoSlowA extends Check implements PostPredictionCheck {
|
||||
}
|
||||
|
||||
if (bestOffset > offsetToFlag) {
|
||||
if (flaggedLastTick && flagWithSetback()) {
|
||||
alert("");
|
||||
if (flaggedLastTick) {
|
||||
flagAndAlertWithSetback();
|
||||
}
|
||||
flaggedLastTick = true;
|
||||
} else {
|
||||
@@ -52,6 +52,6 @@ public class NoSlowA extends Check implements PostPredictionCheck {
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
offsetToFlag = config.getDoubleElse("NoSlowA.threshold", 0.001);
|
||||
offsetToFlag = config.getDoubleElse(getConfigName() + ".threshold", 0.001);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package ac.grim.grimac.checks.impl.movement;
|
||||
|
||||
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 com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
|
||||
@CheckData(name = "NoSlowC", setback = 5, experimental = true)
|
||||
public class NoSlowC extends Check implements PostPredictionCheck {
|
||||
public NoSlowC(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(final PredictionComplete predictionComplete) {
|
||||
if (!predictionComplete.isChecked()) return;
|
||||
|
||||
if (player.isSlowMovement) {
|
||||
ClientVersion client = player.getClientVersion();
|
||||
|
||||
// https://bugs.mojang.com/browse/MC-152728
|
||||
if (client.isNewerThanOrEquals(ClientVersion.V_1_14_2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isSprinting
|
||||
// you can sneak and swim in 1.13 - 1.14.1
|
||||
&& (!player.isSwimming || client.isNewerThan(ClientVersion.V_1_14_1) || client.isOlderThan(ClientVersion.V_1_13))
|
||||
&& player.sneakingSpeedMultiplier < 0.8f
|
||||
) {
|
||||
if (flagWithSetback()) alert("");
|
||||
} else reward();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ public class PredictionRunner extends Check implements PositionCheck {
|
||||
|
||||
@Override
|
||||
public void onPositionUpdate(final PositionUpdate positionUpdate) {
|
||||
if (!player.compensatedEntities.getSelf().inVehicle()) {
|
||||
if (!player.inVehicle()) {
|
||||
player.movementCheckRunner.processAndCheckMovementPacket(positionUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public class SetbackBlocker extends Check implements PacketCheck {
|
||||
}
|
||||
|
||||
// Look is the only valid packet to send while in a vehicle
|
||||
if (player.compensatedEntities.getSelf().inVehicle() && event.getPacketType() != PacketType.Play.Client.PLAYER_ROTATION && !player.packetStateData.lastPacketWasTeleport) {
|
||||
if (player.inVehicle() && event.getPacketType() != PacketType.Play.Client.PLAYER_ROTATION && !player.packetStateData.lastPacketWasTeleport) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class SetbackBlocker extends Check implements PacketCheck {
|
||||
}
|
||||
|
||||
// Player is dead
|
||||
if (player.compensatedEntities.getSelf().isDead) {
|
||||
if (player.compensatedEntities.self.isDead) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public class SetbackBlocker extends Check implements PacketCheck {
|
||||
}
|
||||
|
||||
// Don't let a player move a vehicle when not in a vehicle
|
||||
if (!player.compensatedEntities.getSelf().inVehicle()) {
|
||||
if (!player.inVehicle()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class SetbackBlocker extends Check implements PacketCheck {
|
||||
}
|
||||
|
||||
// Player is dead
|
||||
if (player.compensatedEntities.getSelf().isDead) {
|
||||
if (player.compensatedEntities.self.isDead) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package ac.grim.grimac.checks.impl.multiactions;
|
||||
|
||||
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.InteractionHand;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
|
||||
@CheckData(name = "MultiActionsA", description = "Attacked while using an item", experimental = true)
|
||||
public class MultiActionsA extends Check implements PacketCheck {
|
||||
public MultiActionsA(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.packetStateData.isSlowedByUsingItem() && (player.packetStateData.lastSlotSelected == player.packetStateData.getSlowedByUsingItemSlot() || player.packetStateData.eatingHand == InteractionHand.OFF_HAND) && event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
if (new WrapperPlayClientInteractEntity(event).getAction() == WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package ac.grim.grimac.checks.impl.multiactions;
|
||||
|
||||
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.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
import static ac.grim.grimac.events.packets.patch.ResyncWorldUtil.resyncPosition;
|
||||
|
||||
@CheckData(name = "MultiActionsB", description = "Breaking blocks while using an item", experimental = true)
|
||||
public class MultiActionsB extends Check implements PacketCheck {
|
||||
public MultiActionsB(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (player.packetStateData.isSlowedByUsingItem() && (player.packetStateData.lastSlotSelected == player.packetStateData.getSlowedByUsingItemSlot() || player.packetStateData.eatingHand == InteractionHand.OFF_HAND) && event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
|
||||
// this is vanilla on 1.7
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
|
||||
|
||||
if (packet.getAction() == DiggingAction.START_DIGGING || packet.getAction() == DiggingAction.CANCELLED_DIGGING || packet.getAction() == DiggingAction.FINISHED_DIGGING) {
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
resyncPosition(player, packet.getBlockPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package ac.grim.grimac.checks.impl.multiactions;
|
||||
|
||||
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.event.PacketSendEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
|
||||
@CheckData(name = "MultiActionsC", description = "Clicked in inventory while sprinting", experimental = true)
|
||||
public class MultiActionsC extends Check implements PacketCheck {
|
||||
public MultiActionsC(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private boolean serverOpenedInventoryThisTick;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
|
||||
|
||||
if (player.isSprinting && !player.isSwimming && !serverOpenedInventoryThisTick && flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
|
||||
if (isTickPacket(event.getPacketType())) {
|
||||
serverOpenedInventoryThisTick = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(PacketSendEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Server.OPEN_WINDOW) {
|
||||
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> serverOpenedInventoryThisTick = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package ac.grim.grimac.checks.impl.multiactions;
|
||||
|
||||
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;
|
||||
|
||||
@CheckData(name = "MultiActionsD", description = "Closed inventory while sprinting", experimental = true)
|
||||
public class MultiActionsD extends Check implements PacketCheck {
|
||||
public MultiActionsD(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLOSE_WINDOW) {
|
||||
if (player.isSprinting && !player.isSwimming && flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package ac.grim.grimac.checks.impl.multiactions;
|
||||
|
||||
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.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
@CheckData(name = "MultiActionsE", description = "Swinging while using an item", experimental = true)
|
||||
public class MultiActionsE extends Check implements PacketCheck {
|
||||
public MultiActionsE(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private boolean dropping;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (!dropping && player.packetStateData.isSlowedByUsingItem() && (player.packetStateData.lastSlotSelected == player.packetStateData.getSlowedByUsingItemSlot() || player.packetStateData.eatingHand == InteractionHand.OFF_HAND) && event.getPacketType() == PacketType.Play.Client.ANIMATION) {
|
||||
// this is possible to false on 1.7
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
|
||||
dropping = false;
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_15)) {
|
||||
DiggingAction action = new WrapperPlayClientPlayerDigging(event).getAction();
|
||||
dropping = action == DiggingAction.DROP_ITEM || action == DiggingAction.DROP_ITEM_STACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package ac.grim.grimac.checks.impl.multiactions;
|
||||
|
||||
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.BlockPlace;
|
||||
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static ac.grim.grimac.events.packets.patch.ResyncWorldUtil.resyncPosition;
|
||||
|
||||
@CheckData(name = "MultiActionsF", description = "Interacting with a block and an entity in the same tick", experimental = true)
|
||||
public class MultiActionsF extends BlockPlaceCheck {
|
||||
public MultiActionsF(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private final List<String> flags = new ArrayList<>();
|
||||
boolean entity, block;
|
||||
|
||||
@Override
|
||||
public void onBlockPlace(BlockPlace place) {
|
||||
block = true;
|
||||
if (entity) {
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert("place") && shouldModifyPackets() && shouldCancel()) {
|
||||
place.resync();
|
||||
}
|
||||
} else {
|
||||
flags.add("place");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
entity = true;
|
||||
if (block) {
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert("entity") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
flags.add("entity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
|
||||
WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
|
||||
if (packet.getAction() == DiggingAction.START_DIGGING || packet.getAction() == DiggingAction.FINISHED_DIGGING) {
|
||||
block = true;
|
||||
if (entity) {
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert("dig") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
resyncPosition(player, packet.getBlockPosition());
|
||||
}
|
||||
} else {
|
||||
flags.add("dig");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isTickPacket(event.getPacketType())) {
|
||||
block = entity = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (!player.canSkipTicks()) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (String verbose : flags) {
|
||||
flagAndAlert(verbose);
|
||||
}
|
||||
}
|
||||
|
||||
flags.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClickWindow;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClickWindow.WindowClickType;
|
||||
|
||||
@CheckData(name = "PacketOrderA", experimental = true)
|
||||
public class PacketOrderA extends Check implements PostPredictionCheck {
|
||||
public PacketOrderA(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int invalid;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
|
||||
final WindowClickType clickType = new WrapperPlayClientClickWindow(event).getWindowClickType();
|
||||
|
||||
if ((clickType == WindowClickType.PICKUP || clickType == WindowClickType.PICKUP_ALL) && player.packetOrderProcessor.isQuickMoveClicking()
|
||||
|| clickType == WindowClickType.QUICK_MOVE && player.packetOrderProcessor.isPickUpClicking()) {
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert() && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (!player.canSkipTicks()) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; invalid >= 1; invalid--) {
|
||||
flagAndAlert();
|
||||
}
|
||||
}
|
||||
|
||||
invalid = 0;
|
||||
}
|
||||
}
|
||||
+40
-10
@@ -1,4 +1,4 @@
|
||||
package ac.grim.grimac.checks.impl.badpackets;
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
@@ -9,25 +9,33 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
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.protocol.player.InteractionHand;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
|
||||
@CheckData(name = "BadPacketsM", experimental = true)
|
||||
public class BadPacketsM extends Check implements PacketCheck {
|
||||
public BadPacketsM(final GrimPlayer player) {
|
||||
@CheckData(name = "PacketOrderC")
|
||||
public class PacketOrderC extends Check implements PacketCheck {
|
||||
public PacketOrderC(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
// 1.7 players do not send INTERACT_AT, so we cannot check them
|
||||
private final boolean exempt = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10);
|
||||
private boolean sentInteractAt = false;
|
||||
private int requiredEntity;
|
||||
private InteractionHand requiredHand;
|
||||
private boolean requiredSneaking;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY && !exempt) {
|
||||
if (exempt) {
|
||||
return;
|
||||
}
|
||||
|
||||
final WrapperPlayClientInteractEntity wrapper = new WrapperPlayClientInteractEntity(event);
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
final WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
|
||||
|
||||
final PacketEntity entity = player.compensatedEntities.entityMap.get(wrapper.getEntityId());
|
||||
final PacketEntity entity = player.compensatedEntities.entityMap.get(packet.getEntityId());
|
||||
|
||||
// For armor stands, vanilla clients send:
|
||||
// - when renaming the armor stand or in spectator mode: INTERACT_AT + INTERACT
|
||||
@@ -35,27 +43,49 @@ public class BadPacketsM extends Check implements PacketCheck {
|
||||
// Just exempt armor stands to be safe
|
||||
if (entity != null && entity.getType() == EntityTypes.ARMOR_STAND) return;
|
||||
|
||||
switch (wrapper.getAction()) {
|
||||
final boolean sneaking = packet.isSneaking().orElse(false);
|
||||
|
||||
switch (packet.getAction()) {
|
||||
// INTERACT_AT then INTERACT
|
||||
case INTERACT:
|
||||
if (!sentInteractAt) {
|
||||
if (flagAndAlert("Missed Interact-At") && shouldModifyPackets()) {
|
||||
if (flagAndAlert("Skipped Interact-At") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else if (packet.getEntityId() != requiredEntity || packet.getHand() != requiredHand || sneaking != requiredSneaking) {
|
||||
String verbose = "requiredEntity=" + requiredEntity + ", entity=" + packet.getEntityId()
|
||||
+ ", requiredHand=" + requiredHand + ", hand=" + packet.getHand()
|
||||
+ ", requiredSneaking=" + requiredSneaking + ", sneaking=" + sneaking;
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
|
||||
sentInteractAt = false;
|
||||
break;
|
||||
case INTERACT_AT:
|
||||
if (sentInteractAt) {
|
||||
if (flagAndAlert("Missed Interact") && shouldModifyPackets()) {
|
||||
if (flagAndAlert("Skipped Interact") && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
}
|
||||
|
||||
requiredHand = packet.getHand();
|
||||
requiredEntity = packet.getEntityId();
|
||||
requiredSneaking = sneaking;
|
||||
sentInteractAt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
|
||||
if (sentInteractAt) {
|
||||
sentInteractAt = false;
|
||||
flagAndAlert("Skipped Interact (Tick)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 = "PacketOrderD")
|
||||
public class PacketOrderD extends Check implements PacketCheck {
|
||||
public PacketOrderD(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
@CheckData(name = "PacketOrderE", experimental = true)
|
||||
public class PacketOrderE extends Check implements PostPredictionCheck {
|
||||
public PacketOrderE(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private final ArrayDeque<String> flags = new ArrayDeque<>();
|
||||
private boolean setback;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.HELD_ITEM_CHANGE) {
|
||||
if (player.packetOrderProcessor.isAttacking()
|
||||
|| player.packetOrderProcessor.isRightClicking()
|
||||
|| player.packetOrderProcessor.isOpeningInventory()
|
||||
|| player.packetOrderProcessor.isReleasing()
|
||||
|| player.packetOrderProcessor.isSneaking()
|
||||
|| player.packetOrderProcessor.isSprinting()
|
||||
|| player.packetOrderProcessor.isLeavingBed()
|
||||
|| player.packetOrderProcessor.isStartingToGlide()
|
||||
|| player.packetOrderProcessor.isJumpingWithMount()
|
||||
) {
|
||||
String verbose = "attacking=" + player.packetOrderProcessor.isAttacking()
|
||||
+ ", rightClicking=" + player.packetOrderProcessor.isRightClicking()
|
||||
+ ", openingInventory=" + player.packetOrderProcessor.isOpeningInventory()
|
||||
+ ", releasing=" + player.packetOrderProcessor.isReleasing()
|
||||
+ ", sneaking=" + player.packetOrderProcessor.isSneaking()
|
||||
+ ", sprinting=" + player.packetOrderProcessor.isSprinting()
|
||||
+ ", bed=" + player.packetOrderProcessor.isLeavingBed()
|
||||
+ ", sprinting=" + player.packetOrderProcessor.isSprinting()
|
||||
+ ", gliding=" + player.packetOrderProcessor.isStartingToGlide()
|
||||
+ ", mountJumping=" + player.packetOrderProcessor.isJumpingWithMount();
|
||||
if (player.canSkipTicks() && flags.add(verbose) || flagAndAlert(verbose)) {
|
||||
if (player.packetOrderProcessor.isUsing()) {
|
||||
setback = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (!player.canSkipTicks()) {
|
||||
if (setback) {
|
||||
setback = false;
|
||||
setbackIfAboveSetbackVL();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (String verbose : flags) {
|
||||
if (flagAndAlert(verbose) && setback) {
|
||||
setback = false;
|
||||
setbackIfAboveSetbackVL();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setback = false;
|
||||
flags.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClientStatus;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
@CheckData(name = "PacketOrderF", experimental = true)
|
||||
public class PacketOrderF extends Check implements PostPredictionCheck {
|
||||
public PacketOrderF(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private final ArrayDeque<String> flags = new ArrayDeque<>();
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY
|
||||
|| event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT
|
||||
|| event.getPacketType() == PacketType.Play.Client.USE_ITEM
|
||||
|| event.getPacketType() == PacketType.Play.Client.PICK_ITEM
|
||||
|| event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING
|
||||
|| (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS
|
||||
&& new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT)
|
||||
) if (player.packetOrderProcessor.isSprinting() || player.packetOrderProcessor.isSneaking()) {
|
||||
String verbose = "action=" + (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY ? "interact"
|
||||
: event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT ? "place"
|
||||
: event.getPacketType() == PacketType.Play.Client.USE_ITEM ? "use"
|
||||
: event.getPacketType() == PacketType.Play.Client.PICK_ITEM ? "pick"
|
||||
: event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING ? "dig"
|
||||
: "openInventory")
|
||||
+ ", sprinting=" + player.packetOrderProcessor.isSprinting()
|
||||
+ ", sneaking=" + player.packetOrderProcessor.isSneaking();
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets()) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING
|
||||
&& new WrapperPlayClientPlayerDigging(event).getAction() == DiggingAction.RELEASE_USE_ITEM
|
||||
) return; // don't cause a noslow
|
||||
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
flags.add(verbose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (!player.canSkipTicks()) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (String verbose : flags) {
|
||||
flagAndAlert(verbose);
|
||||
}
|
||||
}
|
||||
|
||||
flags.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClientStatus;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
@CheckData(name = "PacketOrderG", experimental = true)
|
||||
public class PacketOrderG extends Check implements PostPredictionCheck {
|
||||
public PacketOrderG(GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private final ArrayDeque<String> flags = new ArrayDeque<>();
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING || (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS
|
||||
&& new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT)) {
|
||||
DiggingAction action = null;
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
|
||||
action = new WrapperPlayClientPlayerDigging(event).getAction();
|
||||
if (action == DiggingAction.RELEASE_USE_ITEM
|
||||
|| action == DiggingAction.START_DIGGING
|
||||
|| action == DiggingAction.CANCELLED_DIGGING
|
||||
|| action == DiggingAction.FINISHED_DIGGING
|
||||
) return;
|
||||
}
|
||||
|
||||
if (player.packetOrderProcessor.isAttacking()
|
||||
|| player.packetOrderProcessor.isReleasing()
|
||||
|| player.packetOrderProcessor.isRightClicking()
|
||||
|| player.packetOrderProcessor.isPicking()
|
||||
|| player.packetOrderProcessor.isDigging()
|
||||
) {
|
||||
String verbose = "action=" + (action == null ? "openInventory" : action == DiggingAction.SWAP_ITEM_WITH_OFFHAND ? "swap" : "drop")
|
||||
+ ", attacking=" + player.packetOrderProcessor.isAttacking()
|
||||
+ ", releasing=" + player.packetOrderProcessor.isReleasing()
|
||||
+ ", rightClicking=" + player.packetOrderProcessor.isRightClicking()
|
||||
+ ", picking=" + player.packetOrderProcessor.isPicking()
|
||||
+ ", digging=" + player.packetOrderProcessor.isDigging();
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
flags.add(verbose);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (!player.canSkipTicks()) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (String verbose : flags) {
|
||||
flagAndAlert(verbose);
|
||||
}
|
||||
}
|
||||
|
||||
flags.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
|
||||
|
||||
@CheckData(name = "PacketOrderH", experimental = true)
|
||||
public class PacketOrderH extends Check implements PostPredictionCheck {
|
||||
public PacketOrderH(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private int invalid;
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
|
||||
switch (new WrapperPlayClientEntityAction(event).getAction()) {
|
||||
case START_SPRINTING:
|
||||
case STOP_SPRINTING:
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_21_2) && player.packetOrderProcessor.isSneaking()) {
|
||||
if (!player.canSkipTicks()) {
|
||||
flagAndAlert();
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case START_SNEAKING:
|
||||
case STOP_SNEAKING:
|
||||
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_2) && player.packetOrderProcessor.isSprinting()) {
|
||||
if (!player.canSkipTicks()) {
|
||||
flagAndAlert();
|
||||
} else {
|
||||
invalid++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (!player.canSkipTicks()) return;
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (; invalid >= 1; invalid--) {
|
||||
flagAndAlert();
|
||||
}
|
||||
}
|
||||
|
||||
invalid = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package ac.grim.grimac.checks.impl.packetorder;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
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.utils.nmsutil.BlockBreakSpeed;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
@CheckData(name = "PacketOrderI", experimental = true)
|
||||
public class PacketOrderI extends Check implements PostPredictionCheck {
|
||||
public PacketOrderI(final GrimPlayer player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
private boolean exemptPlacingWhileDigging;
|
||||
|
||||
private boolean setback;
|
||||
private boolean digging; // for placing
|
||||
private final ArrayDeque<String> flags = new ArrayDeque<>();
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
|
||||
if (new WrapperPlayClientInteractEntity(event).getAction() == WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
|
||||
if (player.packetOrderProcessor.isRightClicking() || player.packetOrderProcessor.isPicking() || player.packetOrderProcessor.isReleasing() || player.packetOrderProcessor.isDigging()) {
|
||||
String verbose = "type=attack, rightClicking=" + player.packetOrderProcessor.isRightClicking()
|
||||
+ ", picking=" + player.packetOrderProcessor.isPicking()
|
||||
+ ", releasing=" + player.packetOrderProcessor.isReleasing()
|
||||
+ ", digging=" + player.packetOrderProcessor.isDigging();
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
flags.add(verbose);
|
||||
}
|
||||
}
|
||||
} else if (player.packetOrderProcessor.isReleasing() || player.packetOrderProcessor.isDigging()) {
|
||||
String verbose = "type=interact, releasing=" + player.packetOrderProcessor.isReleasing() + ", digging=" + player.packetOrderProcessor.isDigging();
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
flags.add(verbose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT || event.getPacketType() == PacketType.Play.Client.USE_ITEM) {
|
||||
if (player.packetOrderProcessor.isReleasing() || digging) {
|
||||
String verbose = "type=place/use, releasing=" + player.packetOrderProcessor.isReleasing() + ", digging=" + digging;
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert(verbose) && shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
}
|
||||
} else {
|
||||
flags.add(verbose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
|
||||
WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
|
||||
|
||||
switch (packet.getAction()) {
|
||||
case RELEASE_USE_ITEM:
|
||||
if (player.packetOrderProcessor.isAttacking() || player.packetOrderProcessor.isRightClicking() || player.packetOrderProcessor.isPicking() || player.packetOrderProcessor.isDigging()) {
|
||||
String verbose = "type=release, attacking=" + player.packetOrderProcessor.isAttacking()
|
||||
+ ", rightClicking=" + player.packetOrderProcessor.isRightClicking()
|
||||
+ ", picking=" + player.packetOrderProcessor.isPicking()
|
||||
+ ", digging=" + player.packetOrderProcessor.isDigging();
|
||||
if (!player.canSkipTicks()) {
|
||||
if (flagAndAlert(verbose)) {
|
||||
setback = true;
|
||||
}
|
||||
} else {
|
||||
flags.add(verbose);
|
||||
setback = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case START_DIGGING:
|
||||
double damage = BlockBreakSpeed.getBlockDamage(player, packet.getBlockPosition());
|
||||
if (damage >= 1 || damage <= 0 && player.gamemode == GameMode.CREATIVE) {
|
||||
return;
|
||||
}
|
||||
case CANCELLED_DIGGING:
|
||||
case FINISHED_DIGGING:
|
||||
if (exemptPlacingWhileDigging || player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10)) {
|
||||
return;
|
||||
}
|
||||
digging = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isTickPacket(event.getPacketType())) {
|
||||
digging = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (!player.canSkipTicks()) {
|
||||
if (setback) {
|
||||
setbackIfAboveSetbackVL();
|
||||
setback = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isTickingReliablyFor(3)) {
|
||||
for (String verbose : flags) {
|
||||
if (flagAndAlert(verbose) && setback) {
|
||||
setbackIfAboveSetbackVL();
|
||||
setback = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flags.clear();
|
||||
setback = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
exemptPlacingWhileDigging = config.getBooleanElse(getConfigName() + ".exempt-placing-while-digging", false);
|
||||
}
|
||||
}
|
||||
Loaded 100 of 363 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user