Compare commits

..
Author SHA1 Message Date
Axionize e4afe412a5 Revert "Remove unncessary NO_COLLISION entry for torchcrop"
This reverts commit e149ca6be8.
2024-11-03 19:30:08 -05:00
Axionize 45f5b5060c Revert "Remove unncessary NO_COLLISION entries"
This reverts commit 1761d853de.
2024-11-03 19:30:08 -05:00
Axionize a6af4cbbd9 Fix scaffolding hitbox for pre-1.14 clients 2024-11-03 07:06:50 -05:00
Axionize e76a59f14a Enable checks against scaffolding 2024-11-03 07:06:50 -05:00
Axionize ea2673541c Fix Weeping Vines and Vine Plant for all versions; Fix Weeping + Twisted for pre 1.16 players 2024-11-03 06:39:15 -05:00
Axionize 0193d342e0 Fix pitcher crop for pre-1.20 players 2024-11-03 06:39:13 -05:00
Axionize 0a1881592a Fix sniffer egg for pre 1.20 players 2024-11-03 06:39:13 -05:00
Axionize fcfb5d0cbb Fix frogspawn for pre-1.19 players 2024-11-03 06:39:12 -05:00
Axionize a8fc80dd50 Fix Sculk Shrieker hit box for all versions and collision box for pre 1.18.2 2024-11-03 06:39:12 -05:00
Axionize 8805899f39 Fix Spore Blossom hitbox on < 1.17 2024-11-03 06:39:12 -05:00
Axionize 5dc6d47dd0 Fix glow lichen and sculk vein boxes 2024-11-03 06:39:12 -05:00
Axionize 4450bd5c5d Fix Cauldron Hit/Collision Box 2024-11-03 03:52:52 -05:00
Axionize 45faec8290 Remove unncessary NO_COLLISION entries 2024-11-03 02:58:45 -05:00
Axionize a19a70813c Fix Pink Petals Boxes 2024-11-03 02:52:03 -05:00
Axionize 34582ffe50 Add new union() function to collision boxes 2024-11-03 02:52:03 -05:00
Axionize 0d4c1ed81e Fix Coral Fan Collision box 2024-11-03 02:52:03 -05:00
Axionize e1d739be1b Remove unncessary NO_COLLISION entry for torchcrop 2024-11-03 01:18:02 -04:00
Axionize 2c72efd3ea Cleanup and documnet why 2nd rayTrace in getNearestReachHitResult is intentionally non-optimal 2024-11-03 00:49:39 -04:00
Axionize 270f160dd2 Remove unsued getFacing() from vector code 2024-11-02 22:37:58 -04:00
Axionize b026f494d8 Fix falses on blocks with 'insides/internal walls' (different Raycast block placement shape then HitBox shape) like Cauldrons, Hoppers, and Composters 2024-11-02 22:37:57 -04:00
Axionize 8a690e2423 Annotate LOSP functions 2024-11-02 22:37:57 -04:00
Axionize 08678e4252 Fix falses on dead corals 2024-11-01 21:25:40 -04:00
Axionize 980226fab9 Update LOSP to work with new grim config 2024-10-10 23:54:19 -04:00
Axionize 0f726a0f34 Merge remote-tracking branch 'origin/2.0' into los-containers 2024-10-10 23:53:39 -04: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
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
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 0697c425ca Document SimpleCollisionBox and HexCollisionBox with Javadoc 2024-10-03 03:40:32 -04:00
Axionize 428f213e15 Migrate reach-related functions to new BlockRayTrace util class 2024-10-03 01:23:39 -04:00
AxionizeandManInMyVan 593d48a6e6 Button Styling Change
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:15 -04:00
AxionizeandManInMyVan 3dcf3c931a Sapling Styling Change
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:15 -04:00
AxionizeandManInMyVan 8cc45ddba3 TALL_FLOWER Styling Change
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:14 -04:00
AxionizeandManInMyVan 6f23122657 Redstone Wire Comment Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:14 -04:00
AxionizeandManInMyVan c0b0759ed0 Inline Hitbox Calculation
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:14 -04:00
AxionizeandManInMyVan 00252f3b97 getPropaguleMinHeight Spacing
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:13 -04:00
AxionizeandManInMyVan 531c49011b Small Flower Line Spacing/Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:13 -04:00
AxionizeandManInMyVan dea22454f7 Coral Fan Line Spacing/Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:13 -04:00
AxionizeandManInMyVan 12bda63785 Banner Line Spacing/Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:12 -04:00
AxionizeandManInMyVan c65e17cf0c Simplify TALL_FLOWERS handling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:12 -04:00
AxionizeandManInMyVan 753ca0e6ad Rails Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:12 -04:00
AxionizeandManInMyVan 8b85e1711d Mark function as Deprecated
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:12 -04:00
Axionize 12b0dfd19d Fix spelling mistake 2024-10-03 00:07:51 -04:00
Axionize 8c05d41423 Replace RuntimeException in HitBox.java with IllegalStateException 2024-10-03 00:07:26 -04:00
Axionize c5ab0f5440 Merge remote-tracking branch 'origin/2.0' into los-containers
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/collisions/CollisionData.java
2024-10-02 21:01:12 -04:00
ManInMyVan d92f5ef375 fix chains for pre-1.16 players 2024-10-02 21:00:18 -04:00
Axionize c313d6203a Compact all NO_COLLISION states together 2024-10-02 20:51:10 -04:00
ManInMyVan 748eb398b8 fix a BadPacketsZ false
also use MessageUtil
2024-09-28 17:59:06 -06:00
Axionize 070f92aea2 Fix 1.11 Ascending rails hitboxes 2024-09-28 01:53:38 -04:00
Axionize 4e3c5894b5 Fix HitBox of ascending powered rail on 1.9 2024-09-28 01:37:43 -04:00
Axionize 8cfb9f0f17 Fix HitBox of ascending powered rails on 1.7.10 2024-09-28 01:14:49 -04:00
Axionize 4e135e3f92 Make result player.getPossibleEyeHeights() of final in checks and remove unused imports 2024-09-28 00:21:33 -04:00
Axionize 938522974b Replace RotationPlace with LOSP in Turkish config 2024-09-26 21:23:08 -04:00
Axionize 6994975387 Merge remote-tracking branch 'origin/2.0' into los-containers
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/scaffolding/RotationPlace.java
2024-09-26 21:20:07 -04:00
Axionize 6d3a172466 Removing unneeded special case handling 2024-09-26 17:12:07 -04:00
Axionize 3aaa185617 Readability/documentation improvements 2024-09-25 00:51:50 -04:00
Axionize 980cd92333 1.8 Players 2024-09-25 00:28:59 -04:00
Axionize 89da2942c7 Handle player joining on new version -> scale changing -> old version 2024-09-25 00:01:52 -04:00
Axionize 8ea905e053 Optimize returned array for crawling 2024-09-25 00:01:09 -04:00
Axionize 885e959cdb fix conditionall check 2024-09-24 23:22:22 -04:00
Axionize 02904a3dce Only rewrite player possibleEyeHeights when player scale changes 2024-09-24 23:03:10 -04:00
Axionize e8d4bb2376 Don't bother updating scale attribute if no change is made 2024-09-23 21:16:24 -04:00
Axionize 7695167578 Fix intializing array 2024-09-23 20:34:50 -04:00
Axionize 94e5f63a65 Simplify logic and handle caching even when scale changes 2024-09-23 20:19:05 -04:00
Axionize 9fa0f773d5 Cache eyeHeights where possible 2024-09-22 17:41:54 -04:00
Axionize 88111e6f7e make getPossibleEyeHeights return most likely heights 2024-09-22 17:17:25 -04:00
Axionize 9a5c16fe6a Merge branch '2.0' into los-containers 2024-09-21 23:04:16 -04:00
Axionize 4efaf8d497 Fix Array matching error and block
The lower level ArraySupport.mismatch() function doesn't work on Java 8 and requires access modification in modern Java. Repalced with Arrays.equals()

The removal of checking if hitdata.getSecond() == expectedBlockFace during iteration (added in Fix 1.8 Brewing Stand bug - 4a9d8627d3) eliminates cases where a block inbetween the target block has a different blockface intercept.

Ideally we should only check the blockface once we've reached the target block as future optimization.
2024-09-21 22:46:48 -04:00
Axionize 07881da451 More minor optimizations 2024-09-21 21:40:40 -04:00
Axionize bd6c2524e7 Optimize iteration order 2024-09-21 20:19:19 -04:00
Axionize b096e02b9b Optimize getPossibleEyeHeights() 2024-09-21 20:18:55 -04:00
Axionize ad6b24345b Minor Dynamic Fence cleanup 2024-09-20 03:43:41 -04:00
Axionize 9694b756b5 Inline lever hitboxes 2024-09-20 03:35:47 -04:00
Axionize 6b5786be9d Fix legacy hitboxes for versions up to 1.12.2 and make fence hitbox generation static 2024-09-20 03:29:00 -04:00
AxionizeandCyramek 1f49ab2551 Update src/main/java/ac/grim/grimac/player/GrimPlayer.java
Co-authored-by: Cyramek <xcyramek@gmail.com>
2024-09-20 03:21:28 -04:00
Axionize b18a5bec8e Fix fences on legacy servers 2024-09-20 03:20:01 -04:00
Axionize d741459e2f Fix levers and buttons for < 1.13 2024-09-17 23:01:42 -04:00
Axionize 7007722aca Fix cactuses for pre-1.13 2024-09-17 22:48:53 -04:00
Axionize 05e7b3c1e5 Exit conditions early and remove unnccessary if statement 2024-09-17 22:27:43 -04:00
Axionize 13554546eb Deobfuscate and document purpose of misunderstood code in traverseBlocks() 2024-09-17 19:38:38 -04:00
Axionize e2f3722b52 Minor cleanup 2024-09-17 19:21:40 -04:00
AxionizeandManInMyVan 1b75734046 Update src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-09-16 21:55:53 -04:00
Axionize 61d9609328 More minor optimizations 2024-09-16 01:55:13 -04:00
Axionize 4cff51c89f More minor optimizations 2024-09-16 01:32:27 -04:00
Axionize ace5178e99 Minor optimizations 2024-09-16 01:10:44 -04:00
Axionize 4a9d8627d3 Fix 1.8 Brewing Stand bug 2024-09-16 00:26:25 -04:00
Axionize fc89b932dd Cleanup exit conditions 2024-09-15 22:38:42 -04:00
Axionize 0852ac8326 Fix ascending rails on 1.8.9 2024-09-15 22:23:15 -04:00
Axionize 87194d7f1b Fix legacy walls 2024-09-15 22:19:07 -04:00
Axionize 31fa689a98 Fix modern walls 2024-09-15 22:12:40 -04:00
Axionize 5d366e742c Fix rails 2024-09-15 18:44:07 -04:00
Axionize 7cc3c8f5ef Fix blockface false flags 2024-09-15 17:58:14 -04:00
Axionize 7215dfcf60 Add scoring system for most likely blockface 2024-09-15 17:49:15 -04:00
Axionize 5c709c1c54 Check 0.03/0.002 and non-expanded hitbox (for blockfaces) 2024-09-15 17:20:55 -04:00
Axionize 1e5ad65c9f Fix null exception 2024-09-15 14:06:48 -04:00
Axionize f6aeffb264 Quick and dirty button patch 2024-09-15 04:33:14 -04:00
Axionize 4593f3077c Quick and dirty lever fix 2024-09-15 04:29:17 -04:00
Axionize b92c8726de End portals 2024-09-15 04:16:11 -04:00
Axionize c560539a16 Brewing stands (excluding 1.8-1.8.9) 2024-09-15 04:02:53 -04:00
Axionize 9cba7a95f7 Fix cactus 2024-09-15 03:54:00 -04:00
Axionize d6d86ef04d Fix rails 2024-09-15 03:38:03 -04:00
Axionize ed643f3481 legacy pane hitbox faces, still falses because different face? 2024-09-15 03:23:04 -04:00
Axionize d8c2f77a0b Pane fix outline 2024-09-15 02:23:41 -04:00
Axionize 6cfda647f7 Fix flower and short grass offsets for older versions 2024-09-15 01:43:07 -04:00
Axionize fc58fcc721 Fix Wall Banners and Banner Simulation falses 2024-09-15 00:31:30 -04:00
Axionize 5f0707956a Also check blockfaces 2024-09-14 21:37:21 -04:00
Axionize 528712e931 Fix Wall Banners and Banner Simulation falses 2024-09-14 21:13:03 -04:00
Axionize 8fe609452b Bypass check when player near moving shulkers, pistons 2024-09-14 18:52:20 -04:00
Axionize 3afd2c4ac9 Skip post on pre 2024-09-14 18:27:51 -04:00
Axionize 5793d7b678 Merge branch '2.0' into los-containers 2024-09-14 05:13:00 -04:00
Axionize 569a8b4c4d 'Fix' 0.03 for 1.8-1.18.1 2024-09-14 05:11:17 -04:00
Axionize 9cab8f7469 Fix flower offset being visual in 1.8 + bamboo sim 2024-09-09 01:42:07 -04:00
Axionize 1ac0b2efbe Fix Bamboo HitBox & Collision Box 2024-09-08 23:19:34 -04:00
Axionize b78a36f1c2 accidentally added bamboo to No Collision 2024-09-08 22:58:35 -04:00
Axionize e23d191cb8 Merge branch '2.0' into los-containers 2024-09-08 22:50:26 -04:00
Axionize 8854b00b46 Support for buttons in 1.7 2024-09-05 21:03:12 -04:00
Axionize 4be835de07 Skip redstone wires 2024-09-05 20:38:05 -04:00
Axionize b8f59fa99c Fix Pointed Dripstone 2024-09-02 14:40:28 -04:00
Axionize 2236efea4f Fix Small Dripleaf 2024-09-02 14:34:17 -04:00
Axionize 344ba4138d Fix Hanging Roots hit/collision box 2024-09-02 14:23:31 -04:00
Axionize ba0fa7a869 Refactor Bamboo to use OffsetCollisionBox; Fix Bamboo Sapling Hit & Collision Box 2024-09-02 14:16:47 -04:00
Axionize 21668a63fd Fix Tall Grass & Large Ferns 2024-09-02 14:10:45 -04:00
Axionize 2f6f9bcbc5 Fix Tall Seagrass hitbox 2024-09-02 03:25:02 -04:00
Axionize 86d19de452 Reorder HitboxData - Groups Before Individual StateTypes so individual statetypes can override group settings (mangrove and saplings) 2024-09-02 03:18:44 -04:00
Axionize d4986449f1 Fix Mangrove Propagule, add HexOffsetCollisionBox 2024-09-02 03:09:38 -04:00
Axionize 3fc366bf1a Fix Tall Flower Hit and Collision boxes 2024-09-02 02:00:32 -04:00
Axionize 9d192b215e Add OffsetCollisionBox; Document all OffSetBlocks and quirks 2024-09-02 01:54:03 -04:00
AxionizeandCyramek b4ea4517e9 Update src/main/java/ac/grim/grimac/utils/collisions/HitboxData.java
Co-authored-by: Cyramek <xcyramek@gmail.com>
2024-09-01 23:25:07 -04:00
AxionizeandManInMyVan 07ad12a16f Update src/main/java/ac/grim/grimac/utils/collisions/HitboxData.java
Whitespace

Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-09-01 22:46:16 -04:00
Axionize f7529a18df Remove Fence Hack; Fix Lever South Wall Hitbox; Initial Work for Flower Hitbox 2024-09-01 22:34:11 -04:00
Axionize c66522cb47 Move Blocks with NoCollision but a Outline/Hitbox into HitboxData 2024-09-01 21:36:34 -04:00
Axionize 94a31f77ff Fix Sweet Berry Collision + HitBox 2024-09-01 19:57:51 -04:00
Axionize c0630f9f6d Crop Collision Box Overhaul
Add Crop Hitboxes
- NetherWart
- Carrot
- Wheat
- Beetroot
- Potatoes
- COCOA

