Compare commits

...
341 Commits
Author SHA1 Message Date
AxionizeandManInMyVan b3eba2d809 Apply Style Changes From Code Review
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-12-18 18:28:24 -05:00
You dfb53be691 Add comments and cleanup styling 2024-12-16 23:39:46 -05:00
You a1b9479662 Remove unneccessary code from BlockModification 2024-12-16 16:23:11 -05:00
Axionize 2f51ae65ac More comment cleanup 2024-12-16 16:23:11 -05:00
Axionize 7ebe978c80 Cleanup 2024-12-16 16:23:11 -05:00
Axionize 9f66e6341e Finish documenting all edge cases that can false AirLiquidPlace and fixing them 2024-12-16 16:23:11 -05:00
Axionize fa6886a778 Remove debug messages 2024-12-16 16:23:11 -05:00
Axionize 669eb0c778 Move clearing updated blocks logic into an async loop; new ClearRecentlyUpdatedBlocks() class 2024-12-16 16:23:11 -05:00
Axionize d77a914102 Cleanup AirLiquidPlace 2024-12-16 16:23:11 -05:00
Axionize bd603294da Only check first value in iterator() in AirLiquidPlace() 2024-12-16 16:23:11 -05:00
Axionize 8b82a956ff Fix AirLiquidPlace false 2024-12-16 16:23:08 -05:00
Axionize 1ba36bc831 Add new Data classes to see recently modified blocks 2024-12-16 16:22:05 -05: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
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
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
Axionize 3059f21ce6 Revert "Remove unncessary NO_COLLISION entry for torchcrop"
This reverts commit e149ca6be8.
2024-11-03 19:30:42 -05:00
Axionize b48f898c77 Revert "Remove unncessary NO_COLLISION entries"
This reverts commit 1761d853de.
2024-11-03 19:30:42 -05:00
Axionize 6f63743bd8 Fix scaffolding hitbox for pre-1.14 clients 2024-11-03 07:06:25 -05:00
Axionize 21e15f9b8a Fix Weeping Vines and Vine Plant for all versions; Fix Weeping + Twisted for pre 1.16 players 2024-11-03 06:39:40 -05:00
Axionize e505d2b2cd Fix pitcher crop for pre-1.20 players 2024-11-03 06:39:40 -05:00
Axionize c83b374830 Fix sniffer egg for pre 1.20 players 2024-11-03 06:39:40 -05:00
Axionize 1bdca2dae5 Fix frogspawn for pre-1.19 players 2024-11-03 06:39:38 -05:00
Axionize 91241dec7d Fix Sculk Shrieker hit box for all versions and collision box for pre 1.18.2 2024-11-03 06:39:38 -05:00
Axionize 651b0bd83e Fix Spore Blossom hitbox on < 1.17 2024-11-03 06:39:38 -05:00
Axionize 7f71f809c0 Fix glow lichen and sculk vein boxes 2024-11-03 06:39:38 -05:00
Axionize 05444e6f56 Fix Cauldron Hit/Collision Box 2024-11-03 03:52:09 -05:00
Axionize e9e84f5548 Fix Pink Petals Boxes 2024-11-03 02:58:19 -05:00
Axionize 62cb82de6a Add new union() function to collision boxes 2024-11-03 02:58:19 -05:00
Axionize d10f7619e4 Fix Coral Fan Collision box 2024-11-03 02:58:19 -05:00
Axionize 16e464719b Remove unncessary NO_COLLISION entries 2024-11-03 02:58:15 -05:00
Axionize 21f22a8446 Remove unncessary NO_COLLISION entry for torchcrop 2024-11-03 00:51:52 -04: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
Axionize f02d1383c8 Fix falses on dead corals 2024-11-01 21:28:15 -04: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
Axionize 28be03b978 Document SimpleCollisionBox and HexCollisionBox with Javadoc 2024-10-03 03:40:01 -04:00
Axionize e3ccbe2449 Fix spelling mistake 2024-10-03 00:09:51 -04:00
Axionize 5782d356fb Replace RuntimeException in HitBox.java with IllegalStateException 2024-10-03 00:09:51 -04:00
AxionizeandManInMyVan 999d7c7016 Button Styling Change
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:03:40 -04:00
AxionizeandManInMyVan 270db6995c Sapling Styling Change
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:03:23 -04:00
AxionizeandManInMyVan bafb169b76 TALL_FLOWER Styling Change
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:03:08 -04:00
AxionizeandManInMyVan 5bc0f06500 Redstone Wire Comment Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:02:42 -04:00
AxionizeandManInMyVan 1e244ed37b Inline Hitbox Calculation
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:02:25 -04:00
AxionizeandManInMyVan 8b8a9b5ce7 getPropaguleMinHeight Spacing
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:02:03 -04:00
AxionizeandManInMyVan 129549bf2d Small Flower Line Spacing/Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:01:34 -04:00
AxionizeandManInMyVan ed7f9d80f8 Coral Fan Line Spacing/Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:01:15 -04:00
AxionizeandManInMyVan c1054142e0 Banner Line Spacing/Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:01:05 -04:00
AxionizeandManInMyVan 9ee0b82eab Simplify TALL_FLOWERS handling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:00:45 -04:00
AxionizeandManInMyVan 76f5f81f6a Rails Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:00:21 -04:00
AxionizeandManInMyVan 0c51152477 Mark function as Deprecated
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-02 23:59:48 -04:00
Axionize 9b8a0b4969 Port over PR to Fix Chains for 1.16 2024-10-02 20:57:10 -04:00
Axionize a2528beaf9 Merge remote-tracking branch 'origin/2.0' into simulation-changes
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/collisions/CollisionData.java
2024-10-02 20:54:23 -04:00
Axionize a3de70d498 Compact all NO_COLLISION states together 2024-10-02 20:51:44 -04:00
ManInMyVan 748eb398b8 fix a BadPacketsZ false
also use MessageUtil
2024-09-28 17:59:06 -06:00
AoElite ea85282f52 fix lambda 2024-09-28 18:57:53 -04:00
AoElite d723dec820 Merge pull request #1706 from overkidding/perm-fix-pr
Permission Load Fix
2024-09-28 18:30:55 -04:00
AoElite de03945f42 Merge pull request #1742 from ManInMyVan/fix/chains
fix chains for pre-1.16 players
2024-09-28 18:27:29 -04:00
Axionize bb08c78e8a Fix 1.11 Ascending rails hitboxes 2024-09-28 02:01:45 -04:00
Axionize 4da8ddbd12 Fix HitBox of ascending powered rail on 1.9 2024-09-28 02:01:45 -04:00
Axionize 8f89d3615b Fix HitBox of ascending powered rails on 1.7.10 2024-09-28 02:01:45 -04:00
Axionize dc7f6dca93 Make result player.getPossibleEyeHeights() of final in checks and remove unused imports 2024-09-27 23:57:23 -04:00
ManInMyVan 03ea36ad28 fix chains for pre-1.16 players 2024-09-26 20:09:18 -06:00
Axionize 472415e0d4 Removing unneeded special case handling 2024-09-26 17:13:11 -04:00
SamB440 b27678c753 Merge pull request #1740 from ManInMyVan/fix/multiplace
fix MultiPlace
2024-09-25 19:54:42 +01:00
ManInMyVan 6eb99263a2 fix MultiPlace 2024-09-25 12:51:32 -06:00
SamB440 bde44f5136 Merge pull request #1736 from Axionize/optimize-iteration-order-lookdir
Reduce average iterations of RotationPlace
2024-09-25 10:12:46 +01:00
Rothes da61ff673a Fix constructor default value overriding configured value 2024-09-25 17:12:26 +08:00
Axionize 8a09be435e Remove dynamicfence; implement hashcode() function for offset hitboxes 2024-09-25 01:33:24 -04:00
Axionize 7af6cfbb3b Fix Cacti, inline lever hitboxes, fix fence handling 2024-09-25 01:29:47 -04:00
Axionize ce8aee5b8c Groundwork classes for better fence handling 2024-09-25 01:28:56 -04:00
Axionize d5927578a9 Reduce average iterations of rotation place 2024-09-25 01:01:16 -04: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
SamB440 cc9273d05d Duh, 1 2024-09-24 14:45:45 +01:00
SamB440 c354b4481d Max minimum max-transaction-time 1 2024-09-24 14:44:06 +01:00
SamB440 ba8c411ed4 Don't allow invalid max-transaction-time 2024-09-24 14:41:03 +01: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
SamB440 da1468e858 Bump packetevents 2024-09-23 18:15:15 +01: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 9708ebc821 Fix a BadPacketsZ false 2024-09-20 10:18:25 +01:00
ManInMyVan a38f341965 Add MultiInteract Checks 2024-09-19 16:11:51 -06:00
AoElite fad39af575 Merge pull request #1729 from Cyramek/fix-compilation
fix compilation issues
2024-09-18 23:55:07 -04:00
Cyramek 4e4492e417 fix compilation issues 2024-09-19 05:50:04 +02:00
AoElite 5374ee3c0d Merge pull request #1726 from ManInMyVan/multiplace
Add MultiPlace
2024-09-18 22:17:21 -04:00
ManInMyVan 262de24cbf allow setbacks in NegativeTimer 2024-09-18 20:14:11 -06:00
ManInMyVan 936662db2d Add MultiPlace 2024-09-18 17:45:20 -06:00
Axionize 16bb09aee0 All HitBox and CollisionBox Changes made for LineOfSightPlace 2024-09-17 04:08:23 -04:00
Ruxy 330a9782bc Add full Japanese translations for all GrimAC configuration files 2024-09-17 10:31:53 +12:00
overkiddingandManInMyVan 7ac2319c07 fix spacing formatting 6
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-09-14 09:05:48 +02:00
overkiddingandManInMyVan 89a795a7e6 fix spacing formatting 1
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-09-14 07:09:48 +02:00
overkiddingandManInMyVan 510247f3b4 fix spacing formatting 4
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-09-14 07:09:35 +02:00
overkiddingandManInMyVan a61b710e81 fix spacing formatting 3
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-09-14 07:09:26 +02:00
overkiddingandManInMyVan 049c30f8b1 fix spacing formatting 2
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-09-14 07:09:04 +02:00
overkiddingandManInMyVan 21a7bdd395 fix spacing formatting 1
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-09-14 07:08:53 +02:00
AoElite 598caa9259 Merge pull request #1719 from ManInMyVan/fix/BadPacketsZ-false
fix a BadPacketsZ false
2024-09-13 22:11:21 -04:00
AoElite 0d28fa3a9d Merge pull request #1720 from ManInMyVan/fix/BadPacketsX-false
fix a BadPacketsX false
2024-09-13 22:11:05 -04:00
AoElite 87c5c1d6c7 Merge pull request #1721 from ManInMyVan/fix/vine-fastbreak-false
vines are mined faster by swords
2024-09-13 22:10:22 -04:00
ManInMyVan dde9cea757 vines are mined faster by swords 2024-09-13 16:05:51 -06:00
ManInMyVan 1fe77a1dd6 fix a BadPacketsX false 2024-09-13 15:31:35 -06:00
ManInMyVan 72a2dfdde4 fix BadPacketsZ false 2024-09-13 15:27:22 -06:00
ManInMyVan f6ef1df29d exempt 1.14.2+ clients in NoSlowC and NoSlowD 2024-09-13 13:02:40 -06:00
SamB440 4c039e612b Bump version 2024-09-12 15:32:27 +01:00
Cyramek b0cd32622e Fix fences hitbox (#1710) 2024-09-12 15:11:15 +01:00
SamB440 3445a0220f Merge pull request #1695 from ManInMyVan/custom-webhook-embed-title
Allow customizing webhook embed title
2024-09-12 15:09:17 +01:00
SamB440 f1a1e46edc Old servers can set horse.jump_strength 2024-09-11 16:08:43 +01:00
SamB440 343e9ef16d Fix horse jumping with viabackwards, fixes #1713 2024-09-11 15:30:16 +01:00
SamB440 c4c063418a Merge pull request #1709 from Cyramek/fix-main-supporting-block
fix searching for main supporting block
2024-09-11 13:43:57 +01:00
Cyramek 95955b81f6 typo 2024-09-11 05:21:47 +02:00
Cyramek f4cb19c113 fix searching for main supporting block 2024-09-11 05:00:06 +02:00
overkidding f313d0897d fix: permission load 2024-09-10 09:38:07 +02:00
Kayera 0293606dc9 GrimAntiCheat Turkish Translation (#1673)
* Add files via upload

* Add files via upload

* Add files via upload

* Add files via upload
2024-09-06 14:38:07 +01:00
gNewl 705f223a70 Translate updates 2024-09-06 14:36:53 +01:00
gNewl 409b1ae646 Make it clear and objective, fix some incorrect descriptions and improve the messages from the last commiter
Some messages are too long compared to other translations
"log" and "depuramento" can be more accurate as "registro"
2024-09-06 14:36:53 +01:00
gNewl 13bd66de7b Grammar fixes, coherence improvements, standardize and rework in updates. 2024-09-06 14:36:53 +01:00
gNewl b3d59788b3 Grammar fixes, coherence improvements, standardize and rework in updates. 2024-09-06 14:36:53 +01:00
Dg32z_ c58ae74a41 Update chinese translation (#1680) 2024-09-06 14:36:03 +01:00
SamB440 aa6d07f893 Merge pull request #1701 from ManInMyVan/fix/bed-bounce-version
fix bed bouncy version
2024-09-06 11:35:23 +01:00
ManInMyVan cef044c4fe beds became bouncy in 1.12, not 1.8 2024-09-05 19:01:11 -06:00
SamB440 e8c7b9066f Fix strider attribute desync 2024-09-05 21:20:37 +01:00
SamB440 7f0dbdbc28 Fix strider off ground speed 2024-09-05 16:56:44 +01:00
SamB440 3890d12105 Fix strider speed outside of lava 2024-09-05 16:45:29 +01:00
SamB440 d62755bc01 Merge pull request #1630 from ManInMyVan/fix/offhand-noslow
fix a noslow
2024-09-03 17:40:56 +01:00
ManInMyVan dfc8c988d1 Allow customizing embed title 2024-09-02 11:45:07 -06:00
SamB440 508daaa472 Merge pull request #1694 from ManInMyVan/fix/post/held-item-change-1.7
exempt 1.7 in post for HELD_ITEM_CHANGE packets
2024-09-01 19:17:31 +01:00
ManInMyVan a765065f98 exempt 1.7 in post for HELD_ITEM_CHANGE packets 2024-09-01 12:15:33 -06:00
AoElite 7add2b6658 Merge pull request #1684 from ManInMyVan/exempt-specific-checks
allow exempting for specific checks
2024-08-30 14:26:30 -04:00
AoElite b3d780b52b Merge pull request #1688 from ManInMyVan/post-slots
check slot changes in post
2024-08-29 16:53:08 -04:00
AoElite 1e46837fec Merge pull request #1693 from Axionize/debug-improvements
Allow Live Class Reloading for Fast Debugging During Development
2024-08-29 16:52:52 -04:00
Axionize ac516060c0 Clean up 2024-08-29 16:51:20 -04:00
Axionize a5c34a0829 MVP commit 2024-08-29 16:47:04 -04:00
ManInMyVan 06fa4bab17 check slot changes in post 2024-08-28 17:06:32 -06:00
SamB440 aabead19ec Fix some respawn issues 2024-08-25 17:49:20 +01:00
ManInMyVan af60e07327 allow exempting for specific checks 2024-08-24 17:23:06 -06:00
ManInMyVan 0c78830524 fix a noslow 2024-08-14 19:03:48 -06:00
237 changed files with 5191 additions and 2415 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
+1 -1
View File
@@ -7,7 +7,7 @@ GrimAC is an open source Minecraft anticheat designed for 1.21 and supports 1.8-
### 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
3. ./gradlew build
4. The final jar is located in build/libs
### API Information
+67 -25
View File
@@ -6,13 +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.67"
version = "2.3.68"
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
// Checks Project properties -> environment variable -> defaults true
val relocate: Boolean = project.findProperty("relocate")?.toString()?.toBoolean()
?: System.getenv("RELOCATE_JAR")?.toBoolean()
?: true
repositories {
mavenLocal()
@@ -29,24 +55,26 @@ 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/")
mavenCentral()
// FastUtil, Discord-Webhooks
}
dependencies {
implementation("com.github.retrooper:packetevents-spigot:2.5.0-SNAPSHOT")
implementation("com.github.retrooper:packetevents-spigot:2.7.0-SNAPSHOT")
implementation("co.aikar:acf-paper:0.5.1-SNAPSHOT")
implementation("club.minnced:discord-webhooks:0.8.0") // Newer versions include kotlin-stdlib, which leads to incompatibility with plugins that use Kotlin
implementation("it.unimi.dsi:fastutil:8.5.13")
implementation("it.unimi.dsi:fastutil:8.5.15")
implementation("github.scarsz:configuralize:1.4.0")
implementation("com.github.grimanticheat:grimapi:1193c4fa41")
// Used for local testing: implementation("ac.grim.grimac:grimapi:1.0")
//implementation("com.github.grimanticheat:grimapi:1193c4fa41")
// Used for local testing: implementation("ac.grim.grimac:GRIMAPI:1.0")
implementation("com.github.grimanticheat:grimapi:fc5634e444")
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("com.viaversion:viaversion-api:5.0.4-SNAPSHOT")
//
compileOnly("io.netty:netty-all:4.1.85.Final")
}
@@ -55,6 +83,7 @@ bukkit {
name = "GrimAC"
author = "GrimAC"
main = "ac.grim.grimac.GrimAC"
website = "https://grim.ac/"
apiVersion = "1.13"
foliaSupported = true
@@ -115,11 +144,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> {
@@ -133,21 +173,23 @@ publishing.publications.create<MavenPublication>("maven") {
tasks.shadowJar {
minimize()
archiveFileName.set("${project.name}-${project.version}.jar")
relocate("io.github.retrooper.packetevents", "ac.grim.grimac.shaded.io.github.retrooper.packetevents")
relocate("com.github.retrooper.packetevents", "ac.grim.grimac.shaded.com.github.retrooper.packetevents")
relocate("co.aikar.commands", "ac.grim.grimac.shaded.acf")
relocate("co.aikar.locale", "ac.grim.grimac.shaded.locale")
relocate("club.minnced", "ac.grim.grimac.shaded.discord-webhooks")
relocate("github.scarsz.configuralize", "ac.grim.grimac.shaded.configuralize")
relocate("com.github.puregero", "ac.grim.grimac.shaded.com.github.puregero")
relocate("com.google.code.gson", "ac.grim.grimac.shaded.gson")
relocate("alexh", "ac.grim.grimac.shaded.maps")
relocate("it.unimi.dsi.fastutil", "ac.grim.grimac.shaded.fastutil")
relocate("net.kyori", "ac.grim.grimac.shaded.kyori")
relocate("okhttp3", "ac.grim.grimac.shaded.okhttp3")
relocate("okio", "ac.grim.grimac.shaded.okio")
relocate("org.yaml.snakeyaml", "ac.grim.grimac.shaded.snakeyaml")
relocate("org.json", "ac.grim.grimac.shaded.json")
relocate("org.intellij", "ac.grim.grimac.shaded.intellij")
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
if (relocate) {
relocate("io.github.retrooper.packetevents", "ac.grim.grimac.shaded.io.github.retrooper.packetevents")
relocate("com.github.retrooper.packetevents", "ac.grim.grimac.shaded.com.github.retrooper.packetevents")
relocate("co.aikar.commands", "ac.grim.grimac.shaded.acf")
relocate("co.aikar.locale", "ac.grim.grimac.shaded.locale")
relocate("club.minnced", "ac.grim.grimac.shaded.discord-webhooks")
relocate("github.scarsz.configuralize", "ac.grim.grimac.shaded.configuralize")
relocate("com.github.puregero", "ac.grim.grimac.shaded.com.github.puregero")
relocate("com.google.code.gson", "ac.grim.grimac.shaded.gson")
relocate("alexh", "ac.grim.grimac.shaded.maps")
relocate("it.unimi.dsi.fastutil", "ac.grim.grimac.shaded.fastutil")
relocate("net.kyori", "ac.grim.grimac.shaded.kyori")
relocate("okhttp3", "ac.grim.grimac.shaded.okhttp3")
relocate("okio", "ac.grim.grimac.shaded.okio")
relocate("org.yaml.snakeyaml", "ac.grim.grimac.shaded.snakeyaml")
relocate("org.json", "ac.grim.grimac.shaded.json")
relocate("org.intellij", "ac.grim.grimac.shaded.intellij")
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
}
}
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.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
+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) {
+132 -38
View File
@@ -1,25 +1,34 @@
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.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;
@@ -41,7 +50,8 @@ public class GrimExternalAPI implements GrimAbstractAPI, Initable {
@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);
@@ -56,12 +66,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 +88,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 +110,106 @@ 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;
}
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.putIfAbsent("%prefix%", ChatColor.translateAlternateColorCodes('&', GrimAPI.INSTANCE.getConfigManager().getPrefix()));
staticReplacements.putIfAbsent("%grim_version%", getGrimVersion());
}
}
+69 -13
View File
@@ -2,18 +2,22 @@ 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 ac.grim.grimac.utils.common.ConfigReloadObserver;
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;
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 implements AbstractCheck, ConfigReloadObserver {
protected final GrimPlayer player;
public double violations;
@@ -23,11 +27,13 @@ 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() {
@@ -50,13 +56,21 @@ 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;
return isEnabled && !player.disableGrim && !player.noModifyPacketPermission && !exempted;
}
public void updateExempted() {
if (player.bukkitPlayer == null || checkName == null) return;
FoliaScheduler.getEntityScheduler().run(player.bukkitPlayer, GrimAPI.INSTANCE.getPlugin(),
t -> exempted = player.bukkitPlayer.hasPermission("grim.exempt." + checkName.toLowerCase()),
() -> {});
}
public final boolean flagAndAlert(String verbose) {
@@ -72,7 +86,7 @@ public class Check implements AbstractCheck {
}
public final boolean flag() {
if (player.disableGrim || (experimental && !GrimAPI.INSTANCE.getConfigManager().isExperimentalChecks()))
if (player.disableGrim || (experimental && !player.isExperimentalChecks()) || exempted)
return false; // Avoid calling event if disabled
FlagEvent event = new FlagEvent(player, this);
@@ -98,21 +112,26 @@ 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);
if (setbackVL == -1) setbackVL = Double.MAX_VALUE;
updateExempted();
onReload(configuration);
}
@Override
public void onReload(ConfigManager config) {
}
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) {
return player.getSetbackTeleportUtil().executeViolationSetback();
@@ -133,5 +152,42 @@ 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);
}
@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,17 @@ public class AimModulo360 extends Check implements RotationCheck {
@Override
public void process(final RotationUpdate rotationUpdate) {
lastDeltaYaw = rotationUpdate.getDeltaXRot();
if (player.packetStateData.lastPacketWasTeleport) return;
if (player.packetStateData.lastPacketWasTeleport) {
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;
@@ -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.WrapperPlayClientSteerVehicle;
@CheckData(name = "BadPacketsB")
@CheckData(name = "BadPacketsB", description = "Sent impossible steer vehicle packet")
public class BadPacketsB extends Check implements PacketCheck {
public BadPacketsB(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.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);
@@ -6,6 +6,7 @@ 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.wrapper.play.client.WrapperPlayClientPlayerFlying;
@CheckData(name = "BadPacketsE")
@@ -23,10 +24,12 @@ public class BadPacketsE extends Check implements PacketCheck {
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
|| (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_2) && player.compensatedEntities.getSelf().inVehicle())) {
noReminderTicks = 0; // Exempt vehicles
}
if (noReminderTicks > 20) {
flagAndAlert("ticks=" + noReminderTicks); // ban? I don't know how this would false
}
@@ -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,7 +10,6 @@ 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")
public class BadPacketsH extends Check implements PacketCheck {
@@ -44,7 +43,7 @@ public class BadPacketsH extends Check implements PacketCheck {
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_9)
&& PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_8)) 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);
@@ -7,7 +7,7 @@ import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
@CheckData(name = "BadPacketsJ")
@CheckData(name = "BadPacketsJ", description = "Sent steer vehicle packets while not in a vehicle")
public class BadPacketsJ extends Check implements PacketCheck {
public BadPacketsJ(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);
@@ -13,8 +13,7 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPl
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) {
@@ -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, THROW -> button != 0 && button != 1;
case SWAP -> (button > 8 || button < 0) && button != 40;
case CLONE -> button != 2;
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();
}
@@ -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", experimental = true)
public class BadPacketsU extends Check implements PacketCheck {
public BadPacketsU(GrimPlayer player) {
super(player);
@@ -1,31 +0,0 @@
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.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;
@CheckData(name = "BadPacketsV", experimental = true)
public class BadPacketsV extends Check implements PacketCheck {
public BadPacketsV(GrimPlayer player) {
super(player);
}
@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();
}
}
}
}
@@ -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);
@@ -1,45 +1,70 @@
package ac.grim.grimac.checks.impl.badpackets;
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.checks.type.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.nmsutil.BlockBreakSpeed;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
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.wrapper.play.client.WrapperPlayClientPlayerDigging;
import com.github.retrooper.packetevents.util.Vector3i;
@CheckData(name = "BadPacketsX", experimental = true)
public class BadPacketsX extends Check implements PacketCheck {
@CheckData(name = "BadPacketsX")
public class BadPacketsX extends Check implements BlockBreakCheck {
public BadPacketsX(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);
public final void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging dig, StateType block) {
if (dig.getAction() != DiggingAction.START_DIGGING && dig.getAction() != DiggingAction.FINISHED_DIGGING)
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (blockBreak.action != DiggingAction.START_DIGGING && blockBreak.action != DiggingAction.FINISHED_DIGGING)
return;
final boolean invalid;
final StateType block = blockBreak.block.getType();
if (dig.getAction() == DiggingAction.FINISHED_DIGGING) {
invalid = BlockBreakSpeed.getBlockDamage(player, dig.getBlockPosition()) >= 1 || block.getHardness() == -1.0f;
} else invalid = (block == StateTypes.LIGHT && !(player.getInventory().getHeldItem().is(ItemTypes.LIGHT) || player.getInventory().getOffHand().is(ItemTypes.LIGHT)))
// Fixes false from breaking kelp underwater
// The client sends two start digging packets to the server both in the same tick. BadPacketsX 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);
|| 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=" + dig.getAction()) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
if (invalid && flagAndAlert("block=" + block.getName() + ", type=" + blockBreak.action) && shouldModifyPackets()) {
didLastFlag = true;
blockBreak.cancel();
} else {
didLastFlag = false;
}
}
}
@@ -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);
@@ -2,26 +2,27 @@ 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.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
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.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 {
@CheckData(name = "BadPacketsZ")
public class BadPacketsZ extends Check implements BlockBreakCheck {
public BadPacketsZ(final GrimPlayer player) {
super(player);
}
private boolean lastBlockWasInstantBreak = false;
private Vector3i lastBlock, lastCancelledBlock, lastLastBlock = null;
private final int exemptedY = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) ? 4095 : 255;
private final int exemptedY = player.getClientVersion().isOlderThan(ClientVersion.V_1_8) ? 255 : (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_14) ? -1 : 4095);
// The client sometimes sends a wierd cancel packet
private boolean shouldExempt(final Vector3i pos) {
@@ -33,21 +34,14 @@ public class BadPacketsZ extends Check implements PacketCheck {
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) && pos.y != exemptedY)
return false;
// the client only sends this packet if the last block was an instant break
if (getBlockDamage(player, lastBlock) < 1)
return false;
// and if this block is not an instant break
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;
@@ -55,11 +49,11 @@ 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;
lastCancelledBlock = pos;
lastLastBlock = null;
lastBlock = null;
return;
@@ -68,11 +62,9 @@ public class BadPacketsZ extends Check implements PacketCheck {
if (!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();
}
}
}
@@ -84,16 +76,14 @@ 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();
}
}
}
@@ -0,0 +1,71 @@
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.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import java.util.ArrayList;
@CheckData(name = "MultiInteractA", 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.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add(verbose);
}
}
lastEntity = entity;
lastSneaking = sneaking;
hasInteracted = true;
}
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) && !player.packetStateData.lastPacketWasTeleport) {
hasInteracted = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
// we don't need to check pre-1.9 players here (no tick skipping)
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
if (player.isTickingReliablyFor(3) && !player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
}
flags.clear();
hasInteracted = false;
}
}
@@ -0,0 +1,72 @@
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.ClientVersion;
import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import java.util.ArrayList;
@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.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add(verbose);
}
}
lastPos = pos;
hasInteracted = true;
}
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) && !player.packetStateData.lastPacketWasTeleport) {
hasInteracted = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
// we don't need to check pre-1.9 players here (no tick skipping)
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return;
if (player.isTickingReliablyFor(3) && !player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
}
flags.clear();
hasInteracted = false;
}
}
@@ -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,7 +33,8 @@ 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 java.util.*;
@@ -42,7 +44,7 @@ import java.util.*;
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 +82,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 +107,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();
}
}
@@ -136,13 +136,13 @@ public class Reach extends Check implements PacketCheck {
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());
for (Int2ObjectMap.Entry<Vector3d> attack : playerAttackQueue.int2ObjectEntrySet()) {
PacketEntity reachEntity = player.compensatedEntities.entityMap.get(attack.getIntKey());
if (reachEntity != null) {
String result = checkReach(reachEntity, attack.getValue(), false);
if (result != null) {
@@ -200,13 +200,14 @@ public class Reach extends Check implements PacketCheck {
}
// +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 = player.compensatedEntities.getSelf().getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE) + 3;
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
for (Vector lookVec : possibleLookDirs) {
for (double eye : player.getPossibleEyeHeights()) {
for (double eye : possibleEyeHeights) {
Vector eyePos = new Vector(from.getX(), from.getY() + eye, from.getZ());
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;
@@ -224,7 +225,7 @@ public class Reach extends Check implements PacketCheck {
if (minDistance == Double.MAX_VALUE) {
cancelBuffer = 1;
return "Missed hitbox";
} else if (minDistance > player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE)) {
} else if (minDistance > player.compensatedEntities.getSelf().getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE)) {
cancelBuffer = 1;
return String.format("%.5f", minDistance) + " blocks";
} else {
@@ -236,9 +237,8 @@ public class Reach extends Check implements PacketCheck {
}
@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) {
@@ -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) {
@@ -0,0 +1,32 @@
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.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEditBook;
@CheckData(name = "ExploitC", description = "Too long book title")
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.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();
}
}
}
}
}
@@ -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);
}
}
}
}
@@ -9,6 +9,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPluginMessage;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
public class ClientBrand extends Check implements PacketCheck {
@@ -38,6 +39,7 @@ public class ClientBrand extends Check implements PacketCheck {
System.arraycopy(data, 1, minusLength, 0, minusLength.length);
brand = new String(minusLength).replace(" (Velocity)", ""); //removes velocity's brand suffix
brand = ChatColor.stripColor(brand); //strip color codes from client brand
if (player.checkManager.getPrePredictionCheck(ExploitA.class).checkString(brand)) brand = "sent log4j";
if (!GrimAPI.INSTANCE.getConfigManager().isIgnoredClient(brand)) {
String message = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("client-brand-format", "%prefix% &f%player% joined using %brand%");
@@ -1,36 +1,26 @@
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.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.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 {
@CheckData(name = "FastBreak", description = "Breaking blocks too quickly")
public class FastBreak extends Check implements BlockBreakCheck {
public FastBreak(GrimPlayer playerData) {
super(playerData);
}
@@ -49,6 +39,62 @@ public class FastBreak extends Check implements PacketCheck {
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
flagAndAlert("Delay=" + breakDelay);
if (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
@@ -56,95 +102,6 @@ public class FastBreak extends Check implements PacketCheck {
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() {
@@ -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,7 +5,6 @@ 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)
public class TransactionOrder extends Check implements PacketCheck {
@@ -14,4 +13,4 @@ public class TransactionOrder extends Check implements PacketCheck {
super(player);
}
}
}
@@ -1,12 +1,13 @@
package ac.grim.grimac.checks.impl.movement;
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)
@CheckData(name = "NegativeTimer", configName = "NegativeTimer", setback = -1, experimental = true)
public class NegativeTimerCheck extends TimerCheck implements PostPredictionCheck {
public NegativeTimerCheck(GrimPlayer player) {
@@ -23,7 +24,7 @@ public class NegativeTimerCheck extends TimerCheck implements PostPredictionChec
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);
}
}
@@ -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,7 +8,7 @@ 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)
@CheckData(name = "NoSlowA (Prediction)", configName = "NoSlowA", description = "Was not slowed while using an item", setback = 5)
public class NoSlowA extends Check implements PostPredictionCheck {
double offsetToFlag;
double bestOffset = 1;
@@ -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("NoSlowA.threshold", 0.001);
}
}
@@ -7,7 +7,7 @@ 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)
@CheckData(name = "NoSlowB", description = "Sprinting with too low hunger", setback = 5)
public class NoSlowB extends Check implements PacketCheck {
public NoSlowB(GrimPlayer player) {
@@ -35,4 +35,4 @@ public class NoSlowB extends Check implements PacketCheck {
}
}
}
}
}
@@ -2,50 +2,31 @@ 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 ac.grim.grimac.utils.enums.FluidTag;
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 {
@CheckData(name = "NoSlowC", description = "Sprinting while sneaking", setback = 5, experimental = true)
public class NoSlowC extends Check implements PostPredictionCheck {
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) {
if (player.isSlowMovement && player.sneakingSpeedMultiplier < 0.8f) {
ClientVersion client = player.getClientVersion();
// https://bugs.mojang.com/browse/MC-152728
if (startedSprintingBeforeSlowMovement && client.isNewerThanOrEquals(ClientVersion.V_1_14_2)) {
reward();
if (client.isNewerThanOrEquals(ClientVersion.V_1_14_2) && client.isOlderThan(ClientVersion.V_1_21_4)) {
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 (player.isSprinting && !player.isSwimming && (player.fluidOnEyes != FluidTag.WATER || client.isOlderThan(ClientVersion.V_1_21_4))) {
if (flagWithSetback()) alert("");
} else reward();
}
@@ -2,46 +2,32 @@ 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 = "NoSlowD", setback = 5, experimental = true)
public class NoSlowD extends Check implements PostPredictionCheck, PacketCheck {
@CheckData(name = "NoSlowD", description = "Sprinting while using an item", setback = 5, experimental = true)
public class NoSlowD extends Check implements PostPredictionCheck {
public NoSlowD(GrimPlayer player) {
super(player);
}
public boolean startedSprintingBeforeUse = false;
private boolean flaggedLastTick = false;
@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;
}
}
}
@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 (startedSprintingBeforeUse && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14_2)) {
reward();
flaggedLastTick = false;
if (client.isNewerThanOrEquals(ClientVersion.V_1_14_2) && client.isOlderThan(ClientVersion.V_1_21_4)) {
return;
}
if (player.isSprinting) {
if (player.isSprinting && (!player.isSwimming || client.isOlderThan(ClientVersion.V_1_21_4))) {
if (flaggedLastTick && flagWithSetback()) alert("");
flaggedLastTick = true;
} else {
@@ -2,7 +2,6 @@ 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;
@@ -12,8 +11,8 @@ 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 {
@CheckData(name = "NoSlowE", description = "Started sprinting while having blindness", setback = 5, experimental = true)
public class NoSlowE extends Check implements PostPredictionCheck {
public NoSlowE(GrimPlayer player) {
super(player);
}
@@ -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,34 @@
package ac.grim.grimac.checks.impl.movement;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import 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);
receivedTickEnd = false;
flyingPackets++;
} else if (event.getPacketType() == PacketType.Play.Client.CLIENT_TICK_END) {
receivedTickEnd = true;
if (flyingPackets > 1) flagAndAlert("type=end, packets=" + flyingPackets);
flyingPackets = 0;
}
}
}
@@ -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.PacketCheck;
@@ -7,7 +8,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.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 {
@@ -17,11 +17,11 @@ public class TimerCheck extends Check implements PacketCheck {
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;
@@ -72,35 +72,31 @@ 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 (timerBalanceRealTime > System.nanoTime()) {
if (flag()) {
// 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("");
}
alert("");
}
// Reset the violation by 1 movement
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);
}
}
@@ -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,45 @@
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 performing other actions", 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) {
String verbose = player.isSprinting && !player.isSwimming && !serverOpenedInventoryThisTick ? "sprinting" : "";
if (player.packetStateData.isSlowedByUsingItem()) {
verbose += (verbose.isEmpty() ? "" : ", ") + "using";
}
if (!verbose.isEmpty() && flagAndAlert(verbose) && 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,31 @@
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 performing other actions", 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) {
String verbose = player.isSprinting && !player.isSwimming ? "sprinting" : "";
if (player.packetStateData.isSlowedByUsingItem()) {
verbose += (verbose.isEmpty() ? "" : ", ") + "using";
}
if (!verbose.isEmpty() && flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
}
}
@@ -0,0 +1,32 @@
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.InteractionHand;
@CheckData(name = "MultiActionsE", description = "Swinging while using an item", experimental = true)
public class MultiActionsE extends Check implements PacketCheck {
public MultiActionsE(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.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();
}
}
}
}
@@ -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.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
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.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
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.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
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.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
if (flagAndAlert("dig") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
resyncPosition(player, packet.getBlockPosition());
}
} else {
flags.add("dig");
}
}
}
}
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
block = entity = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8) && player.isTickingReliablyFor(3) && !player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
}
flags.clear();
}
}
@@ -15,18 +15,16 @@ 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;
import java.util.ArrayList;
import java.util.List;
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
@@ -34,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);
}
@@ -44,7 +42,7 @@ public class PostCheck extends Check implements PacketCheck, PostPredictionCheck
// Okay, the user might be cheating, let's double check
// 1.8 clients have the idle packet, and this shouldn't false on 1.8 clients
// 1.9+ clients have predictions, which will determine if hidden tick skipping occurred
if (player.isTickingReliablyFor(3)) {
if (player.isTickingReliablyFor(3) && !player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0)) {
for (String flag : flags) {
flagAndAlert(flag);
}
@@ -69,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 {
@@ -87,6 +80,7 @@ public class PostCheck extends Check implements PacketCheck, PostPredictionCheck
post.clear();
sentFlying = false;
} else if (PLAYER_ABILITIES.equals(packetType)
|| (HELD_ITEM_CHANGE.equals(packetType) && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8))
|| INTERACT_ENTITY.equals(packetType) || PLAYER_BLOCK_PLACEMENT.equals(packetType)
|| USE_ITEM.equals(packetType) || PLAYER_DIGGING.equals(packetType)) {
if (sentFlying) post.add(event.getPacketType());
@@ -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;
@@ -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;
}
@@ -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 BadPacketsX 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.getTick() < 2
&& blockPos.equals(blockModification.getLocation())
&& (blockModification.getCause() == BlockModification.Cause.START_DIGGING || blockModification.getCause() == 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.getOldBlockContents().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,11 @@ 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);
@@ -26,7 +24,8 @@ public class FarPlace extends BlockPlaceCheck {
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 +34,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);
@@ -0,0 +1,73 @@
package ac.grim.grimac.checks.impl.scaffolding;
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.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.world.BlockFace;
import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.util.Vector3i;
import java.util.ArrayList;
import java.util.List;
@CheckData(name = "MultiPlace", experimental = true)
public class MultiPlace extends BlockPlaceCheck {
public MultiPlace(GrimPlayer player) {
super(player);
}
private final List<String> flags = new ArrayList<>();
private boolean hasPlaced;
private BlockFace lastFace;
private Vector3f lastCursor;
private Vector3i lastPos;
@Override
public void onBlockPlace(final BlockPlace place) {
final BlockFace face = place.getDirection();
final Vector3f cursor = place.getCursor();
final Vector3i pos = place.getPlacedAgainstBlockLocation();
if (hasPlaced && (face != lastFace || !cursor.equals(lastCursor) || !pos.equals(lastPos))) {
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 (flagAndAlert(verbose) && shouldModifyPackets() && shouldCancel()) {
place.resync();
}
} else {
flags.add(verbose);
}
}
lastFace = face;
lastCursor = cursor;
lastPos = pos;
hasPlaced = true;
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (isTickPacket(event.getPacketType())) {
hasPlaced = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8) && player.isTickingReliablyFor(3) && !player.uncertaintyHandler.lastVehicleSwitch.hasOccurredSince(0)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
}
flags.clear();
}
}
@@ -8,7 +8,6 @@ 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,8 +27,13 @@ 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;
@@ -44,27 +48,21 @@ 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 -> // Z- face
eyePositions.minZ > combined.minZ;
case SOUTH -> // Z+ face
eyePositions.maxZ < combined.maxZ;
case EAST -> // X+ face
eyePositions.maxX < combined.maxX;
case WEST -> // X- face
eyePositions.minX > combined.minX;
case UP -> // Y+ face
eyePositions.maxY < combined.maxY;
case DOWN -> // Y- face
eyePositions.minY > combined.minY;
default -> false;
};
if (flag) {
if (flagAndAlert() && shouldModifyPackets() && shouldCancel()) {
@@ -71,13 +71,19 @@ public class RotationPlace extends BlockPlaceCheck {
SimpleCollisionBox box = new SimpleCollisionBox(place.getPlacedAgainstBlockLocation());
List<Vector3f> possibleLookDirs = new ArrayList<>(Arrays.asList(
new Vector3f(player.lastXRot, player.yRot, 0),
new Vector3f(player.xRot, player.yRot, 0)
new Vector3f(player.xRot, player.yRot, 0),
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,5 +1,6 @@
package ac.grim.grimac.checks.impl.velocity;
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,18 +8,19 @@ import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.data.VelocityData;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
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.protocol.world.states.type.StateValue;
import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerExplosion;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.Nullable;
@@ -47,59 +49,70 @@ public class ExplosionHandler extends Check implements PostPredictionCheck {
if (event.getPacketType() == PacketType.Play.Server.EXPLOSION) {
WrapperPlayServerExplosion explosion = new WrapperPlayServerExplosion(event);
Vector3f velocity = explosion.getPlayerMotion();
final @Nullable WrapperPlayServerExplosion.BlockInteraction blockInteraction = explosion.getBlockInteraction();
final boolean shouldDestroy = blockInteraction != WrapperPlayServerExplosion.BlockInteraction.KEEP_BLOCKS;
if (!explosion.getRecords().isEmpty() && shouldDestroy) {
player.sendTransaction();
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> {
for (Vector3i record : explosion.getRecords()) {
// Null OR not flip redstone blocks, then set to air
if (blockInteraction != WrapperPlayServerExplosion.BlockInteraction.TRIGGER_BLOCKS) {
player.compensatedWorld.updateBlock(record.x, record.y, record.z, 0);
} else {
// We need to flip redstone blocks, or do special things with other blocks
final WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(record);
final StateType type = state.getType();
if (BlockTags.CANDLES.contains(type) || BlockTags.CANDLE_CAKES.contains(type)) {
state.setLit(false);
continue;
} else if (type == StateTypes.BELL) {
// Does this affect anything? I don't know, I don't see anything that relies on whether a bell is ringing.
continue;
}
// Otherwise try and flip/open it.
final Object poweredValue = state.getInternalData().get(StateValue.POWERED);
final boolean canFlip = (poweredValue != null && !(Boolean) poweredValue) || type == StateTypes.LEVER;
if (canFlip) {
player.compensatedWorld.tickOpenable(record.x, record.y, record.z);
}
}
}
});
// Since 1.21.2, the server will instead send these changes via block change packets
final boolean hasBlocks = PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_21_2);
if (hasBlocks) {
this.handleBlockExplosions(explosion);
}
if (velocity.x != 0 || velocity.y != 0 || velocity.z != 0) {
Vector3d velocity = explosion.getKnockback();
if (velocity != null && (velocity.x != 0 || velocity.y != 0 || velocity.z != 0)) {
// No need to spam transactions
if (explosion.getRecords().isEmpty()) player.sendTransaction();
if (!hasBlocks || explosion.getRecords().isEmpty()) player.sendTransaction();
addPlayerExplosion(player.lastTransactionSent.get(), velocity);
event.getTasksAfterSend().add(player::sendTransaction);
}
}
}
private void handleBlockExplosions(WrapperPlayServerExplosion explosion) {
final @Nullable WrapperPlayServerExplosion.BlockInteraction blockInteraction = explosion.getBlockInteraction();
final boolean shouldDestroy = blockInteraction != WrapperPlayServerExplosion.BlockInteraction.KEEP_BLOCKS;
if (explosion.getRecords().isEmpty() || !shouldDestroy) {
return;
}
player.sendTransaction();
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> {
for (Vector3i record : explosion.getRecords()) {
// Null OR not flip redstone blocks, then set to air
if (blockInteraction != WrapperPlayServerExplosion.BlockInteraction.TRIGGER_BLOCKS) {
player.compensatedWorld.updateBlock(record.x, record.y, record.z, 0);
} else {
// We need to flip redstone blocks, or do special things with other blocks
final WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(record);
final StateType type = state.getType();
if (BlockTags.CANDLES.contains(type) || BlockTags.CANDLE_CAKES.contains(type)) {
state.setLit(false);
continue;
} else if (type == StateTypes.BELL) {
// Does this affect anything? I don't know, I don't see anything that relies on whether a bell is ringing.
continue;
}
// Otherwise try and flip/open it.
final Object poweredValue = state.getInternalData().get(StateValue.POWERED);
final boolean canFlip = (poweredValue != null && !(Boolean) poweredValue) || type == StateTypes.LEVER;
if (canFlip) {
player.compensatedWorld.tickOpenable(record.x, record.y, record.z);
}
}
}
});
}
public VelocityData getFutureExplosion() {
// Chronologically in the future
if (firstBreadMap.size() > 0) {
if (!firstBreadMap.isEmpty()) {
return firstBreadMap.peek();
}
// Less in the future
if (lastExplosionsKnownTaken != null) {
return lastExplosionsKnownTaken;
}
// Uncertain, might be in the future
if (player.firstBreadExplosion != null && player.likelyExplosions == null) {
return player.firstBreadExplosion;
@@ -120,7 +133,7 @@ public class ExplosionHandler extends Check implements PostPredictionCheck {
return (player.likelyExplosions != null && player.likelyExplosions.offset > offsetToFlag) || (player.firstBreadExplosion != null && player.firstBreadExplosion.offset > offsetToFlag);
}
public void addPlayerExplosion(int breadOne, Vector3f explosion) {
public void addPlayerExplosion(int breadOne, Vector3d explosion) {
firstBreadMap.add(new VelocityData(-1, breadOne, player.getSetbackTeleportUtil().isSendingSetback, new Vector(explosion.getX(), explosion.getY(), explosion.getZ())));
}
@@ -256,12 +269,10 @@ public class ExplosionHandler extends Check implements PostPredictionCheck {
}
@Override
public void reload() {
super.reload();
offsetToFlag = getConfig().getDoubleElse("Explosion.threshold", 0.00001);
setbackVL = getConfig().getDoubleElse("Explosion.setbackvl", 10);
public void onReload(ConfigManager config) {
offsetToFlag = config.getDoubleElse("Explosion.threshold", 0.00001);
setbackVL = config.getDoubleElse("Explosion.setbackvl", 10);
if (setbackVL == -1) setbackVL = Double.MAX_VALUE;
}
}
@@ -1,6 +1,7 @@
package ac.grim.grimac.checks.impl.velocity;
import ac.grim.grimac.GrimAPI;
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;
@@ -65,6 +66,7 @@ public class KnockbackHandler extends Check implements PostPredictionCheck {
if (playerVelocity.getY() == -0.04) {
velocity.setVelocity(playerVelocity.add(new Vector3d(0, 1 / 8000D, 0)));
playerVelocity = velocity.getVelocity();
event.markForReEncode(true);
}
// Wrap velocity between two transactions
@@ -240,15 +242,14 @@ public class KnockbackHandler extends Check implements PostPredictionCheck {
}
@Override
public void reload() {
super.reload();
offsetToFlag = getConfig().getDoubleElse("Knockback.threshold", 0.001);
maxAdv = getConfig().getDoubleElse("Knockback.max-advantage", 1);
immediate = getConfig().getDoubleElse("Knockback.immediate-setback-threshold", 0.1);
multiplier = getConfig().getDoubleElse("Knockback.setback-decay-multiplier", 0.999);
ceiling = getConfig().getDoubleElse("Knockback.max-ceiling", 4);
public void onReload(ConfigManager config) {
offsetToFlag = config.getDoubleElse("Knockback.threshold", 0.001);
maxAdv = config.getDoubleElse("Knockback.max-advantage", 1);
immediate = config.getDoubleElse("Knockback.immediate-setback-threshold", 0.1);
multiplier = config.getDoubleElse("Knockback.setback-decay-multiplier", 0.999);
ceiling = config.getDoubleElse("Knockback.max-ceiling", 4);
if (maxAdv < 0) maxAdv = Double.MAX_VALUE;
if (immediate < 0) immediate = Double.MAX_VALUE;
}
}
@@ -0,0 +1,7 @@
package ac.grim.grimac.checks.type;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
public interface BlockBreakCheck extends PostPredictionCheck {
default void onBlockBreak(final BlockBreak blockBreak) {}
}
@@ -1,10 +1,12 @@
package ac.grim.grimac.checks.type;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
import ac.grim.grimac.utils.collisions.HitboxData;
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.ComplexCollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
@@ -14,9 +16,10 @@ import com.github.retrooper.packetevents.util.Vector3i;
import java.util.ArrayList;
import java.util.List;
public class BlockPlaceCheck extends Check implements RotationCheck {
public class BlockPlaceCheck extends Check implements RotationCheck, PostPredictionCheck {
private static final List<StateType> weirdBoxes = new ArrayList<>();
private static final List<StateType> buggyBoxes = new ArrayList<>();
private final SimpleCollisionBox[] boxes = new SimpleCollisionBox[ComplexCollisionBox.DEFAULT_MAX_COLLISION_BOX_SIZE];
protected int cancelVL;
@@ -33,9 +36,8 @@ public class BlockPlaceCheck extends Check implements RotationCheck {
}
@Override
public void reload() {
super.reload();
this.cancelVL = getConfig().getIntElse(getConfigName() + ".cancelVL", 5);
public void onReload(ConfigManager config) {
this.cancelVL = config.getIntElse(getConfigName() + ".cancelVL", 5);
}
protected boolean shouldCancel() {
@@ -69,11 +71,11 @@ public class BlockPlaceCheck extends Check implements RotationCheck {
Vector3i clicked = place.getPlacedAgainstBlockLocation();
CollisionBox placedOn = HitboxData.getBlockHitbox(player, place.getMaterial(), player.getClientVersion(), player.compensatedWorld.getWrappedBlockStateAt(clicked), clicked.getX(), clicked.getY(), clicked.getZ());
List<SimpleCollisionBox> boxes = new ArrayList<>();
placedOn.downCast(boxes);
int size = placedOn.downCast(boxes);
SimpleCollisionBox combined = new SimpleCollisionBox(clicked.getX(), clicked.getY(), clicked.getZ());
for (SimpleCollisionBox box : boxes) {
for (int i = 0; i < size; i++) {
SimpleCollisionBox box = boxes[i];
double minX = Math.max(box.minX, combined.minX);
double minY = Math.max(box.minY, combined.minY);
double minZ = Math.max(box.minZ, combined.minZ);
@@ -1,19 +1,10 @@
package ac.grim.grimac.checks.type;
import ac.grim.grimac.api.AbstractCheck;
import ac.grim.grimac.utils.anticheat.update.PositionUpdate;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
public interface PacketCheck extends AbstractCheck {
default void onPacketReceive(final PacketReceiveEvent event) {
}
default void onPacketSend(final PacketSendEvent event) {
}
default void onPositionUpdate(final PositionUpdate positionUpdate) {
}
default void onPacketReceive(final PacketReceiveEvent event) {}
default void onPacketSend(final PacketSendEvent event) {}
}
@@ -1,8 +1,6 @@
package ac.grim.grimac.checks.type;
import ac.grim.grimac.api.AbstractCheck;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.RotationUpdate;
public interface RotationCheck extends AbstractCheck {
@@ -1,8 +1,6 @@
package ac.grim.grimac.checks.type;
import ac.grim.grimac.api.AbstractCheck;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.VehiclePositionUpdate;
public interface VehicleCheck extends AbstractCheck {
@@ -70,4 +70,4 @@ public class GrimDebug extends BaseCommand {
sender.sendMessage("Console output for " + (grimPlayer.bukkitPlayer == null ? grimPlayer.user.getProfile().getName() : grimPlayer.bukkitPlayer.getName()) + " is now " + isOutput);
}
}
}
@@ -1,12 +1,9 @@
package ac.grim.grimac.commands;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.checks.impl.aim.processor.AimProcessor;
import ac.grim.grimac.checks.impl.misc.ClientBrand;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import ac.grim.grimac.utils.anticheat.MultiLibUtil;
import ac.grim.grimac.utils.math.GrimMath;
import co.aikar.commands.BaseCommand;
import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandCompletion;
@@ -1,15 +1,11 @@
package ac.grim.grimac.commands;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import co.aikar.commands.BaseCommand;
import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandPermission;
import co.aikar.commands.annotation.Subcommand;
import com.github.retrooper.packetevents.netty.channel.ChannelHelper;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@CommandAlias("grim|grimac")
@@ -18,14 +14,15 @@ public class GrimReload extends BaseCommand {
@CommandPermission("grim.reload")
public void onReload(CommandSender sender) {
//reload config
try {
GrimAPI.INSTANCE.getExternalAPI().reload();
} catch (RuntimeException e) {
sender.sendMessage(ChatColor.RED + e.getMessage());
return;
}
sender.sendMessage(MessageUtil.format("%prefix% &fConfig has been reloaded."));
sender.sendMessage(MessageUtil.format("%prefix% &7Reloading config..."));
GrimAPI.INSTANCE.getExternalAPI().reloadAsync().exceptionally(throwable -> false)
.thenAccept(bool -> {
if (bool) {
sender.sendMessage(MessageUtil.format("%prefix% &fConfig has been reloaded."));
} else {
sender.sendMessage(MessageUtil.format("%prefix% &cFailed to reload config."));
}
});
}
}
@@ -20,7 +20,7 @@ public class GrimSendAlert extends BaseCommand {
bukkitPlayer.sendMessage(string);
}
if (GrimAPI.INSTANCE.getConfigManager().getConfig().getBooleanElse("alerts.print-to-console", true)) {
if (GrimAPI.INSTANCE.getConfigManager().isPrintAlertsToConsole()) {
LogUtil.console(string); // Print alert to console
}
}
@@ -23,8 +23,7 @@ public class GrimSpectate extends BaseCommand {
@CommandPermission("grim.spectate")
@CommandCompletion("@players")
public void onSpectate(CommandSender sender, @Optional OnlinePlayer target) {
if (!(sender instanceof Player)) return;
Player player = (Player) sender;
if (!(sender instanceof Player player)) return;
if (target != null && target.getPlayer().getUniqueId().equals(player.getUniqueId())) {
String message = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("cannot-run-on-self", "%prefix% &cYou cannot use this command on yourself!");
@@ -3,6 +3,8 @@ package ac.grim.grimac.commands;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import co.aikar.commands.BaseCommand;
import co.aikar.commands.BukkitCommandCompletionContext;
import co.aikar.commands.CommandCompletions.CommandCompletionHandler;
import co.aikar.commands.annotation.CommandAlias;
import co.aikar.commands.annotation.CommandCompletion;
import co.aikar.commands.annotation.CommandPermission;
@@ -10,17 +12,20 @@ import co.aikar.commands.annotation.Subcommand;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
@CommandAlias("grim|grimac")
public class GrimStopSpectating extends BaseCommand {
public static final CommandCompletionHandler<BukkitCommandCompletionContext> completionHandler = context -> context.getSender().hasPermission("grim.spectate.stophere") ? List.of("here") : List.of();
@Subcommand("stopspectating")
@CommandPermission("grim.spectate")
@CommandCompletion("here")
@CommandCompletion("@stopspectating")
public void onStopSpectate(CommandSender sender, String[] args) {
if (!(sender instanceof Player player)) return;
String string = args.length > 0 ? args[0] : null;
if (!(sender instanceof Player)) return;
Player player = (Player) sender;
if (GrimAPI.INSTANCE.getSpectateManager().isSpectating(player.getUniqueId())) {
boolean teleportBack = string == null || !string.equalsIgnoreCase("here");
boolean teleportBack = string == null || !string.equalsIgnoreCase("here") || !sender.hasPermission("grim.spectate.stophere");
GrimAPI.INSTANCE.getSpectateManager().disable(player, teleportBack);
} else {
String message = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("cannot-spectate-return", "%prefix% &cYou can only do this after spectating a player.");
@@ -28,4 +33,3 @@ public class GrimStopSpectating extends BaseCommand {
}
}
}
@@ -1,13 +1,12 @@
package ac.grim.grimac.events.packets;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.checks.impl.badpackets.BadPacketsX;
import ac.grim.grimac.checks.impl.badpackets.BadPacketsZ;
import ac.grim.grimac.events.packets.patch.ResyncWorldUtil;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.*;
import ac.grim.grimac.utils.blockplace.BlockPlaceResult;
import ac.grim.grimac.utils.blockplace.ConsumesBlockPlace;
import ac.grim.grimac.utils.change.BlockModification;
import ac.grim.grimac.utils.collisions.HitboxData;
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
@@ -52,6 +51,7 @@ import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
public class CheckManagerListener extends PacketListenerAbstract {
@@ -224,11 +224,10 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
}
private static void handleBlockPlaceOrUseItem(PacketWrapper packet, GrimPlayer player) {
private static void handleBlockPlaceOrUseItem(PacketWrapper<?> packet, GrimPlayer player) {
// Legacy "use item" packet
if (packet instanceof WrapperPlayClientPlayerBlockPlacement &&
if (packet instanceof WrapperPlayClientPlayerBlockPlacement place &&
PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9)) {
WrapperPlayClientPlayerBlockPlacement place = (WrapperPlayClientPlayerBlockPlacement) packet;
if (player.gamemode == GameMode.SPECTATOR || player.gamemode == GameMode.ADVENTURE) return;
@@ -243,9 +242,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
}
if (packet instanceof WrapperPlayClientUseItem) {
WrapperPlayClientUseItem place = (WrapperPlayClientUseItem) packet;
if (packet instanceof WrapperPlayClientUseItem place) {
if (player.gamemode == GameMode.SPECTATOR || player.gamemode == GameMode.ADVENTURE) return;
ItemStack placedWith = player.getInventory().getHeldItem();
@@ -257,9 +254,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
// Check for interactable first (door, etc)
if (packet instanceof WrapperPlayClientPlayerBlockPlacement) {
WrapperPlayClientPlayerBlockPlacement place = (WrapperPlayClientPlayerBlockPlacement) packet;
if (packet instanceof WrapperPlayClientPlayerBlockPlacement place) {
ItemStack placedWith = player.getInventory().getHeldItem();
ItemStack offhand = player.getInventory().getOffHand();
@@ -295,8 +290,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
}
if (packet instanceof WrapperPlayClientPlayerBlockPlacement) {
WrapperPlayClientPlayerBlockPlacement place = (WrapperPlayClientPlayerBlockPlacement) packet;
if (packet instanceof WrapperPlayClientPlayerBlockPlacement place) {
Vector3i blockPosition = place.getBlockPosition();
BlockFace face = place.getFace();
@@ -348,7 +342,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
// Additionally, only yaw/pitch matters: https://github.com/GrimAnticheat/Grim/issues/1275#issuecomment-1872444018
// 1.9+ isn't impacted by this packet as much.
if (PacketEvents.getAPI().getServerManager().getVersion().isOlderThanOrEquals(ServerVersion.V_1_9)) {
if (GrimAPI.INSTANCE.getConfigManager().getConfig().getBooleanElse("cancel-duplicate-packet", true)) {
if (player.isCancelDuplicatePacket()) {
player.packetStateData.cancelDuplicatePacket = true;
}
} else {
@@ -358,7 +352,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
player.packetStateData.lastPacketWasOnePointSeventeenDuplicate = true;
if (!GrimAPI.INSTANCE.getConfigManager().isIgnoreDuplicatePacketRotation()) {
if (!player.isIgnoreDuplicatePacketRotation()) {
if (player.xRot != location.getYaw() || player.yRot != location.getPitch()) {
player.lastXRot = player.xRot;
player.lastYRot = player.yRot;
@@ -375,6 +369,9 @@ public class CheckManagerListener extends PacketListenerAbstract {
return false;
}
// Manual filter on FINISH_DIGGING to prevent clients setting non-breakable blocks to air
private static final Function<StateType, Boolean> BREAKABLE = type -> !type.isAir() && type.getHardness() != -1.0f && type != StateTypes.WATER && type != StateTypes.LAVA;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getConnectionState() != ConnectionState.PLAY) return;
@@ -428,7 +425,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
WrapperPlayClientPlayerFlying flying = new WrapperPlayClientPlayerFlying(event);
Location pos = flying.getLocation();
boolean ignoreRotation = player.packetStateData.lastPacketWasOnePointSeventeenDuplicate && GrimAPI.INSTANCE.getConfigManager().isIgnoreDuplicatePacketRotation();
boolean ignoreRotation = player.packetStateData.lastPacketWasOnePointSeventeenDuplicate && player.isIgnoreDuplicatePacketRotation();
handleFlying(player, pos.getX(), pos.getY(), pos.getZ(), ignoreRotation ? player.xRot : pos.getYaw(), ignoreRotation ? player.yRot : pos.getPitch(), flying.hasPositionChanged(), flying.hasRotationChanged(), flying.isOnGround(), teleportData, event);
}
@@ -455,41 +452,52 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
WrapperPlayClientPlayerDigging dig = new WrapperPlayClientPlayerDigging(event);
WrappedBlockState block = player.compensatedWorld.getWrappedBlockStateAt(dig.getBlockPosition());
final WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
final DiggingAction action = packet.getAction();
player.checkManager.getPacketCheck(BadPacketsX.class).handle(event, dig, block.getType());
player.checkManager.getPacketCheck(BadPacketsZ.class).handle(event, dig);
if (action == DiggingAction.START_DIGGING || action == DiggingAction.FINISHED_DIGGING || action == DiggingAction.CANCELLED_DIGGING) {
final BlockBreak blockBreak = new BlockBreak(packet.getBlockPosition(), packet.getBlockFace(), action, player.compensatedWorld.getWrappedBlockStateAt(packet.getBlockPosition()));
if (dig.getAction() == DiggingAction.FINISHED_DIGGING) {
// Not unbreakable
if (!block.getType().isAir() && block.getType().getHardness() != -1.0f && !event.isCancelled()) {
player.compensatedWorld.startPredicting();
player.compensatedWorld.updateBlock(dig.getBlockPosition().getX(), dig.getBlockPosition().getY(), dig.getBlockPosition().getZ(), 0);
player.compensatedWorld.stopPredicting(dig);
}
}
player.checkManager.onBlockBreak(blockBreak);
if (dig.getAction() == DiggingAction.START_DIGGING && !event.isCancelled()) {
double damage = BlockBreakSpeed.getBlockDamage(player, dig.getBlockPosition());
//Instant breaking, no damage means it is unbreakable by creative players (with swords)
if (damage >= 1) {
player.compensatedWorld.startPredicting();
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13) && Materials.isWaterSource(player.getClientVersion(), block)) {
// Vanilla uses a method to grab water flowing, but as you can't break flowing water
// We can simply treat all waterlogged blocks or source blocks as source blocks
player.compensatedWorld.updateBlock(dig.getBlockPosition(), StateTypes.WATER.createBlockState(CompensatedWorld.blockVersion));
} else {
player.compensatedWorld.updateBlock(dig.getBlockPosition().getX(), dig.getBlockPosition().getY(), dig.getBlockPosition().getZ(), 0);
if (blockBreak.isCancelled()) {
event.setCancelled(true);
player.onPacketCancel();
ResyncWorldUtil.resyncPosition(player, blockBreak.position, packet.getSequence());
} else {
if (action == DiggingAction.FINISHED_DIGGING && BREAKABLE.apply(blockBreak.block.getType())) {
player.compensatedWorld.startPredicting();
player.compensatedWorld.updateBlock(blockBreak.position.x, blockBreak.position.y, blockBreak.position.z, 0);
player.compensatedWorld.stopPredicting(packet);
}
player.compensatedWorld.stopPredicting(dig);
}
}
if (!event.isCancelled()) {
if (dig.getAction() == DiggingAction.START_DIGGING || dig.getAction() == DiggingAction.FINISHED_DIGGING || dig.getAction() == DiggingAction.CANCELLED_DIGGING) {
player.compensatedWorld.handleBlockBreakPrediction(dig);
if (action == DiggingAction.START_DIGGING) {
double damage = BlockBreakSpeed.getBlockDamage(player, blockBreak.position);
// Instant breaking, no damage means it is unbreakable by creative players (with swords)
if (damage >= 1) {
player.compensatedWorld.startPredicting();
player.blockHistory.add(
new BlockModification(
player.compensatedWorld.getWrappedBlockStateAt(blockBreak.position),
WrappedBlockState.getByGlobalId(0),
blockBreak.position,
GrimAPI.INSTANCE.getTickManager().currentTick,
BlockModification.Cause.START_DIGGING
)
);
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_13) && Materials.isWaterSource(player.getClientVersion(), blockBreak.block)) {
// Vanilla uses a method to grab water flowing, but as you can't break flowing water
// We can simply treat all waterlogged blocks or source blocks as source blocks
player.compensatedWorld.updateBlock(blockBreak.position, StateTypes.WATER.createBlockState(CompensatedWorld.blockVersion));
} else {
player.compensatedWorld.updateBlock(blockBreak.position.x, blockBreak.position.y, blockBreak.position.z, 0);
}
player.compensatedWorld.stopPredicting(packet);
}
}
player.compensatedWorld.handleBlockBreakPrediction(packet);
}
}
}
@@ -576,6 +584,15 @@ public class CheckManagerListener extends PacketListenerAbstract {
player.packetStateData.cancelDuplicatePacket = false;
}
if (event.getPacketType() == PacketType.Play.Client.CLIENT_TICK_END) {
if (!player.packetStateData.didSendMovementBeforeTickEnd) {
// The player didn't send a movement packet, so we can predict this like we had idle tick on 1.8
player.packetStateData.didLastLastMovementIncludePosition = player.packetStateData.didLastMovementIncludePosition;
player.packetStateData.didLastMovementIncludePosition = false;
}
player.packetStateData.didSendMovementBeforeTickEnd = false;
}
// Finally, remove the packet state variables on this packet
player.packetStateData.lastPacketWasOnePointSeventeenDuplicate = false;
player.packetStateData.lastPacketWasTeleport = false;
@@ -745,6 +762,10 @@ public class CheckManagerListener extends PacketListenerAbstract {
player.packetStateData.didLastLastMovementIncludePosition = player.packetStateData.didLastMovementIncludePosition;
player.packetStateData.didLastMovementIncludePosition = hasPosition;
if (!player.packetStateData.lastPacketWasTeleport) {
player.packetStateData.didSendMovementBeforeTickEnd = true;
}
}
private static void placeLilypad(GrimPlayer player, InteractionHand hand) {
@@ -782,7 +803,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
Vector3d startingPos = new Vector3d(player.x, player.y + player.getEyeHeight(), player.z);
Vector startingVec = new Vector(startingPos.getX(), startingPos.getY(), startingPos.getZ());
Ray trace = new Ray(player, startingPos.getX(), startingPos.getY(), startingPos.getZ(), player.xRot, player.yRot);
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.BLOCK_INTERACTION_RANGE);
Vector endVec = trace.getPointAtDistance(distance);
Vector3d endPos = new Vector3d(endVec.getX(), endVec.getY(), endVec.getZ());
@@ -797,14 +818,14 @@ public class CheckManagerListener extends PacketListenerAbstract {
for (SimpleCollisionBox box : boxes) {
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.getFirst() == null) continue; // No intercept
if (intercept.first() == null) continue; // No intercept
Vector hitLoc = intercept.getFirst();
Vector hitLoc = intercept.first();
if (hitLoc.distanceSquared(startingVec) < bestHitResult) {
bestHitResult = hitLoc.distanceSquared(startingVec);
bestHitLoc = hitLoc;
bestFace = intercept.getSecond();
bestFace = intercept.second();
}
}
if (bestHitLoc != null) {
@@ -819,8 +840,8 @@ public class CheckManagerListener extends PacketListenerAbstract {
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.getFirst() != null) {
return new HitData(vector3i, intercept.getFirst(), intercept.getSecond(), block);
if (intercept.first() != null) {
return new HitData(vector3i, intercept.first(), intercept.second(), block);
}
}
@@ -1,9 +1,6 @@
package ac.grim.grimac.events.packets;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.checks.impl.movement.NoSlowC;
import ac.grim.grimac.checks.impl.movement.NoSlowD;
import ac.grim.grimac.checks.impl.movement.NoSlowE;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
@@ -1,6 +1,6 @@
package ac.grim.grimac.events.packets;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
@@ -13,6 +13,7 @@ import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.entity.EntityPositionData;
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
@@ -21,7 +22,6 @@ import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.UserProfile;
import com.github.retrooper.packetevents.protocol.potion.PotionType;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import com.github.retrooper.packetevents.wrapper.play.server.*;
import io.github.retrooper.packetevents.util.viaversion.ViaVersionUtil;
@@ -53,7 +53,6 @@ public class PacketEntityReplication extends Check implements PacketCheck {
private final List<Integer> despawnedEntitiesThisTransaction = new ArrayList<>();
// Maximum ping when a firework boost is removed from the player.
private final int maxFireworkBoostPing = GrimAPI.INSTANCE.getConfigManager().getConfig().getIntElse("max-ping-firework-boost", 1000);
public PacketEntityReplication(GrimPlayer player) {
super(player);
@@ -61,22 +60,19 @@ public class PacketEntityReplication extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
// Teleports don't interpolate, duplicate 1.17 packets don't interpolate
if (player.packetStateData.lastPacketWasTeleport || player.packetStateData.lastPacketWasOnePointSeventeenDuplicate)
return;
// Teleports don't interpolate, duplicate 1.17 packets don't interpolate
if (!isTickPacket(event.getPacketType())) return;
boolean isTickingReliably = player.isTickingReliablyFor(3);
boolean isTickingReliably = player.isTickingReliablyFor(3);
PacketEntity playerVehicle = player.compensatedEntities.getSelf().getRiding();
for (PacketEntity entity : player.compensatedEntities.entityMap.values()) {
if (entity == playerVehicle && !player.vehicleData.lastDummy) {
// The player has this as their vehicle, so they aren't interpolating it.
// And it isn't a dummy position
entity.setPositionRaw(entity.getPossibleCollisionBoxes());
} else {
entity.onMovement(isTickingReliably);
}
PacketEntity playerVehicle = player.compensatedEntities.getSelf().getRiding();
for (PacketEntity entity : player.compensatedEntities.entityMap.values()) {
if (entity == playerVehicle && !player.vehicleData.lastDummy) {
// The player has this as their vehicle, so they aren't interpolating it.
// And it isn't a dummy position
entity.setPositionRaw(entity.getPossibleCollisionBoxes());
} else {
entity.onMovement(isTickingReliably);
}
}
}
@@ -87,44 +83,55 @@ public class PacketEntityReplication extends Check implements PacketCheck {
if ((event.getPacketType() == PacketType.Play.Server.PING || event.getPacketType() == PacketType.Play.Server.WINDOW_CONFIRMATION) && player.packetStateData.lastServerTransWasValid) {
despawnedEntitiesThisTransaction.clear();
}
if (event.getPacketType() == PacketType.Play.Server.SPAWN_LIVING_ENTITY) {
else if (event.getPacketType() == PacketType.Play.Server.SPAWN_LIVING_ENTITY) {
WrapperPlayServerSpawnLivingEntity packetOutEntity = new WrapperPlayServerSpawnLivingEntity(event);
addEntity(packetOutEntity.getEntityId(), packetOutEntity.getEntityUUID(), packetOutEntity.getEntityType(), packetOutEntity.getPosition(), packetOutEntity.getYaw(), packetOutEntity.getPitch(), packetOutEntity.getEntityMetadata(), 0);
}
if (event.getPacketType() == PacketType.Play.Server.SPAWN_ENTITY) {
else if (event.getPacketType() == PacketType.Play.Server.SPAWN_ENTITY) {
WrapperPlayServerSpawnEntity packetOutEntity = new WrapperPlayServerSpawnEntity(event);
addEntity(packetOutEntity.getEntityId(), packetOutEntity.getUUID().orElse(null), packetOutEntity.getEntityType(), packetOutEntity.getPosition(), packetOutEntity.getYaw(), packetOutEntity.getPitch(), null, packetOutEntity.getData());
}
if (event.getPacketType() == PacketType.Play.Server.SPAWN_PLAYER) {
else if (event.getPacketType() == PacketType.Play.Server.SPAWN_PLAYER) {
WrapperPlayServerSpawnPlayer packetOutEntity = new WrapperPlayServerSpawnPlayer(event);
addEntity(packetOutEntity.getEntityId(), packetOutEntity.getUUID(), EntityTypes.PLAYER, packetOutEntity.getPosition(), packetOutEntity.getYaw(), packetOutEntity.getPitch(), packetOutEntity.getEntityMetadata(), 0);
}
if (event.getPacketType() == PacketType.Play.Server.ENTITY_RELATIVE_MOVE) {
else if (event.getPacketType() == PacketType.Play.Server.SPAWN_PAINTING) {
WrapperPlayServerSpawnPainting packetOutEntity = new WrapperPlayServerSpawnPainting(event);
addEntity(packetOutEntity.getEntityId(), packetOutEntity.getUUID(), EntityTypes.PAINTING, packetOutEntity.getPosition().toVector3d(), 0, 0f, null, packetOutEntity.getDirection().getHorizontalIndex());
}
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_RELATIVE_MOVE) {
WrapperPlayServerEntityRelativeMove move = new WrapperPlayServerEntityRelativeMove(event);
handleMoveEntity(event, move.getEntityId(), move.getDeltaX(), move.getDeltaY(), move.getDeltaZ(), null, null, true, true);
}
if (event.getPacketType() == PacketType.Play.Server.ENTITY_RELATIVE_MOVE_AND_ROTATION) {
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_RELATIVE_MOVE_AND_ROTATION) {
WrapperPlayServerEntityRelativeMoveAndRotation move = new WrapperPlayServerEntityRelativeMoveAndRotation(event);
handleMoveEntity(event, move.getEntityId(), move.getDeltaX(), move.getDeltaY(), move.getDeltaZ(), move.getYaw() * 0.7111111F, move.getPitch() * 0.7111111F, true, true);
}
if (event.getPacketType() == PacketType.Play.Server.ENTITY_TELEPORT) {
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_TELEPORT) {
WrapperPlayServerEntityTeleport move = new WrapperPlayServerEntityTeleport(event);
Vector3d pos = move.getPosition();
handleMoveEntity(event, move.getEntityId(), pos.getX(), pos.getY(), pos.getZ(), move.getYaw(), move.getPitch(), false, true);
}
if (event.getPacketType() == PacketType.Play.Server.ENTITY_ROTATION) { // Affects interpolation
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_POSITION_SYNC) {
// ENTITY_TELEPORT but without relative flags
WrapperPlayServerEntityPositionSync move = new WrapperPlayServerEntityPositionSync(event);
final EntityPositionData values = move.getValues();
final Vector3d pos = values.getPosition();
// TODO this isn't technically correct
// If the position sync is to a pos > 4096 from the entity pos, client does some special stuff without interpolation
handleMoveEntity(event, move.getId(), pos.getX(), pos.getY(), pos.getZ(), values.getYaw(), values.getPitch(), false, true);
}
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_ROTATION) { // Affects interpolation
WrapperPlayServerEntityRotation move = new WrapperPlayServerEntityRotation(event);
handleMoveEntity(event, move.getEntityId(), 0, 0, 0, move.getYaw() * 0.7111111F, move.getPitch() * 0.7111111F, true, false);
}
if (event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) {
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) {
WrapperPlayServerEntityMetadata entityMetadata = new WrapperPlayServerEntityMetadata(event);
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> player.compensatedEntities.updateEntityMetadata(entityMetadata.getEntityId(), entityMetadata.getEntityMetadata()));
}
// 1.19.3+
if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO_UPDATE) {
else if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO_UPDATE) {
WrapperPlayServerPlayerInfoUpdate info = new WrapperPlayServerPlayerInfoUpdate(event);
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> {
for (WrapperPlayServerPlayerInfoUpdate.PlayerInfo entry : info.getEntries()) {
@@ -151,7 +158,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
});
}
if (event.getPacketType() == PacketType.Play.Server.ENTITY_EFFECT) {
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_EFFECT) {
WrapperPlayServerEntityEffect effect = new WrapperPlayServerEntityEffect(event);
PotionType type = effect.getPotionType();
@@ -183,7 +190,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
});
}
if (event.getPacketType() == PacketType.Play.Server.REMOVE_ENTITY_EFFECT) {
else if (event.getPacketType() == PacketType.Play.Server.REMOVE_ENTITY_EFFECT) {
WrapperPlayServerRemoveEntityEffect effect = new WrapperPlayServerRemoveEntityEffect(event);
if (isDirectlyAffectingPlayer(player, effect.getEntityId())) player.sendTransaction();
@@ -196,7 +203,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
});
}
if (event.getPacketType() == PacketType.Play.Server.UPDATE_ATTRIBUTES) {
else if (event.getPacketType() == PacketType.Play.Server.UPDATE_ATTRIBUTES) {
WrapperPlayServerUpdateAttributes attributes = new WrapperPlayServerUpdateAttributes(event);
int entityID = attributes.getEntityId();
@@ -208,7 +215,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
() -> player.compensatedEntities.updateAttributes(entityID, attributes.getProperties()));
}
if (event.getPacketType() == PacketType.Play.Server.ENTITY_STATUS) {
else if (event.getPacketType() == PacketType.Play.Server.ENTITY_STATUS) {
WrapperPlayServerEntityStatus status = new WrapperPlayServerEntityStatus(event);
// This hasn't changed from 1.7.2 to 1.17
// Needed to exempt players on dead vehicles, as dead entities have strange physics.
@@ -228,9 +235,8 @@ public class PacketEntityReplication extends Check implements PacketCheck {
if (status.getStatus() == 31) {
PacketEntity hook = player.compensatedEntities.getEntity(status.getEntityId());
if (!(hook instanceof PacketEntityHook)) return;
if (!(hook instanceof PacketEntityHook hookEntity)) return;
PacketEntityHook hookEntity = (PacketEntityHook) hook;
if (hookEntity.attached == player.entityID) {
player.sendTransaction();
// We don't transaction sandwich this, it's too rare to be a real problem.
@@ -243,7 +249,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
}
}
if (event.getPacketType() == PacketType.Play.Server.SET_SLOT) {
else if (event.getPacketType() == PacketType.Play.Server.SET_SLOT) {
WrapperPlayServerSetSlot slot = new WrapperPlayServerSetSlot(event);
if (slot.getWindowId() == 0) {
@@ -261,7 +267,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
}
}
if (event.getPacketType() == PacketType.Play.Server.WINDOW_ITEMS) {
else if (event.getPacketType() == PacketType.Play.Server.WINDOW_ITEMS) {
WrapperPlayServerWindowItems items = new WrapperPlayServerWindowItems(event);
if (items.getWindowId() == 0) { // Player inventory
@@ -271,16 +277,16 @@ public class PacketEntityReplication extends Check implements PacketCheck {
}
// 1.8 clients fail to send the RELEASE_USE_ITEM packet when a window is opened client sided while using an item
if (event.getPacketType() == PacketType.Play.Server.OPEN_WINDOW) {
else if (event.getPacketType() == PacketType.Play.Server.OPEN_WINDOW) {
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> player.packetStateData.setSlowedByUsingItem(false));
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get() + 1, () -> player.packetStateData.setSlowedByUsingItem(false));
}
if (event.getPacketType() == PacketType.Play.Server.OPEN_HORSE_WINDOW) {
else if (event.getPacketType() == PacketType.Play.Server.OPEN_HORSE_WINDOW) {
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> player.packetStateData.setSlowedByUsingItem(false));
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get() + 1, () -> player.packetStateData.setSlowedByUsingItem(false));
}
if (event.getPacketType() == PacketType.Play.Server.SET_PASSENGERS) {
else if (event.getPacketType() == PacketType.Play.Server.SET_PASSENGERS) {
WrapperPlayServerSetPassengers mount = new WrapperPlayServerSetPassengers(event);
int vehicleID = mount.getEntityId();
@@ -289,7 +295,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
handleMountVehicle(event, vehicleID, passengers);
}
if (event.getPacketType() == PacketType.Play.Server.ATTACH_ENTITY) {
else if (event.getPacketType() == PacketType.Play.Server.ATTACH_ENTITY) {
WrapperPlayServerAttachEntity attach = new WrapperPlayServerAttachEntity(event);
// This packet was replaced by the mount packet on 1.9+ servers - to support multiple passengers on one vehicle
@@ -320,7 +326,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
}
}
if (event.getPacketType() == PacketType.Play.Server.DESTROY_ENTITIES) {
else if (event.getPacketType() == PacketType.Play.Server.DESTROY_ENTITIES) {
WrapperPlayServerDestroyEntities destroy = new WrapperPlayServerDestroyEntities(event);
int[] destroyEntityIds = destroy.getEntityIds();
@@ -415,9 +421,13 @@ public class PacketEntityReplication extends Check implements PacketCheck {
// As we don't want vehicles to fly, we need to replace it with a teleport if it is player vehicle
//
// Don't bother with client controlled vehicles though
boolean vanillaVehicleFlight = player.compensatedEntities.serverPlayerVehicle != null && player.compensatedEntities.serverPlayerVehicle == entityId
&& player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) &&
PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9);
boolean vanillaVehicleFlight = player.compensatedEntities.serverPlayerVehicle != null
&& player.compensatedEntities.serverPlayerVehicle == entityId
&& player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)
// TODO: https://discord.com/channels/721686193061888071/721686193515003966/1310659538831020123
// Why does the server now send an entity rel move packet matching the player's vehicle movement every time?
&& PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_21_2)
&& PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9);
// ViaVersion sends two relative packets when moving more than 4 blocks
// This is broken and causes the client to interpolate like (0, 4) and (1, 3) instead of (1, 7)
@@ -455,8 +465,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
player.latencyUtils.addRealTimeTask(lastTrans, () -> {
PacketEntity entity = player.compensatedEntities.getEntity(entityId);
if (entity == null) return;
if (entity instanceof PacketEntityTrackXRot && yaw != null) {
PacketEntityTrackXRot xRotEntity = (PacketEntityTrackXRot) entity;
if (entity instanceof PacketEntityTrackXRot xRotEntity && yaw != null) {
xRotEntity.packetYaw = yaw;
xRotEntity.steps = entity.isBoat() ? 10 : 3;
}
@@ -500,4 +509,12 @@ public class PacketEntityReplication extends Check implements PacketCheck {
public void tickStartTick() {
hasSentPreWavePacket = false;
}
private int maxFireworkBoostPing = 1000;
@Override
public void onReload(ConfigManager config) {
maxFireworkBoostPing = config.getIntElse("max-ping-firework-boost", 1000);
}
}
@@ -5,14 +5,11 @@ import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
import com.github.retrooper.packetevents.protocol.player.UserProfile;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfo;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoUpdate;
@@ -20,22 +17,15 @@ import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
public class PacketSetWrapperNull extends PacketListenerAbstract {
// It's faster (and less buggy) to simply not re-encode the wrapper unless we changed something
// The two packets we change are clientbound entity metadata (to fix a netcode issue)
// and the serverbound player flying packets (to patch NoFall)
public PacketSetWrapperNull() {
public class PacketHidePlayerInfo extends PacketListenerAbstract {
public PacketHidePlayerInfo() {
super(PacketListenerPriority.HIGHEST);
}
@Override
public void onPacketSend(PacketSendEvent event) {
if (event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) {
WrapperPlayServerEntityMetadata wrapper = new WrapperPlayServerEntityMetadata(event);
if (wrapper.getEntityId() != event.getUser().getEntityId()) {
event.setLastUsedWrapper(null);
}
} else if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO) {
if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO) {
//iterate through players and fake their game mode if they are spectating via grim spectate
if (PacketEvents.getAPI().getServerManager().getVersion().isOlderThanOrEquals(ServerVersion.V_1_12_2))
return;
@@ -62,8 +52,8 @@ public class PacketSetWrapperNull extends PacketListenerAbstract {
//if amount of hidden players is the amount of players updated & is an update game mode action just cancel it
if (hideCount == nmsPlayerInfoDataList.size() && info.getAction() == WrapperPlayServerPlayerInfo.Action.UPDATE_GAME_MODE) {
event.setCancelled(true);
} else if (hideCount <= 0) {
event.setLastUsedWrapper(null);
} else if (hideCount > 0) {
event.markForReEncode(true);
}
}
} else if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO_UPDATE) {
@@ -81,12 +71,13 @@ public class PacketSetWrapperNull extends PacketListenerAbstract {
for (WrapperPlayServerPlayerInfoUpdate.PlayerInfo entry : wrapper.getEntries()) {
//check if the player should be hidden
WrapperPlayServerPlayerInfoUpdate.PlayerInfo modifiedPacket = null;
if (GrimAPI.INSTANCE.getSpectateManager().shouldHidePlayer(receiver, entry.getProfileId())) {
final UserProfile gameProfile = entry.getGameProfile();
if (GrimAPI.INSTANCE.getSpectateManager().shouldHidePlayer(receiver, gameProfile.getUUID())) {
hideCount++;
//modify & create a new packet from pre-existing one if they are a spectator
if (entry.getGameMode() == GameMode.SPECTATOR) {
modifiedPacket = new WrapperPlayServerPlayerInfoUpdate.PlayerInfo(
entry.getGameProfile(),
gameProfile,
entry.isListed(),
entry.getLatency(),
GameMode.SURVIVAL,
@@ -104,30 +95,20 @@ public class PacketSetWrapperNull extends PacketListenerAbstract {
} //if only the game mode was updated and the packet was modified, don't send anything
}
//if no hidden players, don't modify packet
if (hideCount <= 0) {
event.setLastUsedWrapper(null);
} else if (hideCount == modified.size()) { //if the amount of hidden players & modified entries are the same
// if the amount of hidden players & modified entries are the same
if (hideCount == modified.size()) {
if (onlyGameMode) { // if only the game mode changed, cancel
event.setCancelled(true);
} else { //if more than the game mode changed, remove the action
wrapper.getActions().remove(WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_GAME_MODE);
event.markForReEncode(true);
}
} else { //modify entries
wrapper.setEntries(modified);
event.markForReEncode(true);
}
}
} else if (event.getPacketType() != PacketType.Play.Server.PLAYER_POSITION_AND_LOOK) {
event.setLastUsedWrapper(null);
}
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
PacketTypeCommon packetType = event.getPacketType();
if (!WrapperPlayClientPlayerFlying.isFlying(packetType) && packetType != PacketType.Play.Client.CLIENT_SETTINGS && !event.isCancelled()) {
event.setLastUsedWrapper(null);
}
}
}
@@ -1,6 +1,6 @@
package ac.grim.grimac.events.packets;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
@@ -37,7 +37,6 @@ public class PacketPlayerAbilities extends Check implements PacketCheck {
if (lastSentPlayerCanFly && !abilities.isFlightAllowed()) {
int noFlying = player.lastTransactionSent.get();
int maxFlyingPing = GrimAPI.INSTANCE.getConfigManager().getConfig().getIntElse("max-ping-out-of-flying", 1000);
if (maxFlyingPing != -1) {
player.runNettyTaskInMs(() -> {
if (player.lastTransactionReceived.get() < noFlying) {
@@ -56,4 +55,12 @@ public class PacketPlayerAbilities extends Check implements PacketCheck {
}
}
int maxFlyingPing = 1000;
@Override
public void onReload(ConfigManager config) {
maxFlyingPing = config.getIntElse("max-ping-out-of-flying", 1000);
}
}
@@ -8,6 +8,8 @@ import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.enchantment.type.EnchantmentTypes;
@@ -72,6 +74,13 @@ public class PacketPlayerAttack extends PacketListenerAbstract {
player.maxPlayerAttackSlow = 1;
}
} else if (!isLegacyPlayer && player.isSprinting) {
// 1.9+ players who have attack speed cannot slow themselves twice in one tick because their attack cooldown gets reset on swing.
if (player.maxPlayerAttackSlow > 0
&& PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)
&& player.compensatedEntities.getSelf().getAttributeValue(Attributes.ATTACK_SPEED) < 16) { // 16 is a reasonable limit
return;
}
// 1.9+ player who might have been slowed, but we can't be sure
player.maxPlayerAttackSlow += 1;
}
@@ -2,7 +2,6 @@ package ac.grim.grimac.events.packets;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.checks.impl.movement.NoSlowA;
import ac.grim.grimac.checks.impl.movement.NoSlowD;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
@@ -23,7 +22,6 @@ import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.wrapper.play.client.*;
import org.bukkit.Bukkit;
public class PacketPlayerDigging extends PacketListenerAbstract {
@@ -170,12 +168,14 @@ public class PacketPlayerDigging extends PacketListenerAbstract {
}
}
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) || event.getPacketType() == PacketType.Play.Client.CLIENT_TICK_END) {
final GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
if (!player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
if (player.packetStateData.isSlowedByUsingItem() && player.packetStateData.getSlowedByUsingItemSlot() != player.packetStateData.lastSlotSelected) {
if (player != null && player.packetStateData.isSlowedByUsingItem()
&& !player.packetStateData.lastPacketWasTeleport
&& !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
if (player.packetStateData.eatingHand != InteractionHand.OFF_HAND
&& player.packetStateData.getSlowedByUsingItemSlot() != player.packetStateData.lastSlotSelected
|| player.getInventory().getItemInHand(player.packetStateData.eatingHand).isEmpty()) {
player.packetStateData.setSlowedByUsingItem(false);
player.checkManager.getPostPredictionCheck(NoSlowA.class).didSlotChangeLastTick = true;
}
@@ -196,7 +196,7 @@ public class PacketPlayerDigging extends PacketListenerAbstract {
if (player.packetStateData.lastSlotSelected != slot) {
// just assume they tick after this
if (!player.isTickingReliablyFor(3) && player.skippedTickInActualMovement) {
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) && !player.supportsEndTick() && !player.isTickingReliablyFor(3) && player.packetStateData.eatingHand != InteractionHand.OFF_HAND) {
player.packetStateData.setSlowedByUsingItem(false);
}
}
@@ -220,13 +220,7 @@ public class PacketPlayerDigging extends PacketListenerAbstract {
final ItemStack item = hand == InteractionHand.MAIN_HAND ?
player.getInventory().getHeldItem() : player.getInventory().getOffHand();
final boolean wasSlow = player.packetStateData.isSlowedByUsingItem();
handleUseItem(player, item, hand);
if (!wasSlow) {
player.checkManager.getPostPredictionCheck(NoSlowD.class).startedSprintingBeforeUse = player.packetStateData.isSlowedByUsingItem() && player.isSprinting;
}
}
}
}
@@ -36,6 +36,9 @@ public class PacketPlayerJoinQuit extends PacketListenerAbstract {
}
if (player.hasPermission("grim.alerts") && player.hasPermission("grim.alerts.enable-on-join")) {
GrimAPI.INSTANCE.getAlertManager().toggleAlerts(player);
if (player.hasPermission("grim.verbose") && player.hasPermission("grim.verbose.enable-on-join")) {
GrimAPI.INSTANCE.getAlertManager().toggleVerbose(player);
}
}
if (player.hasPermission("grim.spectate") && GrimAPI.INSTANCE.getConfigManager().getConfig().getBooleanElse("spectators.hide-regardless", false)) {
GrimAPI.INSTANCE.getSpectateManager().onLogin(player);
@@ -3,6 +3,7 @@ package ac.grim.grimac.events.packets;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.checks.impl.badpackets.BadPacketsE;
import ac.grim.grimac.checks.impl.badpackets.BadPacketsF;
import ac.grim.grimac.checks.impl.badpackets.BadPacketsG;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.TrackerData;
import ac.grim.grimac.utils.data.packetentity.PacketEntitySelf;
@@ -130,9 +131,12 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
player.compensatedEntities.serverPositionsMap.clear();
}
// TODO: What does keep all metadata do?
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get() + 1, () -> {
player.isSneaking = false;
// From 1.16 to 1.19, this doesn't get set to false for whatever reason
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_16) || player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20)) {
player.isSneaking = false;
}
player.lastOnGround = false;
player.onGround = false;
player.isInBed = false;
@@ -141,8 +145,16 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
player.packetStateData.lastClaimedPosition = new Vector3d();
player.filterMojangStupidityOnMojangStupidity = new Vector3d();
final boolean keepTrackedData = this.hasFlag(respawn, KEEP_TRACKED_DATA);
if (!keepTrackedData) {
player.powderSnowFrozenTicks = 0;
player.compensatedEntities.getSelf().hasGravity = true;
player.playerEntityHasGravity = true;
}
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_19_4)) {
if (!this.hasFlag(respawn, KEEP_TRACKED_DATA)) {
if (!keepTrackedData) {
player.isSprinting = false;
}
} else {
@@ -150,6 +162,7 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
}
player.checkManager.getPacketCheck(BadPacketsE.class).handleRespawn(); // Reminder ticks reset
player.checkManager.getPacketCheck(BadPacketsG.class).handleRespawn();
// compensate for immediate respawn gamerule
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_15)) {
@@ -184,7 +197,6 @@ public class PacketPlayerRespawn extends PacketListenerAbstract {
player.compensatedWorld.setDimension(respawn.getDimensionType(), event.getUser());
}
// TODO And there should probably be some attribute holder that we can just call reset() on.
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_16) && !this.hasFlag(respawn, KEEP_ATTRIBUTES)) {
// Reset attributes if not kept
player.compensatedEntities.getSelf().resetAttributes();
@@ -3,6 +3,7 @@ package ac.grim.grimac.events.packets;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.KnownInput;
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
import ac.grim.grimac.utils.data.packetentity.PacketEntityHorse;
import com.github.retrooper.packetevents.PacketEvents;
@@ -10,9 +11,9 @@ import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerInput;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientSteerVehicle;
public class PacketPlayerSteer extends PacketListenerAbstract {
@@ -23,13 +24,12 @@ public class PacketPlayerSteer extends PacketListenerAbstract {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE) {
WrapperPlayClientSteerVehicle steer = new WrapperPlayClientSteerVehicle(event);
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
WrapperPlayClientSteerVehicle steer = new WrapperPlayClientSteerVehicle(event);
float forwards = steer.getForward();
float sideways = steer.getSideways();
@@ -100,6 +100,33 @@ public class PacketPlayerSteer extends PacketListenerAbstract {
}
player.packetStateData.receivedSteerVehicle = true;
} else if (event.getPacketType() == PacketType.Play.Client.PLAYER_INPUT) {
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
WrapperPlayClientPlayerInput input = new WrapperPlayClientPlayerInput(event);
byte forward = 0;
byte sideways = 0;
if (input.isForward()) {
forward++;
}
if (input.isBackward()) {
forward--;
}
if (input.isLeft()) {
sideways++;
}
if (input.isRight()) {
sideways--;
}
player.vehicleData.nextVehicleForward = forward * 0.98f;
player.vehicleData.nextVehicleHorizontal = sideways * 0.98f;
player.packetStateData.knownInput = new KnownInput(input.isForward(), input.isBackward(), input.isLeft(), input.isRight(), input.isJump(), input.isShift(), input.isSprint());
}
}
}
@@ -1,7 +1,6 @@
package ac.grim.grimac.events.packets;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.checks.impl.movement.NoSlowD;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.nmsutil.WatchableIndexUtil;
import com.github.retrooper.packetevents.PacketEvents;
@@ -24,6 +23,7 @@ import java.util.List;
import java.util.Optional;
public class PacketSelfMetadataListener extends PacketListenerAbstract {
public PacketSelfMetadataListener() {
super(PacketListenerPriority.HIGH);
}
@@ -68,6 +68,7 @@ public class PacketSelfMetadataListener extends PacketListenerAbstract {
// Remove the pose metadata from the list
metadataStuff.removeIf(element -> element.getIndex() == 6);
entityMetadata.setEntityMetadata(metadataStuff);
event.markForReEncode(true);
}
EntityData watchable = WatchableIndexUtil.getIndex(entityMetadata.getEntityMetadata(), 0);
@@ -207,8 +208,6 @@ public class PacketSelfMetadataListener extends PacketListenerAbstract {
// The above line is a hack to fake activate use item
player.packetStateData.setSlowedByUsingItem(isActive);
player.checkManager.getPostPredictionCheck(NoSlowD.class).startedSprintingBeforeUse = player.packetStateData.isSlowedByUsingItem() && player.isSprinting;
if (isActive) {
player.packetStateData.eatingHand = isOffhand ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND;
}
@@ -6,14 +6,12 @@ import ac.grim.grimac.utils.data.Pair;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
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.teleport.RelativeFlag;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientTeleportConfirm;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerPositionAndLook;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerVehicleMove;
import org.bukkit.Location;
@@ -99,4 +99,4 @@ public class ProxyAlertMessenger extends PacketListenerAbstract {
if (!file.exists()) return false;
return YamlConfiguration.loadConfiguration(file).getBoolean(pathToValue);
}
}
}
@@ -9,9 +9,13 @@ import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.netty.channel.ChannelHelper;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerAcknowledgeBlockChanges;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerBlockChange;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerMultiBlockChange;
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
@@ -35,18 +39,20 @@ public class ResyncWorldUtil {
|| !player.compensatedWorld.isChunkLoaded(maxBlockX >> 4, minBlockZ >> 4) || !player.compensatedWorld.isChunkLoaded(maxBlockX >> 4, maxBlockZ >> 4))
return;
if (player.bukkitPlayer == null) return;
World world = player.bukkitPlayer.getWorld();
// Takes 0.15ms or so to complete. Not bad IMO. Unsure how I could improve this other than sending packets async.
// But that's on PacketEvents.
FoliaScheduler.getEntityScheduler().execute(player.bukkitPlayer, GrimAPI.INSTANCE.getPlugin(), () -> {
FoliaScheduler.getRegionScheduler().execute(GrimAPI.INSTANCE.getPlugin(), world,
minBlockX >> 4, minBlockZ >> 4, () -> {
boolean flat = PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13);
if (player.bukkitPlayer == null) return;
// Player hasn't spawned, don't spam packets
if (!player.getSetbackTeleportUtil().hasAcceptedSpawnTeleport) return;
// Check the 4 corners of the BB for loaded chunks, don't freeze main thread to load chunks.
if (!player.bukkitPlayer.getWorld().isChunkLoaded(minBlockX >> 4, minBlockZ >> 4) || !player.bukkitPlayer.getWorld().isChunkLoaded(minBlockX >> 4, maxBlockZ >> 4)
|| !player.bukkitPlayer.getWorld().isChunkLoaded(maxBlockX >> 4, minBlockZ >> 4) || !player.bukkitPlayer.getWorld().isChunkLoaded(maxBlockX >> 4, maxBlockZ >> 4))
if (!world.isChunkLoaded(minBlockX >> 4, minBlockZ >> 4) || !world.isChunkLoaded(minBlockX >> 4, maxBlockZ >> 4)
|| !world.isChunkLoaded(maxBlockX >> 4, minBlockZ >> 4) || !world.isChunkLoaded(maxBlockX >> 4, maxBlockZ >> 4))
return;
// This is based on Tuinity's code, thanks leaf. Now merged into paper.
@@ -75,7 +81,7 @@ public class ResyncWorldUtil {
int minX = currChunkX == minChunkX ? minBlockX & 15 : 0; // coordinate in chunk
int maxX = currChunkX == maxChunkX ? maxBlockX & 15 : 15; // coordinate in chunk
Chunk chunk = player.bukkitPlayer.getWorld().getChunkAt(currChunkX, currChunkZ);
Chunk chunk = world.getChunkAt(currChunkX, currChunkZ);
for (int currChunkY = minChunkY; currChunkY <= maxChunkY; ++currChunkY) {
int minY = currChunkY == minChunkY ? minBlockY & 15 : 0; // coordinate in chunk
@@ -111,6 +117,37 @@ public class ResyncWorldUtil {
}
}
}
}, null, 0);
});
}
public static void resyncPosition(GrimPlayer player, Vector3i pos, int sequence) {
if (player.bukkitPlayer == null) return;
final int chunkX = pos.x >> 4;
final int chunkZ = pos.z >> 4;
final World world = player.bukkitPlayer.getWorld();
FoliaScheduler.getRegionScheduler().execute(GrimAPI.INSTANCE.getPlugin(), world, chunkX, chunkZ, () -> {
if (!player.bukkitPlayer.isOnline() || !player.getSetbackTeleportUtil().hasAcceptedSpawnTeleport) return;
if (!player.compensatedWorld.isChunkLoaded(chunkX, chunkZ)) return;
if (player.bukkitPlayer.getLocation().distance(new Location(world, pos.x, pos.y, pos.z)) >= 64) return;
if (!world.isChunkLoaded(chunkX, chunkZ)) return; // Don't load chunks sync
final Block block = world.getChunkAt(chunkX, chunkZ).getBlock(pos.x & 15, pos.y, pos.z & 15);
final int blockId;
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13)) {
// Cache this because strings are expensive
blockId = blockDataToId.computeIfAbsent(block.getBlockData(), data -> WrappedBlockState.getByString(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), data.getAsString(false)).getGlobalId());
} else {
blockId = (block.getType().getId() << 4) | block.getData();
}
player.user.sendPacket(new WrapperPlayServerBlockChange(pos, 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(sequence)); // Make 1.19 clients apply the changes
}
});
}
}
@@ -174,4 +174,4 @@ public class BasePacketWorldReader extends PacketListenerAbstract {
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> player.compensatedWorld.updateBlock(blockChange.getX(), blockChange.getY(), blockChange.getZ(), blockChange.getBlockId()));
}
}
}
}
@@ -15,7 +15,7 @@ import java.util.BitSet;
public class PacketWorldReaderEight extends BasePacketWorldReader {
@Override
public void handleMapChunkBulk(final GrimPlayer player, final PacketSendEvent event) {
PacketWrapper wrapper = new PacketWrapper(event);
PacketWrapper<?> wrapper = new PacketWrapper<>(event);
ByteBuf buffer = (ByteBuf) wrapper.getBuffer();
boolean skylight = wrapper.readBoolean();
@@ -47,7 +47,7 @@ public class PacketWorldReaderEight extends BasePacketWorldReader {
@Override
public void handleMapChunk(final GrimPlayer player, final PacketSendEvent event) {
PacketWrapper wrapper = new PacketWrapper(event);
PacketWrapper<?> wrapper = new PacketWrapper<>(event);
final int chunkX = wrapper.readInt();
final int chunkZ = wrapper.readInt();
@@ -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.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import lombok.Getter;
@Getter
@@ -27,7 +26,7 @@ public class ActionManager extends Check implements PacketCheck {
attacking = true;
lastAttack = System.currentTimeMillis();
}
} else if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
} else if (isTickPacketIncludingNonMovement(event.getPacketType())) {
player.totalFlyingPacketsSent++;
attacking = false;
}
@@ -1,22 +1,25 @@
package ac.grim.grimac.manager;
import ac.grim.grimac.api.AbstractCheck;
import ac.grim.grimac.checks.impl.aim.AimDuplicateLook;
import ac.grim.grimac.checks.impl.aim.AimModulo360;
import ac.grim.grimac.checks.impl.aim.processor.AimProcessor;
import ac.grim.grimac.checks.impl.badpackets.*;
import ac.grim.grimac.checks.impl.combat.MultiInteractA;
import ac.grim.grimac.checks.impl.combat.MultiInteractB;
import ac.grim.grimac.checks.impl.combat.Reach;
import ac.grim.grimac.checks.impl.crash.*;
import ac.grim.grimac.checks.impl.exploit.ExploitA;
import ac.grim.grimac.checks.impl.exploit.ExploitB;
import ac.grim.grimac.checks.impl.exploit.ExploitC;
import ac.grim.grimac.checks.impl.groundspoof.NoFallA;
import ac.grim.grimac.checks.impl.misc.ClientBrand;
import ac.grim.grimac.checks.impl.misc.FastBreak;
import ac.grim.grimac.checks.impl.misc.GhostBlockMitigation;
import ac.grim.grimac.checks.impl.misc.TransactionOrder;
import ac.grim.grimac.checks.impl.movement.*;
import ac.grim.grimac.checks.impl.post.PostCheck;
import ac.grim.grimac.checks.impl.multiactions.*;
import ac.grim.grimac.checks.impl.post.Post;
import ac.grim.grimac.checks.impl.prediction.DebugHandler;
import ac.grim.grimac.checks.impl.prediction.NoFallB;
import ac.grim.grimac.checks.impl.prediction.OffsetHandler;
@@ -42,14 +45,22 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.ImmutableClassToInstanceMap;
import org.bukkit.Bukkit;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import java.util.concurrent.atomic.AtomicBoolean;
public class CheckManager {
private static boolean inited;
private static final AtomicBoolean initedAtomic = new AtomicBoolean(false);
ClassToInstanceMap<PacketCheck> packetChecks;
ClassToInstanceMap<PositionCheck> positionCheck;
ClassToInstanceMap<RotationCheck> rotationCheck;
ClassToInstanceMap<VehicleCheck> vehicleCheck;
ClassToInstanceMap<PacketCheck> prePredictionChecks;
ClassToInstanceMap<BlockBreakCheck> blockBreakChecks;
ClassToInstanceMap<BlockPlaceCheck> blockPlaceCheck;
ClassToInstanceMap<PostPredictionCheck> postPredictionCheck;
@@ -89,12 +100,13 @@ public class CheckManager {
.put(BadPacketsS.class, new BadPacketsS(player))
.put(BadPacketsT.class, new BadPacketsT(player))
.put(BadPacketsU.class, new BadPacketsU(player))
.put(BadPacketsV.class, new BadPacketsV(player))
.put(BadPacketsW.class, new BadPacketsW(player))
.put(BadPacketsX.class, new BadPacketsX(player))
.put(BadPacketsY.class, new BadPacketsY(player))
.put(BadPacketsZ.class, new BadPacketsZ(player))
.put(FastBreak.class, new FastBreak(player))
.put(MultiActionsA.class, new MultiActionsA(player))
.put(MultiActionsB.class, new MultiActionsB(player))
.put(MultiActionsC.class, new MultiActionsC(player))
.put(MultiActionsD.class, new MultiActionsD(player))
.put(MultiActionsE.class, new MultiActionsE(player))
.put(TransactionOrder.class, new TransactionOrder(player))
.put(NoSlowB.class, new NoSlowB(player))
.put(SetbackBlocker.class, new SetbackBlocker(player)) // Must be last class otherwise we can't check while blocking packets
@@ -119,7 +131,7 @@ public class CheckManager {
.put(KnockbackHandler.class, new KnockbackHandler(player))
.put(GhostBlockDetector.class, new GhostBlockDetector(player))
.put(Phase.class, new Phase(player))
.put(PostCheck.class, new PostCheck(player))
.put(Post.class, new Post(player))
.put(NoFallB.class, new NoFallB(player))
.put(OffsetHandler.class, new OffsetHandler(player))
.put(SuperDebug.class, new SuperDebug(player))
@@ -129,6 +141,8 @@ public class CheckManager {
.put(NoSlowC.class, new NoSlowC(player))
.put(NoSlowD.class, new NoSlowD(player))
.put(NoSlowE.class, new NoSlowE(player))
.put(MultiInteractA.class, new MultiInteractA(player))
.put(MultiInteractB.class, new MultiInteractB(player))
.put(SetbackTeleportUtil.class, new SetbackTeleportUtil(player)) // Avoid teleporting to new position, update safe pos last
.put(CompensatedFireworks.class, player.compensatedFireworks)
.put(SneakingEstimator.class, new SneakingEstimator(player))
@@ -139,6 +153,8 @@ public class CheckManager {
.put(InvalidPlaceA.class, new InvalidPlaceA(player))
.put(InvalidPlaceB.class, new InvalidPlaceB(player))
.put(AirLiquidPlace.class, new AirLiquidPlace(player))
.put(MultiPlace.class, new MultiPlace(player))
.put(MultiActionsF.class, new MultiActionsF(player))
.put(FarPlace.class, new FarPlace(player))
.put(FabricatedPlace.class, new FabricatedPlace(player))
.put(PositionPlace.class, new PositionPlace(player))
@@ -149,6 +165,7 @@ public class CheckManager {
prePredictionChecks = new ImmutableClassToInstanceMap.Builder<PacketCheck>()
.put(TimerCheck.class, new TimerCheck(player))
.put(TickTimer.class, new TickTimer(player))
.put(CrashA.class, new CrashA(player))
.put(CrashB.class, new CrashB(player))
.put(CrashC.class, new CrashC(player))
@@ -159,9 +176,16 @@ public class CheckManager {
.put(CrashH.class, new CrashH(player))
.put(ExploitA.class, new ExploitA(player))
.put(ExploitB.class, new ExploitB(player))
.put(ExploitC.class, new ExploitC(player))
.put(VehicleTimer.class, new VehicleTimer(player))
.build();
blockBreakChecks = new ImmutableClassToInstanceMap.Builder<BlockBreakCheck>()
.put(BadPacketsX.class, new BadPacketsX(player))
.put(BadPacketsZ.class, new BadPacketsZ(player))
.put(FastBreak.class, new FastBreak(player))
.build();
allChecks = new ImmutableClassToInstanceMap.Builder<AbstractCheck>()
.putAll(packetChecks)
.putAll(positionCheck)
@@ -170,7 +194,10 @@ public class CheckManager {
.putAll(postPredictionCheck)
.putAll(blockPlaceCheck)
.putAll(prePredictionChecks)
.putAll(blockBreakChecks)
.build();
init();
}
@SuppressWarnings("unchecked")
@@ -201,6 +228,12 @@ public class CheckManager {
for (PostPredictionCheck check : postPredictionCheck.values()) {
check.onPacketReceive(packet);
}
for (BlockPlaceCheck check : blockPlaceCheck.values()) {
check.onPacketReceive(packet);
}
for (BlockBreakCheck check : blockBreakChecks.values()) {
check.onPacketReceive(packet);
}
}
public void onPacketSend(final PacketSendEvent packet) {
@@ -213,6 +246,12 @@ public class CheckManager {
for (PostPredictionCheck check : postPredictionCheck.values()) {
check.onPacketSend(packet);
}
for (BlockPlaceCheck check : blockPlaceCheck.values()) {
check.onPacketSend(packet);
}
for (BlockBreakCheck check : blockBreakChecks.values()) {
check.onPacketSend(packet);
}
}
public void onPositionUpdate(final PositionUpdate position) {
@@ -240,6 +279,12 @@ public class CheckManager {
for (PostPredictionCheck check : postPredictionCheck.values()) {
check.onPredictionComplete(complete);
}
for (BlockPlaceCheck check : blockPlaceCheck.values()) {
check.onPredictionComplete(complete);
}
for (BlockBreakCheck check : blockBreakChecks.values()) {
check.onPredictionComplete(complete);
}
}
public void onBlockPlace(final BlockPlace place) {
@@ -254,6 +299,12 @@ public class CheckManager {
}
}
public void onBlockBreak(final BlockBreak blockBreak) {
for (BlockBreakCheck check : blockBreakChecks.values()) {
check.onBlockBreak(blockBreak);
}
}
public ExplosionHandler getExplosionHandler() {
return getPostPredictionCheck(ExplosionHandler.class);
}
@@ -314,4 +365,25 @@ public class CheckManager {
public <T extends PostPredictionCheck> T getPostPredictionCheck(Class<T> check) {
return (T) postPredictionCheck.get(check);
}
private void init() {
// Fast non-thread safe check
if (inited) return;
// Slow thread safe check
if (!initedAtomic.compareAndSet(false, true)) return;
inited = true;
for (AbstractCheck check : allChecks.values()) {
if (check.getCheckName() != null) {
String permissionName = "grim.exempt." + check.getCheckName().toLowerCase();
Permission permission = Bukkit.getPluginManager().getPermission(permissionName);
if (permission == null) {
Bukkit.getPluginManager().addPermission(new Permission(permissionName, PermissionDefault.FALSE));
} else {
permission.setDefault(PermissionDefault.FALSE);
}
}
}
}
}
@@ -19,6 +19,7 @@ public class DiscordManager implements Initable {
private static WebhookClient client;
private int embedColor;
private String staticContent = "";
private String embedTitle = "";
public static final Pattern WEBHOOK_PATTERN = Pattern.compile("(?:https?://)?(?:\\w+\\.)?\\w+\\.\\w+/api(?:/v\\d+)?/webhooks/(\\d+)/([\\w-]+)(?:/(?:\\w+)?)?");
@@ -40,6 +41,8 @@ public class DiscordManager implements Initable {
client = WebhookClient.withId(Long.parseUnsignedLong(matcher.group(1)), matcher.group(2));
client.setTimeout(15000); // Requests expire after 15 seconds
embedTitle = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("embed-title", "**Grim Alert**");
try {
embedColor = Color.decode(GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("embed-color", "#00FFFF")).getRGB();
} catch (NumberFormatException e) {
@@ -67,12 +70,12 @@ public class DiscordManager implements Initable {
return list;
}
public void sendAlert(GrimPlayer player, String verbose, String checkName, String violations) {
public void sendAlert(GrimPlayer player, String verbose, String checkName, int violations) {
if (client != null) {
String content = staticContent + "";
String content = staticContent;
content = content.replace("%check%", checkName);
content = content.replace("%violations%", violations);
content = content.replace("%violations%", Integer.toString(violations));
content = GrimAPI.INSTANCE.getExternalAPI().replaceVariables(player, content, false);
content = content.replace("_", "\\_");
@@ -80,7 +83,7 @@ public class DiscordManager implements Initable {
.setImageUrl("https://i.stack.imgur.com/Fzh0w.png") // Constant width
.setThumbnailUrl("https://crafthead.net/helm/" + player.user.getProfile().getUUID())
.setColor(embedColor)
.setTitle(new WebhookEmbed.EmbedTitle("**Grim Alert**", null))
.setTitle(new WebhookEmbed.EmbedTitle(embedTitle, null))
.setDescription(content)
.setTimestamp(Instant.now())
.setFooter(new WebhookEmbed.EmbedFooter("", "https://grim.ac/images/grim.png"));
Loaded 100 of 237 files, more files were not shown because too many files have changed in this diff. Show more