Compare commits

...
Author SHA1 Message Date
Axionize ee36c2559a Refactor HitboxData.getBlockHitbox() to include isTargetBlock as parameter
Also fixes a rare NPE
2025-01-20 02:31:34 -05:00
ManInMyVan 75bcac7a49 don't check item usage in MultiActionsC/D 2025-01-19 14:30:33 -07:00
ManInMyVan 111cc7aafd finally use that util I added a while ago 2025-01-19 12:45:11 -07:00
AoElite 924dcf9014 update elytra feature & use switches 2025-01-19 03:03:31 -05:00
AoElite 63aa1ed632 update feature manager 2025-01-19 03:00:35 -05:00
ManInMyVan eda4dc7236 actually fix it 2025-01-18 20:21:32 -07:00
ManInMyVan 85e1e20e41 fix BadPacketsX false 2025-01-18 19:12:28 -07:00
ManInMyVan b6a79b74b6 this also applies to horses 2025-01-18 18:45:39 -07:00
SamB440 783240c06f Merge pull request #1952 from Cyramek/fix-fastbreak
account for fastbreak flag cancellation
2025-01-18 17:36:49 +00:00
cyramek fbcad3e605 account for fastbreak flag cancellation 2025-01-18 18:35:52 +01:00
SamB440 10c1a1350c Warn about plugin incompatibility 2025-01-18 14:50:04 +00:00
ManInMyVan 69875008c3 exempt 1.8 players from elytra checks 2025-01-16 19:37:52 -07:00
ManInMyVan e39eb89f59 fix possible BadPacketsQ npe 2025-01-16 19:35:15 -07:00
ManInMyVan 71015ec3c7 Add VehicleD 2025-01-16 17:10:12 -07:00
ManInMyVan 09b8071f5b make VehicleC a PacketCheck 2025-01-16 16:49:45 -07:00
ManInMyVan e011b2dbbd Vehicle check catagory 2025-01-16 16:37:21 -07:00
ManInMyVan 7208842b0c perf 2025-01-16 16:24:50 -07:00
ManInMyVan 2830856812 per check nosetback and nomodifypacket permissions 2025-01-16 16:24:34 -07:00
ManInMyVan 50f9b6ecbd fix ElytraH name 2025-01-15 21:55:02 -07:00
ManInMyVan f31182419f fix pose desync 2025-01-15 18:58:31 -07:00
ManInMyVan 918dbf28ce ElytraF to I 2025-01-15 18:08:24 -07:00
ManInMyVan 5c73e7d0f1 BadPacketsD description 2025-01-15 17:05:34 -07:00
ManInMyVan 950d7a7a86 add ElytraE 2025-01-15 16:46:39 -07:00
ManInMyVan 0f068c763f add ElytraD 2025-01-15 16:46:25 -07:00
ManInMyVan 32b799735a add ElytraC 2025-01-15 16:36:54 -07:00
ManInMyVan fba015809f fix #1932 2025-01-13 19:39:43 -07:00
ManInMyVan 917d115a54 |= is a thing 2025-01-13 19:21:16 -07:00
ManInMyVan bf2de308ed fix #1949 2025-01-13 19:02:32 -07:00
ManInMyVan 0d278ed756 Merge pull request #1950 from twcult/patch-1
Update CrashH.java
2025-01-13 15:21:58 -07:00
twcult 99cab0a346 Update CrashH.java 2025-01-14 01:04:17 +03:00
SamB440 b83c04ddca Count invalid packets in TickTimer 2025-01-13 20:55:47 +00:00
SamB440 83fba052a5 Fix AimModulo360 falses when entering vehicle (fixes #1942) 2025-01-13 17:33:00 +00:00
SamB440 66438dd0c0 Fix 1.9+ server check for BadPacketsH, fixes #1946 2025-01-13 17:21:09 +00:00
SamB440 470776e49e Don't alert for BadPacketsR 2025-01-12 13:03:01 +00:00
ManInMyVan c1e02d5731 support glider component 2025-01-11 19:06:58 -07:00
ManInMyVan 9303ca77bb &= is a thing 2025-01-11 17:47:55 -07:00
ManInMyVan f2043ff12e check for releasing jump in ElytraB 2025-01-11 17:45:44 -07:00
ManInMyVan 9fc6e2f696 fix WrongBreak false 2025-01-10 20:39:14 -07:00
ManInMyVan 6fb84703d0 use flagAndAlert 2025-01-10 20:37:01 -07:00
ManInMyVan 35ca5dcfe9 SprintF 2025-01-10 20:34:56 -07:00
ManInMyVan 77d07fb444 patch sideways sprint 2025-01-10 19:57:42 -07:00
ManInMyVan dbce0b70e5 patch spigot antispam bypass 2025-01-10 19:35:33 -07:00
ManInMyVan 83bb7eaf64 Merge pull request #1938 from twcult/2.0
Remove method `canSkipTicks()` inlining
2025-01-10 18:59:31 -07:00
twcult ec0b723ae9 Update Reach.java 2025-01-11 04:52:42 +03:00
ManInMyVan e2049c7998 exempt redstone in PositionBreakA 2025-01-10 16:30:55 -07:00
ManInMyVan 8968acf214 pass verbose to flag() 2025-01-10 07:56:57 -07:00
ManInMyVan 405b679d68 Merge pull request #1937 from MatrixU5er/patch-1
Better Chinese translation
2025-01-09 19:34:01 -07:00
ManInMyVan dcc134ef37 add elytra to punishments config 2025-01-09 19:30:05 -07:00
MatrixU5er b356c1d162 Better Chinese translation
Added new Chinese translations and made some changes to make them easier to understand
2025-01-10 09:59:04 +08:00
ManInMyVan c4f224f406 add 2 elytra checks 2025-01-09 18:37:59 -07:00
SamB440 10ff3cefb5 Merge pull request #1936 from Penguin285/Penguin285-patch-1
Fixed Client Brands not sending properly
2025-01-09 16:30:42 +00:00
Penguin285 5c80e28c7d Fixed Client Brands not sending properly
The previous code was checking if the player had verbose enabled, instead of checking if they had brands enabled
2025-01-09 16:09:08 +00:00
AoElite bdb1330706 bump api 2025-01-08 00:37:44 -05:00
AoElite b30f4e18da Merge pull request #1930 from spring-dependency-management/badpacketsc-spectator-false
Fix badpacketsC false when in spectator
2025-01-07 22:45:41 -05:00
spring-dependency-management 7563b53fa1 Fix spectator false 2025-01-08 02:54:52 +00:00
AoElite f852f16c9c implement sendMessage 2025-01-07 11:54:34 -05:00
AoElite de730d73c0 implement more new API additions 2025-01-07 11:27:44 -05:00
AoElite dbe72a7fbf update API implementation 2025-01-07 06:21:56 -05:00
SamB440 c1225cb920 Brand handling improvements 2025-01-04 17:19:09 +00:00
ManInMyVan 17927c11bf remove grim.brand.exempt because it causes npes 2025-01-04 10:13:41 -07:00
SamB440 66f6bd72d0 More Jabba 17 cleanup 2025-01-03 18:29:54 +00:00
ManInMyVan 6816df7a93 fix #1921 2025-01-03 10:53:17 -07:00
SamB440 7e0699d1bb Merge pull request #1903 from matsu1213/fix-bpn-setbacks
Fix BadPacketsN setbacks for relative teleports
2025-01-03 14:58:41 +00:00
ManInMyVan 1ce5a530ff small optimization for older servers 2025-01-02 12:53:21 -07:00
ManInMyVan 61e506437b add methods for nms item usage 2025-01-02 12:41:57 -07:00
ManInMyVan a23e1a10f4 add /grim brand and grim.brand.enable-on-join 2025-01-02 11:46:16 -07:00
ManInMyVan d1f6a47519 add verbose toggle messages to messages.yml 2025-01-02 11:46:04 -07:00
ManInMyVan 4cb6de2cb1 remove unused import 2025-01-02 11:44:52 -07:00
ManInMyVan 000758e7f1 include action in invalidbreak verbose 2025-01-02 11:12:34 -07:00
ManInMyVan 57157d068e add grim.brand.exempt 2025-01-02 11:04:22 -07:00
ManInMyVan 368db15026 make BadPacketsL stricter 2025-01-02 11:00:23 -07:00
ManInMyVan a0b1d290b5 Merge pull request #1919 from calcastor/invalidbreak-1.7
Exempt block face id 255 for 1.7.10- players in InvalidBreak
2025-01-02 10:56:53 -07:00
ManInMyVan e75b987a6e check action 2025-01-02 10:56:40 -07:00
ManInMyVan 7955563931 make PositionBreakB stricter for 1.7 2025-01-02 10:54:37 -07:00
matsu1213 cd9e22aad4 Use getMask 2025-01-02 23:17:24 +09:00
BT (calcastor/mame) cf66554afe Exempt block face id 255 for 1.7.10- players in InvalidBreak 2025-01-02 00:33:09 -08:00
ManInMyVan a179f3e625 fix #1918 2025-01-01 19:15:36 -07:00
ManInMyVan fe96f848ad import DiggingAction 2025-01-01 13:36:28 -07:00
ManInMyVan 37b12ac56b fix PositionBreakA falses 2025-01-01 13:10:12 -07:00
ManInMyVan 6846e2d6a3 small refactor 2024-12-31 11:46:10 -07:00
ManInMyVan 5da77e2aa5 Merge pull request #1917 from 483378/2.0
BadPacketsV: fix >= 1.21.2 false flag
2024-12-31 11:01:02 -07:00
483378 7ac3d4104f BadPacketsV: make check stricter again for 1.8 players 2024-12-31 18:58:05 +01:00
SamB440 1c1f1d7031 Fix redstone wall torch powered state 2024-12-31 17:40:11 +00:00
SamB440 47a26f86dc Merge pull request #1909 from caneeeeee/adjust-german-translation
Adjust German translation
2024-12-31 17:02:30 +00:00
483378 9e054c2b6c BadPacketsV: fix >= 1.21.2 false flag 2024-12-31 17:34:40 +01:00
ManInMyVan c685c47d16 exempt spectators in FarPlace and FarBreak 2024-12-30 20:21:53 -07:00
ManInMyVan b968bd98f3 add PositionBreakB 2024-12-30 18:36:34 -07:00
ManInMyVan 5902fec4a8 add PositionBreak 2024-12-30 18:32:50 -07:00
ManInMyVan 2171a57757 Merge pull request #1916 from jonesdevelopment/feat/remove-log4j-checks
Remove ExploitA since it's useless and broken
2024-12-30 17:11:03 -07:00
Jones 882990fe84 Remove ExploitA since it's useless and broken 2024-12-31 00:54:22 +01:00
ManInMyVan c1e070e7ba decrease movement threshold leniency for 1.21.2+ 2024-12-30 16:09:20 -07:00
ManInMyVan 7e879aab9d add InvalidBreak 2024-12-30 15:59:43 -07:00
ManInMyVan 08a73ba2c6 add AirLiquidBreak description 2024-12-30 15:53:31 -07:00
ManInMyVan 411d3577e8 add description for NoSwingBreak 2024-12-30 15:51:44 -07:00
ManInMyVan a24f6ac26c add FarBreak 2024-12-30 15:51:12 -07:00
ManInMyVan 58e05442fe add NoSwingBreak 2024-12-30 15:41:07 -07:00
ManInMyVan c79928a8c8 Add MultiBreak 2024-12-30 15:30:32 -07:00
ManInMyVan 994990e4df Merge pull request #1530 from ManInMyVan/bp3
Add BadPacketsX
2024-12-30 14:39:38 -07:00
ManInMyVan f6b55d3ca5 Add BadPacketsX 2024-12-30 14:37:30 -07:00
ManInMyVan 649ffe0f71 add description for BadPacketsH 2024-12-30 14:07:27 -07:00
ManInMyVan f861181959 Merge pull request #1915 from AbdisKiosk/fix-nosuchmethoderror
Fix nosuchmethoderror in grimversion in old minecraft versions
2024-12-30 14:05:43 -07:00
ManInMyVan bc2ebf7222 rename BadPacketsX to AirLiquidBreak 2024-12-30 14:04:30 -07:00
ManInMyVan ac204c99b2 rename BadPacketsZ to WrongBreak 2024-12-30 14:02:55 -07:00
ManInMyVan 606a89ea61 make "FastBreak" "Break" in punishments.yml 2024-12-30 13:59:56 -07:00
ManInMyVan 4340962786 fix sprint check names 2024-12-30 13:27:08 -07:00
ManInMyVan e2f22682bd move sprint checks to their own package 2024-12-30 13:22:35 -07:00
ManInMyVan f4ab6de6af move timer checks to their own package 2024-12-30 13:22:01 -07:00
ManInMyVan 7bb1f01f28 cleanup 2024-12-30 13:17:21 -07:00
SamB440 8d7217439f Make PlayerBaseTick static to reduce allocations, make Column a record 2024-12-30 17:59:50 +00:00
SamB440 3308b4d7e3 Let TickTimer setback 2024-12-30 17:17:36 +00:00
SamB440 f6513b5537 Reduce reach uncertainty for 1.21.2+ end tick 2024-12-30 17:07:23 +00:00
SamB440 20217fd40b Avoid an allocation here 2024-12-30 17:05:40 +00:00
SamB440 6c5ff42045 Fix Reach verbose 2024-12-30 17:02:41 +00:00
SamB440 1e1a176b73 Split reach missed hitbox into hitboxes 2024-12-30 16:57:45 +00:00
SamB440 ba85055e5a Code cleanup 2024-12-30 16:00:57 +00:00
AbdisKiosk caed9e1850 Fix nosuchmethoderror in grimversion 2024-12-30 15:20:29 +01:00
SamB440 5acbb1d514 Fix inside block epsilon thing 2024-12-30 01:15:19 +00:00
ManInMyVan 5532ae0c34 fix falses 2024-12-29 15:59:53 -07:00
ManInMyVan bc276d0ca9 fix #1801 2024-12-29 14:39:53 -07:00
SamB440 251f1c13a9 revert this because im an idiot and didn't notice it's changing a different velocity 2024-12-29 21:27:09 +00:00
SamB440 9322d5d7b4 refactor and mention mojang broke movement here 2024-12-29 21:25:31 +00:00
ManInMyVan cf8f2d04f6 fix more falses on legacy versions 2024-12-29 14:08:45 -07:00
ManInMyVan dc8329e2cd fix clicking on trapdoors with blocks causing falses on legacy version 2024-12-29 13:34:16 -07:00
ManInMyVan 4351fb0531 fix falses in spectator mode 2024-12-29 12:57:07 -07:00
ManInMyVan 3b9fcefae0 tiny cleanup 2024-12-29 12:40:01 -07:00
ManInMyVan e90601f2b9 use canSkipTicks in BadPacketsV 2024-12-29 12:14:23 -07:00
ManInMyVan 5fbbabadf7 don't count stop sprinting as a start sprinting packet 2024-12-28 19:48:46 -07:00
ManInMyVan 105f0eceab small cleanup 2024-12-28 19:41:32 -07:00
ManInMyVan 8c15640a44 move FastBreak to breaking package 2024-12-28 19:39:42 -07:00
ManInMyVan 51b6141f91 Merge pull request #1485 from ManInMyVan/BadPackets1
Add BadPacketsV
2024-12-28 19:36:56 -07:00
ManInMyVan a4624f6907 add BadPacketsV description 2024-12-28 19:36:26 -07:00
ManInMyVan 3ac459d42c get offset after checking isChecked 2024-12-28 18:10:55 -07:00
ManInMyVan 726f6f84bf use flagAndAlert in ExplosionHandler 2024-12-28 18:02:43 -07:00
ManInMyVan c880dbb4ce use flagAndAlert a bit more 2024-12-28 17:58:39 -07:00
ManInMyVan 097b471aed add SprintE 2024-12-28 15:14:12 -07:00
ManInMyVan 069c503bda rename NoSlowB-E to SprintA-D
they aren't really "NoSlow" cheats
2024-12-28 13:42:13 -07:00
ManInMyVan b7c8ca1683 add MultiActions to tr.yml and ja.yml 2024-12-28 13:40:20 -07:00
ManInMyVan 27f4f34b16 fix falses 2024-12-28 12:44:18 -07:00
caneeeeee d388d3f5db Adjust German translation: preserve placeholders and improve contextual accuracy 2024-12-28 15:14:29 +01:00
ManInMyVan 744be32389 Merge pull request #1908 from GrimAnticheat/fix/sculk-vein-hitbox
Fix Sculk Vein hitbox
2024-12-27 19:53:27 -07:00
You 8c97274929 Fix Sculk Vein hitbox 2024-12-27 21:40:42 -05:00
AoElite a630dbe028 Added /grim dump. A command that dumps useful debugging information into a link. 2024-12-26 01:54:51 -05:00
ManInMyVan 3e42fe9d5e remove random comment 2024-12-25 22:42:12 -07:00
AoElite 06fad2ecaf Added /grim version command. Uses Modrinth API to check if Grim is up to date. 2024-12-26 00:36:31 -05:00
ManInMyVan 3ddc1e846a allow usage of grim variables outside of grim (PAPI expansion)) 2024-12-25 20:08:25 -07:00
ManInMyVan af6c859b16 support for &x&r&r&g&g&b&b hex codes 2024-12-24 19:30:42 -07:00
ManInMyVan d138d0d602 remove inaccurate messages.yml header 2024-12-24 19:23:44 -07:00
ManInMyVan 70d0fa96c2 fix hex codes 2024-12-24 19:11:09 -07:00
ManInMyVan 133e7dc490 this is also stable 2024-12-24 18:38:16 -07:00
ManInMyVan 4cb0a46797 this is stable 2024-12-24 18:37:10 -07:00
ManInMyVan 4298031d3f fix fluid hitbox for pre 1.13 players 2024-12-24 14:41:53 -07:00
ManInMyVan f4c43735f7 fix getEyeHeight() for 1.8 players 2024-12-24 14:39:33 -07:00
ManInMyVan 61f90fe721 fix reach for lily pads and buckets 2024-12-24 14:19:08 -07:00
ManInMyVan 431200c855 fix viaversion snow 2024-12-24 12:45:12 -07:00
ManInMyVan 481a115ba1 fix fluid placement distance 2024-12-24 11:39:32 -07:00
SamB440 b0f6e49109 Remove useless semicolon 2024-12-24 18:30:12 +00:00
SamB440 122ad4a93c Make hasSentPreWavePacket atomic 2024-12-24 18:29:19 +00:00
ManInMyVan 464e61b6b0 fix some issues with fluid placements on pre-1.13 2024-12-24 10:36:27 -07:00
matsu1213 1405faa391 Fix BadPacketsN setbacks for relative teleports 2024-12-24 12:46:37 +09:00
SamB440 1f93dff26c Update Gradle wrapper 2024-12-23 17:22:42 +00:00
ManInMyVan 002b027e2b don't apply changes to tags that don't exist in the player's version 2024-12-22 20:25:01 -07:00
ManInMyVan 2a5b25e927 oops 2024-12-22 19:33:46 -07:00
ManInMyVan 597e3ba820 Check lastVehicleSwitch in isTickingReliablyFor (#1876) 2024-12-22 21:01:26 -05:00
SamB440 20234319e6 Update Gradle wrapper 2024-12-22 17:26:53 +00:00
ManInMyVan 8b76fd36d7 fix falses with custom mining tags 2024-12-20 17:10:04 -07:00
ManInMyVan 6ca375ff61 Merge pull request #1895 from jonesdevelopment/fix/variable-replacements
Fix variables never actually updating
2024-12-20 13:53:47 -07:00
Jones 1836b14d5d The Grim version is also static 2024-12-20 21:49:49 +01:00
Jones 618b6aca24 Only change static variables 2024-12-20 21:49:22 +01:00
ManInMyVan 4a45918971 fix pale moss carpets 2024-12-20 13:02:48 -07:00
ManInMyVan f8af107a1a Merge pull request #1896 from ManInMyVan/fix/snow
fix snow collisions
2024-12-20 12:19:24 -07:00
ManInMyVan 94491d293b fix snow collisions 2024-12-20 12:11:44 -07:00
Jones 49debf6cd0 Fix variables never actually updating 2024-12-20 18:21:37 +01:00
ManInMyVan c87ae3af8b rename NoFallA and NoFallB classes to match check name 2024-12-19 18:00:34 -07:00
ManInMyVan 423f2d0711 remove redundant configName declarations 2024-12-19 17:54:36 -07:00
AoElite 9a0ec5d010 update grim api 2024-12-19 04:46:36 -05:00
ManInMyVan 60ed674228 Merge pull request #1894 from ManInMyVan/bump-packetevents
bump packetevents
2024-12-18 23:19:45 -07:00
ManInMyVan 8bec79abc6 bump packetevents 2024-12-18 23:09:04 -07:00
ManInMyVan 0ee4b2551f Merge pull request #1893 from ManInMyVan/fix/autoblock
patch autoblock in 1.8
2024-12-18 20:43:13 -07:00
Axionize ad3cbd739a Fix AirLiquidPlace falses (and BadPacketsX false) (#1822)
* Add new Data classes to see recently modified blocks
* Fix AirLiquidPlace false
* Cleanup AirLiquidPlace
* Finish documenting all edge cases that can false AirLiquidPlace and fixing them
* Apply Style Changes From Code Review
2024-12-18 22:21:53 -05:00
ManInMyVan d9718b308f patch autoblock in 1.8 2024-12-18 17:48:01 -07:00
AoElite 4b03892c86 Update README.md
fix typo
2024-12-18 01:52:52 -05:00
AoElite 7668ddb6d6 Update README.md
add Java 17 warning
2024-12-17 15:43:48 -05:00
AoElite 33582cd417 Update README.md
add installation notes
2024-12-17 14:59:47 -05:00
AoElite 2474c550cc Update README.md 2024-12-17 14:49:52 -05:00
SamB440 4f8357f5a1 Bump version (2.3.69) 2024-12-17 17:59:58 +00:00
SamB440 b4ac002779 Warn about viabackwards and promote placement config warn to error 2024-12-17 16:01:46 +00:00
SamB440 f04cadb38d Fix BadPacketsE with viabackwards 2024-12-17 15:35:21 +00:00
ManInMyVan 79ec178845 Merge pull request #1887 from ManInMyVan/localized-desciptions
allow localizing check descriptions
2024-12-16 16:10:47 -07:00
ManInMyVan a8da7dde72 allow localizing check descriptions 2024-12-16 15:49:18 -07:00
ManInMyVan 576a67502b Merge pull request #1621 from ManInMyVan/minimessage
Add MiniMessage And PlaceHolderAPI Support
2024-12-16 15:35:01 -07:00
SamB440 eb72a7c86d Add Camel simulation support 2024-12-16 21:40:31 +00:00
Axionize 5d486a5707 Merge pull request #1824 from Axionize/fix-modern-client-legacy-server-walls
Fix Modern Client + Legacy Server Walls
2024-12-15 17:12:06 -05:00
Axionize 9975d1a6bf Merge pull request #1886 from Axionize/fix/pink-petals-ccb-size
Fix IndexOutofBoundsException when interacting with Pink Petals with 3 or more flowers
2024-12-15 17:02:35 -05:00
Axionize dd74dc9737 Fix IndexOutofBoundsException when interacting with Pink Petals with 3 or more flowers 2024-12-15 16:52:02 -05:00
SamB440 bf37add382 Merge pull request #1880 from Currypan1229/maint/yml-cu-853275982
Fix namespace of punishments.yml for japanese
2024-12-15 19:09:48 +00:00
Currypan1229 432a0aed02 Fix namespace of punishments.yml for japanese 2024-12-16 04:07:30 +09:00
ManInMyVan 6a1a5f81ed add UNKNOWN branch to BadPacketsP 2024-12-13 13:59:05 -07:00
ManInMyVan a620149a93 Merge pull request #1860 from ManInMyVan/bpP
show click type name and use enhanced switch statements in BadPacketsP
2024-12-13 13:04:46 -07:00
ManInMyVan 4c21c11484 Merge pull request #1842 from ManInMyVan/descriptions
Add descriptions to checks
2024-12-12 18:39:15 -07:00
ManInMyVan ca72cd5997 Add descriptions to some checks 2024-12-12 18:36:26 -07:00
ManInMyVan 3952600032 Merge pull request #1875 from ManInMyVan/don't-check-skippedTickInActualMovement
don't check skippedTickInActualMovement when handling slot changes
2024-12-11 22:11:41 -07:00
ManInMyVan d42bc4bec7 Merge pull request #1879 from ManInMyVan/deprecations
fix some deprecation warnings
2024-12-11 19:34:27 -07:00
ManInMyVan 30a6e7c336 Merge pull request #1878 from ManInMyVan/use-new-java-features
use new java features more
2024-12-11 15:25:13 -07:00
ManInMyVan d82b168cd6 use new java features more 2024-12-10 18:44:02 -07:00
ManInMyVan 284effc237 fix some deprecation warnings 2024-12-09 17:58:30 -07:00
ManInMyVan e97566cd5f and check client version 2024-12-09 16:36:07 -07:00
ManInMyVan 8c2b87f472 don't check skippedTickInActualMovement when handling slot changes 2024-12-09 16:14:33 -07:00
ManInMyVan f3433f3011 Merge pull request #1874 from ManInMyVan/postcheck-to-post
rename PostCheck to Post
2024-12-08 23:13:52 -07:00
ManInMyVan 587b317cb6 rename PostCheck to Post 2024-12-08 20:23:10 -07:00
ManInMyVan febe00e950 Add MiniMessage and PlaceHolderAPI Support 2024-12-08 20:09:59 -07:00
AoElite c7445019f9 Merge pull request #1847 from ManInMyVan/blockbreakcheck
BlockBreakCheck
2024-12-08 21:54:37 -05:00
SamB440 ff1c3043b3 Merge pull request #1871 from ManInMyVan/noslowc&d-1.21.4
check 1.21.4 players in NoSlowC and NoSlowD
2024-12-08 11:35:11 +00:00
ManInMyVan 0b038d38e9 check 1.21.4 players in NoSlowC and NoSlowD 2024-12-07 13:58:56 -07:00
SamB440 b0790af3e1 Update packetevents 2024-12-07 19:42:47 +00:00
SamB440 912939a5f4 Another 1.21.2 fix 2024-12-07 19:33:33 +00:00
SamB440 7d30183af3 Use an identity hash set for synced tags 2024-12-06 20:00:33 +00:00
SamB440 2ac8a86d4f Update ExplosionHandler to account for 1.21.2 changes 2024-12-06 14:57:37 +00:00
AoElite d598ae0057 Merge pull request #1863 from ManInMyVan/fix/multiactionsc-false
fix MultiActionsC false with server opened inventories
2024-12-05 21:25:25 -05:00
ManInMyVan d3fde8025a fix MultiActionsC false with server opened inventories 2024-12-05 17:31:56 -07:00
ManInMyVan 7fe146db05 show click type name and use enhanced switch statements in BadPacketsP 2024-12-04 19:49:53 -07:00
ManInMyVan 227458a633 BlockBreakCheck 2024-12-04 17:30:05 -07:00
ManInMyVan e61fb9b3e4 Add BadPacketsV 2024-12-04 17:25:58 -07:00
AoElite 97abaaf8ad Merge pull request #1846 from Axionize/remove-use-of-var
Remove Usage of Var
2024-12-04 15:36:17 -05:00
SamB440 1f3ac2a174 Merge pull request #1831 from GrimAnticheat/update/1.21.3
1.21.3 update
2024-12-04 13:37:52 +00:00
SamB440 ff0629d0b7 Merging really sucks 2024-12-04 13:36:17 +00:00
SamB440 9936984534 Merge branch '2.0' into update/1.21.3 2024-12-04 13:34:06 +00:00
SamB440 ca56975136 Revert BadPacketsE changes 2024-12-04 13:31:49 +00:00
AoElite 348daf6a52 Merge pull request #1850 from SergioK29/fix-missing-should-cancel-packets
Fix missing shouldModifyPackets
2024-12-04 08:05:46 -05:00
AoElite d67b470ff6 better BadPackets E & R support for 1.21.2+ 2024-12-04 08:00:12 -05:00
SamB440 130f9e1023 Merge pull request #1597 from ManInMyVan/multiactions
Add MultiActions Checks
2024-12-03 22:13:59 +00:00
SamB440 eaac8ad908 Merge pull request #1835 from Axionize/fix-riptide-teams-and-non-pushable
Fix riptide trident attacks on entities that are non-pushable or the same team as the attacker
2024-12-03 21:12:19 +00:00
SamB440 89f8696d88 Merge pull request #1715 from ManInMyVan/elytra-fly
Allow exempting elytras
2024-12-03 18:01:08 +00:00
AoElite 940a1f819f punishment manager performance improvements 2024-12-03 12:07:33 -05:00
AoElite 3f01edba9d fixed paintings not being registered 2024-12-03 11:37:58 -05:00
SergioK29 24409a5771 Fix missing shouldModifyPackets 2024-12-03 14:00:27 +00:00
ManInMyVan 88e0f98241 fix swimming false 2024-12-02 18:11:48 -07:00
SamB440 fde99a7cbf Remove fastutil usage from CorrectingPlayerInventoryStorage 2024-12-02 13:54:46 +00:00
Axionize 1c3929834a Remove usage of var 2024-12-01 17:08:01 -05:00
ManInMyVan 3a839d7240 add parenthesis 2024-12-01 12:51:19 -07:00
SamB440 7737337a86 Don't let setbacks bypass stuck speed 2024-12-01 18:34:52 +00:00
MachineBreaker 88dc6a42a9 Merge pull request #1832 from Axionize/replace-var-with-explicit-types
Make var type in ExploitC explicitly String
2024-12-01 14:34:09 -04:00
MachineBreaker bcc93aab4a Merge pull request #1804 from GrimAnticheat/2.0-optimise-menu-type
Optimise MenuType#getMenuType
2024-12-01 14:30:33 -04:00
SamB440 b88561284c Disable verbose enable-on-join by default even for OPs 2024-12-01 17:38:41 +00:00
SamB440 5fd8230884 Fix timer ping-abuse-limit-threshold 2024-12-01 17:37:19 +00:00
SamB440 ca0fa88a77 Merge pull request #932 from SamB440/fix/BadPacketsG
Reimplement BadPacketsG
2024-12-01 15:01:56 +00:00
SamB440 cbb3c1cc0f Fix BadPacketsG falses & a sneak desync 2024-12-01 14:59:02 +00:00
SamB440 519968b85a Fix BadPacketsG teleport status 2024-12-01 14:58:38 +00:00
SamB440 6314b78e47 Merge pull request #1837 from ManInMyVan/cleanup/packetcheck
remove unused method from PacketCheck
2024-12-01 14:49:25 +00:00
SamB440 b791897dbc Merge pull request #1833 from Axionize/verbose-on-join
Add permission to enable verbose on join
2024-12-01 14:46:53 +00:00
SamB440 61af1d1e72 Merge pull request #1830 from ManInMyVan/blockbreak-class
add BlockBreak class
2024-12-01 14:42:08 +00:00
SamB440 bf3fc94d92 More big changes 2024-12-01 14:14:07 +00:00
Axionize 4887415912 Add verbose to appropiate places; makes sure player have alert for auto activation of verbose 2024-11-29 22:50:29 -05:00
SamB440 7f0838832d Merge pull request #1839 from Cyramek/limit-jump-possibilities
[1.21.3] Limit jump possibilities
2024-11-29 18:06:24 +00:00
cyramek 336efafbd3 limit jump possibilities 2024-11-29 18:46:47 +01:00
SamB440 782f8f8a09 Big changes 2024-11-29 17:15:37 +00:00
SamB440 c1858e49d8 Merge pull request #1815 from Axionize/explicit-flush-detection
Warn users who want extra reach accuracy that they need to add paper.explicit-flush=true
2024-11-29 12:24:00 +00:00
SamB440 7dce3a7a12 Merge pull request #1836 from ManInMyVan/cleanup/pair
cleanup Pair class
2024-11-29 12:22:22 +00:00
Axionize 7786da7296 Fix evicting queue for riptide entities 2024-11-28 21:46:43 -05:00
ManInMyVan bc365176b1 remove unused method from PacketCheck 2024-11-28 17:29:45 -07:00
ManInMyVan 7fe224c206 cleanup Pair class 2024-11-28 17:27:32 -07:00
Axionize 48e5f54341 Fix riptide trident attacks on entities that are non-pushable or the same team as the attacker 2024-11-28 17:14:56 -05:00
SamB440 5edf92f124 Merge pull request #1834 from Cyramek/fix-known-input
[1.21.3] fix looping through invalid values caused by known input
2024-11-28 14:33:13 +00:00
cyramek 1c3e938f0f fix looping through invalid values caused by known input 2024-11-28 15:09:54 +01:00
Axionize ec71581eae Add permission to enable verbose on join 2024-11-27 23:46:10 -05:00
Axionize 0904b61df0 Make var type in ExploitC explicitly String 2024-11-27 22:04:50 -05:00
Axionize c9e082257c Put -Dpaper.explicit-flush=true in quotes 2024-11-27 22:01:27 -05:00
Axionize 53dd27e95d split union() in SCB into union() and new encompass() method; fixes Simulation false on walls 2024-11-27 21:59:56 -05:00
SamB440 8875bbf991 Re-encode this 2024-11-27 17:53:49 +00:00
SamB440 e933186d2e determineCanSkipTick idle for 1.21.2+ 2024-11-27 16:53:50 +00:00
SamB440 89bec80b34 Fix 1.21.2+ jump false 2024-11-27 16:07:11 +00:00
SamB440 cc78eca02f Fix offground precision loss to make us consistent 1E-15 offset 2024-11-27 16:06:58 +00:00
SamB440 77a91ec627 1.21.3 update 2024-11-27 16:06:07 +00:00
ManInMyVan 1036563b24 add BlockBreak class 2024-11-26 17:48:45 -07:00
AoElite dd5ea74ae4 update fastutils 2024-11-26 12:43:55 -05:00
AoElite aa7a4dc155 Merge pull request #1828 from ManInMyVan/paper-dupe-patch
patch paper dupe
2024-11-25 21:49:57 -05:00
ManInMyVan 3387365732 remove unused import 2024-11-25 17:55:25 -07:00
ManInMyVan 411aa4f2b2 patch paper dupe 2024-11-25 17:48:30 -07:00
SamB440 63a8e394a9 Merge pull request #1827 from ItsClairton/fix/cauldron
fix: Legacy cauldron collision box.
2024-11-26 00:02:59 +00:00
Clairton Santos 9804b8b62f fix: Legacy cauldron collision box. 2024-11-25 20:44:55 -03:00
Axionize f59279ad51 Comment cleanup 2024-11-25 16:20:32 -05:00
SamB440 f82cce32f6 Merge pull request #1724 from K-Lqrs/2.0
[Improved] Add full Japanese translations for all GrimAC configuration files
2024-11-25 15:29:13 +00:00
AoElite 474ae7dd27 small ResyncWorldUtil refactor 2024-11-25 07:16:47 -05:00
SamB440 d85c1d267b Merge pull request #1825 from Cyramek/fix-reach
fix wrongly ported reach changes from grim 3.0
2024-11-25 09:02:36 +00:00
cyramek 6ce2bcb9e9 fix wrongly ported changes from grim 3.0 2024-11-25 09:30:21 +01:00
AoElite 48eff610c3 fixed BadPackets E & R falsing on 1.21.2+ players in vehicles 2024-11-25 00:04:00 -05:00
AoElite 677dd044ff refactor bstats for packetevents 2024-11-25 00:02:34 -05:00
AoElite 87f30eea37 added a todo 2024-11-25 00:02:02 -05:00
AoElite 370da407ce update packetevents 2024-11-25 00:01:54 -05:00
Axionize 43e4c29f2c Document current state 2024-11-24 23:54:39 -05:00
Axionize 7924107b00 Finish faster equivalent impl 2024-11-24 23:54:39 -05:00
SamB440 1ef4b4eec9 Merge pull request #1821 from Axionize/fix-complex-fence-boxes
Fix CCB constructor for DynamicHitboxFence
2024-11-24 14:00:36 +00:00
AoElite 954eb8b51c Merge pull request #1783 from ManInMyVan/track-paintings
track paintings
2024-11-24 06:52:30 -05:00
AoElite 84ceaa29dc Merge pull request #1797 from ManInMyVan/stopspectating-here-permission
add permission for /grim stopspectating here
2024-11-24 06:49:33 -05:00
AoElite 6974d61b9d Merge pull request #1817 from Axionize/badpacketsx
Fix BadPacketsX false and mark it as no longer experimental
2024-11-24 06:46:58 -05:00
AoElite d9a3a890c8 Merge pull request #1818 from Axionize/badpacketsz
Mark BadPacketsZ as no longer experimental
2024-11-24 06:46:29 -05:00
AoElite c4495d995a Merge pull request #1820 from Axionize/use-movement-threshold
Use movementThreshold() instead of 0.03 where appropiate
2024-11-24 06:42:44 -05:00
Axionize 9bd5c2db0b Fix CCB constructor for DynamicHitboxFence 2024-11-24 02:38:55 -05:00
Axionize 2518b23f8b Use movementThreshold() instead of 0.03 where appropiate 2024-11-24 01:37:53 -05:00
Axionize bd2ceeeed4 Style fix 2024-11-24 00:28:46 -05:00
Axionize a6d082b355 Mark BadPacketsX as no longer experimental 2024-11-24 00:00:47 -05:00
Axionize 8af0dbc46d Mark BadPacketsZ as no longer experimental 2024-11-23 23:59:56 -05:00
Axionize 3fedd558d6 Fix BadPacketsX falses 2024-11-23 23:58:02 -05:00
Axionize 547a2965dd Warn players who want extra reach accuracy that they need to add paper.explicit-flush=true 2024-11-23 22:31:31 -05:00
ManInMyVan c19914e83f fix MutliActionsF false 2024-11-23 16:37:45 -07:00
ManInMyVan 6c14faa51d fix MutliActionsF falses 2024-11-23 16:37:06 -07:00
ManInMyVan 6b4060e0c4 fix MultiActionsF false 2024-11-23 16:37:06 -07:00
ManInMyVan 483706151b check sprinting in MultiActionsC and MultiActionsD 2024-11-23 16:37:06 -07:00
ManInMyVan 9dc128cc1d add MultiActionsF 2024-11-23 16:37:06 -07:00
ManInMyVan 50b7e84f58 offhand 2024-11-23 16:37:06 -07:00
ManInMyVan a77067ffe5 Add MultiActionsE 2024-11-23 16:37:06 -07:00
ManInMyVan 2a49635497 Add MutliActionsD 2024-11-23 16:37:05 -07:00
ManInMyVan a158019d66 Add MultiActions Checks 2024-11-23 16:37:05 -07:00
SamB440 5f7d296b4d Merge pull request #1814 from Axionize/dynamically-configurable-relocate
Make relocate read from project properties --> environment variable --> default to true
2024-11-23 19:11:32 +00:00
Axionize c4cd8136bf Ensure ComplexCollisionBoxes can only contain SimpleCollisionBoxes (#1805)
* Ensure ComplexCollisionBoxes can only contain SimpleCollisionBoxes

* Optimize ComplexCollisionBoxes by using primitives internally; Make new more efficient constructors available

* Port everything to new internal .downCast() API besides getCollisionBoxes

* implement new downCast() API for Dynamic, Simple, and No Collision Boxes

* Manually size ComplexCollisionBoxes Pt. 1

* Manually size ComplexCollisionBoxes Pt. 2

* Fix new downCast() for SimpleCollisionBox

* Fix logic error in CCB constructor

* Optimize DynamicHitboxFence

* Fix logic error again in CCB constructor

* Remove debug print statement

* Fix copying CCBs in edge case

* Rename variable for clarity

* Make CCD length private var

* Make makeShapes() CCD extra maxIndex explicit; Fix DynamicCollisionWall error

* Remove unused calls to makeShapes()
2024-11-23 10:57:15 +00:00
SamB440 dbc0c11795 Merge pull request #1813 from ManInMyVan/fix/falses
fix falses
2024-11-23 10:56:35 +00:00
Axionize d30b024bd3 Make whether or not to relocate deps read from project properties -> environment variable"
Prevents having to modify build.gradle.kts when disabling relocating.
2024-11-22 21:23:12 -05:00
ManInMyVan a3e979abc8 fix falses 2024-11-22 14:33:57 -07:00
SamB440 497d72e13b Merge pull request #1812 from Axionize/fix-pink-petal-hitbox-1.12.2-1.19.3
Fix Pink Petals Hitbox (Coral Fan) for > 1.12.2 and =< 1.19.3 players
2024-11-22 10:30:31 +00:00
Axionize 02c5021ce2 Fix Pink Petals Hitbox (Coral Fan) for > 1.12.2 and =< 1.19.3 players 2024-11-21 19:21:57 -05:00
AoElite e5bd42c15a Merge pull request #1811 from crimilo/2.0
Fix race condition and exception when registering check permissions during rapid consecutive player joins on server start
2024-11-20 19:22:44 -05:00
Cristian Milani 67a25de202 Fix race condition and exception when registering check permissions during rapid consecutive player joins on server start 2024-11-21 00:26:33 +01:00
AoElite 187d70d1f1 Merge pull request #1809 from Rothes/folia
Fix reading world asynchronously on Folia
2024-11-18 14:47:05 -05:00
Rothes 31fd590968 Fix reading world asynchronously on Folia 2024-11-19 02:21:43 +08:00
SamB440 2f57704bae Merge pull request #1807 from ManInMyVan/fix/multiplace-and-multiinteract-falses
fix MultiInteract and MultiPlace falses
2024-11-18 13:30:53 +00:00
ManInMyVan 4385073234 fix MultiInteract and MultiPlace falses 2024-11-17 18:05:10 -07:00
MachineBreaker 93f14a5b40 Optimise MenuType#getMenuType 2024-11-17 11:15:07 -04:00
MachineBreaker 39a812c5ff Merge pull request #1803 from GrimAnticheat/2.0-fastutil-usage
Use FastUtil collections where possible
2024-11-17 10:19:14 -04:00
MachineBreaker 367aac0274 Use FastUtil collections where possible 2024-11-17 10:06:22 -04:00
ManInMyVan 2de0f49af9 add permission for /grim stopspectating here 2024-11-15 15:04:04 -07:00
SamB440 c749a560fd Merge pull request #1795 from Axionize/button-pre-1.13-fix
Fix Button hitboxes for pre-1.13 players
2024-11-15 09:33:31 +00:00
Axionize 3c6742d040 Fix Button hitboxes for pre-1.13 players 2024-11-15 03:13:42 -05:00
SamB440 5dc3e08f22 This might fix aim modulo teleport falses 2024-11-14 16:39:12 +00:00
SamB440 1fb5762351 Gradle 8.10.2 2024-11-14 16:26:24 +00:00
SamB440 b51b661e23 Merge pull request #1788 from ManInMyVan/fix/noslow-alerts
fix NoSlowA alerting when flag returns false
2024-11-14 16:20:28 +00:00
SamB440 a540a9abb7 Merge pull request #1735 from GrimAnticheat/java-17
Java 17 update
2024-11-14 16:15:26 +00:00
SamB440 9035180db8 Update for HitboxData and CollisionData 2024-11-14 16:12:26 +00:00
SamB440 5a6f87fe22 Java 17 update 2024-11-14 15:59:51 +00:00
SamB440 fe95424e28 Merge pull request #1725 from Axionize/simulation-changes
All HitBox and CollisionBox Changes made for LineOfSightPlace
2024-11-14 15:57:12 +00:00
SamB440 d70e778f2d Merge pull request #1789 from ManInMyVan/folia
fix folia error
2024-11-14 15:50:40 +00:00
SamB440 8faa0db0ed Merge pull request #1793 from ManInMyVan/fix/shields
fix shields breaking causing noslow falses
2024-11-14 15:50:15 +00:00
MachineBreaker c4f133891d Merge pull request #1785 from jonesdevelopment/fix/dont-setback-crashb
Don't setback on CrashB
2024-11-14 06:43:08 -04:00
ManInMyVan 4b6eeadcc9 fix shields breaking causing noslow falses 2024-11-13 17:25:14 -07:00
ManInMyVan 9028135f61 fix folia error 2024-11-12 15:20:58 -07:00
ManInMyVan 8307e58449 fix NoSlowA alerting when flag returns false 2024-11-11 22:33:45 -07:00
SamB440 33766b11bc Limit when 1.9+ players can increase attack slow 2024-11-10 16:18:57 +00:00
SamB440 44fa35e6c7 Filter lava and water on FINISH_DIGGING 2024-11-10 15:53:25 +00:00
SamB440 26f205173e Merge pull request #1728 from ManInMyVan/multiaura
Add MultiInteract Checks
2024-11-10 15:46:16 +00:00
SamB440 7ff1ed0307 Merge pull request #1718 from ManInMyVan/exempt-MC-152728
exempt 1.14.2+ clients in NoSlowC and NoSlowD
2024-11-10 15:44:44 +00:00
SamB440 e50348ee32 Add spotless 2024-11-10 14:59:35 +00:00
Jones aee84e92cb Don't setback on CrashB 2024-11-10 15:58:59 +01:00
SamB440 a1f376bdb1 Merge pull request #1784 from jonesdevelopment/fix/strip-client-brand-colors
Strip color codes from client brand
2024-11-10 14:39:53 +00:00
SamB440 6483debd0a Merge pull request #1767 from BadPackage/patch-1
small doc fix
2024-11-10 14:39:39 +00:00
Jones 946c7a97a9 Strip color codes from client brand 2024-11-10 15:08:02 +01:00
ManInMyVan 39a53db067 track paintings 2024-11-09 17:08:10 -07:00
ManInMyVan b2db9ed9ff check sneaking in MutliInteractA 2024-11-08 13:54:03 -07:00
Lars 9bfc7d7d9b わずかな間違いを修正・2 2024-11-02 23:41:34 +13:00
Lars 7c93eda985 わずかな間違いを修正 2024-11-02 19:13:51 +13:00
Lars 1e7a858aa0 Japanese向けの翻訳を修正 2024-11-02 19:10:17 +13:00
Lars 11fba1b6bd configのja.ymlを修正済み 2024-11-02 19:06:11 +13:00
ManInMyVan b65f42a480 add check displaynames (#1669)
* add check displaynames

* oops
2024-11-01 16:32:34 +00:00
SamB440 e829c25c82 Merge pull request #1727 from ManInMyVan/negativetimer-setbacks
allow setbacks in NegativeTimer
2024-11-01 16:24:11 +00:00
SamB440 30c2d361a3 Merge pull request #1732 from Axionize/optimize-iteration-order
Optimizing getPossibleEyeHeights()
2024-10-31 21:54:17 +00:00
SamB440 15984b0a94 Merge branch '2.0' into optimize-iteration-order 2024-10-31 21:53:50 +00:00
AoElite 97de474b79 Merge pull request #1772 from ManInMyVan/fix/perm
fix permission default for already defined permissions
2024-10-30 19:53:03 -04:00
ManInMyVan cea13a719d fix permission default 2024-10-30 16:31:04 -06:00
AoElite faa471b197 catch permission error 2024-10-30 18:20:50 -04:00
ManInMyVan ce9d66c199 Allow exempting elytras 2024-10-27 12:51:33 -06:00
BadPackage d0eb36c87a small doc fix 2024-10-26 13:04:13 +02:00
SamB440 60f8812efd Merge pull request #1737 from Rothes/2.0
Fix config for Timer
2024-10-24 18:18:46 +01:00
SamB440 7e82f19961 Correctly handle reEncodeByDefault = false by last commit 2024-10-22 18:15:10 +01:00
AoElite 27aae68f14 add website 2024-10-22 12:00:33 -04:00
AoElite a65f24424f improved custom config manager handling 2024-10-22 11:59:43 -04:00
AoElite bfd3433423 regex optimization 2024-10-22 11:55:38 -04:00
AoElite 09e6cec6ef fix older versions of via throwing an error due to PR 2024-10-22 10:56:36 -04:00
AoElite 4ffe6f4fc5 packetevent optimizations 2024-10-22 10:11:02 -04:00
AoElite 4aaeb579e7 Merge pull request #1759 from ManInMyVan/fix/perm
fix exempt permission default
2024-10-22 02:09:38 -04:00
AoElite 487e9c6590 when reloading player configuration reload their checks & punishment manager as well for better API ease of use 2024-10-21 23:37:30 -04:00
SamB440 bdf7eb7c06 Merge pull request #1754 from Cyramek/via-version-fix
warn about `ViaVersion rotation-place fix`
2024-10-16 12:29:30 +01:00
ManInMyVan c70e5b8fff fix exempt permission default 2024-10-15 17:32:47 -06:00
SamB440 9599b1c631 Reduce Optional allocs with attribute methods 2024-10-14 14:24:19 +01:00
SamB440 85b42fa90e Merge pull request #1756 from ManInMyVan/fix/fr-config-noslow
fix fr.yml noslow
2024-10-13 19:50:11 +01:00
ManInMyVan 0c1a6c7775 fix fr.yml noslow 2024-10-13 12:47:08 -06:00
SamB440 d4508fa36b Fix AimModulo360? 2024-10-13 17:53:02 +01:00
SamB440 3cb1bb3792 Update actions 2024-10-13 17:50:51 +01:00
SamB440 faf0c7d3d6 Gradle 8.10.1 2024-10-13 17:49:47 +01:00
Cyramek c8ff1109e1 reverse that patch 2024-10-10 14:31:50 +02:00
AoElite de0c28beab reloading rework, allows you to have per player configurations & other things, doesn't cover every option yet 2024-10-10 08:00:33 -04:00
Cyramek acdacffcc0 take care of viaversion rotation fix, and warn server admin about that option 2024-10-10 13:56:22 +02:00
AoElite 3cab3fe680 Merge pull request #1744 from ManInMyVan/fix/bpZ
fix a BadPacketsZ false
2024-10-07 16:09:44 -04:00
AoElite 880a7b5e74 Merge pull request #1751 from Axionize/optimize-attribute-iteration
Optimize looping over attribute modifier properties
2024-10-07 16:09:30 -04:00
ManInMyVan 504e667d40 fix MultiInteractB false 2024-10-05 22:38:09 -06:00
ManInMyVan f8aa611a4b fix MultiInteractA false 2024-10-05 22:35:55 -06:00
Axionize c4848efc8a Optimize looping over attribute modifier properties 2024-10-05 19:32:14 -04:00
SamB440 0ddf0b5d22 Merge pull request #1749 from ManInMyVan/fix/mutliplace
fix multiplace false
2024-10-06 00:26:26 +01:00
SamB440 fde6e03b98 Merge pull request #1750 from Axionize/fix-attribute-clamp
Fix incorrect casting to float before clamping attribute values
2024-10-06 00:19:44 +01:00
Axionize 55c084216d Fix incorrect casting to float before clamping attribute values 2024-10-05 17:32:07 -04:00
ManInMyVan f3074e3934 fix multiplace false 2024-10-05 13:15:11 -06:00
ManInMyVan 748eb398b8 fix a BadPacketsZ false
also use MessageUtil
2024-09-28 17:59:06 -06:00
Axionize dc7f6dca93 Make result player.getPossibleEyeHeights() of final in checks and remove unused imports 2024-09-27 23:57:23 -04:00
Axionize 472415e0d4 Removing unneeded special case handling 2024-09-26 17:13:11 -04:00
Rothes da61ff673a Fix constructor default value overriding configured value 2024-09-25 17:12:26 +08:00
Axionize 01ca8c894e Readability/documentation improvements 2024-09-25 00:51:22 -04:00
Axionize f724d6d78e 1.8 Players 2024-09-25 00:32:07 -04:00
Axionize ee6183db90 Handle player joining on new version -> scale changing -> old version 2024-09-25 00:32:07 -04:00
Axionize e959ef37db Optimize returned array for crawling 2024-09-25 00:32:07 -04:00
Axionize f62d8602b8 fix conditionall check 2024-09-25 00:32:07 -04:00
Axionize bf44dd6855 Only rewrite player possibleEyeHeights when player scale changes 2024-09-25 00:32:07 -04:00
Axionize 1beedd77c3 Don't bother updating scale attribute if no change is made 2024-09-23 21:14:30 -04:00
Axionize c34ad88a13 Fix intializing array 2024-09-23 21:02:33 -04:00
Axionize 619e7f1404 Simplify logic and handle caching even when scale changes 2024-09-23 21:02:33 -04:00
Axionize 927b330c4b Cache eyeHeights where possible 2024-09-22 17:30:02 -04:00
Axionize bff6854189 make getPossibleEyeHeights return most likely heights 2024-09-22 17:18:06 -04:00
Axionize 290bf9032e Backport patch 2024-09-21 20:33:30 -04:00
Axionize 2629536ad7 Optimize getPossibleEyeHeights() 2024-09-21 20:24:31 -04:00
ManInMyVan a38f341965 Add MultiInteract Checks 2024-09-19 16:11:51 -06:00
ManInMyVan 262de24cbf allow setbacks in NegativeTimer 2024-09-18 20:14:11 -06:00
Ruxy 330a9782bc Add full Japanese translations for all GrimAC configuration files 2024-09-17 10:31:53 +12:00
ManInMyVan f6ef1df29d exempt 1.14.2+ clients in NoSlowC and NoSlowD 2024-09-13 13:02:40 -06:00
308 changed files with 6651 additions and 3171 deletions

No files matched your search

+4 -4
View File
@@ -39,11 +39,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -54,7 +54,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v3
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -68,4 +68,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v3
+4 -4
View File
@@ -19,9 +19,9 @@ jobs:
packages: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
@@ -29,10 +29,10 @@ jobs:
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
uses: gradle/actions/setup-gradle@v3
with:
arguments: build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v3.1.0
uses: actions/upload-artifact@v4
with:
path: /home/runner/work/Grim/Grim/build/libs/**.jar
+31 -10
View File
@@ -1,21 +1,42 @@
# 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
> [!WARNING]
> Java 17 is now required. More information [here](https://github.com/GrimAnticheat/Grim/wiki/Updating-to-Java-17).
- 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
+60 -13
View File
@@ -6,17 +6,39 @@ plugins {
id("com.github.johnrengelman.shadow") version "8.1.1"
id("io.freefair.lombok") version "8.6"
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
id("com.diffplug.spotless") version "6.25.0"
}
spotless {
java {
endWithNewline()
indentWithSpaces(4)
removeUnusedImports()
trimTrailingWhitespace()
targetExclude("build/generated/**/*")
}
kotlinGradle {
endWithNewline()
indentWithSpaces(4)
trimTrailingWhitespace()
}
}
group = "ac.grim.grimac"
version = "2.3.68"
version = "2.3.69"
description = "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0."
java.sourceCompatibility = JavaVersion.VERSION_1_8
java.targetCompatibility = JavaVersion.VERSION_1_8
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
}
// 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
repositories {
mavenLocal()
@@ -33,25 +55,32 @@ 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")
implementation("com.github.retrooper:packetevents-spigot:2.7.1-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.github.grimanticheat:grimapi:1193c4fa41")
// Used for local testing: implementation("ac.grim.grimac:grimapi:1.0")
// Used for local testing:
//implementation("ac.grim.grimac:GrimAPI:1.0")
implementation("com.github.grimanticheat:grimapi:ed1ec7b4a1")
implementation("net.kyori:adventure-text-minimessage:4.17.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:4.9.4-SNAPSHOT")
//
compileOnly("io.papermc.paper:paper-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")
}
@@ -59,6 +88,7 @@ bukkit {
name = "GrimAC"
author = "GrimAC"
main = "ac.grim.grimac.GrimAC"
website = "https://grim.ac/"
apiVersion = "1.13"
foliaSupported = true
@@ -71,7 +101,8 @@ bukkit {
"ViaRewind",
"Geyser-Spigot",
"floodgate",
"FastLogin"
"FastLogin",
"PlaceholderAPI",
)
permissions {
@@ -100,6 +131,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
@@ -119,11 +155,22 @@ 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
}
}
}
tasks.build {
dependsOn(tasks.shadowJar)
dependsOn(tasks.spotlessApply)
}
tasks.withType<JavaCompile> {
@@ -156,4 +203,4 @@ tasks.shadowJar {
relocate("org.intellij", "ac.grim.grimac.shaded.intellij")
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
}
}
}
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+1 -2
View File
@@ -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
+2 -6
View File
@@ -1,17 +1,16 @@
package ac.grim.grimac;
import ac.grim.grimac.api.GrimAbstractAPI;
import ac.grim.grimac.manager.*;
import ac.grim.grimac.manager.config.BaseConfigManager;
import ac.grim.grimac.utils.anticheat.PlayerDataManager;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
@Getter
public enum GrimAPI {
INSTANCE;
private final BaseConfigManager configManager = new BaseConfigManager();
private final AlertManagerImpl alertManager = new AlertManagerImpl();
private final SpectateManager spectateManager = new SpectateManager();
private final DiscordManager discordManager = new DiscordManager();
@@ -19,12 +18,10 @@ public enum GrimAPI {
private final TickManager tickManager = new TickManager();
private final GrimExternalAPI externalAPI = new GrimExternalAPI(this);
private InitManager initManager;
private ConfigManager configManager;
private JavaPlugin plugin;
public void load(final JavaPlugin plugin) {
this.plugin = plugin;
this.configManager = new ConfigManager();
initManager = new InitManager();
initManager.load();
}
@@ -32,7 +29,6 @@ public enum GrimAPI {
public void start(final JavaPlugin plugin) {
this.plugin = plugin;
initManager.start();
Bukkit.getServicesManager().register(GrimAbstractAPI.class, externalAPI, plugin, ServicePriority.Normal);
}
public void stop(final JavaPlugin plugin) {
+148 -42
View File
@@ -1,25 +1,35 @@
package ac.grim.grimac;
import ac.grim.grimac.api.AbstractCheck;
import ac.grim.grimac.api.GrimAbstractAPI;
import ac.grim.grimac.api.GrimUser;
import ac.grim.grimac.api.alerts.AlertManager;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.api.events.GrimReloadEvent;
import ac.grim.grimac.manager.config.ConfigManagerFileImpl;
import ac.grim.grimac.manager.init.Initable;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.common.ConfigReloadObserver;
import com.github.retrooper.packetevents.netty.channel.ChannelHelper;
import io.github.retrooper.packetevents.util.SpigotReflectionUtil;
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginDescriptionFile;
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;
//This is used for grim's external API. It has its own class just for organization.
public class GrimExternalAPI implements GrimAbstractAPI, Initable {
public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, Initable {
private final GrimAPI api;
@@ -34,17 +44,19 @@ public class GrimExternalAPI implements GrimAbstractAPI, Initable {
}
@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
private final Map<String, Function<GrimUser, String>> variableReplacements = new ConcurrentHashMap<>();
@Getter private final Map<String, String> staticReplacements = new ConcurrentHashMap<>();
@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());
}
@@ -56,12 +68,20 @@ public class GrimExternalAPI implements GrimAbstractAPI, Initable {
@Override
public void registerVariable(String string, Function<GrimUser, String> replacement) {
variableReplacements.put(string, replacement);
if (replacement == null) {
variableReplacements.remove(string);
} else {
variableReplacements.put(string, replacement);
}
}
@Override
public void registerVariable(String variable, String replacement) {
staticReplacements.put(variable, replacement);
if (replacement == null) {
staticReplacements.remove(variable);
} else {
staticReplacements.put(variable, replacement);
}
}
@Override
@@ -70,34 +90,20 @@ public class GrimExternalAPI implements GrimAbstractAPI, Initable {
return description.getVersion();
}
private final Map<String, Function<Object, Object>> functions = new ConcurrentHashMap<>();
@Override
public void registerFunction(String key, Function<Object, Object> function) {
if (function == null) {
functions.remove(key);
} else {
functions.put(key, function);
}
}
@Override
public Function<Object, Object> getFunction(String key) {
return null;
}
@Override
public void reload() {
GrimAPI.INSTANCE.getConfigManager().reload();
//Reload checks for all players
for (GrimPlayer grimPlayer : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
ChannelHelper.runInEventLoop(grimPlayer.user.getChannel(), () -> {
grimPlayer.onReload();
grimPlayer.updatePermissions();
grimPlayer.punishmentManager.reload();
for (AbstractCheck value : grimPlayer.checkManager.allChecks.values()) {
value.reload();
}
});
}
//Restart
GrimAPI.INSTANCE.getDiscordManager().start();
GrimAPI.INSTANCE.getSpectateManager().start();
GrimAPI.INSTANCE.getExternalAPI().start();
return functions.get(key);
}
@Override
@@ -106,16 +112,116 @@ public class GrimExternalAPI implements GrimAbstractAPI, Initable {
}
@Override
public void start() {
variableReplacements.put("%player%", GrimUser::getName);
variableReplacements.put("%uuid%", user -> user.getUniqueId().toString());
variableReplacements.put("%ping%", user -> user.getTransactionPing() + "");
variableReplacements.put("%brand%", GrimUser::getBrand);
variableReplacements.put("%h_sensitivity%", user -> ((int) Math.round(user.getHorizontalSensitivity() * 200)) + "");
variableReplacements.put("%v_sensitivity%", user -> ((int) Math.round(user.getVerticalSensitivity() * 200)) + "");
variableReplacements.put("%fast_math%", user -> !user.isVanillaMath() + "");
variableReplacements.put("%tps%", user -> String.format("%.2f", SpigotReflectionUtil.getTPS()));
variableReplacements.put("%version%", GrimUser::getVersionName);
variableReplacements.put("%prefix%", user -> ChatColor.translateAlternateColorCodes('&', GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("prefix", "&bGrim &8»")));
public ConfigManager getConfigManager() {
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;
// on load, load the config & register the service
public void load() {
reload(configManagerFile);
Bukkit.getServicesManager().register(GrimAbstractAPI.class, this, GrimAPI.INSTANCE.getPlugin(), ServicePriority.Normal);
}
// handles any config loading that's needed to be done after load
@Override
public void start() {
started = true;
try {
GrimAPI.INSTANCE.getConfigManager().start();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void reload(ConfigManager config) {
if (config.isLoadedAsync() && started) {
FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
o -> successfulReload(config));
} else {
successfulReload(config);
}
}
@Override
public CompletableFuture<Boolean> reloadAsync(ConfigManager config) {
if (config.isLoadedAsync() && started) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
o -> future.complete(successfulReload(config)));
return future;
}
return CompletableFuture.completedFuture(successfulReload(config));
}
private boolean successfulReload(ConfigManager config) {
try {
config.reload();
GrimAPI.INSTANCE.getConfigManager().load(config);
if (started) GrimAPI.INSTANCE.getConfigManager().start();
onReload(config);
if (started) FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
o -> Bukkit.getPluginManager().callEvent(new GrimReloadEvent(true)));
return true;
} catch (Exception e) {
e.printStackTrace();
}
if (started) FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
o -> Bukkit.getPluginManager().callEvent(new GrimReloadEvent(false)));
return false;
}
@Override
public void onReload(ConfigManager newConfig) {
if (newConfig == null) {
LogUtil.warn("ConfigManager not set. Using default config file manager.");
configManager = configManagerFile;
} else {
configManager = newConfig;
}
// Update variables
updateVariables();
// Restart
GrimAPI.INSTANCE.getDiscordManager().start();
GrimAPI.INSTANCE.getSpectateManager().start();
// Don't reload players if the plugin hasn't started yet
if (!started) return;
// Reload checks for all players
for (GrimPlayer grimPlayer : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
ChannelHelper.runInEventLoop(grimPlayer.user.getChannel(), () -> {
grimPlayer.updatePermissions();
grimPlayer.reload(configManager);
});
}
}
private void updateVariables() {
variableReplacements.putIfAbsent("%player%", GrimUser::getName);
variableReplacements.putIfAbsent("%uuid%", user -> user.getUniqueId().toString());
variableReplacements.putIfAbsent("%ping%", user -> user.getTransactionPing() + "");
variableReplacements.putIfAbsent("%brand%", GrimUser::getBrand);
variableReplacements.putIfAbsent("%h_sensitivity%", user -> ((int) Math.round(user.getHorizontalSensitivity() * 200)) + "");
variableReplacements.putIfAbsent("%v_sensitivity%", user -> ((int) Math.round(user.getVerticalSensitivity() * 200)) + "");
variableReplacements.putIfAbsent("%fast_math%", user -> !user.isVanillaMath() + "");
variableReplacements.putIfAbsent("%tps%", user -> String.format("%.2f", SpigotReflectionUtil.getTPS()));
variableReplacements.putIfAbsent("%version%", GrimUser::getVersionName);
// static variables
staticReplacements.put("%prefix%", ChatColor.translateAlternateColorCodes('&', GrimAPI.INSTANCE.getConfigManager().getPrefix()));
staticReplacements.putIfAbsent("%grim_version%", getGrimVersion());
}
}
+82 -33
View File
@@ -2,11 +2,13 @@ package ac.grim.grimac.checks;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.AbstractCheck;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.api.events.FlagEvent;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import github.scarsz.configuralize.DynamicConfig;
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;
@@ -14,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 {
public class Check extends GrimProcessor implements AbstractCheck {
protected final GrimPlayer player;
public double violations;
@@ -24,25 +26,22 @@ public class Check implements AbstractCheck {
private String checkName;
private String configName;
private String alternativeName;
private String displayName;
private String description;
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
@@ -52,24 +51,33 @@ public class Check implements AbstractCheck {
this.alternativeName = checkData.alternativeName();
this.experimental = checkData.experimental();
this.description = checkData.description();
this.displayName = this.checkName;
}
reload();
}
public boolean shouldModifyPackets() {
return isEnabled && !player.disableGrim && !player.noModifyPacketPermission && !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;
}
@@ -81,16 +89,21 @@ public class Check implements AbstractCheck {
}
public final boolean flag() {
if (player.disableGrim || (experimental && !GrimAPI.INSTANCE.getConfigManager().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;
}
@@ -107,32 +120,36 @@ public class Check implements AbstractCheck {
violations = Math.max(0, violations - decay);
}
public void reload() {
decay = getConfig().getDoubleElse(configName + ".decay", decay);
setbackVL = getConfig().getDoubleElse(configName + ".setbackvl", setbackVL);
@Override
public void reload(ConfigManager configuration) {
decay = configuration.getDoubleElse(configName + ".decay", decay);
setbackVL = configuration.getDoubleElse(configName + ".setbackvl", setbackVL);
displayName = configuration.getStringElse(configName + ".displayname", checkName);
description = configuration.getStringElse(configName + ".description", description);
if (setbackVL == -1) setbackVL = Double.MAX_VALUE;
updatePermissions();
onReload(configuration);
}
@Override
public void onReload(ConfigManager config) {
updateExempted();
}
public boolean alert(String verbose) {
return player.punishmentManager.handleAlert(player, verbose, this);
}
public DynamicConfig getConfig() {
return GrimAPI.INSTANCE.getConfigManager().getConfig();
}
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) {
@@ -144,5 +161,37 @@ public class Check implements AbstractCheck {
packetType == PacketType.Play.Client.WINDOW_CONFIRMATION;
}
}
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());
}
}
@@ -11,7 +11,8 @@ import ac.grim.grimac.utils.anticheat.update.RotationUpdate;
// It works on clients who % 360 their rotation.
@CheckData(name = "AimModulo360", decay = 0.005)
public class AimModulo360 extends Check implements RotationCheck {
float lastDeltaYaw;
private float lastDeltaYaw;
public AimModulo360(GrimPlayer playerData) {
super(playerData);
@@ -19,12 +20,18 @@ public class AimModulo360 extends Check implements RotationCheck {
@Override
public void process(final RotationUpdate rotationUpdate) {
lastDeltaYaw = rotationUpdate.getDeltaXRot();
if (player.packetStateData.lastPacketWasTeleport) return;
// Exempt for teleport or entering a vehicle due to rotation reset
if (player.packetStateData.lastPacketWasTeleport || player.vehicleData.wasVehicleSwitch) {
lastDeltaYaw = rotationUpdate.getDeltaXRot();
return;
}
if (player.xRot < 360 && player.xRot > -360 && Math.abs(rotationUpdate.getDeltaXRot()) > 320 && Math.abs(lastDeltaYaw) < 30) {
flagAndAlert();
} else {
reward();
}
lastDeltaYaw = rotationUpdate.getDeltaXRot();
}
}
@@ -59,15 +59,15 @@ public class AimProcessor extends Check implements RotationCheck {
if (this.xRotMode.size() > SIGNIFICANT_SAMPLES_THRESHOLD) {
Pair<Double, Integer> modeX = this.xRotMode.getMode();
if (modeX.getSecond() > SIGNIFICANT_SAMPLES_THRESHOLD) {
this.modeX = modeX.getFirst();
if (modeX.second() > SIGNIFICANT_SAMPLES_THRESHOLD) {
this.modeX = modeX.first();
this.sensitivityX = convertToSensitivity(this.modeX);
}
}
if (this.yRotMode.size() > SIGNIFICANT_SAMPLES_THRESHOLD) {
Pair<Double, Integer> modeY = this.yRotMode.getMode();
if (modeY.getSecond() > SIGNIFICANT_SAMPLES_THRESHOLD) {
this.modeY = modeY.getFirst();
if (modeY.second() > SIGNIFICANT_SAMPLES_THRESHOLD) {
this.modeY = modeY.first();
this.sensitivityY = convertToSensitivity(this.modeY);
}
}
@@ -81,4 +81,4 @@ public class AimProcessor extends Check implements RotationCheck {
double var9 = Math.cbrt(var11);
return (var9 - 0.2f) / 0.6f;
}
}
}
@@ -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.compensatedEntities.getSelf().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;
}
}
@@ -10,9 +10,8 @@ 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.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
@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
@@ -42,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();
@@ -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 = "BadPacketsM", experimental = true)
@CheckData(name = "BadPacketsM")
public class BadPacketsM extends Check implements PacketCheck {
public BadPacketsM(final GrimPlayer player) {
super(player);
@@ -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);
@@ -39,7 +39,7 @@ public class BadPacketsO extends Check implements PacketCheck {
boolean hasID = false;
for (Pair<Long, Long> iterator : keepaliveMap) {
if (iterator.getFirst() == id) {
if (iterator.first() == id) {
hasID = true;
break;
}
@@ -55,7 +55,7 @@ public class BadPacketsO extends Check implements PacketCheck {
do {
data = keepaliveMap.poll();
if (data == null) break;
} while (data.getFirst() != id);
} while (data.first() != id);
}
}
}
@@ -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,22 @@ 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
boolean flag = switch (clickType) {
case PICKUP, QUICK_MOVE, CLONE -> button > 2 || button < 0;
case SWAP -> (button > 8 || button < 0) && button != 40;
case THROW -> button != 0 && button != 1;
case QUICK_CRAFT -> button == 3 || button == 7 || button > 10 || button < 0;
case PICKUP_ALL -> button != 0;
case UNKNOWN -> false;
};
//TODO: Adjust for containers
switch (clickType) {
case 0:
case 1:
case 4:
if (button != 0 && button != 1) flag = true;
break;
case 2:
if ((button > 8 || button < 0) && button != 40) flag = true;
break;
case 3:
if (button != 2) flag = true;
break;
case 5:
if (button == 3 || button == 7 || button > 10 || button < 0) flag = true;
break;
case 6:
if (button != 0) flag = true;
break;
}
//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();
@@ -26,7 +26,7 @@ public class BadPacketsR extends Check implements PacketCheck {
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);
flag("time=" + ms + "ms, " + "lst=" + diff + "ms, positions=" + positions);
} else {
reward();
}
@@ -41,7 +41,8 @@ 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()) {
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)) {
@@ -6,7 +6,6 @@ import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
@@ -15,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,43 +2,78 @@ 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.nmsutil.BlockBreakSpeed;
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--) {
if (flagAndAlert()) {
setbackIfAboveSetbackVL();
}
}
}
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) {
switch (new WrapperPlayClientEntityAction(event).getAction()) {
case START_SNEAKING, STOP_SNEAKING -> {
if (sneak) {
if (player.canSkipTicks() || flagAndAlert()) {
flags++;
}
}
sneak = true;
}
case START_SPRINTING, STOP_SPRINTING -> {
if (player.inVehicle()) {
return;
}
if (sprint) {
if (player.canSkipTicks() || flagAndAlert()) {
flags++;
}
}
sprint = true;
}
}
}
}
}
@@ -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,70 @@
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;
@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;
private Vector3i lastBreakLoc;
private StateType lastBlockType;
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.compensatedEntities.getSelf().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.getSelf().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,111 @@
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.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
// 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 {
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
if (WrappedBlockState.getDefaultState(player.getClientVersion(), block.getType()).getType() == StateTypes.AIR) {
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) && 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 + ",Balance=" + blockBreakBalance) && shouldModifyPackets()) {
blockBreak.cancel();
}
}
lastFinishBreak = 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,61 @@
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.compensatedEntities.getSelf().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 -> eyePositions.minZ > combined.minZ; // Z- face
case SOUTH -> eyePositions.maxZ < combined.maxZ; // Z+ face
case EAST -> eyePositions.maxX < combined.maxX; // X+ face
case WEST -> eyePositions.minX > combined.minX; // X- face
case UP -> eyePositions.maxY < combined.maxY; // Y+ face
case DOWN -> eyePositions.minY > combined.minY; // Y- face
default -> false;
};
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;
}
}
}
@@ -1,23 +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);
}
@@ -39,13 +38,10 @@ public class BadPacketsZ extends Check implements PacketCheck {
return player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || getBlockDamage(player, pos) < 1;
}
private String formatted(Vector3i vec) {
return vec == null ? "null" : vec.x + ", " + vec.y + ", " + vec.z;
}
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;
@@ -53,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 = null;
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=" + formatted(lastBlock) + ", pos=" + formatted(pos))) {
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();
}
}
}
@@ -82,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=" + formatted(lastBlock) + ", pos=" + formatted(pos))) {
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 = "Hitboxes", setback = 10)
public class Hitboxes extends Check implements PacketCheck {
public Hitboxes(GrimPlayer player) {
super(player);
}
}
@@ -0,0 +1,68 @@
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.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.GameMode;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import java.util.ArrayList;
@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);
}
private final ArrayList<String> flags = new ArrayList<>();
private int lastEntity;
private boolean lastSneaking;
private boolean hasInteracted = false;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
int entity = packet.getEntityId();
boolean sneaking = packet.isSneaking().orElse(false);
if (hasInteracted && entity != lastEntity) {
String verbose = "lastEntity=" + lastEntity + ", entity=" + entity
+ ", lastSneaking=" + lastSneaking + ", sneaking=" + sneaking;
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add(verbose);
}
}
lastEntity = entity;
lastSneaking = sneaking;
hasInteracted = true;
}
if (player.gamemode == GameMode.SPECTATOR || isTickPacket(event.getPacketType())) {
hasInteracted = 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,69 @@
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.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
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.GameMode;
import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import java.util.ArrayList;
@CheckData(name = "MultiInteractB", experimental = true)
public class MultiInteractB extends Check implements PostPredictionCheck {
public MultiInteractB(final GrimPlayer player) {
super(player);
}
private final ArrayList<String> flags = new ArrayList<>();
private Vector3f lastPos;
private boolean hasInteracted = false;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
Vector3f pos = new WrapperPlayClientInteractEntity(event).getTarget().orElse(null);
if (pos == null) {
return;
}
if (hasInteracted && !pos.equals(lastPos)) {
String verbose = "pos=" + MessageUtil.toUnlabledString(pos) + ", lastPos=" + MessageUtil.toUnlabledString(lastPos);
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add(verbose);
}
}
lastPos = pos;
hasInteracted = true;
}
if (player.gamemode == GameMode.SPECTATOR || isTickPacket(event.getPacketType())) {
hasInteracted = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
}
flags.clear();
}
}
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
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.type.PacketCheck;
@@ -32,17 +33,20 @@ import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.util.Vector3d;
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.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 Map<Integer, Vector3d> playerAttackQueue = new HashMap<>();
private final Int2ObjectMap<Vector3d> playerAttackQueue = new Int2ObjectOpenHashMap<>();
private static final List<EntityType> blacklisted = Arrays.asList(
EntityTypes.BOAT,
EntityTypes.CHEST_BOAT,
@@ -80,7 +84,7 @@ public class Reach extends Check implements PacketCheck {
}
return;
}
// Dead entities cause false flags (https://github.com/GrimAnticheat/Grim/issues/546)
if (entity.isDead) return;
@@ -105,9 +109,7 @@ 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) {
if (isUpdate(event.getPacketType())) {
tickBetterReachCheckWithAngle();
}
}
@@ -130,34 +132,40 @@ public class Reach extends Check implements PacketCheck {
// 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
CheckResult result = checkReach(reachEntity, new Vector3d(player.x, player.y, player.z), true);
return result.isFlag(); // 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.getSelf().getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE);
}
}
private void tickBetterReachCheckWithAngle() {
for (Map.Entry<Integer, Vector3d> attack : playerAttackQueue.entrySet()) {
PacketEntity reachEntity = player.compensatedEntities.entityMap.get(attack.getKey().intValue());
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());
}
for (Int2ObjectMap.Entry<Vector3d> attack : playerAttackQueue.int2ObjectEntrySet()) {
PacketEntity reachEntity = player.compensatedEntities.entityMap.get(attack.getIntKey());
if (reachEntity == null) continue;
CheckResult result = checkReach(reachEntity, attack.getValue(), false);
switch (result.type()) {
case REACH -> {
String added = reachEntity.getType() == EntityTypes.PLAYER ? "" : ", type=" + reachEntity.getType().getName().getKey();
flagAndAlert(result.verbose() + added);
}
case HITBOX -> {
String added = reachEntity.getType() == EntityTypes.PLAYER ? "" : "type=" + reachEntity.getType().getName().getKey();
player.checkManager.getPacketCheck(Hitboxes.class).flagAndAlert(result.verbose() + added);
}
}
}
playerAttackQueue.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
@@ -176,7 +184,8 @@ public class Reach extends Check implements PacketCheck {
// 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;
@@ -199,14 +208,17 @@ public class Reach extends Check implements PacketCheck {
}
}
final double maxReach = player.compensatedEntities.getSelf().getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE);
// +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 distance = maxReach + 3;
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
final Vector eyePos = new Vector(from.getX(), 0, from.getZ());
for (Vector lookVec : possibleLookDirs) {
for (double eye : player.getPossibleEyeHeights()) {
Vector eyePos = new Vector(from.getX(), from.getY() + eye, from.getZ());
for (double eye : possibleEyeHeights) {
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).getFirst();
Vector intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).first();
if (ReachUtils.isVecInside(targetBox, eyePos)) {
minDistance = 0;
@@ -223,22 +235,33 @@ public class Reach extends Check implements PacketCheck {
if ((!blacklisted.contains(reachEntity.getType()) && reachEntity.isLivingEntity()) || reachEntity.getType() == EntityTypes.END_CRYSTAL) {
if (minDistance == Double.MAX_VALUE) {
cancelBuffer = 1;
return "Missed hitbox";
} else if (minDistance > player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE)) {
return new CheckResult(ResultType.HITBOX, "");
} else if (minDistance > maxReach) {
cancelBuffer = 1;
return String.format("%.5f", minDistance) + " blocks";
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 record CheckResult(ResultType type, String verbose) {
public boolean isFlag() {
return type != ResultType.NONE;
}
}
private enum ResultType {
REACH, HITBOX, NONE
}
@Override
public void reload() {
super.reload();
this.cancelImpossibleHits = getConfig().getBooleanElse("Reach.block-impossible-hits", true);
this.threshold = getConfig().getDoubleElse("Reach.threshold", 0.0005);
public void onReload(ConfigManager config) {
this.cancelImpossibleHits = config.getBooleanElse("Reach.block-impossible-hits", true);
this.threshold = 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);
@@ -18,7 +18,6 @@ public class CrashB extends Check implements PacketCheck {
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CREATIVE_INVENTORY_ACTION) {
if (player.gamemode != GameMode.CREATIVE) {
player.getSetbackTeleportUtil().executeViolationSetback();
event.setCancelled(true);
player.onPacketCancel();
flagAndAlert(); // Could be transaction split, no need to setback though
@@ -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,7 +32,7 @@ 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();
@@ -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.getSelf().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,55 @@
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();
if (!command.stripTrailing().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();
}
}
}
}
}
@@ -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);
}
@@ -43,7 +43,10 @@ public class NoFallA extends Check implements PacketCheck {
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 (shouldModifyPackets()) wrapper.setOnGround(false);
if (shouldModifyPackets()) {
wrapper.setOnGround(false);
event.markForReEncode(true);
}
}
}
}
@@ -59,10 +62,16 @@ public class NoFallA extends Check implements PacketCheck {
// Also flip teleports because I don't trust vanilla's handling of teleports and ground
if (flipPlayerGroundStatus) {
flipPlayerGroundStatus = false;
if (shouldModifyPackets()) wrapper.setOnGround(!wrapper.isOnGround());
if (shouldModifyPackets()) {
wrapper.setOnGround(!wrapper.isOnGround());
event.markForReEncode(true);
}
}
if (player.packetStateData.lastPacketWasTeleport) {
if (shouldModifyPackets()) wrapper.setOnGround(false);
if (shouldModifyPackets()) {
wrapper.setOnGround(false);
event.markForReEncode(true);
}
}
}
}
@@ -2,18 +2,24 @@ 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.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
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;
@Getter
private String brand = "vanilla";
private boolean hasBrand = false;
public ClientBrand(GrimPlayer player) {
super(player);
@@ -23,39 +29,39 @@ 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);
private void handle(String channel, byte[] data) {
final String expectedChannel = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13) ? "minecraft:brand" : "MC|Brand";
if (!channel.equals(expectedChannel)) return;
brand = new String(minusLength).replace(" (Velocity)", ""); //removes velocity's brand suffix
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);
}
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%");
message = MessageUtil.replacePlaceholders(player, message);
Component component = 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);
}
}
@@ -1,5 +1,6 @@
package ac.grim.grimac.checks.impl.misc;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.checks.type.BlockPlaceCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
@@ -63,10 +64,9 @@ public class GhostBlockMitigation extends BlockPlaceCheck {
}
@Override
public void reload() {
super.reload();
allow = getConfig().getBooleanElse("exploit.allow-building-on-ghostblocks", true);
distance = getConfig().getIntElse("exploit.distance-to-check-for-ghostblocks", 2);
public void onReload(ConfigManager config) {
allow = config.getBooleanElse("exploit.allow-building-on-ghostblocks", true);
distance = config.getIntElse("exploit.distance-to-check-for-ghostblocks", 2);
if (distance < 2 || distance > 4) distance = 2;
}
@@ -5,13 +5,9 @@ import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import java.util.ArrayList;
@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();
}
}
@@ -1,5 +1,6 @@
package ac.grim.grimac.checks.impl.movement;
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;
@@ -7,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 (Prediction)", configName = "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
@@ -16,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);
}
@@ -33,8 +34,7 @@ public class NoSlowA extends Check implements PostPredictionCheck {
}
if (bestOffset > offsetToFlag) {
if (flaggedLastTick) {
flagWithSetback();
if (flaggedLastTick && flagWithSetback()) {
alert("");
}
flaggedLastTick = true;
@@ -51,8 +51,7 @@ public class NoSlowA extends Check implements PostPredictionCheck {
}
@Override
public void reload() {
super.reload();
offsetToFlag = getConfig().getDoubleElse("NoSlowA.threshold", 0.001);
public void onReload(ConfigManager config) {
offsetToFlag = config.getDoubleElse("NoSlow.threshold", 0.001);
}
}
@@ -1,53 +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.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.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
@CheckData(name = "NoSlowC", setback = 5, experimental = true)
public class NoSlowC extends Check implements PostPredictionCheck, PacketCheck {
public NoSlowC(GrimPlayer player) {
super(player);
}
public boolean startedSprintingBeforeSlowMovement = false;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
if (new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_SPRINTING) {
startedSprintingBeforeSlowMovement = false;
}
}
}
@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 (startedSprintingBeforeSlowMovement && client.isNewerThanOrEquals(ClientVersion.V_1_14_2)) {
reward();
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();
}
}
}
@@ -6,7 +6,6 @@ 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.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
public class SetbackBlocker extends Check implements PacketCheck {
@@ -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();
}
}
@@ -15,7 +15,6 @@ 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.WrapperPlayClientEntityAction;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityAnimation;
import java.util.ArrayDeque;
@@ -25,7 +24,7 @@ import java.util.Locale;
import static com.github.retrooper.packetevents.protocol.packettype.PacketType.Play.Client.*;
@CheckData(name = "Post")
public class PostCheck extends Check implements PacketCheck, PostPredictionCheck {
public class Post extends Check implements PacketCheck, PostPredictionCheck {
private final ArrayDeque<PacketTypeCommon> post = new ArrayDeque<>();
// Due to 1.9+ missing the idle packet, we must queue flags
// 1.8 clients will have the same logic for simplicity, although it's not needed
@@ -33,7 +32,7 @@ public class PostCheck extends Check implements PacketCheck, PostPredictionCheck
private boolean sentFlying = false;
private int isExemptFromSwingingCheck = Integer.MIN_VALUE;
public PostCheck(GrimPlayer playerData) {
public Post(GrimPlayer playerData) {
super(playerData);
}
@@ -68,12 +67,7 @@ public class PostCheck extends Check implements PacketCheck, PostPredictionCheck
@Override
public void onPacketReceive(final PacketReceiveEvent event) {
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
// Don't count teleports or duplicates as movements
if (player.packetStateData.lastPacketWasTeleport || player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
return;
}
if (isTickPacket(event.getPacketType())) { // Don't count teleports or duplicates as movements
post.clear();
sentFlying = true;
} else {
@@ -9,10 +9,10 @@ import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
@CheckData(name = "GroundSpoof", configName = "GroundSpoof", setback = 10, decay = 0.01)
public class NoFallB extends Check implements PostPredictionCheck {
@CheckData(name = "GroundSpoof", setback = 10, decay = 0.01)
public class GroundSpoof extends Check implements PostPredictionCheck {
public NoFallB(GrimPlayer player) {
public GroundSpoof(GrimPlayer player) {
super(player);
}
@@ -29,11 +29,9 @@ public class NoFallB extends Check implements PostPredictionCheck {
// Viaversion sends wrong ground status... (doesn't matter but is annoying)
if (player.packetStateData.lastPacketWasTeleport) return;
boolean invalid = player.clientClaimsLastOnGround != player.onGround;
if (invalid) {
if (flagWithSetback()) {
alert("claimed " + player.clientClaimsLastOnGround);
if (player.clientClaimsLastOnGround != player.onGround) {
if (flagAndAlert("claimed " + player.clientClaimsLastOnGround)) {
setbackIfAboveSetbackVL();
}
player.checkManager.getNoFall().flipPlayerGroundStatus = true;
}
@@ -1,5 +1,6 @@
package ac.grim.grimac.checks.impl.prediction;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.api.events.CompletePredictionEvent;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
@@ -10,7 +11,7 @@ import org.bukkit.Bukkit;
import java.util.concurrent.atomic.AtomicInteger;
@CheckData(name = "Simulation", configName = "Simulation", decay = 0.02)
@CheckData(name = "Simulation", decay = 0.02)
public class OffsetHandler extends Check implements PostPredictionCheck {
// Config
double setbackDecayMultiplier;
@@ -29,11 +30,11 @@ public class OffsetHandler extends Check implements PostPredictionCheck {
}
public void onPredictionComplete(final PredictionComplete predictionComplete) {
double offset = predictionComplete.getOffset();
if (!predictionComplete.isChecked()) return;
CompletePredictionEvent completePredictionEvent = new CompletePredictionEvent(getPlayer(), this, predictionComplete.getOffset());
double offset = predictionComplete.getOffset();
CompletePredictionEvent completePredictionEvent = new CompletePredictionEvent(player, this, "", offset);
Bukkit.getPluginManager().callEvent(completePredictionEvent);
if (completePredictionEvent.isCancelled()) return;
@@ -42,7 +43,7 @@ public class OffsetHandler extends Check implements PostPredictionCheck {
if ((offset >= threshold || offset >= immediateSetbackThreshold) && flag()) {
advantageGained += offset;
boolean isSetback = advantageGained >= maxAdvantage || offset >= immediateSetbackThreshold;
boolean isSetback = (advantageGained >= maxAdvantage || offset >= immediateSetbackThreshold) && !isNoSetbackPermission();
giveOffsetLenienceNextTick(offset);
if (isSetback) {
@@ -66,7 +67,7 @@ public class OffsetHandler extends Check implements PostPredictionCheck {
humanFormattedOffset = humanFormattedOffset.replace("0.", ".");
}
if(alert(humanFormattedOffset + " /gl " + flagId)) {
if (alert(humanFormattedOffset + " /gl " + flagId)) {
flags.incrementAndGet(); // This debug was sent somewhere
predictionComplete.setIdentifier(flagId);
}
@@ -99,14 +100,12 @@ public class OffsetHandler extends Check implements PostPredictionCheck {
}
@Override
public void reload() {
super.reload();
setbackDecayMultiplier = getConfig().getDoubleElse("Simulation.setback-decay-multiplier", 0.999);
threshold = getConfig().getDoubleElse("Simulation.threshold", 0.001);
immediateSetbackThreshold = getConfig().getDoubleElse("Simulation.immediate-setback-threshold", 0.1);
maxAdvantage = getConfig().getDoubleElse("Simulation.max-advantage", 1);
maxCeiling = getConfig().getDoubleElse("Simulation.max-ceiling", 4);
public void onReload(ConfigManager config) {
setbackDecayMultiplier = config.getDoubleElse("Simulation.setback-decay-multiplier", 0.999);
threshold = config.getDoubleElse("Simulation.threshold", 0.001);
immediateSetbackThreshold = config.getDoubleElse("Simulation.immediate-setback-threshold", 0.1);
maxAdvantage = config.getDoubleElse("Simulation.max-advantage", 1);
maxCeiling = config.getDoubleElse("Simulation.max-ceiling", 4);
if (maxAdvantage == -1) maxAdvantage = Double.MAX_VALUE;
if (immediateSetbackThreshold == -1) immediateSetbackThreshold = Double.MAX_VALUE;
}
@@ -15,7 +15,7 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import java.util.ArrayList;
import java.util.List;
@CheckData(name = "Phase", configName = "Phase", setback = 1, decay = 0.005)
@CheckData(name = "Phase", setback = 1, decay = 0.005)
public class Phase extends Check implements PostPredictionCheck {
SimpleCollisionBox oldBB;
@@ -1,9 +1,12 @@
package ac.grim.grimac.checks.impl.scaffolding;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.config.ConfigManager;
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.change.BlockModification;
import ac.grim.grimac.utils.nmsutil.Materials;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
@@ -15,12 +18,65 @@ public class AirLiquidPlace extends BlockPlaceCheck {
super(player);
}
/*
* This check has been plagued by falses for ages, and I've finally figured it out.
* When breaking and placing on the same tick in the same tick, I believe the vanilla client always sends DIGGING ACTION packets first
* This check's falses all seem to stem from processing DiggingAction.START_DIGGING before PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT in the same tick
* Since we process the break first, when we go to process the place it looks like the player placed against air in the async world
*
* We will often see:
* Async world updated: short_grass -> air at X: -32, Y: 69, Z: -240, tick 0, cause/source: DiggingAction.START_DIGGING
* AirLiquidPlace Check: Block state at X: -32, Y: 69, Z: -240 is air (valid: false), tick +0-1, cause/source: PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT <---- previously falsed here
* Async world updated: air -> short_grass at X: -32, Y: 69, Z: -240, tick +3-4, cause: realtime task in applyBlockChanges(List<Vector3i> toApplyBlocks) source: PacketType.Play.Client.PONG
* Async world updated: short_grass -> air at X: -32, Y: 69, Z: -240, tick +0-1, cause: handleNettySyncTransaction(LatencyUtils.java:56) source: PacketType.Play.Client.PONG
*
* In addition, it is possible for:
* Async world updated: short_grass -> air at X: -49, Y: 69, Z: -190, tick 0, cause: realtime task in applyBlockChanges(List<Vector3i> toApplyBlocks) source: PacketType.Play.Client.PONG
* AirLiquidPlace Check: Block state at X: -49, Y: 69, Z: -190 is air (valid=false), tick 0 <--- false due to change from applyBlockChanges()
* Async world updated: grass_block[snowy=false] -> grass_block[snowy=false] at X: -49, Y: 69, Z: -189, tick 0, cause: handleNettySyncTransaction(LatencyUtils.java:56) source: PacketType.Play.Client.PONG
*
* And in even more rare cases:
* Async world updated: air -> air at X: -51, Y: 71, Z: -179, tick 0, cause: handleNettySyncTransaction(LatencyUtils.java:56) source: PacketType.Play.Client.PONG
* AirLiquidPlace Check: Block state at X: -49, Y: 70, Z: -180 is short_grass (valid=true), tick 0
* Async world updated: short_grass -> air at X: -49, Y: 70, Z: -180, tick 1, cause/source: DiggingAction.START_DIGGING <--- double dig here (see my AirLiquidBreak patch) this is legit behaviour. Can only be up to 2 in 1 tick though.
* Async world updated: air -> short_grass at X: -49, Y: 70, Z: -180, tick 1, cause/source: DiggingAction.START_DIGGING
* Async world updated: short_grass -> air at X: -51, Y: 70, Z: -179, tick 1, cause: realtime task in applyBlockChanges(List<Vector3i> toApplyBlocks) source: PacketType.Play.Client.PONG
* AirLiquidPlace Check: Block state at X: -49, Y: 70, Z: -179 is air (valid=false), tick 2 <--- falses here due to double dig if we only check the latest changed blockstate. We have to check all changes at the location in same tick.
* AirLiquidPlace Check: Block state at X: -49, Y: 70, Z: -179 is air (valid=true), tick 2
*
* All of which previously would've caused a false.
* To solve this we store recently changed blocks caused by DiggingAction.START_DIGGING (instant breaking) and check against the old block.
* Lots of other checks have similar issues, and with the new player.blockHistory we can patch those.
*
* So that's it right? It's unfalsable?
* Very close but not quite. Vanilla's client game desyncs, especially on a laggy connection where a player is breaking and placing grass 20 cps/sec in the same tick
* it is possible for short grass to be interacted with even if server-side the block is air much later, and it won't be accounted for because the modification isn't recent.
* This is incredibly rare, unreliable and is only triggerable if you intentionally want to false the check. I consider a violation lvl of 2-3 to be reliable
* and 5-6 to be autobannable (if you don't care about people who are deliberately trying to get themselves false banned)
*/
@Override
public void onBlockPlace(final BlockPlace place) {
if (player.gamemode == GameMode.CREATIVE) return;
Vector3i blockPos = place.getPlacedAgainstBlockLocation();
StateType placeAgainst = player.compensatedWorld.getStateTypeAt(blockPos.getX(), blockPos.getY(), blockPos.getZ());
int currentTick = GrimAPI.INSTANCE.getTickManager().currentTick;
// this is actual more lenient then we need to be, We can check up to 1 ticks for all changes at location sand up to 0 ticks for first change
// But for such tiny differences in legitness its not worth it.
Iterable<BlockModification> blockModifications = player.blockHistory.getRecentModifications((blockModification) -> currentTick - blockModification.tick() < 2
&& blockPos.equals(blockModification.location())
&& (blockModification.cause() == BlockModification.Cause.START_DIGGING || blockModification.cause() == BlockModification.Cause.HANDLE_NETTY_SYNC_TRANSACTION));
// Check if old block from instant breaking in same tick as the current placement was valid
// There should only be one block here for legit clients
for (BlockModification blockModification : blockModifications) {
StateType stateType = blockModification.oldBlockContents().getType();
if (!stateType.isAir() && !Materials.isNoPlaceLiquid(stateType)) {
return;
}
}
if (placeAgainst.isAir() || Materials.isNoPlaceLiquid(placeAgainst)) { // fail
if (flagAndAlert() && shouldModifyPackets() && shouldCancel()) {
place.resync();
@@ -29,8 +85,7 @@ public class AirLiquidPlace extends BlockPlaceCheck {
}
@Override
public void reload() {
super.reload();
this.cancelVL = getConfig().getIntElse(getConfigName() + ".cancelVL", 0);
public void onReload(ConfigManager config) {
this.cancelVL = config.getIntElse(getConfigName() + ".cancelVL", 0);
}
}
@@ -7,13 +7,12 @@ import ac.grim.grimac.utils.anticheat.update.BlockPlace;
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.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import org.bukkit.util.Vector;
@CheckData(name = "FarPlace")
@CheckData(name = "FarPlace", description = "Placing blocks from too far away")
public class FarPlace extends BlockPlaceCheck {
public FarPlace(GrimPlayer player) {
super(player);
@@ -21,12 +20,15 @@ public class FarPlace extends BlockPlaceCheck {
@Override
public void onBlockPlace(final BlockPlace place) {
if (player.gamemode == GameMode.SPECTATOR) return;
Vector3i blockPos = place.getPlacedAgainstBlockLocation();
if (place.getMaterial() == StateTypes.SCAFFOLDING) return;
double min = Double.MAX_VALUE;
for (double d : player.getPossibleEyeHeights()) {
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
for (double d : possibleEyeHeights) {
SimpleCollisionBox box = new SimpleCollisionBox(blockPos);
Vector eyes = new Vector(player.x, player.y + d, player.z);
Vector best = VectorUtils.cutBoxToVector(eyes, box);
@@ -35,7 +37,7 @@ public class FarPlace extends BlockPlaceCheck {
// getPickRange() determines this?
// With 1.20.5+ the new attribute determines creative mode reach using a modifier
double maxReach = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
double maxReach = player.compensatedEntities.getSelf().getAttributeValue(Attributes.BLOCK_INTERACTION_RANGE);
double threshold = player.getMovementThreshold();
maxReach += Math.hypot(threshold, threshold);
@@ -7,7 +7,7 @@ import ac.grim.grimac.utils.anticheat.update.BlockPlace;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
@CheckData(name = "InvalidPlaceB")
@CheckData(name = "InvalidPlaceB", description = "Sent impossible block face id")
public class InvalidPlaceB extends BlockPlaceCheck {
public InvalidPlaceB(GrimPlayer player) {
super(player);
@@ -7,11 +7,10 @@ import ac.grim.grimac.utils.anticheat.MessageUtil;
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.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import java.util.ArrayList;
import java.util.List;
@@ -39,7 +38,7 @@ public class MultiPlace extends BlockPlaceCheck {
final String verbose = "face=" + face + ", lastFace=" + lastFace
+ ", cursor=" + MessageUtil.toUnlabledString(cursor) + ", lastCursor=" + MessageUtil.toUnlabledString(lastCursor)
+ ", pos=" + MessageUtil.toUnlabledString(pos) + ", lastPos=" + MessageUtil.toUnlabledString(lastPos);
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose) && shouldModifyPackets() && shouldCancel()) {
place.resync();
}
@@ -56,14 +55,16 @@ public class MultiPlace extends BlockPlaceCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
if (player.gamemode == GameMode.SPECTATOR || isTickPacket(event.getPacketType())) {
hasPlaced = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8) && !player.skippedTickInActualMovement) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
@@ -5,11 +5,8 @@ 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.collisions.datatypes.SimpleCollisionBox;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import java.util.Collections;
@CheckData(name = "PositionPlace")
public class PositionPlace extends BlockPlaceCheck {
@@ -28,11 +25,16 @@ public class PositionPlace extends BlockPlaceCheck {
// Each position represents the best case scenario to have clicked
//
// We will now calculate the most optimal position for the player's head to be in
double minEyeHeight = Collections.min(player.getPossibleEyeHeights());
double maxEyeHeight = Collections.max(player.getPossibleEyeHeights());
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);
}
// I love the idle packet, why did you remove it mojang :(
// Don't give 0.03 lenience if the player is a 1.8 player and we know they couldn't have 0.03'd because idle packet
double movementThreshold = !player.packetStateData.didLastMovementIncludePosition || player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? player.getMovementThreshold() : 0;
double movementThreshold = !player.packetStateData.didLastMovementIncludePosition || player.canSkipTicks() ? player.getMovementThreshold() : 0;
SimpleCollisionBox eyePositions = new SimpleCollisionBox(player.x, player.y + minEyeHeight, player.z, player.x, player.y + maxEyeHeight, player.z);
eyePositions.expand(movementThreshold);
@@ -44,32 +46,18 @@ public class PositionPlace extends BlockPlaceCheck {
// So now we have the player's possible eye positions
// So then look at the face that the player has clicked
boolean flag = false;
switch (place.getDirection()) {
case NORTH: // Z- face
flag = eyePositions.minZ > combined.minZ;
break;
case SOUTH: // Z+ face
flag = eyePositions.maxZ < combined.maxZ;
break;
case EAST: // X+ face
flag = eyePositions.maxX < combined.maxX;
break;
case WEST: // X- face
flag = eyePositions.minX > combined.minX;
break;
case UP: // Y+ face
flag = eyePositions.maxY < combined.maxY;
break;
case DOWN: // Y- face
flag = eyePositions.minY > combined.minY;
break;
}
boolean flag = switch (place.getDirection()) {
case NORTH -> eyePositions.minZ > combined.minZ; // Z- face
case SOUTH -> eyePositions.maxZ < combined.maxZ; // Z+ face
case EAST -> eyePositions.maxX < combined.maxX; // X+ face
case WEST -> eyePositions.minX > combined.minX; // X- face
case UP -> eyePositions.maxY < combined.maxY; // Y+ face
case DOWN -> eyePositions.minY > combined.minY; // Y- face
default -> false;
};
if (flag) {
if (flagAndAlert() && shouldModifyPackets() && shouldCancel()) {
place.resync();
}
if (flag && flagAndAlert() && shouldModifyPackets() && shouldCancel()) {
place.resync();
}
}
}
@@ -75,9 +75,15 @@ public class RotationPlace extends BlockPlaceCheck {
new Vector3f(player.lastXRot, player.yRot, 0)
));
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
// Start checking if player is in the block
double minEyeHeight = Collections.min(player.getPossibleEyeHeights());
double maxEyeHeight = Collections.max(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);
eyePositions.expand(player.getMovementThreshold());
@@ -98,8 +104,8 @@ public class RotationPlace extends BlockPlaceCheck {
possibleLookDirs = Collections.singletonList(new Vector3f(player.xRot, player.yRot, 0));
}
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
for (double d : player.getPossibleEyeHeights()) {
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.BLOCK_INTERACTION_RANGE);
for (double d : possibleEyeHeights) {
for (Vector3f lookDir : possibleLookDirs) {
// x, y, z are correct for the block placement even after post tick because of code elsewhere
Vector3d starting = new Vector3d(player.x, player.y + d, player.z);
@@ -107,7 +113,7 @@ public class RotationPlace extends BlockPlaceCheck {
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.getFirst() != null) return true;
if (intercept.first() != null) return true;
}
}
@@ -1,4 +1,4 @@
package ac.grim.grimac.checks.impl.movement;
package ac.grim.grimac.checks.impl.sprint;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
@@ -7,10 +7,10 @@ import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
@CheckData(name = "NoSlowB", setback = 5)
public class NoSlowB extends Check implements PacketCheck {
@CheckData(name = "SprintA", description = "Sprinting with too low hunger", setback = 0)
public class SprintA extends Check implements PacketCheck {
public NoSlowB(GrimPlayer player) {
public SprintA(GrimPlayer player) {
super(player);
}
@@ -21,18 +21,19 @@ public class NoSlowB extends Check implements PacketCheck {
if (player.canFly) return;
if (player.food < 6.0F && player.isSprinting) {
if (flag()) {
if (flagAndAlert()) {
// Cancel the packet
if (shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
alert("");
player.getSetbackTeleportUtil().executeNonSimulatingSetback();
if (shouldSetback()) {
player.getSetbackTeleportUtil().executeNonSimulatingSetback();
}
}
} else {
reward();
}
}
}
}
}
@@ -0,0 +1,40 @@
package ac.grim.grimac.checks.impl.sprint;
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.enums.FluidTag;
import ac.grim.grimac.utils.enums.Pose;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
@CheckData(name = "SprintB", description = "Sprinting while sneaking", setback = 5, experimental = true)
public class SprintB extends Check implements PostPredictionCheck {
public SprintB(GrimPlayer player) {
super(player);
}
@Override
public void onPredictionComplete(final PredictionComplete predictionComplete) {
if (!predictionComplete.isChecked()) return;
if (player.isSlowMovement && player.sneakingSpeedMultiplier < 0.8f) {
ClientVersion version = player.getClientVersion();
// https://bugs.mojang.com/browse/MC-152728
if (version.isNewerThanOrEquals(ClientVersion.V_1_14_2) && version.isOlderThan(ClientVersion.V_1_21_4)) {
return;
}
// https://github.com/GrimAnticheat/Grim/issues/1932
if (version.isNewerThanOrEquals(ClientVersion.V_1_14) && player.wasFlying && player.lastPose == Pose.FALL_FLYING && !player.isGliding) {
return;
}
if (player.isSprinting && !player.isSwimming && (player.fluidOnEyes != FluidTag.WATER || version.isOlderThan(ClientVersion.V_1_21_4))) {
if (flagWithSetback()) alert("");
} else reward();
}
}
}
@@ -0,0 +1,39 @@
package ac.grim.grimac.checks.impl.sprint;
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 = "SprintC", description = "Sprinting while using an item", setback = 5, experimental = true)
public class SprintC extends Check implements PostPredictionCheck {
public SprintC(GrimPlayer player) {
super(player);
}
private boolean flaggedLastTick = false;
@Override
public void onPredictionComplete(final PredictionComplete predictionComplete) {
if (!predictionComplete.isChecked()) return;
if (player.packetStateData.isSlowedByUsingItem()) {
ClientVersion client = player.getClientVersion();
// https://bugs.mojang.com/browse/MC-152728
if (client.isNewerThanOrEquals(ClientVersion.V_1_14_2) && client.isOlderThan(ClientVersion.V_1_21_4)) {
return;
}
if (player.isSprinting && (!player.isSwimming || client.isOlderThan(ClientVersion.V_1_21_4))) {
if (flaggedLastTick && flagWithSetback()) alert("");
flaggedLastTick = true;
} else {
reward();
flaggedLastTick = false;
}
}
}
}
@@ -1,8 +1,7 @@
package ac.grim.grimac.checks.impl.movement;
package ac.grim.grimac.checks.impl.sprint;
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;
@@ -12,9 +11,9 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEn
import static com.github.retrooper.packetevents.protocol.potion.PotionTypes.BLINDNESS;
@CheckData(name = "NoSlowE", setback = 5, experimental = true)
public class NoSlowE extends Check implements PostPredictionCheck, PacketCheck {
public NoSlowE(GrimPlayer player) {
@CheckData(name = "SprintD", description = "Started sprinting while having blindness", setback = 5, experimental = true)
public class SprintD extends Check implements PostPredictionCheck {
public SprintD(GrimPlayer player) {
super(player);
}
@@ -1,8 +1,7 @@
package ac.grim.grimac.checks.impl.movement;
package ac.grim.grimac.checks.impl.sprint;
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;
@@ -11,20 +10,19 @@ 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 = "NoSlowD", setback = 5, experimental = true)
public class NoSlowD extends Check implements PostPredictionCheck, PacketCheck {
public NoSlowD(GrimPlayer player) {
@CheckData(name = "SprintE", description = "Sprinting while colliding with a wall", setback = 5, experimental = true)
public class SprintE extends Check implements PostPredictionCheck {
public SprintE(GrimPlayer player) {
super(player);
}
public boolean startedSprintingBeforeUse = false;
private boolean flaggedLastTick = false;
private boolean startedSprintingThisTick, wasHorizontalCollision;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
if (new WrapperPlayClientEntityAction(event).getAction() == WrapperPlayClientEntityAction.Action.START_SPRINTING) {
startedSprintingBeforeUse = false;
startedSprintingThisTick = true;
}
}
}
@@ -33,21 +31,17 @@ public class NoSlowD extends Check implements PostPredictionCheck, PacketCheck {
public void onPredictionComplete(final PredictionComplete predictionComplete) {
if (!predictionComplete.isChecked()) return;
if (player.packetStateData.isSlowedByUsingItem()) {
// https://bugs.mojang.com/browse/MC-152728
if (startedSprintingBeforeUse && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14_2)) {
reward();
flaggedLastTick = false;
return;
}
// there's a mechanic in 1.18+ that allows this if you are looking far enough away from the wall
// I'll probably check 1.18+ later
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_18)) return;
if (wasHorizontalCollision && !startedSprintingThisTick) {
if (player.isSprinting) {
if (flaggedLastTick && flagWithSetback()) alert("");
flaggedLastTick = true;
} else {
reward();
flaggedLastTick = false;
}
if (flagAndAlert()) setbackIfAboveSetbackVL();
} else reward();
}
wasHorizontalCollision = player.horizontalCollision;
startedSprintingThisTick = false;
}
}
@@ -0,0 +1,26 @@
package ac.grim.grimac.checks.impl.sprint;
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 = "SprintF", description = "Sprinting while gliding", experimental = true)
public class SprintF extends Check implements PostPredictionCheck {
public SprintF(GrimPlayer player) {
super(player);
}
@Override
public void onPredictionComplete(final PredictionComplete predictionComplete) {
if (player.wasGliding && player.isGliding && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_4)) {
if (player.isSprinting) {
if (flagAndAlert()) setbackIfAboveSetbackVL();
} else {
reward();
}
}
}
}
@@ -1,15 +1,16 @@
package ac.grim.grimac.checks.impl.movement;
package ac.grim.grimac.checks.impl.timer;
import ac.grim.grimac.api.config.ConfigManager;
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;
@CheckData(name = "NegativeTimer", configName = "NegativeTimer", setback = 10, experimental = true)
public class NegativeTimerCheck extends TimerCheck implements PostPredictionCheck {
@CheckData(name = "NegativeTimer", setback = -1, experimental = true)
public class NegativeTimer extends Timer implements PostPredictionCheck {
public NegativeTimerCheck(GrimPlayer player) {
public NegativeTimer(GrimPlayer player) {
super(player);
timerBalanceRealTime = System.nanoTime() + clockDrift;
}
@@ -17,13 +18,13 @@ public class NegativeTimerCheck extends TimerCheck implements PostPredictionChec
@Override
public void onPredictionComplete(final PredictionComplete predictionComplete) {
// We can't negative timer check a 1.9+ player who is standing still.
if (!player.canThePlayerBeCloseToZeroMovement(2) || !predictionComplete.isChecked()) {
if (player.uncertaintyHandler.lastPointThree.hasOccurredSince(2) || !predictionComplete.isChecked()) {
timerBalanceRealTime = System.nanoTime() + clockDrift;
}
if (timerBalanceRealTime < lastMovementPlayerClock - clockDrift) {
int lostMS = (int) ((System.nanoTime() - timerBalanceRealTime) / 1e6);
flagAndAlert("-" + lostMS);
if (flagAndAlert("-" + lostMS)) setbackIfAboveSetbackVL();
timerBalanceRealTime += 50e6;
}
}
@@ -35,8 +36,7 @@ public class NegativeTimerCheck extends TimerCheck implements PostPredictionChec
}
@Override
public void reload() {
super.reload();
clockDrift = (long) (getConfig().getDoubleElse(getConfigName() + ".drift", 1200.0) * 1e6);
public void onReload(ConfigManager config) {
clockDrift = (long) (config.getDoubleElse(getConfigName() + ".drift", 1200.0) * 1e6);
}
}
@@ -0,0 +1,44 @@
package ac.grim.grimac.checks.impl.timer;
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 com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
@CheckData(name = "TickTimer", setback = 1)
public class TickTimer extends Check implements PostPredictionCheck {
private boolean receivedTickEnd = true;
private int flyingPackets = 0;
public TickTimer(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (!player.supportsEndTick()) return;
if (isFlying(event.getPacketType()) && !player.packetStateData.lastPacketWasTeleport) {
if (!receivedTickEnd && flagAndAlert("type=flying, packets=" + flyingPackets)) {
handleViolation();
}
receivedTickEnd = false;
flyingPackets++;
} else if (event.getPacketType() == PacketType.Play.Client.CLIENT_TICK_END) {
receivedTickEnd = true;
if (flyingPackets > 1 && flagAndAlert("type=end, packets=" + flyingPackets)) {
handleViolation();
}
flyingPackets = 0;
}
}
private void handleViolation() {
setbackIfAboveSetbackVL();
// Although we don't cancel the packet, this should be counted as an invalid packet.
player.onPacketCancel();
}
}
@@ -1,5 +1,6 @@
package ac.grim.grimac.checks.impl.movement;
package ac.grim.grimac.checks.impl.timer;
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.PacketCheck;
@@ -7,21 +8,20 @@ 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.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
@CheckData(name = "Timer", configName = "TimerA", setback = 10)
public class TimerCheck extends Check implements PacketCheck {
public class Timer extends Check implements PacketCheck {
long timerBalanceRealTime = 0;
// Default value is real time minus max keep-alive time
long knownPlayerClockTime = (long) (System.nanoTime() - 6e10);
long lastMovementPlayerClock = (long) (System.nanoTime() - 6e10);
// How long should the player be able to fall back behind their ping?
// How long should the player be able to fall back behind their ping? (nanos)
// Default: 120 milliseconds
long clockDrift = (long) 120e6;
long limitAbuseOverPing = 1000;
long clockDrift;
// At what ping should we start to limit the balance advantage? (nanos)
long limitAbuseOverPing;
boolean hasGottenMovementAfterTransaction = false;
@@ -52,7 +52,7 @@ public class TimerCheck extends Check implements PacketCheck {
//
// We then take the last transaction before this to increase stability with these lag spikes and
// to guarantee that we are at least 50 ms back before adding the time
public TimerCheck(GrimPlayer player) {
public Timer(GrimPlayer player) {
super(player);
}
@@ -72,27 +72,18 @@ public class TimerCheck extends Check implements PacketCheck {
doCheck(event);
}
public void doCheck(final PacketReceiveEvent event) {
final double transactionPing = player.getTransactionPing();
// Limit using transaction ping if over 1000ms (default)
final boolean needsAdjustment = limitAbuseOverPing != -1 && transactionPing >= limitAbuseOverPing;
final boolean wouldFailNormal = timerBalanceRealTime > System.nanoTime();
final boolean failsAdjusted = needsAdjustment && (timerBalanceRealTime + ((transactionPing * 1e6) - clockDrift - 50e6)) > System.nanoTime();
if (wouldFailNormal || failsAdjusted) {
if (flag()) {
if (timerBalanceRealTime > System.nanoTime()) {
if (flagAndAlert()) {
// Cancel the packet
// Only cancel if not an adjustment setback
if (wouldFailNormal && shouldModifyPackets()) {
if (shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
if (isAboveSetbackVl()) player.getSetbackTeleportUtil().executeNonSimulatingSetback();
if (wouldFailNormal) {
// Only alert if we would fail without adjusted limit
alert("");
if (shouldSetback()) {
player.getSetbackTeleportUtil().executeNonSimulatingSetback();
}
}
@@ -100,7 +91,12 @@ public class TimerCheck extends Check implements PacketCheck {
timerBalanceRealTime -= 50e6;
}
timerBalanceRealTime = Math.max(timerBalanceRealTime, lastMovementPlayerClock - clockDrift);
// Limit using transaction ping if over 1000ms (default)
long playerClock = lastMovementPlayerClock;
if (System.nanoTime() - playerClock > limitAbuseOverPing) {
playerClock = System.nanoTime() - limitAbuseOverPing;
}
timerBalanceRealTime = Math.max(timerBalanceRealTime, playerClock - clockDrift);
}
public boolean checkForTransaction(PacketTypeCommon packetType) {
@@ -110,14 +106,12 @@ public class TimerCheck extends Check implements PacketCheck {
public boolean shouldCountPacketForTimer(PacketTypeCommon packetType) {
// If not flying, or this was a teleport, or this was a duplicate 1.17 mojang stupidity packet
return WrapperPlayClientPlayerFlying.isFlying(packetType) &&
!player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate;
return isTickPacket(packetType);
}
@Override
public void reload() {
super.reload();
clockDrift = (long) (getConfig().getDoubleElse(getConfigName() + ".drift", 120.0) * 1e6);
limitAbuseOverPing = (long) (getConfig().getDoubleElse(getConfigName() + ".ping-abuse-limit-threshold", 1000));
public void onReload(ConfigManager config) {
clockDrift = (long) (config.getDoubleElse(getConfigName() + ".drift", 120.0) * 1e6);
limitAbuseOverPing = (long) (config.getDoubleElse(getConfigName() + ".ping-abuse-limit-threshold", 1000) * 1e6);
}
}
Loaded 100 of 308 files, more files were not shown because too many files have changed in this diff. Show more