Replace CollisionBoxes with NoCollisionBox
- NetherWart
- Carrot
- Wheat
- Beatroot
- Pumpkin Stem
- Melon Stem

Added new CollisionBox and set to NoCollisionBox for
- Potatoes
2024-08-31 21:05:24 -04:00
Axionize 3a145cb615 Fix banners 2024-08-31 20:03:34 -04:00
Axionize 837516ea86 Fix syntax error 2024-08-31 14:57:07 -04:00
Axionize 66228f59be Add lever hitboxes and fix banner hitboxes 2024-08-31 14:55:33 -04:00
Axionize 800c79a898 Document Hex vs Simple CollisionBox purpose 2024-08-31 14:55:16 -04:00
Axionize 2177b12bcf Print out target block when flagged - help find falses from constant flagging on non-standard blocks 2024-08-30 14:44:22 -04:00
Axionize 050c22ce27 Clean up 2024-08-29 17:02:29 -04:00
Axionize ded614f30f MVP commit 2024-08-29 17:02:28 -04:00
Axionize 88e439ebfd Improve temporary fix - delete unncessary code 2024-08-29 02:55:40 -04:00
AxionizeandManInMyVan a027355c7d Update src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-08-29 02:53:48 -04:00
AxionizeandManInMyVan 8a351ec928 Update src/main/java/ac/grim/grimac/utils/collisions/datatypes/ComplexCollisionBox.java
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-08-29 02:52:53 -04:00
AxionizeandManInMyVan b2fa4974ef Update src/main/java/ac/grim/grimac/utils/collisions/HitboxData.java
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-08-29 02:52:29 -04:00
Axionize 9c2a034b43 Temporary Hacky Fix to demonstrate cause of fence false flag 2024-08-29 02:35:29 -04:00
Axionize 45ba746300 Comment cleanup 2024-08-26 01:22:07 -04:00
Axionize 483f317f83 Remove unneeded entry in punishments.yml 2024-08-26 01:16:26 -04:00
Axionize dee3268bce Make variables private 2024-08-26 01:14:30 -04:00
Axionize 2a88d3eef4 Account for player being inside of target block 2024-08-26 00:39:00 -04:00
Axionize 2898fed15a 1.9+ tick behind and 1.7 ticking behaviour compensation 2024-08-26 00:20:40 -04:00
Axionize d2721077c9 Remove print statements and cleanup comments 2024-08-26 00:13:54 -04:00
Axionize dd7bb81b46 Rework whitelist to use HashSet 2024-08-26 00:13:04 -04:00
Axionize 4515d21023 Seperate LOS-block-place checks from Sam's LOS reach checks 2024-08-26 00:01:14 -04:00
Axionize 3315e3c148 Revert "Merge reach wall hit check"
This reverts commit b5990080
2024-08-25 23:58:36 -04:00
Axionize 2b552680a7 Fix styling 2024-08-25 13:44:26 -04:00
Axionize f78c80f04d Temporarily comment out system.out.println 2024-08-25 03:18:17 -04:00
Axionize bc239a7994 Fix block whitelist 2024-08-25 03:15:00 -04:00
Axionize a508ec2279 0.03/0.0002 changes, cleanup code, add comments 2024-08-24 23:15:46 -04:00
Axionize cccecbacbc Remove RotationPlace, replacec with LineOfSightPlace 2024-08-24 23:09:06 -04:00
Axionize 177a8b0527 Add config options for check and enable it by adding to punishments 2024-08-24 23:08:41 -04:00
Axionize d869ff959f Add config options for check and enable it by adding to punishments 2024-08-24 23:05:04 -04:00
Axionize 772ba562e6 Rename check 2024-08-24 23:04:50 -04:00
Axionize 1786360d7c Clean up Code and add code for blockTypeWhitelist to BlockLOS checks for performance. 2024-08-24 22:24:23 -04:00
Axionize 328596f01f Expand hitbox of target block by 0.03/0.0002 to account for known MC bug 2024-08-24 19:18:43 -04:00
Axionize 6a13c9f822 Expand hitbox of target block by 0.03/0.0002 to account for known MC bug 2024-08-24 19:18:41 -04:00
Axionize 3c78a63719 Workable check 2024-08-24 19:18:41 -04:00
Axionize 8b645b75df Stash commits - loop alternate possible scenarios 2024-08-24 19:18:41 -04:00
Axionize ae3ea30c92 Stash commits - compensated everything 2024-08-24 19:18:40 -04:00
Axionize 01bd2c0c11 Stash commits - compensated world 2024-08-24 19:18:40 -04:00
Axionize e91721299a Container LOS initial commit 2024-08-24 19:18:39 -04:00
Axionize 4e08ec9fca Deobfuscate and document purpose of misunderstood code in traverseBlocks() 2024-08-24 19:18:39 -04:00
Axionize b599008040 Merge reach wall hit check
(cherry picked from commit 335c33b109)
2024-08-24 19:18:39 -04:00
46 changed files with 1628 additions and 454 deletions

No files matched your search

+5 -4
View File
@@ -11,8 +11,8 @@ plugins {
group = "ac.grim.grimac"
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.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17
// Set to false for debug builds
// You cannot live reload classes if the jar relocates dependencies
@@ -44,8 +44,9 @@ dependencies {
implementation("it.unimi.dsi:fastutil:8.5.13")
implementation("github.scarsz:configuralize:1.4.0")
implementation("com.github.grimanticheat:grimapi:1193c4fa41")
// Used for local testing: implementation("ac.grim.grimac:grimapi:1.0")
//implementation("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")
+2 -2
View File
@@ -19,12 +19,12 @@ public enum GrimAPI {
private final TickManager tickManager = new TickManager();
private final GrimExternalAPI externalAPI = new GrimExternalAPI(this);
private InitManager initManager;
private ConfigManager configManager;
private ConfigManagerImpl configManager;
private JavaPlugin plugin;
public void load(final JavaPlugin plugin) {
this.plugin = plugin;
this.configManager = new ConfigManager();
this.configManager = new ConfigManagerImpl();
initManager = new InitManager();
initManager.load();
}
@@ -4,22 +4,29 @@ 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.init.Initable;
import ac.grim.grimac.player.GrimPlayer;
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.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 +48,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 +64,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 +86,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
@@ -105,8 +107,16 @@ public class GrimExternalAPI implements GrimAbstractAPI, Initable {
return GrimAPI.INSTANCE.getAlertManager();
}
@Override
public ConfigManager getConfigManager() {
return configManager;
}
private ConfigManager configManager = null;
@Override
public void start() {
if (configManager == null) configManager = GrimAPI.INSTANCE.getConfigManager();
variableReplacements.put("%player%", GrimUser::getName);
variableReplacements.put("%uuid%", user -> user.getUniqueId().toString());
variableReplacements.put("%ping%", user -> user.getTransactionPing() + "");
@@ -118,4 +128,61 @@ public class GrimExternalAPI implements GrimAbstractAPI, Initable {
variableReplacements.put("%version%", GrimUser::getVersionName);
variableReplacements.put("%prefix%", user -> ChatColor.translateAlternateColorCodes('&', GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("prefix", "&bGrim &8»")));
}
@Override
public void reload(ConfigManager config) {
if (config.isLoadedAsync()) {
FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
o -> successfulReload(config));
} else {
successfulReload(config);
}
}
@Override
public CompletableFuture<Boolean> reloadAsync(ConfigManager config) {
if (config.isLoadedAsync()) {
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();
onReload(config);
FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
o -> Bukkit.getPluginManager().callEvent(new GrimReloadEvent(true)));
return true;
} catch (Exception e) {
e.printStackTrace();
}
FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
o -> Bukkit.getPluginManager().callEvent(new GrimReloadEvent(false)));
return false;
}
@Override
public void onReload(ConfigManager newConfig) {
configManager = newConfig != null ? newConfig : configManager;
//Reload checks for all players
for (GrimPlayer grimPlayer : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
ChannelHelper.runInEventLoop(grimPlayer.user.getChannel(), () -> {
grimPlayer.reload(configManager);
grimPlayer.updatePermissions();
grimPlayer.punishmentManager.reload(configManager);
for (AbstractCheck value : grimPlayer.checkManager.allChecks.values()) {
value.reload(configManager);
}
});
}
//Restart
GrimAPI.INSTANCE.getDiscordManager().start();
GrimAPI.INSTANCE.getSpectateManager().start();
GrimAPI.INSTANCE.getExternalAPI().start();
}
}
+20 -13
View File
@@ -2,11 +2,12 @@ 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 io.github.retrooper.packetevents.util.folia.FoliaScheduler;
import lombok.Getter;
import lombok.Setter;
@@ -14,7 +15,7 @@ import org.bukkit.Bukkit;
// Class from https://github.com/Tecnio/AntiCheatBase/blob/master/src/main/java/me/tecnio/anticheat/check/Check.java
@Getter
public class Check implements AbstractCheck {
public class Check implements AbstractCheck, ConfigReloadObserver {
protected final GrimPlayer player;
public double violations;
@@ -53,8 +54,8 @@ public class Check implements AbstractCheck {
this.experimental = checkData.experimental();
this.description = checkData.description();
}
reload();
//
reload(GrimAPI.INSTANCE.getConfigManager().getConfig());
}
public boolean shouldModifyPackets() {
@@ -107,23 +108,24 @@ 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);
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();
@@ -144,5 +146,10 @@ public class Check implements AbstractCheck {
packetType == PacketType.Play.Client.WINDOW_CONFIRMATION;
}
@Override
public void reload() {
reload(GrimAPI.INSTANCE.getConfigManager().getConfig());
}
}
@@ -4,6 +4,7 @@ import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
@@ -39,10 +40,6 @@ public class BadPacketsZ extends Check implements PacketCheck {
return player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || getBlockDamage(player, pos) < 1;
}
private String formatted(Vector3i vec) {
return vec == null ? "null" : vec.x + ", " + vec.y + ", " + vec.z;
}
public void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging dig) {
if (dig.getAction() == DiggingAction.START_DIGGING) {
final Vector3i pos = dig.getBlockPosition();
@@ -57,7 +54,7 @@ public class BadPacketsZ extends Check implements PacketCheck {
final Vector3i pos = dig.getBlockPosition();
if (shouldExempt(pos)) {
lastCancelledBlock = null;
lastCancelledBlock = pos;
lastLastBlock = null;
lastBlock = null;
return;
@@ -66,7 +63,7 @@ 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();
@@ -87,7 +84,7 @@ public class BadPacketsZ extends Check implements PacketCheck {
// 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();
@@ -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;
@@ -201,8 +202,9 @@ 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[] 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));
@@ -236,9 +238,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);
}
}
@@ -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;
}
@@ -1,5 +1,6 @@
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;
@@ -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;
@@ -51,8 +52,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);
}
}
@@ -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;
@@ -115,9 +116,8 @@ public class TimerCheck extends Check implements PacketCheck {
}
@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));
}
}
@@ -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,5 +1,6 @@
package ac.grim.grimac.checks.impl.scaffolding;
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;
@@ -29,8 +30,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);
}
}
@@ -26,7 +26,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);
@@ -0,0 +1,196 @@
package ac.grim.grimac.checks.impl.scaffolding;
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.collisions.HitboxData;
import ac.grim.grimac.utils.collisions.RaycastData;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.HitData;
import ac.grim.grimac.utils.nmsutil.BlockRayTrace;
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.BlockFace;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import org.bukkit.util.Vector;
import java.util.HashSet;
import java.util.List;
@CheckData(name = "LineOfSightPlace")
public class LineOfSightPlace extends BlockPlaceCheck {
private double flagBuffer = 0; // If the player flags once, force them to play legit, or we will cancel the tick before.
private boolean ignorePost = false;
private boolean useBlockWhitelist;
private HashSet<StateType> blockWhitelist;
public LineOfSightPlace(GrimPlayer player) {
super(player);
}
@Override
public void onBlockPlace(final BlockPlace place) {
if (checkIfShouldSkip(place)) return;
if (flagBuffer > 0 && !didRayTraceHit(place)) {
ignorePost = true;
// If the player hit and has flagged this check recently
if (flagAndAlert("pre-flying: " + player.compensatedWorld.getWrappedBlockStateAt(place.getPlacedAgainstBlockLocation()).getType()) && shouldModifyPackets() && shouldCancel()) {
place.resync(); // Deny the block placement.
}
}
}
// Use post flying because it has the correct rotation, and can't false easily.
@Override
public void onPostFlyingBlockPlace(BlockPlace place) {
if (checkIfShouldSkip(place)) return;
// Don't flag twice
if (ignorePost) {
ignorePost = false;
return;
}
// Ray trace to try and hit the target block.
boolean hit = didRayTraceHit(place);
// This can false with rapidly moving yaw in 1.8+ clients
if (!hit) {
flagBuffer = 1;
flagAndAlert("post-flying: " + player.compensatedWorld.getWrappedBlockStateAt(place.getPlacedAgainstBlockLocation()).getType());
} else {
flagBuffer = Math.max(0, flagBuffer - 0.1);
}
}
private boolean checkIfShouldSkip(BlockPlace place) {
StateType targetBlockStateType = player.compensatedWorld.getWrappedBlockStateAt(place.getPlacedAgainstBlockLocation()).getType();
if (player.gamemode == GameMode.SPECTATOR) return true; // A waste to check creative mode players
if (targetBlockStateType == StateTypes.REDSTONE_WIRE) return true; // Redstone too buggy
if (player.compensatedWorld.isNearHardEntity(player.boundingBox.copy().expand(4))) return true; // Shulkers and Pistons are too buggy
if (useBlockWhitelist) {
return !isBlockTypeWhitelisted(targetBlockStateType);
}
return false;
}
private boolean didRayTraceHit(BlockPlace place) {
double[] possibleEyeHeights = player.getPossibleEyeHeights();
// Start checking if player is in the block
double minEyeHeight = Double.MAX_VALUE;
double maxEyeHeight = Double.MIN_VALUE;
for (double height : possibleEyeHeights) {
minEyeHeight = Math.min(minEyeHeight, height);
maxEyeHeight = Math.max(maxEyeHeight, height);
}
double movementThreshold = player.getMovementThreshold();
SimpleCollisionBox eyePositions = new SimpleCollisionBox(player.x, player.y + minEyeHeight, player.z, player.x, player.y + maxEyeHeight, player.z);
eyePositions.expand(movementThreshold);
int[] interactBlockVec = new int[]{place.blockPosition.x, place.blockPosition.y, place.blockPosition.z};
BlockFace expectedBlockFace = place.getDirection();
// If the player is inside a block, then they can ray trace through the block and hit the other side of the block
// This may potentially be exploitable as a minor bypass
if (eyePositions.isIntersected(new SimpleCollisionBox(interactBlockVec[0], interactBlockVec[1], interactBlockVec[2]))) {
return true;
}
// End checking if the player is in the block
double[][] possibleLookDirs;
// 1.9+ players could be a tick behind because we don't get skipped ticks
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
possibleLookDirs = new double[][]{
{player.xRot, player.yRot},
{player.lastXRot, player.lastYRot},
{player.lastXRot, player.yRot}
};
} else if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
// 1.7 players do not have any of these issues! They are always on the latest look vector
possibleLookDirs = new double[][]{{player.xRot, player.yRot}};
} else {
possibleLookDirs = new double[][]{
{player.xRot, player.yRot},
{player.lastXRot, player.yRot}
};
}
// We do not need to add 0.03/0.0002 to maxDistance to ensure our raytrace hits blocks
// Since we expand the hitboxes of the expectedTargetBlock by 0.03/0.002 already later
double maxDistance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
// Define possible offsets
// TODO, vectorize this with SIMD or AVX for performance
double[][] offsets = {
{0, 0, 0},
{movementThreshold, 0, 0},
{-movementThreshold, 0, 0},
{0, movementThreshold, 0},
{0, -movementThreshold, 0},
{0, 0, movementThreshold},
{0, 0, -movementThreshold}
};
double[] eyePosition = new double[3];
double[] eyeLookDir = new double[3];
for (double eyeHeight : possibleEyeHeights) {
for (double[] lookDir : possibleLookDirs) {
for (double[] offset : offsets) {
eyePosition[0] = player.x + offset[0];
eyePosition[1] = player.y + eyeHeight + offset[1];
eyePosition[2] = player.z + offset[2];
calculateDirection(eyeLookDir, lookDir[0], lookDir[1]);
if (getTargetBlock(eyePosition, eyeLookDir, maxDistance, interactBlockVec, expectedBlockFace)) {
return true; // If any possible face matches the client-side placement, assume it's legitimate
}
}
}
}
return false; // No matching face found
}
// Helper method to calculate direction (replace the Ray class method)
private void calculateDirection(double[] result, double xRot, double yRot) {
float rotX = (float) Math.toRadians(xRot);
float rotY = (float) Math.toRadians(yRot);
result[1] = -player.trigHandler.sin(rotY);
double xz = player.trigHandler.cos(rotY);
result[0] = -xz * player.trigHandler.sin(rotX);
result[2] = xz * player.trigHandler.cos(rotX);
}
private boolean getTargetBlock(double[] eyePos, double[] eyeDir, double maxDistance, int[] targetBlockVec, BlockFace expectedBlockFace) {
HitData hitData = BlockRayTrace.getNearestReachHitResult(player, eyePos, eyeDir, maxDistance, maxDistance, targetBlockVec, false);
// we check for hitdata != null because of being in expanded hitbox, or there was no result, do we still need this?
return hitData != null && new Vector3i(targetBlockVec[0], targetBlockVec[1], targetBlockVec[2]).equals(hitData.getPosition()) && hitData.getClosestDirection() == expectedBlockFace;
}
private boolean isBlockTypeWhitelisted(StateType type) {
return blockWhitelist.contains(type);
}
@Override
public void onReload(ConfigManager config) {
useBlockWhitelist = config.getBooleanElse("LineOfSightPlace.use-block-whitelist", false);
blockWhitelist = new HashSet<>();
List<String> blocks = config.getStringList("LineOfSightPlace.block-whitelist");
for (String block : blocks) {
blockWhitelist.add(StateTypes.getByName(block));
}
}
}
@@ -63,7 +63,7 @@ public class MultiPlace extends BlockPlaceCheck {
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8) && !player.skippedTickInActualMovement) {
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8) && !player.skippedTickInActualMovement && predictionComplete.isChecked()) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
@@ -28,8 +28,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;
@@ -1,116 +0,0 @@
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.update.BlockPlace;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.Pair;
import ac.grim.grimac.utils.nmsutil.Ray;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3f;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@CheckData(name = "RotationPlace")
public class RotationPlace extends BlockPlaceCheck {
double flagBuffer = 0; // If the player flags once, force them to play legit, or we will cancel the tick before.
boolean ignorePost = false;
public RotationPlace(GrimPlayer player) {
super(player);
}
@Override
public void onBlockPlace(final BlockPlace place) {
if (place.getMaterial() == StateTypes.SCAFFOLDING) return;
if (player.gamemode == GameMode.SPECTATOR) return; // you don't send flying packets when spectating entities
if (flagBuffer > 0 && !didRayTraceHit(place)) {
ignorePost = true;
// If the player hit and has flagged this check recently
if (flagAndAlert("pre-flying") && shouldModifyPackets() && shouldCancel()) {
place.resync(); // Deny the block placement.
}
}
}
// Use post flying because it has the correct rotation, and can't false easily.
@Override
public void onPostFlyingBlockPlace(BlockPlace place) {
if (place.getMaterial() == StateTypes.SCAFFOLDING) return;
if (player.gamemode == GameMode.SPECTATOR) return; // you don't send flying packets when spectating entities
// Don't flag twice
if (ignorePost) {
ignorePost = false;
return;
}
// Ray trace to try and hit the target block.
boolean hit = didRayTraceHit(place);
// This can false with rapidly moving yaw in 1.8+ clients
if (!hit) {
flagBuffer = 1;
flagAndAlert("post-flying");
} else {
flagBuffer = Math.max(0, flagBuffer - 0.1);
}
}
private boolean didRayTraceHit(BlockPlace place) {
SimpleCollisionBox box = new SimpleCollisionBox(place.getPlacedAgainstBlockLocation());
List<Vector3f> possibleLookDirs = new ArrayList<>(Arrays.asList(
new Vector3f(player.xRot, player.yRot, 0),
new Vector3f(player.lastXRot, player.yRot, 0)
));
// Start checking if player is in the block
double minEyeHeight = Collections.min(player.getPossibleEyeHeights());
double maxEyeHeight = Collections.max(player.getPossibleEyeHeights());
SimpleCollisionBox eyePositions = new SimpleCollisionBox(player.x, player.y + minEyeHeight, player.z, player.x, player.y + maxEyeHeight, player.z);
eyePositions.expand(player.getMovementThreshold());
// If the player is inside a block, then they can ray trace through the block and hit the other side of the block
if (eyePositions.isIntersected(box)) {
return true;
}
// End checking if the player is in the block
// 1.9+ players could be a tick behind because we don't get skipped ticks
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
possibleLookDirs.add(new Vector3f(player.lastXRot, player.lastYRot, 0));
}
// 1.7 players do not have any of these issues! They are always on the latest look vector
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
possibleLookDirs = Collections.singletonList(new Vector3f(player.xRot, player.yRot, 0));
}
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
for (double d : player.getPossibleEyeHeights()) {
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);
// xRot and yRot are a tick behind
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;
}
}
return false;
}
}
@@ -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;
@@ -18,7 +19,6 @@ import com.github.retrooper.packetevents.util.Vector3f;
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;
@@ -256,12 +256,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;
@@ -240,15 +241,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;
}
}
@@ -1,5 +1,6 @@
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;
@@ -33,9 +34,8 @@ public class BlockPlaceCheck extends Check implements RotationCheck, PostPredict
}
@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() {
@@ -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."));
}
});
}
}
@@ -8,13 +8,9 @@ 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.collisions.HitboxData;
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.*;
import ac.grim.grimac.utils.inventory.Inventory;
import ac.grim.grimac.utils.latency.CompensatedWorld;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.math.VectorUtils;
import ac.grim.grimac.utils.nmsutil.*;
import com.github.retrooper.packetevents.PacketEvents;
@@ -24,7 +20,6 @@ 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.ConnectionState;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
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;
@@ -36,6 +31,7 @@ import com.github.retrooper.packetevents.protocol.player.InteractionHand;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.Location;
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;
@@ -47,11 +43,6 @@ import com.github.retrooper.packetevents.wrapper.play.client.*;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerAcknowledgeBlockChanges;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetSlot;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
public class CheckManagerListener extends PacketListenerAbstract {
@@ -59,79 +50,8 @@ public class CheckManagerListener extends PacketListenerAbstract {
super(PacketListenerPriority.LOW);
}
// Copied from MCP...
// Returns null if there isn't anything.
//
// I do have to admit that I'm starting to like bifunctions/new java 8 things more than I originally did.
// although I still don't understand Mojang's obsession with streams in some of the hottest methods... that kills performance
public static HitData traverseBlocks(GrimPlayer player, Vector3d start, Vector3d end, BiFunction<WrappedBlockState, Vector3i, HitData> predicate) {
// I guess go back by the collision epsilon?
double endX = GrimMath.lerp(-1.0E-7D, end.x, start.x);
double endY = GrimMath.lerp(-1.0E-7D, end.y, start.y);
double endZ = GrimMath.lerp(-1.0E-7D, end.z, start.z);
double startX = GrimMath.lerp(-1.0E-7D, start.x, end.x);
double startY = GrimMath.lerp(-1.0E-7D, start.y, end.y);
double startZ = GrimMath.lerp(-1.0E-7D, start.z, end.z);
int floorStartX = GrimMath.floor(startX);
int floorStartY = GrimMath.floor(startY);
int floorStartZ = GrimMath.floor(startZ);
if (start.equals(end)) return null;
WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(floorStartX, floorStartY, floorStartZ);
HitData apply = predicate.apply(state, new Vector3i(floorStartX, floorStartY, floorStartZ));
if (apply != null) {
return apply;
}
double xDiff = endX - startX;
double yDiff = endY - startY;
double zDiff = endZ - startZ;
double xSign = Math.signum(xDiff);
double ySign = Math.signum(yDiff);
double zSign = Math.signum(zDiff);
double posXInverse = xSign == 0 ? Double.MAX_VALUE : xSign / xDiff;
double posYInverse = ySign == 0 ? Double.MAX_VALUE : ySign / yDiff;
double posZInverse = zSign == 0 ? Double.MAX_VALUE : zSign / zDiff;
double d12 = posXInverse * (xSign > 0 ? 1.0D - GrimMath.frac(startX) : GrimMath.frac(startX));
double d13 = posYInverse * (ySign > 0 ? 1.0D - GrimMath.frac(startY) : GrimMath.frac(startY));
double d14 = posZInverse * (zSign > 0 ? 1.0D - GrimMath.frac(startZ) : GrimMath.frac(startZ));
// Can't figure out what this code does currently
while (d12 <= 1.0D || d13 <= 1.0D || d14 <= 1.0D) {
if (d12 < d13) {
if (d12 < d14) {
floorStartX += xSign;
d12 += posXInverse;
} else {
floorStartZ += zSign;
d14 += posZInverse;
}
} else if (d13 < d14) {
floorStartY += ySign;
d13 += posYInverse;
} else {
floorStartZ += zSign;
d14 += posZInverse;
}
state = player.compensatedWorld.getWrappedBlockStateAt(floorStartX, floorStartY, floorStartZ);
apply = predicate.apply(state, new Vector3i(floorStartX, floorStartY, floorStartZ));
if (apply != null) {
return apply;
}
}
return null;
}
private static void placeWaterLavaSnowBucket(GrimPlayer player, ItemStack held, StateType toPlace, InteractionHand hand) {
HitData data = getNearestHitResult(player, StateTypes.AIR, false);
HitData data = BlockRayTrace.getNearestHitResult(player, StateTypes.AIR, false);
if (data != null) {
BlockPlace blockPlace = new BlockPlace(player, hand, data.getPosition(), data.getClosestDirection().getFaceValue(), data.getClosestDirection(), held, data);
@@ -268,7 +188,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
// The offhand is unable to interact with blocks like this... try to stop some desync points before they happen
if ((!player.isSneaking || onlyAir) && place.getHand() == InteractionHand.MAIN_HAND) {
Vector3i blockPosition = place.getBlockPosition();
BlockPlace blockPlace = new BlockPlace(player, place.getHand(), blockPosition, place.getFaceId(), place.getFace(), placedWith, getNearestHitResult(player, null, true));
BlockPlace blockPlace = new BlockPlace(player, place.getHand(), blockPosition, place.getFaceId(), place.getFace(), placedWith, BlockRayTrace.getNearestHitResult(player, null, true));
// Right-clicking a trapdoor/door/etc.
StateType placedAgainst = blockPlace.getPlacedAgainstMaterial();
@@ -308,7 +228,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
placedWith = player.getInventory().getOffHand();
}
BlockPlace blockPlace = new BlockPlace(player, place.getHand(), blockPosition, place.getFaceId(), face, placedWith, getNearestHitResult(player, null, true));
BlockPlace blockPlace = new BlockPlace(player, place.getHand(), blockPosition, place.getFaceId(), face, placedWith, BlockRayTrace.getNearestHitResult(player, null, true));
// At this point, it is too late to cancel, so we can only flag, and cancel subsequent block places more aggressively
if (!player.compensatedEntities.getSelf().inVehicle()) {
player.checkManager.onPostFlyingBlockPlace(blockPlace);
@@ -508,7 +428,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
player.placeUseItemPackets.add(new BlockPlaceSnapshot(packet, player.isSneaking));
} else {
// Anti-air place
BlockPlace blockPlace = new BlockPlace(player, packet.getHand(), packet.getBlockPosition(), packet.getFaceId(), packet.getFace(), placedWith, getNearestHitResult(player, null, true));
BlockPlace blockPlace = new BlockPlace(player, packet.getHand(), packet.getBlockPosition(), packet.getFaceId(), packet.getFace(), placedWith, BlockRayTrace.getNearestHitResult(player, null, true));
blockPlace.setCursor(packet.getCursorPosition());
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_11) && player.getClientVersion().isOlderThan(ClientVersion.V_1_11)) {
@@ -582,7 +502,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
private static void placeBucket(GrimPlayer player, InteractionHand hand) {
HitData data = getNearestHitResult(player, null, true);
HitData data = BlockRayTrace.getNearestHitResult(player, null, true);
if (data != null) {
BlockPlace blockPlace = new BlockPlace(player, hand, data.getPosition(), data.getClosestDirection().getFaceValue(), data.getClosestDirection(), ItemStack.EMPTY, data);
@@ -748,7 +668,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
private static void placeLilypad(GrimPlayer player, InteractionHand hand) {
HitData data = getNearestHitResult(player, null, true);
HitData data = BlockRayTrace.getNearestHitResult(player, null, true);
if (data != null) {
// A lilypad cannot replace a fluid
@@ -778,56 +698,6 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
}
private static HitData getNearestHitResult(GrimPlayer player, StateType heldItem, boolean sourcesHaveHitbox) {
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);
Vector endVec = trace.getPointAtDistance(distance);
Vector3d endPos = new Vector3d(endVec.getX(), endVec.getY(), endVec.getZ());
return traverseBlocks(player, startingPos, endPos, (block, vector3i) -> {
CollisionBox data = HitboxData.getBlockHitbox(player, heldItem, player.getClientVersion(), block, vector3i.getX(), vector3i.getY(), vector3i.getZ());
List<SimpleCollisionBox> boxes = new ArrayList<>();
data.downCast(boxes);
double bestHitResult = Double.MAX_VALUE;
Vector bestHitLoc = null;
BlockFace bestFace = null;
for (SimpleCollisionBox box : boxes) {
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.getFirst() == null) continue; // No intercept
Vector hitLoc = intercept.getFirst();
if (hitLoc.distanceSquared(startingVec) < bestHitResult) {
bestHitResult = hitLoc.distanceSquared(startingVec);
bestHitLoc = hitLoc;
bestFace = intercept.getSecond();
}
}
if (bestHitLoc != null) {
return new HitData(vector3i, bestHitLoc, bestFace, block);
}
if (sourcesHaveHitbox &&
(player.compensatedWorld.isWaterSourceBlock(vector3i.getX(), vector3i.getY(), vector3i.getZ())
|| player.compensatedWorld.getLavaFluidLevelAt(vector3i.getX(), vector3i.getY(), vector3i.getZ()) == (8 / 9f))) {
double waterHeight = player.compensatedWorld.getFluidLevelAt(vector3i.getX(), vector3i.getY(), vector3i.getZ());
SimpleCollisionBox box = new SimpleCollisionBox(vector3i.getX(), vector3i.getY(), vector3i.getZ(), vector3i.getX() + 1, vector3i.getY() + waterHeight, vector3i.getZ() + 1);
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);
}
}
return null;
});
}
@Override
public void onPacketSend(PacketSendEvent event) {
if (event.getConnectionState() != ConnectionState.PLAY) return;
@@ -836,4 +706,8 @@ public class CheckManagerListener extends PacketListenerAbstract {
player.checkManager.onPacketSend(event);
}
private static boolean isFence(StateType state) {
return BlockTags.FENCES.contains(state);
}
}
@@ -143,8 +143,8 @@ public class CheckManager {
.put(FarPlace.class, new FarPlace(player))
.put(FabricatedPlace.class, new FabricatedPlace(player))
.put(PositionPlace.class, new PositionPlace(player))
.put(RotationPlace.class, new RotationPlace(player))
.put(DuplicateRotPlace.class, new DuplicateRotPlace(player))
.put(LineOfSightPlace.class, new LineOfSightPlace(player))
.put(GhostBlockMitigation.class, new GhostBlockMitigation(player))
.build();
@@ -2,8 +2,9 @@ package ac.grim.grimac.manager;
import ac.grim.grimac.GrimAC;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.common.BasicReloadable;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.math.GrimMath;
import github.scarsz.configuralize.DynamicConfig;
import github.scarsz.configuralize.Language;
import lombok.Getter;
@@ -16,8 +17,13 @@ import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class ConfigManager {
@Getter
public class ConfigManagerImpl implements ConfigManager, BasicReloadable {
public ConfigManager getConfig() {
if (GrimAPI.INSTANCE.getInitManager().isStarted()) return GrimAPI.INSTANCE.getExternalAPI().getConfigManager();
return this;
}
private final DynamicConfig config;
@Getter
private final File configFile = new File(GrimAPI.INSTANCE.getPlugin().getDataFolder(), "config.yml");
@@ -28,8 +34,6 @@ public class ConfigManager {
@Getter
private final File punishFile = new File(GrimAPI.INSTANCE.getPlugin().getDataFolder(), "punishments.yml");
@Getter
private int maxPingTransaction = 60; // This is just a really hot variable so cache it.
@Getter
private boolean ignoreDuplicatePacketRotation = false;
@Getter
@@ -37,9 +41,8 @@ public class ConfigManager {
private final List<Pattern> ignoredClientPatterns = new ArrayList<>();
public ConfigManager() {
public ConfigManagerImpl() {
upgrade();
// load config
GrimAPI.INSTANCE.getPlugin().getDataFolder().mkdirs();
config = new DynamicConfig();
@@ -51,6 +54,7 @@ public class ConfigManager {
reload();
}
@Override
public void reload() {
String languageCode = System.getProperty("user.language").toUpperCase();
@@ -79,12 +83,9 @@ public class ConfigManager {
throw new RuntimeException("Failed to load config", e);
}
final int configuredMaxTransactionTime = config.getIntElse("max-transaction-time", 60);
maxPingTransaction = (int) GrimMath.clamp(configuredMaxTransactionTime, 1, 180);
if (maxPingTransaction != configuredMaxTransactionTime) {
LogUtil.warn("Detected invalid max-transaction-time! This setting is clamped between 1 and 180 to prevent issues. " +
"Changed: " + configuredMaxTransactionTime + " -> " + maxPingTransaction);
LogUtil.warn("Attempting to disable or set this too high can result in memory usage issues.");
int configuredMaxTransactionTime = config.getIntElse("max-transaction-time", 60);
if (configuredMaxTransactionTime > 180 || configuredMaxTransactionTime < 1) {
LogUtil.warn("Detected invalid max-transaction-time! This setting is clamped between 1 and 180 to prevent issues. Attempting to disable or set this too high can result in memory usage issues.");
}
ignoredClientPatterns.clear();
@@ -326,4 +327,45 @@ public class ConfigManager {
);
Files.write(config.toPath(), configString.getBytes());
}
@Override
public String getStringElse(String key, String otherwise) {
return config.getStringElse(key, otherwise);
}
@Override
public List<String> getStringList(String key) {
return config.getStringList(key);
}
@Override
public List<String> getStringListElse(String key, List<String> otherwise) {
return config.getStringListElse(key, otherwise);
}
@Override
public int getIntElse(String key, int other) {
return config.getIntElse(key, other);
}
@Override
public long getLongElse(String key, long otherwise) {
return config.getLongElse(key, otherwise);
}
@Override
public double getDoubleElse(String key, double otherwise) {
return config.getDoubleElse(key, otherwise);
}
@Override
public boolean getBooleanElse(String key, boolean otherwise) {
return config.getBooleanElse(key, otherwise);
}
@Override
public <T> T get(String key) {
return config.get(key);
}
}
@@ -8,11 +8,16 @@ import ac.grim.grimac.manager.init.start.*;
import ac.grim.grimac.manager.init.stop.TerminatePacketEvents;
import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.ImmutableClassToInstanceMap;
import lombok.Getter;
public class InitManager {
ClassToInstanceMap<Initable> initializersOnLoad;
ClassToInstanceMap<Initable> initializersOnStart;
ClassToInstanceMap<Initable> initializersOnStop;
private final ClassToInstanceMap<Initable> initializersOnLoad;
private final ClassToInstanceMap<Initable> initializersOnStart;
private final ClassToInstanceMap<Initable> initializersOnStop;
@Getter private boolean loaded = false;
@Getter private boolean started = false;
@Getter private boolean stopped = false;
public InitManager() {
initializersOnLoad = new ImmutableClassToInstanceMap.Builder<Initable>()
@@ -20,6 +25,7 @@ public class InitManager {
.build();
initializersOnStart = new ImmutableClassToInstanceMap.Builder<Initable>()
.put(GrimExternalAPI.class, GrimAPI.INSTANCE.getExternalAPI())
.put(ExemptOnlinePlayers.class, new ExemptOnlinePlayers())
.put(EventManager.class, new EventManager())
.put(PacketManager.class, new PacketManager())
@@ -31,7 +37,6 @@ public class InitManager {
.put(PacketLimiter.class, new PacketLimiter())
.put(DiscordManager.class, GrimAPI.INSTANCE.getDiscordManager())
.put(SpectateManager.class, GrimAPI.INSTANCE.getSpectateManager())
.put(GrimExternalAPI.class, GrimAPI.INSTANCE.getExternalAPI())
.put(JavaVersion.class, new JavaVersion())
.build();
@@ -44,17 +49,20 @@ public class InitManager {
for (Initable initable : initializersOnLoad.values()) {
initable.start();
}
loaded = true;
}
public void start() {
for (Initable initable : initializersOnStart.values()) {
initable.start();
}
started = true;
}
public void stop() {
for (Initable initable : initializersOnStop.values()) {
initable.start();
}
stopped = true;
}
}
@@ -2,13 +2,14 @@ package ac.grim.grimac.manager;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.AbstractCheck;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.api.config.ConfigReloadable;
import ac.grim.grimac.api.events.CommandExecuteEvent;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.events.packets.ProxyAlertMessenger;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import github.scarsz.configuralize.DynamicConfig;
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
import lombok.Getter;
import lombok.Setter;
@@ -17,18 +18,18 @@ import org.bukkit.entity.Player;
import java.util.*;
public class PunishmentManager {
public class PunishmentManager implements ConfigReloadable {
GrimPlayer player;
List<PunishGroup> groups = new ArrayList<>();
String experimentalSymbol = "*";
public PunishmentManager(GrimPlayer player) {
this.player = player;
reload();
reload(GrimAPI.INSTANCE.getConfigManager().getConfig());
}
public void reload() {
DynamicConfig config = GrimAPI.INSTANCE.getConfigManager().getConfig();
@Override
public void reload(ConfigManager config) {
List<String> punish = config.getStringListElse("Punishments", new ArrayList<>());
experimentalSymbol = config.getStringElse("experimental-symbol", "*");
@@ -3,6 +3,7 @@ package ac.grim.grimac.player;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.AbstractCheck;
import ac.grim.grimac.api.GrimUser;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.impl.aim.processor.AimProcessor;
import ac.grim.grimac.checks.impl.misc.ClientBrand;
@@ -52,6 +53,7 @@ import net.kyori.adventure.text.TranslatableComponent;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.Nullable;
@@ -199,6 +201,8 @@ public class GrimPlayer implements GrimUser {
public long lastBlockPlaceUseItem = 0;
public AtomicInteger cancelledPackets = new AtomicInteger(0);
public MainSupportingBlockData mainSupportingBlockData = new MainSupportingBlockData(null, false);
// possibleEyeHeights[0] = Standing eye heights, [1] = Sneaking. [2] = Elytra, Swimming, and Riptide Trident which only exists in 1.9+
public double[][] possibleEyeHeights = new double[3][];
public void onPacketCancel() {
if (spamThreshold != -1 && cancelledPackets.incrementAndGet() > spamThreshold) {
@@ -217,7 +221,7 @@ public class GrimPlayer implements GrimUser {
public GrimPlayer(User user) {
this.user = user;
this.playerUUID = user.getUUID();
onReload();
reload(GrimAPI.INSTANCE.getConfigManager().getConfig());
boundingBox = GetBoundingBox.getBoundingBoxFromPosAndSizeRaw(x, y, z, 0.6f, 1.8f);
@@ -240,6 +244,21 @@ public class GrimPlayer implements GrimUser {
packetStateData = new PacketStateData();
uncertaintyHandler.collidingEntities.add(0);
if (getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14)) {
final float scale = (float) compensatedEntities.getSelf().getAttributeValue(Attributes.GENERIC_SCALE);
possibleEyeHeights[2] = new double[]{0.4 * scale, 1.62 * scale, 1.27 * scale}; // Elytra, standing, sneaking (1.14)
possibleEyeHeights[1] = new double[]{1.27 * scale, 1.62 * scale, 0.4 * scale}; // sneaking (1.14), standing, Elytra
possibleEyeHeights[0] = new double[]{1.62 * scale, 1.27 * scale, 0.4 * scale}; // standing, sneaking (1.14), Elytra
} else if (getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) { // standing, sneaking Elytra
possibleEyeHeights[2] = new double[]{0.4, 1.62, 1.54}; // Elytra, standing, sneaking (1.13)
possibleEyeHeights[1] = new double[]{1.54, 1.62, 0.4}; // sneaking (1.9-1.13), standing, Elytra
possibleEyeHeights[0] = new double[]{1.62, 1.54, 0.4}; // standing, sneaking (1.9-1.13), Elytra
} else {
possibleEyeHeights[1] = new double[]{(double) (1.62f - 0.08f), (double) (1.62f)}; // sneaking, standing
possibleEyeHeights[0] = new double[]{(double) (1.62f), (double) (1.62f - 0.08f)}; // standing, sneaking
}
}
public Set<VectorData> getPossibleVelocities() {
@@ -316,7 +335,8 @@ public class GrimPlayer implements GrimUser {
// Transactions that we send don't count towards total limit
if (packetTracker != null) packetTracker.setIntervalPackets(packetTracker.getIntervalPackets() - 1);
if (skipped > 0 && System.currentTimeMillis() - joinTime > 5000) checkManager.getPacketCheck(TransactionOrder.class).flagAndAlert("skipped: " + skipped);
if (skipped > 0 && System.currentTimeMillis() - joinTime > 5000)
checkManager.getPacketCheck(TransactionOrder.class).flagAndAlert("skipped: " + skipped);
do {
data = transactionsSent.poll();
@@ -450,7 +470,7 @@ public class GrimPlayer implements GrimUser {
if (lastTransSent != 0 && lastTransSent + 80 < System.currentTimeMillis()) {
sendTransaction(true); // send on netty thread
}
if ((System.nanoTime() - getPlayerClockAtLeast()) > GrimAPI.INSTANCE.getConfigManager().getMaxPingTransaction() * 1e9) {
if ((System.nanoTime() - getPlayerClockAtLeast()) > maxTransactionTime * 1e9) {
timedOut();
}
@@ -515,10 +535,6 @@ public class GrimPlayer implements GrimUser {
private int spamThreshold = 100;
public void onReload() {
spamThreshold = GrimAPI.INSTANCE.getConfigManager().getConfig().getIntElse("packet-spam-threshold", 100);
}
public boolean isPointThree() {
return getClientVersion().isOlderThan(ClientVersion.V_1_18_2);
}
@@ -548,7 +564,7 @@ public class GrimPlayer implements GrimUser {
// - 3 ticks is a magic value, but it should buffer out incorrect predictions somewhat.
// 2. The player is in a vehicle
public boolean isTickingReliablyFor(int ticks) {
return (getClientVersion().isOlderThan(ClientVersion.V_1_9)
return (getClientVersion().isOlderThan(ClientVersion.V_1_9)
|| !uncertaintyHandler.lastPointThree.hasOccurredSince(ticks))
|| compensatedEntities.getSelf().inVehicle();
}
@@ -561,14 +577,23 @@ public class GrimPlayer implements GrimUser {
return checkManager.getInventory();
}
public List<Double> getPossibleEyeHeights() { // We don't return sleeping eye height
if (getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14)) { // Elytra, sneaking (1.14), standing
final float scale = (float) compensatedEntities.getSelf().getAttributeValue(Attributes.GENERIC_SCALE);
return Arrays.asList(0.4 * scale, 1.27 * scale, 1.62 * scale);
} else if (getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) { // Elytra, sneaking, standing
return Arrays.asList(0.4, 1.54, 1.62);
} else { // Only sneaking or standing
return Arrays.asList((double) (1.62f - 0.08f), (double) (1.62f));
public double[] getPossibleEyeHeights() { // We don't return sleeping eye height
// 1.8 Players once again ruin my clean switch-case
if (this.getClientVersion().isOlderThan(ClientVersion.V_1_9)) {
return this.isSneaking ? this.possibleEyeHeights[1] : this.possibleEyeHeights[0];
} else {
// 1.8 players just have their pose set to standing all the time
switch (pose) {
case FALL_FLYING: // Elytra gliding
case SPIN_ATTACK: // Riptide trident
case SWIMMING: // Swimming (includes crawling in 1.14+)
return this.possibleEyeHeights[2]; // [swimming/gliding/riptide height, standing height, sneaking height]
case NINE_CROUCHING:
case CROUCHING:
return this.possibleEyeHeights[1]; // [sneaking height, standing height, swimming/gliding/riptide height]
default:
return this.possibleEyeHeights[0]; // [standing height, sneaking height, swimming/gliding/riptide height]
}
}
}
@@ -716,10 +741,21 @@ public class GrimPlayer implements GrimUser {
return checkManager.allChecks.values();
}
public void runNettyTaskInMs(Runnable runnable, int ms) {
Channel channel = (Channel) user.getChannel();
channel.eventLoop().schedule(runnable, ms, TimeUnit.MILLISECONDS);
}
private int maxTransactionTime = 60;
@Override
public void reload(ConfigManager config) {
spamThreshold = config.getIntElse("packet-spam-threshold", 100);
maxTransactionTime = (int) GrimMath.clamp(config.getIntElse("max-transaction-time", 60), 1, 180);
}
@Override
public void reload() {
reload(GrimAPI.INSTANCE.getConfigManager().getConfig());
}
}
@@ -46,7 +46,7 @@ public class BlockPlace {
private static final BlockFace[] BY_2D = new BlockFace[]{BlockFace.SOUTH, BlockFace.WEST, BlockFace.NORTH, BlockFace.EAST};
static final BlockFace[] BY_3D = new BlockFace[]{BlockFace.DOWN, BlockFace.UP, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST, BlockFace.EAST};
@Setter
Vector3i blockPosition;
public Vector3i blockPosition;
@Getter
InteractionHand hand;
@Getter
@@ -0,0 +1,98 @@
package ac.grim.grimac.utils.collisions;
/*
*/
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.*;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
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 org.jetbrains.annotations.Nullable;
import java.util.*;
// Expansion to the CollisionData class, which is different than regular ray tracing hitboxes
public enum RaycastData {
HOPPER((player, item, version, data, x, y, z) -> {
CollisionBox insideShape = new HexCollisionBox(2.0, 11.0, 2.0, 14.0, 16.0, 14.0);
switch (data.getFacing()) {
case NORTH:
new ComplexCollisionBox(insideShape, new HexCollisionBox(6.0, 8.0, 0.0, 10.0, 10.0, 4.0));
case SOUTH:
new ComplexCollisionBox(insideShape, new HexCollisionBox(6.0, 8.0, 12.0, 10.0, 10.0, 16.0));
case WEST:
new ComplexCollisionBox(insideShape, new HexCollisionBox(0.0, 8.0, 6.0, 4.0, 10.0, 10.0));
case EAST:
new ComplexCollisionBox(insideShape, new HexCollisionBox(12.0, 8.0, 6.0, 16.0, 10.0, 10.0));
default:
return insideShape;
}
}, StateTypes.HOPPER),
CAULDRON((player, item, version, data, x, y, z) -> {
return new HexCollisionBox(2.0, 4.0, 2.0, 14.0, 16.0, 14.0);
}, BlockTags.CAULDRONS.getStates().toArray(new StateType[0])),
FULL_BLOCK((player, item, version, data, x, y, z) -> {
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
}, StateTypes.COMPOSTER, StateTypes.SCAFFOLDING);
private static final Map<StateType, RaycastData> lookup = new HashMap<>();
static {
for (RaycastData data : RaycastData.values()) {
for (StateType type : data.materials) {
lookup.put(type, data);
}
}
}
private final StateType[] materials;
private CollisionBox box;
private HitBoxFactory dynamic;
RaycastData(CollisionBox box, StateType... materials) {
this.box = box;
Set<StateType> mList = new HashSet<>(Arrays.asList(materials));
mList.remove(null); // Sets can contain one null
this.materials = mList.toArray(new StateType[0]);
}
RaycastData(HitBoxFactory dynamic, StateType... materials) {
this.dynamic = dynamic;
Set<StateType> mList = new HashSet<>(Arrays.asList(materials));
mList.remove(null); // Sets can contain one null
this.materials = mList.toArray(new StateType[0]);
}
public static RaycastData getData(StateType material) {
return lookup.get(material);
}
@Nullable
public static CollisionBox getBlockHitbox(GrimPlayer player, StateType heldItem, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
RaycastData data = getData(block.getType());
if (data == null) {
// We explicitly do not want to fallback on HitBoxData or CollisionBox
// Because we only ever use this as a 2nd ray trace
return NoCollisionBox.INSTANCE;
}
// Simple collision box to override
if (data.box != null)
return data.box.copy().offset(x, y, z);
// Allow this class to override collision boxes when they aren't the same as regular boxes
HitBoxFactory hitBoxFactory = data.dynamic;
CollisionBox collisionBox = hitBoxFactory.fetch(player, heldItem, version, block, x, y, z);
collisionBox.offset(x, y, z);
return collisionBox;
}
}
@@ -0,0 +1,10 @@
package ac.grim.grimac.utils.common;
import ac.grim.grimac.api.config.ConfigManager;
public interface ConfigReloadObserver {
void onReload(ConfigManager config);
}
@@ -101,29 +101,29 @@ public final class ValuedAttribute {
}
public double with(WrapperPlayServerUpdateAttributes.Property property) {
double d0 = property.getValue();
double baseValue = property.getValue();
double additionSum = 0;
double multiplyBaseSum = 0;
double multiplyTotalProduct = 1.0;
List<WrapperPlayServerUpdateAttributes.PropertyModifier> modifiers = property.getModifiers();
modifiers.removeIf(modifier -> modifier.getUUID().equals(SPRINTING_MODIFIER_UUID) || modifier.getName().getKey().equals("sprinting"));
for (WrapperPlayServerUpdateAttributes.PropertyModifier attributemodifier : modifiers) {
if (attributemodifier.getOperation() == WrapperPlayServerUpdateAttributes.PropertyModifier.Operation.ADDITION)
d0 += attributemodifier.getAmount();
for (WrapperPlayServerUpdateAttributes.PropertyModifier modifier : modifiers) {
switch (modifier.getOperation()) {
case ADDITION:
additionSum += modifier.getAmount();
break;
case MULTIPLY_BASE:
multiplyBaseSum += modifier.getAmount();
break;
case MULTIPLY_TOTAL:
multiplyTotalProduct *= (1.0 + modifier.getAmount());
break;
}
}
double d1 = d0;
for (WrapperPlayServerUpdateAttributes.PropertyModifier attributemodifier : modifiers) {
if (attributemodifier.getOperation() == WrapperPlayServerUpdateAttributes.PropertyModifier.Operation.MULTIPLY_BASE)
d1 += d0 * attributemodifier.getAmount();
}
for (WrapperPlayServerUpdateAttributes.PropertyModifier attributemodifier : modifiers) {
if (attributemodifier.getOperation() == WrapperPlayServerUpdateAttributes.PropertyModifier.Operation.MULTIPLY_TOTAL)
d1 *= 1.0D + attributemodifier.getAmount();
}
double newValue = GrimMath.clampFloat((float) d1, (float) min, (float) max);
double newValue = GrimMath.clamp((baseValue + additionSum) * (1 + multiplyBaseSum) * multiplyTotalProduct, min, max);
if (setRewriter != null) {
newValue = setRewriter.apply(this.value, newValue);
}
@@ -47,6 +47,28 @@ public class PacketEntitySelf extends PacketEntity {
setAttribute(Attributes.GENERIC_STEP_HEIGHT, 0.5f);
}
getAttribute(Attributes.GENERIC_SCALE).get().withSetRewriter((oldValue, newValue) -> {
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_20_5) || (newValue).equals(oldValue)) {
return oldValue;
} else {
// Elytra, standing, sneaking (1.14)
player.possibleEyeHeights[2][0] = 0.4 * newValue;
player.possibleEyeHeights[2][1] = 1.62 * newValue;
player.possibleEyeHeights[2][2] = 1.27 * newValue;
// sneaking (1.14), standing, Elytra
player.possibleEyeHeights[1][0] = 1.27 * newValue;
player.possibleEyeHeights[1][1] = 1.62 * newValue;
player.possibleEyeHeights[1][2] = 0.4 * newValue;
// standing, sneaking (1.14), Elytra
player.possibleEyeHeights[0][0] = 1.62 * newValue;
player.possibleEyeHeights[0][1] = 1.27 * newValue;
player.possibleEyeHeights[0][2] = 0.4 * newValue;
return newValue;
}
});
final ValuedAttribute movementSpeed = ValuedAttribute.ranged(Attributes.GENERIC_MOVEMENT_SPEED, 0.1f, 0, 1024);
movementSpeed.with(new WrapperPlayServerUpdateAttributes.Property("MOVEMENT_SPEED", 0.1f, new ArrayList<>()));
trackAttribute(movementSpeed);
@@ -1,5 +1,7 @@
package ac.grim.grimac.utils.math;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.util.Vector3d;
import lombok.experimental.UtilityClass;
import java.util.List;
@@ -0,0 +1,309 @@
package ac.grim.grimac.utils.nmsutil;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.HitboxData;
import ac.grim.grimac.utils.collisions.RaycastData;
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.NoCollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.HitData;
import ac.grim.grimac.utils.data.Pair;
import ac.grim.grimac.utils.math.GrimMath;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;
public class BlockRayTrace {
// Copied from MCP...
// Returns null if there isn't anything.
//
// I do have to admit that I'm starting to like bifunctions/new java 8 things more than I originally did.
// although I still don't understand Mojang's obsession with streams in some of the hottest methods... that kills performance
@Nullable
public static Pair<int[], BlockFace> traverseBlocksLOSP(GrimPlayer player, double[] start, double[] end, BiFunction<WrappedBlockState, int[], Pair<int[], BlockFace>> predicate) {
// I guess go back by the collision epsilon?
double endX = GrimMath.lerp(-1.0E-7D, end[0], start[0]);
double endY = GrimMath.lerp(-1.0E-7D, end[1], start[1]);
double endZ = GrimMath.lerp(-1.0E-7D, end[2], start[2]);
double startX = GrimMath.lerp(-1.0E-7D, start[0], end[0]);
double startY = GrimMath.lerp(-1.0E-7D, start[1], end[1]);
double startZ = GrimMath.lerp(-1.0E-7D, start[2], end[2]);
int[] floorStart = new int[]{GrimMath.floor(startX), GrimMath.floor(startY), GrimMath.floor(startZ)};
if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) return null;
WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(floorStart[0], floorStart[1], floorStart[2]);
Pair<int[], BlockFace> apply = predicate.apply(state, floorStart);
if (apply != null) {
return apply;
}
double xDiff = endX - startX;
double yDiff = endY - startY;
double zDiff = endZ - startZ;
double xSign = Math.signum(xDiff);
double ySign = Math.signum(yDiff);
double zSign = Math.signum(zDiff);
double posXInverse = xSign == 0 ? Double.MAX_VALUE : xSign / xDiff;
double posYInverse = ySign == 0 ? Double.MAX_VALUE : ySign / yDiff;
double posZInverse = zSign == 0 ? Double.MAX_VALUE : zSign / zDiff;
double tMaxX = posXInverse * (xSign > 0 ? 1.0D - GrimMath.frac(startX) : GrimMath.frac(startX));
double tMaxY = posYInverse * (ySign > 0 ? 1.0D - GrimMath.frac(startY) : GrimMath.frac(startY));
double tMaxZ = posZInverse * (zSign > 0 ? 1.0D - GrimMath.frac(startZ) : GrimMath.frac(startZ));
// tMax represents the maximum distance along each axis before crossing a block boundary
// The loop continues as long as the ray hasn't reached its end point along at least one axis.
// In each iteration, it moves to the next block boundary along the axis with the smallest tMax value,
// updates the corresponding coordinate, and checks for a hit in the new block, Google "3D DDA" for more info
while (tMaxX <= 1.0D || tMaxY <= 1.0D || tMaxZ <= 1.0D) {
if (tMaxX < tMaxY) {
if (tMaxX < tMaxZ) {
floorStart[0] += xSign;
tMaxX += posXInverse;
} else {
floorStart[2] += zSign;
tMaxZ += posZInverse;
}
} else if (tMaxY < tMaxZ) {
floorStart[1] += ySign;
tMaxY += posYInverse;
} else {
floorStart[2] += zSign;
tMaxZ += posZInverse;
}
state = player.compensatedWorld.getWrappedBlockStateAt(floorStart[0], floorStart[1], floorStart[2]);
apply = predicate.apply(state, floorStart);
if (apply != null) {
return apply;
}
}
return null;
}
public static HitData traverseBlocks(GrimPlayer player, double[] start, double[] end, BiFunction<WrappedBlockState, Vector3i, HitData> predicate) {
// I guess go back by the collision epsilon?
double endX = GrimMath.lerp(-1.0E-7D, end[0], start[0]);
double endY = GrimMath.lerp(-1.0E-7D, end[1], start[1]);
double endZ = GrimMath.lerp(-1.0E-7D, end[2], start[2]);
double startX = GrimMath.lerp(-1.0E-7D, start[0], end[0]);
double startY = GrimMath.lerp(-1.0E-7D, start[1], end[1]);
double startZ = GrimMath.lerp(-1.0E-7D, start[2], end[2]);
int floorStartX = GrimMath.floor(startX);
int floorStartY = GrimMath.floor(startY);
int floorStartZ = GrimMath.floor(startZ);
if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) return null;
WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(floorStartX, floorStartY, floorStartZ);
HitData apply = predicate.apply(state, new Vector3i(floorStartX, floorStartY, floorStartZ));
if (apply != null) {
return apply;
}
double xDiff = endX - startX;
double yDiff = endY - startY;
double zDiff = endZ - startZ;
double xSign = Math.signum(xDiff);
double ySign = Math.signum(yDiff);
double zSign = Math.signum(zDiff);
double posXInverse = xSign == 0 ? Double.MAX_VALUE : xSign / xDiff;
double posYInverse = ySign == 0 ? Double.MAX_VALUE : ySign / yDiff;
double posZInverse = zSign == 0 ? Double.MAX_VALUE : zSign / zDiff;
double tMaxX = posXInverse * (xSign > 0 ? 1.0D - GrimMath.frac(startX) : GrimMath.frac(startX));
double tMaxY = posYInverse * (ySign > 0 ? 1.0D - GrimMath.frac(startY) : GrimMath.frac(startY));
double tMaxZ = posZInverse * (zSign > 0 ? 1.0D - GrimMath.frac(startZ) : GrimMath.frac(startZ));
// tMax represents the maximum distance along each axis before crossing a block boundary
// The loop continues as long as the ray hasn't reached its end point along at least one axis.
// In each iteration, it moves to the next block boundary along the axis with the smallest tMax value,
// updates the corresponding coordinate, and checks for a hit in the new block, Google "3D DDA" for more info
while (tMaxX <= 1.0D || tMaxY <= 1.0D || tMaxZ <= 1.0D) {
if (tMaxX < tMaxY) {
if (tMaxX < tMaxZ) {
floorStartX += xSign;
tMaxX += posXInverse;
} else {
floorStartZ += zSign;
tMaxZ += posZInverse;
}
} else if (tMaxY < tMaxZ) {
floorStartY += ySign;
tMaxY += posYInverse;
} else {
floorStartZ += zSign;
tMaxZ += posZInverse;
}
state = player.compensatedWorld.getWrappedBlockStateAt(floorStartX, floorStartY, floorStartZ);
apply = predicate.apply(state, new Vector3i(floorStartX, floorStartY, floorStartZ));
if (apply != null) {
return apply;
}
}
return null;
}
public static HitData traverseBlocks(GrimPlayer player, Vector3d start, Vector3d end, BiFunction<WrappedBlockState, Vector3i, HitData> predicate) {
return traverseBlocks(player, new double[]{start.x, start.y, start.z}, new double[]{end.x, end.y, end.z}, predicate);
}
@Nullable
public static HitData getNearestReachHitResult(GrimPlayer player, double[] startPos, double[] lookVec, double currentDistance, double maxDistance, int[] targetBlockVec, boolean raycastContext) {
double[] endPos = new double[]{
startPos[0] + lookVec[0] * maxDistance,
startPos[1] + lookVec[1] * maxDistance,
startPos[2] + lookVec[2] * maxDistance
};
return traverseBlocks(player, startPos, endPos, (block, vector3i) -> {
CollisionBox data;
if (!raycastContext) {
data = HitboxData.getBlockHitbox(player, player.getInventory().getHeldItem().getType().getPlacedType(), player.getClientVersion(), block, vector3i.x, vector3i.y, vector3i.z);
} else {
data = RaycastData.getBlockHitbox(player, null, player.getClientVersion(), block, vector3i.x, vector3i.y, vector3i.z);
}
if (data == NoCollisionBox.INSTANCE) return null;
List<SimpleCollisionBox> boxes = new ArrayList<>();
data.downCast(boxes);
double bestHitResult = Double.MAX_VALUE;
double[] bestHitLoc = null;
BlockFace bestFace = null;
// BEWARE OF https://bugs.mojang.com/browse/MC-85109 FOR 1.8 PLAYERS
// 1.8 Brewing Stand hitbox is a fullblock until it is hit sometimes, can be caused be restarting client and joining server
if (block.getType() == StateTypes.BREWING_STAND && player.getClientVersion().equals(ClientVersion.V_1_8) && Arrays.equals(new int[]{vector3i.x, vector3i.y, vector3i.z}, targetBlockVec)) {
boxes.add(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true));
}
double[] currentEnd = new double[]{
startPos[0] + lookVec[0] * currentDistance,
startPos[1] + lookVec[1] * currentDistance,
startPos[2] + lookVec[2] * currentDistance
};
for (SimpleCollisionBox box : boxes) {
Pair<double[], BlockFace> intercept = ReachUtilsPrimitives.calculateIntercept(box, startPos, currentEnd);
if (intercept.getFirst() == null) continue; // No intercept or wrong blockFace
double[] hitLoc = intercept.getFirst();
double distSq = distanceSquared(hitLoc, startPos);
if (distSq < bestHitResult) {
bestHitResult = distSq;
bestHitLoc = hitLoc;
bestFace = intercept.getSecond();
}
}
// Yes, this is not the most optimal algorithm for handling Cauldrons, Hoppers, Composters, and Scaffolding
// that is to say, blocks that have a different outline/hitbox shape from the box used to calculate placement blockfaces
// but it is the one vanilla uses
// No we will not
// 1. Calculate the ray trace from a new closer startPos to reduce iterations
// because it adds a lot of code complexity for very little performance gain
// 2. Run a switch case on the target block and check if the index of the SimpleCollisionBox corresponds to a wall with an inside face
// and hardcode in blockface fixes for placements against those compnents above a certain relative y level
// because that is version-specific, will break if the implementation of the returned ComplexCollisionBox changes
// and again, lots of code complexity for little performance gain
if (bestHitLoc != null) {
HitData hitData = new HitData(vector3i, new Vector(bestHitLoc[0], bestHitLoc[1], bestHitLoc[2]), bestFace, block);
if (!raycastContext) {
HitData hitData2 = BlockRayTrace.getNearestReachHitResult(player, startPos, lookVec, maxDistance, maxDistance, targetBlockVec, true);
if (hitData2 != null) {
Vector startVector = new Vector(startPos[0], startPos[1], startPos[2]);
if (hitData2.getBlockHitLocation().subtract(startVector).lengthSquared() <
hitData.getBlockHitLocation().subtract(startVector).lengthSquared()) {
return new HitData(vector3i, hitData.getBlockHitLocation(), hitData2.getClosestDirection(), block);
}
}
}
return hitData;
}
return null;
});
}
private static double distanceSquared(double[] vec1, double[] vec2) {
double dx = vec1[0] - vec2[0];
double dy = vec1[1] - vec2[1];
double dz = vec1[2] - vec2[2];
return dx * dx + dy * dy + dz * dz;
}
public static HitData getNearestHitResult(GrimPlayer player, StateType heldItem, boolean sourcesHaveHitbox) {
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);
Vector endVec = trace.getPointAtDistance(distance);
Vector3d endPos = new Vector3d(endVec.getX(), endVec.getY(), endVec.getZ());
return traverseBlocks(player, startingPos, endPos, (block, vector3i) -> {
CollisionBox data = HitboxData.getBlockHitbox(player, heldItem, player.getClientVersion(), block, vector3i.getX(), vector3i.getY(), vector3i.getZ());
List<SimpleCollisionBox> boxes = new ArrayList<>();
data.downCast(boxes);
double bestHitResult = Double.MAX_VALUE;
Vector bestHitLoc = null;
BlockFace bestFace = null;
for (SimpleCollisionBox box : boxes) {
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.getFirst() == null) continue; // No intercept
Vector hitLoc = intercept.getFirst();
if (hitLoc.distanceSquared(startingVec) < bestHitResult) {
bestHitResult = hitLoc.distanceSquared(startingVec);
bestHitLoc = hitLoc;
bestFace = intercept.getSecond();
}
}
if (bestHitLoc != null) {
return new HitData(vector3i, bestHitLoc, bestFace, block);
}
if (sourcesHaveHitbox &&
(player.compensatedWorld.isWaterSourceBlock(vector3i.getX(), vector3i.getY(), vector3i.getZ())
|| player.compensatedWorld.getLavaFluidLevelAt(vector3i.getX(), vector3i.getY(), vector3i.getZ()) == (8 / 9f))) {
double waterHeight = player.compensatedWorld.getFluidLevelAt(vector3i.getX(), vector3i.getY(), vector3i.getZ());
SimpleCollisionBox box = new SimpleCollisionBox(vector3i.getX(), vector3i.getY(), vector3i.getZ(), vector3i.getX() + 1, vector3i.getY() + waterHeight, vector3i.getZ() + 1);
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);
}
}
return null;
});
}
}
@@ -181,7 +181,8 @@ public class ReachUtils {
double lowest = Double.MAX_VALUE;
for (double eyes : player.getPossibleEyeHeights()) {
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
for (double eyes : possibleEyeHeights) {
if (giveMovementThresholdLenience) targetBox.expand(player.getMovementThreshold());
Vector from = new Vector(player.x, player.y + eyes, player.z);
Vector closestPoint = VectorUtils.cutBoxToVector(from, targetBox);
@@ -0,0 +1,184 @@
package ac.grim.grimac.utils.nmsutil;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.Pair;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jetbrains.annotations.NotNull;
public class ReachUtilsPrimitives {
public static @NotNull Pair<@Nullable double[], @Nullable BlockFace> calculateIntercept(SimpleCollisionBox self, double[] origin, double[] end) {
double[] minX = getIntermediateWithXValue(origin, end, self.minX);
double[] maxX = getIntermediateWithXValue(origin, end, self.maxX);
double[] minY = getIntermediateWithYValue(origin, end, self.minY);
double[] maxY = getIntermediateWithYValue(origin, end, self.maxY);
double[] minZ = getIntermediateWithZValue(origin, end, self.minZ);
double[] maxZ = getIntermediateWithZValue(origin, end, self.maxZ);
BlockFace bestFace = null;
if (!isVecInYZ(self, minX)) minX = null;
if (!isVecInYZ(self, maxX)) maxX = null;
if (!isVecInXZ(self, minY)) minY = null;
if (!isVecInXZ(self, maxY)) maxY = null;
if (!isVecInXY(self, minZ)) minZ = null;
if (!isVecInXY(self, maxZ)) maxZ = null;
double[] best = null;
double bestDistSq = Double.MAX_VALUE;
if (minX != null) {
best = minX;
bestDistSq = distanceSquared(origin, minX);
bestFace = BlockFace.WEST;
}
if (maxX != null) {
double distSq = distanceSquared(origin, maxX);
if (best == null || distSq < bestDistSq) {
best = maxX;
bestDistSq = distSq;
bestFace = BlockFace.EAST;
}
}
if (minY != null) {
double distSq = distanceSquared(origin, minY);
if (best == null || distSq < bestDistSq) {
best = minY;
bestDistSq = distSq;
bestFace = BlockFace.DOWN;
}
}
if (maxY != null) {
double distSq = distanceSquared(origin, maxY);
if (best == null || distSq < bestDistSq) {
best = maxY;
bestDistSq = distSq;
bestFace = BlockFace.UP;
}
}
if (minZ != null) {
double distSq = distanceSquared(origin, minZ);
if (best == null || distSq < bestDistSq) {
best = minZ;
bestDistSq = distSq;
bestFace = BlockFace.NORTH;
}
}
if (maxZ != null) {
double distSq = distanceSquared(origin, maxZ);
if (best == null || distSq < bestDistSq) {
best = maxZ;
bestFace = BlockFace.SOUTH;
}
}
return new Pair<>(best, bestFace);
}
private static double[] getIntermediateWithXValue(double[] self, double[] other, double x) {
double d0 = other[0] - self[0];
double d1 = other[1] - self[1];
double d2 = other[2] - self[2];
if (d0 * d0 < 1.0000000116860974E-7D) {
return null;
} else {
double d3 = (x - self[0]) / d0;
return d3 >= 0.0D && d3 <= 1.0D ? new double[]{self[0] + d0 * d3, self[1] + d1 * d3, self[2] + d2 * d3} : null;
}
}
private static double[] getIntermediateWithYValue(double[] self, double[] other, double y) {
double d0 = other[0] - self[0];
double d1 = other[1] - self[1];
double d2 = other[2] - self[2];
if (d1 * d1 < 1.0000000116860974E-7D) {
return null;
} else {
double d3 = (y - self[1]) / d1;
return d3 >= 0.0D && d3 <= 1.0D ? new double[]{self[0] + d0 * d3, self[1] + d1 * d3, self[2] + d2 * d3} : null;
}
}
private static double[] getIntermediateWithZValue(double[] self, double[] other, double z) {
double d0 = other[0] - self[0];
double d1 = other[1] - self[1];
double d2 = other[2] - self[2];
if (d2 * d2 < 1.0000000116860974E-7D) {
return null;
} else {
double d3 = (z - self[2]) / d2;
return d3 >= 0.0D && d3 <= 1.0D ? new double[]{self[0] + d0 * d3, self[1] + d1 * d3, self[2] + d2 * d3} : null;
}
}
private static boolean isVecInYZ(SimpleCollisionBox self, double[] vec) {
return vec != null && vec[1] >= self.minY && vec[1] <= self.maxY && vec[2] >= self.minZ && vec[2] <= self.maxZ;
}
private static boolean isVecInXZ(SimpleCollisionBox self, double[] vec) {
return vec != null && vec[0] >= self.minX && vec[0] <= self.maxX && vec[2] >= self.minZ && vec[2] <= self.maxZ;
}
private static boolean isVecInXY(SimpleCollisionBox self, double[] vec) {
return vec != null && vec[0] >= self.minX && vec[0] <= self.maxX && vec[1] >= self.minY && vec[1] <= self.maxY;
}
public static boolean isVecInside(SimpleCollisionBox self, double[] vec) {
return vec[0] > self.minX && vec[0] < self.maxX &&
vec[1] > self.minY && vec[1] < self.maxY &&
vec[2] > self.minZ && vec[2] < self.maxZ;
}
private static double distanceSquared(double[] vec1, double[] vec2) {
double dx = vec1[0] - vec2[0];
double dy = vec1[1] - vec2[1];
double dz = vec1[2] - vec2[2];
return dx * dx + dy * dy + dz * dz;
}
// The following methods remain unchanged but are included for completeness
public static double[] getLook(GrimPlayer player, float yaw, float pitch) {
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_12_2)) {
float f = player.trigHandler.cos(-yaw * 0.017453292F - (float)Math.PI);
float f1 = player.trigHandler.sin(-yaw * 0.017453292F - (float)Math.PI);
float f2 = -player.trigHandler.cos(-pitch * 0.017453292F);
float f3 = player.trigHandler.sin(-pitch * 0.017453292F);
return new double[]{f1 * f2, f3, f * f2};
} else {
float f = pitch * ((float) Math.PI / 180F);
float f1 = -yaw * ((float) Math.PI / 180F);
float f2 = player.trigHandler.cos(f1);
float f3 = player.trigHandler.sin(f1);
float f4 = player.trigHandler.cos(f);
float f5 = player.trigHandler.sin(f);
return new double[]{f3 * f4, -f5, f2 * f4};
}
}
// public static double getMinReachToBox(GrimPlayer player, SimpleCollisionBox targetBox) {
// boolean giveMovementThresholdLenience = player.packetStateData.didLastMovementIncludePosition || player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9);
// if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) targetBox.expand(0.1);
//
// double lowest = Double.MAX_VALUE;
//
// for (double eyes : player.getPossibleEyeHeights()) {
// if (giveMovementThresholdLenience) targetBox.expand(player.getMovementThreshold());
// double[] from = new double[]{player.x, player.y + eyes, player.z};
// double[] closestPoint = VectorUtils.cutBoxToVector(from, targetBox);
// lowest = Math.min(lowest, Math.sqrt(distanceSquared(from, closestPoint)));
// }
//
// return lowest;
// }
}
+46 -2
View File
@@ -81,9 +81,53 @@ FarPlace:
PositionPlace:
cancelvl: 5
RotationPlace:
cancelvl: 5
LineOfSightPlace:
cancelvl: 1
# Determines whether to only run the LineOfSightPlace check on specific blocks
# Increases performance, mainly intended for mini-game servers which already prevent block placement
# And want to stop container or workstation access through walls
use-block-whitelist: false
block-whitelist:
- ANVIL
- BARREL
- BEACON
- BEEHIVE
- BEE_NEST
- BLAST_FURNACE
- BREWING_STAND
- CAMPFIRE
- CARTOGRAPHY_TABLE
- CHEST
- CHEST_MINECART
- CHIPPED_ANVIL
- COMPOSTER
- CRAFTING_TABLE
- DAMAGED_ANVIL
- DISPENSER
- DROPPER
- ENCHANTING_TABLE
- ENDER_CHEST
- FURNACE
- FURNACE_MINECART
- FLETCHING_TABLE
- GRINDSTONE
- HOPPER
- HOPPER_MINECART
- ITEM_FRAME
- JUKEBOX
- LECTERN
- LOOM
- RESPAWN_ANCHOR
- SHULKER_BOX
- SMITHING_TABLE
- SMOKER
- SOUL_CAMPFIRE
- STONECUTTER
- TRAPPED_CHEST
- COMMAND_BLOCK
- STRUCTURE_BLOCK
- JIGSAW
# Prediction-based no slow check
# Grim ist verantwortlich für den fehlerhaften Netcode hier... schwer zu falsen, selbst wenn man Rechtsklick und Offhand-Taste spammt.
# Viel stabiler als andere Anticheats, aber bitte melde alle Falses... Ich habe hier eine Menge Netcode-Probleme behoben.
+46 -2
View File
@@ -81,8 +81,52 @@ FarPlace:
PositionPlace:
cancelvl: 5
RotationPlace:
cancelvl: 5
LineOfSightPlace:
cancelvl: 1
# Determines whether to only run the LineOfSightPlace check on specific blocks
# Increases performance, mainly intended for mini-game servers which already prevent block placement
# And want to stop container or workstation access through walls
use-block-whitelist: false
block-whitelist:
- ANVIL
- BARREL
- BEACON
- BEEHIVE
- BEE_NEST
- BLAST_FURNACE
- BREWING_STAND
- CAMPFIRE
- CARTOGRAPHY_TABLE
- CHEST
- CHEST_MINECART
- CHIPPED_ANVIL
- COMPOSTER
- CRAFTING_TABLE
- DAMAGED_ANVIL
- DISPENSER
- DROPPER
- ENCHANTING_TABLE
- ENDER_CHEST
- FURNACE
- FURNACE_MINECART
- FLETCHING_TABLE
- GRINDSTONE
- HOPPER
- HOPPER_MINECART
- ITEM_FRAME
- JUKEBOX
- LECTERN
- LOOM
- RESPAWN_ANCHOR
- SHULKER_BOX
- SMITHING_TABLE
- SMOKER
- SOUL_CAMPFIRE
- STONECUTTER
- TRAPPED_CHEST
- COMMAND_BLOCK
- STRUCTURE_BLOCK
- JIGSAW
# Prediction-based no slow check
# Grim accounts for buggy netcode here... hard to false even when spamming right click and offhand button
+46 -3
View File
@@ -82,9 +82,52 @@ FarPlace:
PositionPlace:
cancelvl: 5
RotationPlace:
cancelvl: 5
LineOfSightPlace:
cancelvl: 1
# Determines whether to only run the LineOfSightPlace check on specific blocks
# Increases performance, mainly intended for mini-game servers which already prevent block placement
# And want to stop container or workstation access through walls
use-block-whitelist: false
block-whitelist:
- ANVIL
- BARREL
- BEACON
- BEEHIVE
- BEE_NEST
- BLAST_FURNACE
- BREWING_STAND
- CAMPFIRE
- CARTOGRAPHY_TABLE
- CHEST
- CHEST_MINECART
- CHIPPED_ANVIL
- COMPOSTER
- CRAFTING_TABLE
- DAMAGED_ANVIL
- DISPENSER
- DROPPER
- ENCHANTING_TABLE
- ENDER_CHEST
- FURNACE
- FURNACE_MINECART
- FLETCHING_TABLE
- GRINDSTONE
- HOPPER
- HOPPER_MINECART
- ITEM_FRAME
- JUKEBOX
- LECTERN
- LOOM
- RESPAWN_ANCHOR
- SHULKER_BOX
- SMITHING_TABLE
- SMOKER
- SOUL_CAMPFIRE
- STONECUTTER
- TRAPPED_CHEST
- COMMAND_BLOCK
- STRUCTURE_BLOCK
- JIGSAW
# Comprobación de NoSlow basado en predicciones
# Grim compensa por código de red con errores aquí... difícil de sacar un falso positivo incluso haciendo spam del
# clic derecho y la mano secundaria.
+46 -3
View File
@@ -81,9 +81,52 @@ FarPlace:
PositionPlace:
cancelvl: 5
RotationPlace:
cancelvl: 5
LineOfSightPlace:
cancelvl: 1
# Determines whether to only run the LineOfSightPlace check on specific blocks
# Increases performance, mainly intended for mini-game servers which already prevent block placement
# And want to stop container or workstation access through walls
use-block-whitelist: false
block-whitelist:
- ANVIL
- BARREL
- BEACON
- BEEHIVE
- BEE_NEST
- BLAST_FURNACE
- BREWING_STAND
- CAMPFIRE
- CARTOGRAPHY_TABLE
- CHEST
- CHEST_MINECART
- CHIPPED_ANVIL
- COMPOSTER
- CRAFTING_TABLE
- DAMAGED_ANVIL
- DISPENSER
- DROPPER
- ENCHANTING_TABLE
- ENDER_CHEST
- FURNACE
- FURNACE_MINECART
- FLETCHING_TABLE
- GRINDSTONE
- HOPPER
- HOPPER_MINECART
- ITEM_FRAME
- JUKEBOX
- LECTERN
- LOOM
- RESPAWN_ANCHOR
- SHULKER_BOX
- SMITHING_TABLE
- SMOKER
- SOUL_CAMPFIRE
- STONECUTTER
- TRAPPED_CHEST
- COMMAND_BLOCK
- STRUCTURE_BLOCK
- JIGSAW
# Vérification de no-slow basée sur la prédiction.
# Grim tient compte des problèmes de netcode ici... difficile à tromper même en spamant le clic droit et le bouton de la main secondaire.
# Bien plus stable que les autres anti-triche, mais veuillez signaler toute fausse détection... J'ai corrigé de nombreux problèmes de netcode ici.
+46 -3
View File
@@ -78,9 +78,52 @@ PositionPlace:
# Livello di violazione per il piazzamento in una posizione specifica
cancelvl: 5
RotationPlace:
# Livello di violazione per il piazzamento con rotazione specifica
cancelvl: 5
LineOfSightPlace:
cancelvl: 1
# Determines whether to only run the LineOfSightPlace check on specific blocks
# Increases performance, mainly intended for mini-game servers which already prevent block placement
# And want to stop container or workstation access through walls
use-block-whitelist: false
block-whitelist:
- ANVIL
- BARREL
- BEACON
- BEEHIVE
- BEE_NEST
- BLAST_FURNACE
- BREWING_STAND
- CAMPFIRE
- CARTOGRAPHY_TABLE
- CHEST
- CHEST_MINECART
- CHIPPED_ANVIL
- COMPOSTER
- CRAFTING_TABLE
- DAMAGED_ANVIL
- DISPENSER
- DROPPER
- ENCHANTING_TABLE
- ENDER_CHEST
- FURNACE
- FURNACE_MINECART
- FLETCHING_TABLE
- GRINDSTONE
- HOPPER
- HOPPER_MINECART
- ITEM_FRAME
- JUKEBOX
- LECTERN
- LOOM
- RESPAWN_ANCHOR
- SHULKER_BOX
- SMITHING_TABLE
- SMOKER
- SOUL_CAMPFIRE
- STONECUTTER
- TRAPPED_CHEST
- COMMAND_BLOCK
- STRUCTURE_BLOCK
- JIGSAW
NoSlowA:
# Limite per rilevare l'uso scorretto dell'oggetto
+46 -3
View File
@@ -81,9 +81,52 @@ FarPlace:
PositionPlace:
cancelvl: 5
RotationPlace:
cancelvl: 5
LineOfSightPlace:
cancelvl: 1
# Determines whether to only run the LineOfSightPlace check on specific blocks
# Increases performance, mainly intended for mini-game servers which already prevent block placement
# And want to stop container or workstation access through walls
use-block-whitelist: false
block-whitelist:
- ANVIL
- BARREL
- BEACON
- BEEHIVE
- BEE_NEST
- BLAST_FURNACE
- BREWING_STAND
- CAMPFIRE
- CARTOGRAPHY_TABLE
- CHEST
- CHEST_MINECART
- CHIPPED_ANVIL
- COMPOSTER
- CRAFTING_TABLE
- DAMAGED_ANVIL
- DISPENSER
- DROPPER
- ENCHANTING_TABLE
- ENDER_CHEST
- FURNACE
- FURNACE_MINECART
- FLETCHING_TABLE
- GRINDSTONE
- HOPPER
- HOPPER_MINECART
- ITEM_FRAME
- JUKEBOX
- LECTERN
- LOOM
- RESPAWN_ANCHOR
- SHULKER_BOX
- SMITHING_TABLE
- SMOKER
- SOUL_CAMPFIRE
- STONECUTTER
- TRAPPED_CHEST
- COMMAND_BLOCK
- STRUCTURE_BLOCK
- JIGSAW
# Op voorspelling gebaseerde NoSlow-controle
# Grim is verantwoordelijk voor buggy netcode hier... moeilijk om vals te spelen, zelfs als je met rechts klikt en de offhand-knop spamt
# Veel stabieler dan andere anticheats, maar rapporteer alsjeblieft alle falses... Ik heb hier een heleboel netcode-problemen opgelost.
+46 -3
View File
@@ -82,9 +82,52 @@ FarPlace:
PositionPlace:
cancelvl: 5
RotationPlace:
cancelvl: 5
LineOfSightPlace:
cancelvl: 1
# Determines whether to only run the LineOfSightPlace check on specific blocks
# Increases performance, mainly intended for mini-game servers which already prevent block placement
# And want to stop container or workstation access through walls
use-block-whitelist: false
block-whitelist:
- ANVIL
- BARREL
- BEACON
- BEEHIVE
- BEE_NEST
- BLAST_FURNACE
- BREWING_STAND
- CAMPFIRE
- CARTOGRAPHY_TABLE
- CHEST
- CHEST_MINECART
- CHIPPED_ANVIL
- COMPOSTER
- CRAFTING_TABLE
- DAMAGED_ANVIL
- DISPENSER
- DROPPER
- ENCHANTING_TABLE
- ENDER_CHEST
- FURNACE
- FURNACE_MINECART
- FLETCHING_TABLE
- GRINDSTONE
- HOPPER
- HOPPER_MINECART
- ITEM_FRAME
- JUKEBOX
- LECTERN
- LOOM
- RESPAWN_ANCHOR
- SHULKER_BOX
- SMITHING_TABLE
- SMOKER
- SOUL_CAMPFIRE
- STONECUTTER
- TRAPPED_CHEST
- COMMAND_BLOCK
- STRUCTURE_BLOCK
- JIGSAW
# Verificação de NoSlow por simulação.
# Grim considera erros no netcode. Difícil de gerar falsos positivos, até mesmo spamando o blotão direito e a offhand.
# Muito mais estável que outros anticheats, mas por favor, reporte quaisquer falsos positivos. Eu já arrumei diversos
+46 -3
View File
@@ -81,9 +81,52 @@ FarPlace:
PositionPlace:
cancelvl: 5
RotationPlace:
cancelvl: 5
LineOfSightPlace:
cancelvl: 1
# Determines whether to only run the LineOfSightPlace check on specific blocks
# Increases performance, mainly intended for mini-game servers which already prevent block placement
# And want to stop container or workstation access through walls
use-block-whitelist: false
block-whitelist:
- ANVIL
- BARREL
- BEACON
- BEEHIVE
- BEE_NEST
- BLAST_FURNACE
- BREWING_STAND
- CAMPFIRE
- CARTOGRAPHY_TABLE
- CHEST
- CHEST_MINECART
- CHIPPED_ANVIL
- COMPOSTER
- CRAFTING_TABLE
- DAMAGED_ANVIL
- DISPENSER
- DROPPER
- ENCHANTING_TABLE
- ENDER_CHEST
- FURNACE
- FURNACE_MINECART
- FLETCHING_TABLE
- GRINDSTONE
- HOPPER
- HOPPER_MINECART
- ITEM_FRAME
- JUKEBOX
- LECTERN
- LOOM
- RESPAWN_ANCHOR
- SHULKER_BOX
- SMITHING_TABLE
- SMOKER
- SOUL_CAMPFIRE
- STONECUTTER
- TRAPPED_CHEST
- COMMAND_BLOCK
- STRUCTURE_BLOCK
- JIGSAW
# Основанная на предсказаниях проверка на отсутствие замедления
# Grim учитывает баги неткода здесь... трудно ошибиться, даже если спамить правым кликом и кнопкой оффхенд.
# Намного стабильнее, чем другие античиты, но, пожалуйста, сообщайте о любых фейлах... Я исправил тонну проблем с неткодом.
+46 -2
View File
@@ -81,8 +81,52 @@ FarPlace:
PositionPlace:
cancelvl: 5
RotationPlace:
cancelvl: 5
LineOfSightPlace:
cancelvl: 1
# Determines whether to only run the LineOfSightPlace check on specific blocks
# Increases performance, mainly intended for mini-game servers which already prevent block placement
# And want to stop container or workstation access through walls
use-block-whitelist: false
block-whitelist:
- ANVIL
- BARREL
- BEACON
- BEEHIVE
- BEE_NEST
- BLAST_FURNACE
- BREWING_STAND
- CAMPFIRE
- CARTOGRAPHY_TABLE
- CHEST
- CHEST_MINECART
- CHIPPED_ANVIL
- COMPOSTER
- CRAFTING_TABLE
- DAMAGED_ANVIL
- DISPENSER
- DROPPER
- ENCHANTING_TABLE
- ENDER_CHEST
- FURNACE
- FURNACE_MINECART
- FLETCHING_TABLE
- GRINDSTONE
- HOPPER
- HOPPER_MINECART
- ITEM_FRAME
- JUKEBOX
- LECTERN
- LOOM
- RESPAWN_ANCHOR
- SHULKER_BOX
- SMITHING_TABLE
- SMOKER
- SOUL_CAMPFIRE
- STONECUTTER
- TRAPPED_CHEST
- COMMAND_BLOCK
- STRUCTURE_BLOCK
- JIGSAW
# Tahmin tabanlı yavaşlama kontrolü
# Grim burada hatalı ağ kodunu dikkate alır... sağ tıklama ve el yan tuşunu spam yapsanız bile yanlış pozitiflik oluşturması zordur
+46 -2
View File
@@ -82,8 +82,52 @@ FarPlace:
PositionPlace:
cancelvl: 5
RotationPlace:
cancelvl: 5
LineOfSightPlace:
cancelvl: 1
# Determines whether to only run the LineOfSightPlace check on specific blocks
# Increases performance, mainly intended for mini-game servers which already prevent block placement
# And want to stop container or workstation access through walls
use-block-whitelist: false
block-whitelist:
- ANVIL
- BARREL
- BEACON
- BEEHIVE
- BEE_NEST
- BLAST_FURNACE
- BREWING_STAND
- CAMPFIRE
- CARTOGRAPHY_TABLE
- CHEST
- CHEST_MINECART
- CHIPPED_ANVIL
- COMPOSTER
- CRAFTING_TABLE
- DAMAGED_ANVIL
- DISPENSER
- DROPPER
- ENCHANTING_TABLE
- ENDER_CHEST
- FURNACE
- FURNACE_MINECART
- FLETCHING_TABLE
- GRINDSTONE
- HOPPER
- HOPPER_MINECART
- ITEM_FRAME
- JUKEBOX
- LECTERN
- LOOM
- RESPAWN_ANCHOR
- SHULKER_BOX
- SMITHING_TABLE
- SMOKER
- SOUL_CAMPFIRE
- STONECUTTER
- TRAPPED_CHEST
- COMMAND_BLOCK
- STRUCTURE_BLOCK
- JIGSAW
# 使用模拟移动进行的NoSlow(使用物品时不会减速)检查
# 在这里解释错误的服务器代码......即使在发送垃圾数据包时右键单击和副手按钮也很分辨