Compare commits

...
Author SHA1 Message Date
Axionize cf115fd9c5 Disable requirements processor 2025-03-25 03:46:17 -04:00
Axionize 999f083363 I hate this 2025-03-25 03:24:34 -04:00
Axionize 96657b399f Fix build issues with downloading Conditional Mixin library for PE Fabric 2025-03-25 03:24:18 -04:00
Axionize 2cdca3ed72 Bump RAM allocation to Gradle in root gradle.properties 2025-03-24 14:35:25 -04:00
Axionize 196d4f592b Minor Build optimization 2025-03-24 08:48:19 -04:00
Axionize 588ba8def2 New API refactor with getEventBus() 2025-03-24 01:19:45 -04:00
Axionize 55cf328063 Only include fabricAPI modules we use, reuse dependency code for multiple projects 2025-03-23 08:10:26 -04:00
Axionize ddab7562fd Add support for Spigot 1.17 - 1.18.2 itemUsageReset()
- Also decrease allocated via gradle.properties
- Forces rebuild with new PE which will fix Geyser detection
2025-03-23 07:51:12 -04:00
Axionize 804e34f20d Make Grim rely on JiJed and loaded PE API; Transition PacketPlayerDigging to be cross-platform from upstream 2025-03-23 03:38:38 -04:00
Axionize fa65721116 Translation parity (and more/better) with pre-platform-independence port 2025-03-23 01:50:51 -04:00
Axionize 0c81517639 Fix updating native ServerPlayerEntity reference; Refactor @NonNull annotations 2025-03-23 01:50:50 -04:00
Axionize b71c44c2e1 Initable refactor; support multiple types of initables as one object; shutdown fabric bstats 2025-03-23 01:49:33 -04:00
Axionize d7437bce97 Fix Geyser-Fabric compatability 2025-03-23 01:49:33 -04:00
Axionize 888f209994 Build against slim configuralize for fabric support 2025-03-23 01:49:33 -04:00
Axionize f6397c978b Bump snakeyaml version for Fabric support 2025-03-23 01:49:33 -04:00
Axionize d612a522cc Fix library relocation typo 2025-03-23 01:49:33 -04:00
Axionize 661010805f Fix build issues with relocation on bukkit; force rebuild for fabric registry fix with PE 2025-03-23 01:49:33 -04:00
Axionize 6848c03e47 Code cleanup to address code review concerns 2025-03-23 01:49:33 -04:00
Axionize 0b168e2d60 Fix Build error from rebasing https://github.com/GrimAnticheat/Grim/commit/aab710dd8b55bc6fbe88f0f4c79aa214527a20dd 2025-03-23 01:49:33 -04:00
Axionize a1d0a6a73d Fix rare preconditions error with checking for null platformPlayer 2025-03-23 01:49:33 -04:00
Axionize a88c506518 Cleanup Fabric buildscript 2025-03-23 01:49:33 -04:00
Axionize 04f4bd7d21 Hopefully Fix inventory errors 2025-03-23 01:49:33 -04:00
Axionize cae28699a3 Fix running fabric in IDE and dev mode
Credit: @Bawnorton
2025-03-23 01:49:33 -04:00
Axionize ee689d1503 Fix 1.8 support using non-existent inventory method 2025-03-23 01:49:33 -04:00
Axionize 695e1ad5a3 Bump Fabric loom version; trigger rebuild on updated PE fork with Fabric fixes 2025-03-23 01:49:33 -04:00
Axionize bc766b51dd Minor code cleanup 2025-03-23 01:49:33 -04:00
Axionize fb1f3cda72 Code cleanup 2025-03-23 01:49:33 -04:00
Axionize 554d6d62db Configure builds to use shared lib versions files; push for rebuild with updated PE; (Working 1.20.1) 2025-03-23 01:49:33 -04:00
Axionize b9f71bce4e Fix project build issues and fix 1.20.1 support 2025-03-23 01:49:31 -04:00
Axionize f4f9092bd7 Fix Legacy (< 1.16.5) Big DripLeaf CollisionBox modeling 2025-03-23 01:49:19 -04:00
Axionize ff461cf041 Actuallly commit 1.20.4 support 2025-03-23 01:49:18 -04:00
Axionize 9b5264f0f3 Add 1.20.1 support (once PE is fixed) 2025-03-23 01:49:18 -04:00
Axionize 5cb5ce634d Refactor Fabric to support 1.21.4, 1.21.1, and (soon) 1.16.1 2025-03-23 01:49:18 -04:00
Axionize 0403565830 Fix endTick on Folia 2025-03-23 01:49:18 -04:00
Axionize 4d0a3696c9 PE datatype refactor; Fix Folia support 2025-03-23 01:49:18 -04:00
Axionize f1440bad93 Moderate refactoring and codebase cleanup
Fixed GitHub actions

Note that Fabric platform is missing:
- Pistons
- Providing an instance of GrimExternalAPI for other plugins/mods to get
- and more
2025-03-23 01:49:17 -04:00
Axionize a92e1e3892 Fix scheduler hierachy issue 2025-03-23 01:44:38 -04:00
Axionize c60355536e Temporarily build against my fork to fix PacketEvent's broken Fabric support 2025-03-23 01:44:38 -04:00
Axionize 2aeafe14cc Build against new Grim API instead of locally 2025-03-23 01:44:38 -04:00
Axionize e5d011b681 Fix Actions workflow 2025-03-23 01:43:34 -04:00
Axionize 5b59392817 Finish Fabric buildscript; now builds runnable jar 2025-03-23 01:43:34 -04:00
Axionize 656e73a07d Fix Fabric execution and shutdown; Initial Fabric build script 2025-03-23 01:43:34 -04:00
Axionize 7d9836ca50 Beta Fabric Support Complete + General Bug Fixes:
- Generate autocompletions for permissions
- Make OP, and enable-on-join permissions false by default even for ops

- Fixed usage of isWorldLoaded() in pre-migration codebase from breaking 1.8 support
- Numerous command loader bugs fixed
- A lot more
2025-03-23 01:43:34 -04:00
Axionize 7e91c739b2 Refactor resyncPosition() internally; may move to platformPlayer in future 2025-03-23 01:43:34 -04:00
Axionize 9aaf8b9491 Platform loading fixes 2025-03-23 01:43:34 -04:00
Axionize 3869a2077d Fabric Support MVP
- Registering permissions likely incomplete
- Building jar incomplete; only works in Debug mode
- Exempting on reload not done
- Plugin Channels not implemented
2025-03-23 01:43:34 -04:00
Axionize 525c380560 Complete multi-module project setup 2025-03-23 01:43:34 -04:00
Axionize ca7326cbd7 Multi-module project init setup 2025-03-23 01:43:32 -04:00
Axionize e9f2d29fd5 Platform Independence Achieved! 2025-03-23 01:43:26 -04:00
Axionize dfdab62763 Refactor Part 3:
Checkpoint
Need to implement:
- Fix PlaceHolderAPI and ManInMyVan's MessageUtil logic error
- Add BStats back
- Add platform independent Permissions
- Make TickEndEvent handling platform independent

Need to Test:
- ProxyAlertMessenger
- Commands
2025-03-23 01:43:26 -04:00
Axionize e339626ce1 Fix plugin compilation and exeution of commands 2025-03-23 01:43:26 -04:00
Axionize b0df122cb9 Almost there; just events and bukkit extensions left 2025-03-23 01:43:26 -04:00
Axionize ae284e2886 Stash code 2025-03-23 01:43:26 -04:00
Axionize 586f4bde69 Refactor Part 2:
- Replace Vectors
- Replace ChatColor.translateColorCodes()
2025-03-23 01:43:25 -04:00
Axionize c3d1b14dc1 Seperated/Abstracted:
- Thread Management
- GrimEntity/PlatformPlayer + PlatformInventory
- PlatformWorld, PlatformChunk, Location
- Removed many bukkit dependencies
- Migrated Bukkit Events to own code section

- Disabled BStats temporarily
2025-03-23 01:43:24 -04:00
Axionize b71c11882a Fix rare AirLiquidBreak NPE 2025-03-23 00:52:38 -04:00
ManInMyVan 990efdd6d2 fix a noslow 2025-03-22 15:31:21 -06:00
ManInMyVan 3c89193fff rename mitigate-autoblock and mitigate-desync-noslow 2025-03-22 15:25:49 -06:00
SamB440 aff9dc3c25 Merge pull request #2030 from Dream23322/patch-1
Update README.md
2025-03-22 18:43:15 +00:00
ManInMyVan 6b17d5fd0e fix spectate command 2025-03-19 16:06:07 -06:00
SamB440 319dca27ae Use single runnable for multi block changes 2025-03-19 14:24:27 +00:00
SamB440 5d20372645 Fix 1.21.2+ item cooldown
How to make simple feature more complex?
2025-03-14 18:26:39 +00:00
ManInMyVan 74108a2088 fix #1962 2025-03-14 11:56:23 -06:00
Cyramek aab710dd8b Fix Block Collisions [1.21.2+] (#2015) 2025-03-11 08:51:52 -04:00
SamB440 1fb1a73060 Fix teleport check 2025-03-02 20:37:41 +00:00
ManInMyVan 6811bc71fc Merge pull request #2033 from 483378/2.0
AimModulo360: fix horse false flag <= 1.13
2025-03-02 11:18:14 -07:00
SamB440 6205a23edd Merge pull request #2034 from 483378/Add-Hitboxes-to-punishments-config
Add Hitboxes to punishments config
2025-03-02 13:33:44 +00:00
483378 2f844bc56e Add Hitboxes to punishments config 2025-03-02 11:59:17 +01:00
483378 5ca4082675 AimModulo360: fix horse false flag <= 1.13 2025-03-02 10:59:51 +01:00
ManInMyVan 078bc139f7 revert changes from 68a04d05 and 45da02e7
it could be bypassed
2025-03-01 12:49:11 -07:00
Me. 37d07d3b03 Update README.md 2025-03-01 11:01:31 +10:00
SamB440 5bccfe831d Fix not reencoding stupidity packet 2025-02-28 14:31:41 +00:00
ManInMyVan 3fbaa0a0e6 why does OnlinePlayer exist 2025-02-23 10:42:20 -07:00
SamB440 931d26569c Don't need to throw 2025-02-23 12:42:05 +00:00
SamB440 b207fe233e Add option to debug packet cancelling 2025-02-22 20:40:23 +00:00
SamB440 0cc0910455 Merge pull request #2019 from Cyramek/water-push-fix
fix water flow push [1.21.4]
2025-02-22 19:25:09 +00:00
cyramek b5acee4911 fix water flow push 2025-02-22 20:04:57 +01:00
ManInMyVan ccada109b1 include "ms" in fastbreak verbose 2025-02-21 17:30:59 -07:00
ManInMyVan 16c0d37b54 include block type in fastbreak verbose 2025-02-21 17:30:16 -07:00
ManInMyVan f6c16ea567 make fastbreak verbose case consistent 2025-02-21 17:29:33 -07:00
ManInMyVan b9934f5130 same with tridents and debug sticks 2025-02-21 17:18:05 -07:00
ManInMyVan 3c48b6edab creative mode players cannot mine with a mace 2025-02-21 17:10:14 -07:00
ManInMyVan fdf8bc26a5 very minor changes 2025-02-21 16:07:00 -07:00
AoElite 900cbed5fa update api 2025-02-19 07:06:28 -05:00
SamB440 233cd2a7d7 Fix TAB server version check 2025-02-17 21:00:46 +00:00
AoElite 0c8b60018a build with Java 21 2025-02-14 03:14:54 -05:00
AoElite a54787152d bump deepsource runtime version to 17 2025-02-14 03:11:19 -05:00
AoElite 2932f0a40c handle end tick support for folia better & try to use paper's end tick event if reflection fails 2025-02-14 03:08:37 -05:00
AoElite 94d47391af correct wrong method name 2025-02-14 02:55:08 -05:00
AoElite 9964478ce1 added a better way to log exceptions 2025-02-14 02:33:38 -05:00
AoElite d3667e1add use teleportAsync when possible, this also should fix the spectating command not working on folia 2025-02-14 02:28:17 -05:00
ManInMyVan 04e1459d9e Merge pull request #2006 from ManInMyVan/fix/item-reset-exceptions
fix exceptions caused by resetting item usage async
2025-02-13 12:09:15 -07:00
ManInMyVan e99855bdc5 inline the class field 2025-02-12 15:54:59 -07:00
ManInMyVan 028a526c51 fix exceptions caused by resetting item usage async 2025-02-12 12:10:22 -07:00
SamB440 9650cdb4f2 Entity pushing fixes and performance improvement 2025-02-12 16:03:24 +00:00
GigaZelensky 5326845c7a Add Custom Setback Violation Threshold (#2001)
* Add Custom Setback Violation Threshold

This change introduces a configurable threshold for setbacks, allowing more flexibility in how violations are handled. It can be useful in multiple scenarios, such as integrating Grim with other anti-cheat systems like Vulcan. By delaying setbacks, more obvious cheats (e.g., flying) can be detected and handled by other systems first, preventing unnecessary interference that might limit their effectiveness.

Additionally, this feature helps reduce the impact of small false positives or minor violations on legitimate players, ensuring that occasional detection inaccuracies don’t result in unnecessary movement corrections.

The option is set to 1 by default to maintain the existing behavior, but it can be adjusted in the config for more customized handling.

* Update en.yml

* Update config to match custom Setback Violation Threshold

* Update config to match custom Setback Violation Threshold

* Update config to match custom Setback Violation Threshold

* Update config to match custom Setback Violation Threshold

* Update config to match custom Setback Violation Threshold

* Update config to match custom Setback Violation Threshold

* Update ja.yml

* Update config to match custom Setback Violation Threshold

* Update config to match custom Setback Violation Threshold

* Update tr.yml

* Update config to match custom Setback Violation Threshold

* Update config to match custom Setback Violation Threshold

* Update config to match custom Setback Violation Threshold
2025-02-12 15:09:01 +00:00
Axionize 7646df0563 Fix a rare CME in LatencyUtils (#1984) 2025-02-08 12:53:02 -05:00
Axionize 23369cf1d6 Fix modeling teleport packets for entities on clients < 1.16.2 (#1985)
* Fix modeling teleport packets for entities on clients < 1.16.2
* Fix new entity modeling to handle riding entities
* Fix merge issues from backporting
2025-02-08 12:52:24 -05:00
ManInMyVan 864e9de3e8 fix #1948 2025-02-05 16:57:46 -07:00
ManInMyVan 68b4fa7805 fix SprintE false 2025-02-05 16:43:38 -07:00
ManInMyVan c7e1fda7bb correct checking water for in sprint checks 2025-02-05 16:20:25 -07:00
ManInMyVan 6c42bdcd4e MC152728 was unfixed 2025-02-05 15:31:29 -07:00
Ty_Regotly 439cbc6db3 Correct some translation errors, and update the time (#1996)
* Update de.yml

* Update en.yml

* Update es.yml

* Update fr.yml

* Update it.yml

* Update ja.yml

* Update nl.yml

* Update pt.yml

* Update ru.yml

* Update tr.yml

* Update zh.yml
2025-02-05 11:35:21 +00:00
ManInMyVan 652b66202d Merge pull request #1997 from TrollsterCooleg/2.0
Make the placeholders persist
2025-02-04 21:03:11 -07:00
TrollsterCooleg 9f031e638a Make the placeholders persist 2025-02-04 21:54:30 -06:00
ManInMyVan 45da02e7c0 check slot 2025-02-04 20:21:12 -07:00
ManInMyVan 68a04d05f8 hopefuly fix errors with mitigate-desync-noslow 2025-02-04 17:29:08 -07:00
ManInMyVan e329171b11 add check-for-updates to all config files 2025-02-03 15:15:46 -07:00
SamB440 b8121543ee Add setting for checking for updates on startup (implements #1995) 2025-02-03 19:42:49 +00:00
SamB440 70cf56fad6 Stop paper taking 10 years to remap the plugin 2025-02-03 19:33:20 +00:00
SamB440 f88a114e0e Bump version 2025-02-01 15:17:30 +00:00
SamB440 ff888f8c73 Kick players if a transaction error occurs 2025-01-31 20:28:14 +00:00
SamB440 66a250eb9e Maybe fix flint and steel prediction (fixes #1991) 2025-01-31 20:06:57 +00:00
SamB440 3c56ba9880 Support creaking hitbox (fixes #1986) 2025-01-31 19:08:43 +00:00
SamB440 514a48e508 Update Gradle wrapper 2025-01-31 19:05:53 +00:00
SamB440 32b66cb4ff Fix checking for elytra on servers older than 1.21.2 2025-01-31 19:01:59 +00:00
SamB440 057de4d4e2 Update shadow plugin 2025-01-31 18:48:31 +00:00
ManInMyVan 081e2d3b2b fix resin hitbox
closes #1982
2025-01-30 19:17:28 -07:00
SamB440 856a51e574 Bump version 2025-01-30 21:35:29 +00:00
SamB440 a4786a16c0 Exempt TRIAL_SPAWNER on fastbreak (#1962) as temp-fix 2025-01-30 21:22:43 +00:00
SamB440 c904f14c7b Use Component instead of String 2025-01-30 21:19:54 +00:00
ManInMyVan 896cf12b71 patch civ 2025-01-29 16:02:04 -07:00
ManInMyVan 1506c97ffc fix comment 2025-01-29 07:56:20 -07:00
ManInMyVan 9107586fc1 assume cooldown is full on 1.8 servers 2025-01-28 19:44:24 -07:00
ManInMyVan bc96460eb3 RotationBreak
closes #1196
2025-01-28 17:12:53 -07:00
ManInMyVan 94705fcd09 why are we ticking velocity on duplicates? 2025-01-28 12:47:27 -07:00
Axionize 7ae935f5e3 Revert "More Accurate Position Reach Modeling for MC clients < 1.16.2 (#1964)" (#1980)
This reverts commit 6d06b9b559.
2025-01-28 05:55:36 -05:00
Axionize 6d06b9b559 More Accurate Position Reach Modeling for MC clients < 1.16.2 (#1964)
* Stop using server-side tracked position when attempting to account for teleports not always moving entity client side; expand from client area instead

* Seperate getting possible locations and possible hitbox to reduce how often expandNonRelative() needs to be called

* Add documention explaining getPossibleLocationCombined() and getPossibleHitboxCombined()

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

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

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

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

* Manually size ComplexCollisionBoxes Pt. 1

* Manually size ComplexCollisionBoxes Pt. 2

* Fix new downCast() for SimpleCollisionBox

* Fix logic error in CCB constructor

* Optimize DynamicHitboxFence

* Fix logic error again in CCB constructor

* Remove debug print statement

* Fix copying CCBs in edge case

* Rename variable for clarity

* Make CCD length private var

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

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

* oops
2024-11-01 16:32:34 +00:00
SamB440 e829c25c82 Merge pull request #1727 from ManInMyVan/negativetimer-setbacks
allow setbacks in NegativeTimer
2024-11-01 16:24:11 +00:00
SamB440 30c2d361a3 Merge pull request #1732 from Axionize/optimize-iteration-order
Optimizing getPossibleEyeHeights()
2024-10-31 21:54:17 +00:00
SamB440 15984b0a94 Merge branch '2.0' into optimize-iteration-order 2024-10-31 21:53:50 +00:00
AoElite 97de474b79 Merge pull request #1772 from ManInMyVan/fix/perm
fix permission default for already defined permissions
2024-10-30 19:53:03 -04:00
ManInMyVan cea13a719d fix permission default 2024-10-30 16:31:04 -06:00
AoElite faa471b197 catch permission error 2024-10-30 18:20:50 -04:00
ManInMyVan ce9d66c199 Allow exempting elytras 2024-10-27 12:51:33 -06:00
BadPackage d0eb36c87a small doc fix 2024-10-26 13:04:13 +02:00
SamB440 60f8812efd Merge pull request #1737 from Rothes/2.0
Fix config for Timer
2024-10-24 18:18:46 +01:00
SamB440 7e82f19961 Correctly handle reEncodeByDefault = false by last commit 2024-10-22 18:15:10 +01:00
AoElite 27aae68f14 add website 2024-10-22 12:00:33 -04:00
AoElite a65f24424f improved custom config manager handling 2024-10-22 11:59:43 -04:00
AoElite bfd3433423 regex optimization 2024-10-22 11:55:38 -04:00
AoElite 09e6cec6ef fix older versions of via throwing an error due to PR 2024-10-22 10:56:36 -04:00
AoElite 4ffe6f4fc5 packetevent optimizations 2024-10-22 10:11:02 -04:00
AoElite 4aaeb579e7 Merge pull request #1759 from ManInMyVan/fix/perm
fix exempt permission default
2024-10-22 02:09:38 -04:00
AoElite 487e9c6590 when reloading player configuration reload their checks & punishment manager as well for better API ease of use 2024-10-21 23:37:30 -04:00
SamB440 bdf7eb7c06 Merge pull request #1754 from Cyramek/via-version-fix
warn about `ViaVersion rotation-place fix`
2024-10-16 12:29:30 +01:00
ManInMyVan c70e5b8fff fix exempt permission default 2024-10-15 17:32:47 -06:00
SamB440 9599b1c631 Reduce Optional allocs with attribute methods 2024-10-14 14:24:19 +01:00
SamB440 85b42fa90e Merge pull request #1756 from ManInMyVan/fix/fr-config-noslow
fix fr.yml noslow
2024-10-13 19:50:11 +01:00
ManInMyVan 0c1a6c7775 fix fr.yml noslow 2024-10-13 12:47:08 -06:00
SamB440 d4508fa36b Fix AimModulo360? 2024-10-13 17:53:02 +01:00
SamB440 3cb1bb3792 Update actions 2024-10-13 17:50:51 +01:00
SamB440 faf0c7d3d6 Gradle 8.10.1 2024-10-13 17:49:47 +01:00
Cyramek c8ff1109e1 reverse that patch 2024-10-10 14:31:50 +02:00
AoElite de0c28beab reloading rework, allows you to have per player configurations & other things, doesn't cover every option yet 2024-10-10 08:00:33 -04:00
Cyramek acdacffcc0 take care of viaversion rotation fix, and warn server admin about that option 2024-10-10 13:56:22 +02:00
AoElite 3cab3fe680 Merge pull request #1744 from ManInMyVan/fix/bpZ
fix a BadPacketsZ false
2024-10-07 16:09:44 -04:00
AoElite 880a7b5e74 Merge pull request #1751 from Axionize/optimize-attribute-iteration
Optimize looping over attribute modifier properties
2024-10-07 16:09:30 -04:00
ManInMyVan 504e667d40 fix MultiInteractB false 2024-10-05 22:38:09 -06:00
ManInMyVan f8aa611a4b fix MultiInteractA false 2024-10-05 22:35:55 -06:00
Axionize c4848efc8a Optimize looping over attribute modifier properties 2024-10-05 19:32:14 -04:00
SamB440 0ddf0b5d22 Merge pull request #1749 from ManInMyVan/fix/mutliplace
fix multiplace false
2024-10-06 00:26:26 +01:00
SamB440 fde6e03b98 Merge pull request #1750 from Axionize/fix-attribute-clamp
Fix incorrect casting to float before clamping attribute values
2024-10-06 00:19:44 +01:00
ManInMyVan f3074e3934 fix multiplace false 2024-10-05 13:15:11 -06:00
Axionize 28be03b978 Document SimpleCollisionBox and HexCollisionBox with Javadoc 2024-10-03 03:40:01 -04:00
Axionize e3ccbe2449 Fix spelling mistake 2024-10-03 00:09:51 -04:00
Axionize 5782d356fb Replace RuntimeException in HitBox.java with IllegalStateException 2024-10-03 00:09:51 -04:00
AxionizeandManInMyVan 999d7c7016 Button Styling Change
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:03:40 -04:00
AxionizeandManInMyVan 270db6995c Sapling Styling Change
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:03:23 -04:00
AxionizeandManInMyVan bafb169b76 TALL_FLOWER Styling Change
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:03:08 -04:00
AxionizeandManInMyVan 5bc0f06500 Redstone Wire Comment Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:02:42 -04:00
AxionizeandManInMyVan 1e244ed37b Inline Hitbox Calculation
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:02:25 -04:00
AxionizeandManInMyVan 8b8a9b5ce7 getPropaguleMinHeight Spacing
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:02:03 -04:00
AxionizeandManInMyVan 129549bf2d Small Flower Line Spacing/Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:01:34 -04:00
AxionizeandManInMyVan ed7f9d80f8 Coral Fan Line Spacing/Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:01:15 -04:00
AxionizeandManInMyVan c1054142e0 Banner Line Spacing/Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:01:05 -04:00
AxionizeandManInMyVan 9ee0b82eab Simplify TALL_FLOWERS handling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:00:45 -04:00
AxionizeandManInMyVan 76f5f81f6a Rails Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:00:21 -04:00
AxionizeandManInMyVan 0c51152477 Mark function as Deprecated
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-02 23:59:48 -04:00
Axionize 9b8a0b4969 Port over PR to Fix Chains for 1.16 2024-10-02 20:57:10 -04:00
Axionize a2528beaf9 Merge remote-tracking branch 'origin/2.0' into simulation-changes
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/collisions/CollisionData.java
2024-10-02 20:54:23 -04:00
Axionize a3de70d498 Compact all NO_COLLISION states together 2024-10-02 20:51:44 -04:00
ManInMyVan 748eb398b8 fix a BadPacketsZ false
also use MessageUtil
2024-09-28 17:59:06 -06:00
Axionize bb08c78e8a Fix 1.11 Ascending rails hitboxes 2024-09-28 02:01:45 -04:00
Axionize 4da8ddbd12 Fix HitBox of ascending powered rail on 1.9 2024-09-28 02:01:45 -04:00
Axionize 8f89d3615b Fix HitBox of ascending powered rails on 1.7.10 2024-09-28 02:01:45 -04:00
Axionize dc7f6dca93 Make result player.getPossibleEyeHeights() of final in checks and remove unused imports 2024-09-27 23:57:23 -04:00
Axionize 472415e0d4 Removing unneeded special case handling 2024-09-26 17:13:11 -04:00
Rothes da61ff673a Fix constructor default value overriding configured value 2024-09-25 17:12:26 +08:00
Axionize 8a09be435e Remove dynamicfence; implement hashcode() function for offset hitboxes 2024-09-25 01:33:24 -04:00
Axionize 7af6cfbb3b Fix Cacti, inline lever hitboxes, fix fence handling 2024-09-25 01:29:47 -04:00
Axionize ce8aee5b8c Groundwork classes for better fence handling 2024-09-25 01:28:56 -04:00
Axionize 01ca8c894e Readability/documentation improvements 2024-09-25 00:51:22 -04:00
Axionize f724d6d78e 1.8 Players 2024-09-25 00:32:07 -04:00
Axionize ee6183db90 Handle player joining on new version -> scale changing -> old version 2024-09-25 00:32:07 -04:00
Axionize e959ef37db Optimize returned array for crawling 2024-09-25 00:32:07 -04:00
Axionize f62d8602b8 fix conditionall check 2024-09-25 00:32:07 -04:00
Axionize bf44dd6855 Only rewrite player possibleEyeHeights when player scale changes 2024-09-25 00:32:07 -04:00
Axionize 1beedd77c3 Don't bother updating scale attribute if no change is made 2024-09-23 21:14:30 -04:00
Axionize c34ad88a13 Fix intializing array 2024-09-23 21:02:33 -04:00
Axionize 619e7f1404 Simplify logic and handle caching even when scale changes 2024-09-23 21:02:33 -04:00
Axionize 927b330c4b Cache eyeHeights where possible 2024-09-22 17:30:02 -04:00
Axionize bff6854189 make getPossibleEyeHeights return most likely heights 2024-09-22 17:18:06 -04:00
Axionize 290bf9032e Backport patch 2024-09-21 20:33:30 -04:00
Axionize 2629536ad7 Optimize getPossibleEyeHeights() 2024-09-21 20:24:31 -04:00
ManInMyVan a38f341965 Add MultiInteract Checks 2024-09-19 16:11:51 -06:00
ManInMyVan 262de24cbf allow setbacks in NegativeTimer 2024-09-18 20:14:11 -06:00
Axionize 16bb09aee0 All HitBox and CollisionBox Changes made for LineOfSightPlace 2024-09-17 04:08:23 -04:00
Ruxy 330a9782bc Add full Japanese translations for all GrimAC configuration files 2024-09-17 10:31:53 +12:00
ManInMyVan f6ef1df29d exempt 1.14.2+ clients in NoSlowC and NoSlowD 2024-09-13 13:02:40 -06:00
658 changed files with 24548 additions and 10010 deletions

No files matched your search

+1 -1
View File
@@ -5,4 +5,4 @@ name = "java"
enabled = true
[analyzers.meta]
runtime_version = "16"
runtime_version = "17"
+17
View File
@@ -0,0 +1,17 @@
root = true
[*]
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = true
max_line_length = 100
tab_width = 4
# intellij specific configuration
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = false
ij_smart_tabs = false
ij_wrap_on_typing = false
+4 -4
View File
@@ -39,11 +39,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -54,7 +54,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v3
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -68,4 +68,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v3
+40 -8
View File
@@ -19,20 +19,52 @@ jobs:
packages: write
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '17'
java-version: '21'
distribution: 'temurin'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
# Temporary tasks so built jar works because PacketEvents won't merge my fixes for their broken fabric support
- name: Clone Axionize's PacketEvents Repository
run: |
git clone -b fix/fabric-events https://github.com/Axionize/packetevents.git packetevents
cd packetevents
echo "Cloned PacketEvents repository"
- name: Build and Publish PacketEvents to Maven Local
uses: gradle/actions/setup-gradle@v3
with:
build-root-directory: packetevents
arguments: publishToMavenLocal
- name: Extract Version from build.gradle.kts
id: extract-version
run: |
# Extract the version from build.gradle.kts using grep and sed
VERSION=$(grep "^version\s*=" build.gradle.kts | sed 's/version\s*=\s*"\(.*\)"/\1/')
echo "VERSION: $VERSION"
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
uses: gradle/actions/setup-gradle@v3
with:
arguments: build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v3.1.0
- name: Upload Bukkit Artifact
uses: actions/upload-artifact@v4
with:
path: /home/runner/work/Grim/Grim/build/libs/**.jar
name: grimac-bukkit
path: ${{ github.workspace }}/bukkit/build/libs/grimac-bukkit-${{ env.VERSION }}.jar
- name: Upload Fabric Artifact
uses: actions/upload-artifact@v4
with:
name: grimac-fabric
path: ${{ github.workspace }}/fabric/build/libs/grimac-fabric-${{ env.VERSION }}.jar
+7 -1
View File
@@ -65,4 +65,10 @@ nb-configuration.xml
##############################
## OS X
##############################
.DS_Store
.DS_Store
##############################
## Fabric
##############################
run/
fabric/run/
+33 -12
View File
@@ -1,27 +1,48 @@
# GrimAC
This project is considered feature complete for the 2.0 (open-source) branch of this project. If you would like a bugfix or enhancement and cannot sponsor the work, pull requests are welcome. You can join the [discord](https://discord.com/invite/kqQAhTmkUF) for jar releases & changelogs.
GrimAC is an open source Minecraft anticheat designed for 1.21 and supports 1.8-1.21. It is free while in beta. It will eventually become paid and/or will include offering additional subscription based paid checks. Geyser players are fully exempt.
### Compiling through terminal/command prompt
1. git clone https://github.com/GrimAnticheat/Grim.git (or click the green code button, download ZIP, then unzip it.)
2. cd Grim
3. gradlew build
4. The final jar is located in build/libs
This project is considered feature complete for the 2.0 (open-source) branch of this project. If you would like a bugfix or enhancement and cannot sponsor the work, pull requests are welcome.
### API Information
Grim's API allows you to integrate Grim into your own plugins. For more information, check out the API's GitHub repository [here](https://github.com/GrimAnticheat/GrimAPI).
## Downloads
- [Modrinth](https://modrinth.com/plugin/grimac)
- [Hangar](https://hangar.papermc.io/GrimAnticheat/GrimAnticheat)
- [SpigotMC](https://www.spigotmc.org/resources/grim-anticheat.99923/)
- *For bleeding edge builds use* [Github artifacts](https://nightly.link/GrimAnticheat/Grim/workflows/gradle-publish/2.0/artifact.zip)
## Installation notes
> [!WARNING]
> Java 17 is now required. More information [here](https://github.com/GrimAnticheat/Grim/wiki/Updating-to-Java-17).
- Paper, Spigot, and Folia are currently supported.
- If you use Geyser, place Floodgate on the backend server so grim can exempt bedrock players. Grim cannot access the Floodgate API if it is on the proxy.
- If you use ViaVersion, it should be on the backend server as movement is highly dependent on client version.
## Support & wiki information
- Support & discussion: [Discord](https://discord.com/invite/kqQAhTmkUF)
- Report issues: [Issues](https://github.com/GrimAnticheat/Grim/issues/new/choose)
- Wiki & examples: [Wiki](https://github.com/GrimAnticheat/Grim/wiki)
## Developer API
Grim's API allows you to integrate Grim into your own plugins.
- API repository: [GrimAPI](https://github.com/GrimAnticheat/GrimAPI)
- Wiki info: [Wiki](https://github.com/GrimAnticheat/GrimAPI)
## How to compile
1. `git clone https://github.com/GrimAnticheat/Grim.git`
2. `cd Grim`
3. `./gradlew build`
4. The final jar will compile into the build/libs folder
## Grim supremacy
Here are the main cores that make Grim stand out against other anticheats
What makes Grim stand out against other anticheats?
### Movement Simulation Engine
* We have a 1:1 replication of the player's possible movements
* This covers everything from basic walking, swimming, knockback, cobwebs, to bubble columns
* It even covers riding entities from boats to pigs to striders
* This covers everything from basic walking, swimming, knockback, cobwebs, to bubble columns
* It even covers riding entities from boats to pigs to striders
* Built upon covering edge cases to confirm accuracy
* 1.13+ clients on 1.13+ servers, 1.12- clients on 1.13+ servers, 1.13+ clients on 1.12- servers, and 1.12- clients on 1.12- servers are all supported regardless of the large technical changes between these versions.
* The order of collisions depends on the client version and is correct
+11 -152
View File
@@ -1,159 +1,18 @@
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription.Permission
plugins {
id("java")
id("maven-publish")
id("com.github.johnrengelman.shadow") version "8.1.1"
id("io.freefair.lombok") version "8.6"
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
}
group = "ac.grim.grimac"
version = "2.3.68"
version = "2.3.71"
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
// Set to false for debug builds
// You cannot live reload classes if the jar relocates dependencies
var relocate = true;
// Checks Project properties -> environment variable -> defaults true
extra["relocate"] = project.findProperty("relocate")?.toString()?.toBoolean()
?: System.getenv("RELOCATE_JAR")?.toBoolean()
?: true
repositories {
mavenLocal()
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot
maven("https://jitpack.io/") { // Grim API
content {
includeGroup("com.github.grimanticheat")
}
}
maven("https://repo.viaversion.com") // ViaVersion
maven("https://repo.aikar.co/content/groups/aikar/") // ACF
maven("https://nexus.scarsz.me/content/repositories/releases") // Configuralize
maven("https://repo.opencollab.dev/maven-snapshots/") // Floodgate
maven("https://repo.opencollab.dev/maven-releases/") // Cumulus (for Floodgate)
maven("https://repo.codemc.io/repository/maven-releases/") // PacketEvents
maven("https://repo.codemc.io/repository/maven-snapshots/")
mavenCentral()
// FastUtil, Discord-Webhooks
// Build Optimization:
// - Add parallel build support
// - Add build caching
tasks.withType<JavaCompile>().configureEach {
options.isFork = true
options.isIncremental = true
}
dependencies {
implementation("com.github.retrooper:packetevents-spigot:2.5.1-SNAPSHOT")
implementation("co.aikar:acf-paper:0.5.1-SNAPSHOT")
implementation("club.minnced:discord-webhooks:0.8.0") // Newer versions include kotlin-stdlib, which leads to incompatibility with plugins that use Kotlin
implementation("it.unimi.dsi:fastutil:8.5.13")
implementation("github.scarsz:configuralize:1.4.0")
implementation("com.github.grimanticheat:grimapi:1193c4fa41")
// Used for local testing: implementation("ac.grim.grimac:grimapi:1.0")
implementation("org.jetbrains:annotations:24.1.0")
compileOnly("org.geysermc.floodgate:api:2.0-SNAPSHOT")
compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
compileOnly("com.viaversion:viaversion-api:4.9.4-SNAPSHOT")
//
compileOnly("io.netty:netty-all:4.1.85.Final")
}
bukkit {
name = "GrimAC"
author = "GrimAC"
main = "ac.grim.grimac.GrimAC"
apiVersion = "1.13"
foliaSupported = true
softDepend = listOf(
"ProtocolLib",
"ProtocolSupport",
"Essentials",
"ViaVersion",
"ViaBackwards",
"ViaRewind",
"Geyser-Spigot",
"floodgate",
"FastLogin"
)
permissions {
register("grim.alerts") {
description = "Receive alerts for violations"
default = Permission.Default.OP
}
register("grim.alerts.enable-on-join") {
description = "Enable alerts on join"
default = Permission.Default.OP
}
register("grim.performance") {
description = "Check performance metrics"
default = Permission.Default.OP
}
register("grim.profile") {
description = "Check user profile"
default = Permission.Default.OP
}
register("grim.brand") {
description = "Show client brands on join"
default = Permission.Default.OP
}
register("grim.sendalert") {
description = "Send cheater alert"
default = Permission.Default.OP
}
register("grim.nosetback") {
description = "Disable setback"
default = Permission.Default.FALSE
}
register("grim.nomodifypacket") {
description = "Disable modifying packets"
default = Permission.Default.FALSE
}
register("grim.exempt") {
description = "Exempt from all checks"
default = Permission.Default.FALSE
}
}
}
tasks.build {
dependsOn(tasks.shadowJar)
}
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
}
publishing.publications.create<MavenPublication>("maven") {
artifact(tasks["shadowJar"])
}
tasks.shadowJar {
minimize()
archiveFileName.set("${project.name}-${project.version}.jar")
if (relocate) {
relocate("io.github.retrooper.packetevents", "ac.grim.grimac.shaded.io.github.retrooper.packetevents")
relocate("com.github.retrooper.packetevents", "ac.grim.grimac.shaded.com.github.retrooper.packetevents")
relocate("co.aikar.commands", "ac.grim.grimac.shaded.acf")
relocate("co.aikar.locale", "ac.grim.grimac.shaded.locale")
relocate("club.minnced", "ac.grim.grimac.shaded.discord-webhooks")
relocate("github.scarsz.configuralize", "ac.grim.grimac.shaded.configuralize")
relocate("com.github.puregero", "ac.grim.grimac.shaded.com.github.puregero")
relocate("com.google.code.gson", "ac.grim.grimac.shaded.gson")
relocate("alexh", "ac.grim.grimac.shaded.maps")
relocate("it.unimi.dsi.fastutil", "ac.grim.grimac.shaded.fastutil")
relocate("net.kyori", "ac.grim.grimac.shaded.kyori")
relocate("okhttp3", "ac.grim.grimac.shaded.okhttp3")
relocate("okio", "ac.grim.grimac.shaded.okio")
relocate("org.yaml.snakeyaml", "ac.grim.grimac.shaded.snakeyaml")
relocate("org.json", "ac.grim.grimac.shaded.json")
relocate("org.intellij", "ac.grim.grimac.shaded.intellij")
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
}
}
+16
View File
@@ -0,0 +1,16 @@
plugins {
`kotlin-dsl`
kotlin("plugin.serialization") version "1.9.0" // Use the same Kotlin version as your main project
}
repositories {
mavenCentral()
gradlePluginPortal()
}
dependencies {
implementation(libs.spotless)
implementation(libs.lombok)
implementation(libs.shadow)
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
}
+7
View File
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../libs.versions.toml"))
}
}
}
@@ -0,0 +1,72 @@
plugins {
`java-library`
id("io.freefair.lombok")
id("com.diffplug.spotless")
}
group = rootProject.group
version = rootProject.version
description = rootProject.description
// Java compilation settings
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
disableAutoTargetJvm()
withSourcesJar()
withJavadocJar()
}
tasks.withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
options.release.set(17)
}
// Lombok configuration
//lombok {
// version.set("1.18.30") // Use the version from your version catalog if available
//}
// Spotless configuration
spotless {
java {
endWithNewline()
indentWithSpaces(4)
removeUnusedImports()
trimTrailingWhitespace()
targetExclude("build/generated/**/*")
}
kotlinGradle {
endWithNewline()
indentWithSpaces(4)
trimTrailingWhitespace()
}
}
// Ensure spotlessApply runs before build
tasks.build {
dependsOn(tasks.named("spotlessApply"))
}
// Process resources (e.g., for plugin metadata files)
//tasks.processResources {
// inputs.property("version", project.version)
// filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json")) {
// expand("version" to project.version)
// }
//}
// Javadoc configuration
tasks.javadoc {
title = "${rootProject.name}-${project.name} v${rootProject.version}"
options.encoding = "UTF-8"
options.overview =
rootProject.file("buildSrc/src/main/resources/javadoc-overview.html").toString()
setDestinationDir(file("${project.layout.buildDirectory.asFile.get()}/docs/javadoc"))
options {
(this as CoreJavadocOptions).addBooleanOption("Xdoclint:none", true)
}
}
// Default tasks
defaultTasks("build")
@@ -0,0 +1,391 @@
import kotlinx.serialization.json.*
import java.util.jar.JarFile
import java.util.zip.ZipEntry
plugins {
`java-library`
}
val jijDependencies: Configuration by project.configurations.creating {
isCanBeResolved = true
isCanBeConsumed = false
extendsFrom(project.configurations.getByName("implementation"))
project.configurations.findByName("modImplementation")?.let { extendsFrom(it) }
}
data class DependencyIdentifier(
val group: String,
val name: String,
val version: String,
val classifier: String = "" // Add classifier field, default to empty string
) {
override fun toString() = "$group:$name:$version${if (classifier.isNotEmpty()) ":$classifier" else ""}"
}
// Does not support extracting classifiers but while the fabric standard is ambiguous on whether they can be included
// It does not appear dependency classifiers are in use by any mod I am aware of or can find
fun parseFabricModJson(jarFile: File, project: Project): Set<DependencyIdentifier> {
val nestedJars = mutableSetOf<DependencyIdentifier>()
try {
JarFile(jarFile).use { jar ->
val fabricModJsonEntry: ZipEntry? = jar.getEntry("fabric.mod.json")
if (fabricModJsonEntry != null) {
jar.getInputStream(fabricModJsonEntry).bufferedReader().use { reader ->
val jsonContent = reader.readText()
val jsonElement = Json.parseToJsonElement(jsonContent)
val jsonObject = jsonElement.jsonObject
val jarsArray = jsonObject["jars"]?.jsonArray ?: return@use
jarsArray.forEach { jarEntry: JsonElement ->
val filePath =
jarEntry.jsonObject["file"]?.jsonPrimitive?.content ?: return@forEach
project.logger.debug(
"Found nested JAR in fabric.mod.json: {} in {}",
filePath,
jarFile
)
val jarName = filePath.substringAfterLast("/")
val parts = jarName.removeSuffix(".jar").split("-")
if (parts.size >= 2) {
val inferredName = parts.dropLast(1).joinToString("-")
val inferredVersion = parts.last()
nestedJars.add(DependencyIdentifier("", inferredName, inferredVersion))
project.logger.debug("Inferred nested dependency from fabric.mod.json: :$inferredName:$inferredVersion")
}
}
}
}
}
} catch (e: Exception) {
project.logger.error("Failed to parse fabric.mod.json in $jarFile: ${e.message}")
}
return nestedJars
}
fun extractEmbeddedJars(jarFile: File, project: Project): Set<DependencyIdentifier> {
val embeddedJars = mutableSetOf<DependencyIdentifier>()
embeddedJars.addAll(parseFabricModJson(jarFile, project))
try {
JarFile(jarFile).use { jar ->
val entries = jar.entries()
while (entries.hasMoreElements()) {
val entry = entries.nextElement()
val entryName = entry.name
if (entryName.endsWith(".jar") && (entryName.startsWith("META-INF/jarjar/") || entryName.startsWith(
"libs/"
) || entryName.startsWith("META-INF/jars/"))
) {
project.logger.debug("Found embedded JAR: {} in {}", entryName, jarFile)
val tempFile = File.createTempFile("embedded-", ".jar")
tempFile.deleteOnExit()
jar.getInputStream(entry).use { input ->
tempFile.outputStream().use { output ->
input.copyTo(output)
}
}
JarFile(tempFile).use { embeddedJar ->
val manifest = embeddedJar.manifest
if (manifest != null) {
val group =
manifest.mainAttributes.getValue("Implementation-Vendor") ?: ""
val name = manifest.mainAttributes.getValue("Implementation-Title")
?: embeddedJar.name
val version =
manifest.mainAttributes.getValue("Implementation-Version") ?: ""
if (group.isNotEmpty() && name.isNotEmpty() && version.isNotEmpty()) {
embeddedJars.add(DependencyIdentifier(group, name, version))
project.logger.debug("Identified embedded dependency: $group:$name:$version")
} else {
val jarName = entryName.substringAfterLast("/")
val parts = jarName.removeSuffix(".jar").split("-")
if (parts.size >= 2) {
val inferredName = parts.dropLast(1).joinToString("-")
val inferredVersion = parts.last()
embeddedJars.add(
DependencyIdentifier(
"",
inferredName,
inferredVersion
)
)
project.logger.debug("Inferred embedded dependency from filename: :$inferredName:$inferredVersion")
}
}
}
}
}
}
}
} catch (e: Exception) {
project.logger.error("Failed to analyze JAR file $jarFile for embedded JARs: ${e.message}")
}
return embeddedJars
}
fun shouldExcludeDependency(
dependency: ResolvedDependency,
allEmbeddedDependencies: Set<DependencyIdentifier>,
actuallyIncludedDependencies: Set<DependencyIdentifier>,
project: Project
): Boolean {
val group = dependency.moduleGroup
val name = dependency.moduleName
val version = dependency.moduleVersion
// Extract classifier from resolved dependency (if available)
val classifier = dependency.moduleArtifacts.firstOrNull()?.classifier ?: ""
val depId = DependencyIdentifier(group, name, version, classifier)
if (group.startsWith("net.minecraft") ||
group.startsWith("net.fabricmc") ||
name == "minecraft" ||
name == "fabric-loader" ||
name == "fastutil" ||
name.startsWith("fabric_") ||
name.startsWith("fabric-api")
) {
project.logger.debug("Excluding platform dependency: {}", depId)
return true
}
if (name.endsWith("-bom") || name.contains("_bom")) {
project.logger.debug("Excluding BOM file: {}", depId)
return true
}
if (allEmbeddedDependencies.any { it.name == name && it.version == version && it.classifier == classifier }) {
project.logger.debug("Excluding dependency already embedded in another JAR: {}", depId)
return true
}
if (actuallyIncludedDependencies.any { it.name == name && it.version == version && it.classifier == classifier }) {
project.logger.debug("Excluding duplicate dependency: {}", depId)
return true
}
return false
}
fun isJijTarget(
dependency: ResolvedDependency,
allEmbeddedDependencies: Set<DependencyIdentifier>,
actuallyIncludedDependencies: Set<DependencyIdentifier>,
project: Project
): Boolean {
val classifier = dependency.moduleArtifacts.firstOrNull()?.classifier ?: ""
project.logger.debug(
"Checking JIJ target: {}",
DependencyIdentifier(
dependency.moduleGroup,
dependency.moduleName,
dependency.moduleVersion,
classifier
)
)
return !shouldExcludeDependency(
dependency,
allEmbeddedDependencies,
actuallyIncludedDependencies,
project
)
}
fun includeDependencyWithExclusions(
depId: DependencyIdentifier,
project: Project,
actuallyIncludedDependencies: MutableSet<DependencyIdentifier>,
allEmbeddedDependencies: Set<DependencyIdentifier>
) {
project.logger.debug("Including external dependency as JIJ with dynamic exclusions: {}", depId)
project.dependencies {
// Include dependency with classifier (if present)
"include"("${depId.group}:${depId.name}:${depId.version}${if (depId.classifier.isNotEmpty()) ":${depId.classifier}" else ""}") {
allEmbeddedDependencies.forEach { embeddedDep ->
if (embeddedDep.group.isNotEmpty()) {
exclude(group = embeddedDep.group, module = embeddedDep.name)
} else {
exclude(module = embeddedDep.name)
}
project.logger.debug("Excluding embedded transitive dependency: ${embeddedDep.name}:${embeddedDep.version}${if (embeddedDep.classifier.isNotEmpty()) ":${embeddedDep.classifier}" else ""}")
}
}
}
actuallyIncludedDependencies.add(depId)
}
fun processDependencies(
dependencies: Set<ResolvedDependency>,
processed: MutableSet<String>,
allEmbeddedDependencies: MutableMap<DependencyIdentifier, File>,
actuallyIncludedDependencies: MutableSet<DependencyIdentifier>,
project: Project
) {
dependencies.forEach { dep: ResolvedDependency ->
val classifier = dep.moduleArtifacts.firstOrNull()?.classifier ?: ""
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}${if (classifier.isNotEmpty()) ":$classifier" else ""}"
val depId = DependencyIdentifier(dep.moduleGroup, dep.moduleName, dep.moduleVersion, classifier)
if (!processed.contains(depKey)) {
processed.add(depKey)
project.logger.debug("Resolved dependency: {}", depId)
val jarFile = dep.moduleArtifacts.firstOrNull()?.file
if (jarFile != null && jarFile.exists()) {
val embeddedJars = extractEmbeddedJars(jarFile, project)
embeddedJars.forEach { embeddedDep ->
allEmbeddedDependencies[embeddedDep] = jarFile
}
}
if (isJijTarget(
dep,
allEmbeddedDependencies.keys,
actuallyIncludedDependencies,
project
)
) {
project.logger.debug("Processing JIJ dependency: {}", depId)
val isProjectDependency = project.rootProject.allprojects.any { subproject ->
subproject.name == dep.moduleName && (subproject.group == dep.moduleGroup || dep.moduleGroup.isEmpty())
}
if (isProjectDependency) {
val projectPath = project.rootProject.allprojects.find { subproject ->
subproject.name == dep.moduleName && (subproject.group == dep.moduleGroup || dep.moduleGroup.isEmpty())
}?.path
?: throw IllegalStateException("Project dependency not found: ${dep.moduleName}")
project.logger.debug("Including project dependency as JIJ: $projectPath")
project.dependencies {
"include"(project.project(projectPath))
}
actuallyIncludedDependencies.add(depId)
} else {
includeDependencyWithExclusions(
depId,
project,
actuallyIncludedDependencies,
allEmbeddedDependencies.keys
)
}
}
processDependencies(
dep.children,
processed,
allEmbeddedDependencies,
actuallyIncludedDependencies,
project
)
}
}
}
project.afterEvaluate {
project.logger.debug("Resolving jijDependencies configuration")
val resolvedDependencies = jijDependencies.resolvedConfiguration.firstLevelModuleDependencies
val processed = mutableSetOf<String>()
val allEmbeddedDependencies = mutableMapOf<DependencyIdentifier, File>()
val actuallyIncludedDependencies = mutableSetOf<DependencyIdentifier>()
fun collectAllEmbeddedDependencies(dependencies: Set<ResolvedDependency>) {
dependencies.forEach { dep ->
val classifier = dep.moduleArtifacts.firstOrNull()?.classifier ?: ""
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}${if (classifier.isNotEmpty()) ":$classifier" else ""}"
if (!processed.contains(depKey)) {
processed.add(depKey)
val jarFile = dep.moduleArtifacts.firstOrNull()?.file
if (jarFile != null && jarFile.exists()) {
val embeddedJars = extractEmbeddedJars(jarFile, project)
embeddedJars.forEach { embeddedDep ->
allEmbeddedDependencies[embeddedDep] = jarFile
project.logger.debug(
"Collected embedded dependency: {} from {}",
embeddedDep,
jarFile
)
}
}
collectAllEmbeddedDependencies(dep.children)
}
}
}
processed.clear()
collectAllEmbeddedDependencies(resolvedDependencies)
processed.clear()
processDependencies(
resolvedDependencies,
processed,
allEmbeddedDependencies,
actuallyIncludedDependencies,
project
)
}
tasks.withType<Jar>().configureEach {
doFirst {
project.logger.debug("Resolving JIJ dependencies for JAR inclusion")
val resolvedDependencies =
jijDependencies.resolvedConfiguration.firstLevelModuleDependencies
val processed = mutableSetOf<String>()
val allEmbeddedDependencies = mutableMapOf<DependencyIdentifier, File>()
val actuallyIncludedDependencies = mutableSetOf<DependencyIdentifier>()
fun collectAllEmbeddedDependencies(dependencies: Set<ResolvedDependency>) {
dependencies.forEach { dep ->
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}"
if (!processed.contains(depKey)) {
processed.add(depKey)
val jarFile = dep.moduleArtifacts.firstOrNull()?.file
if (jarFile != null && jarFile.exists()) {
val embeddedJars = extractEmbeddedJars(jarFile, project)
embeddedJars.forEach { embeddedDep ->
allEmbeddedDependencies[embeddedDep] = jarFile
project.logger.debug(
"Collected embedded dependency for JAR: {} from {}",
embeddedDep,
jarFile
)
}
}
collectAllEmbeddedDependencies(dep.children)
}
}
}
processed.clear()
collectAllEmbeddedDependencies(resolvedDependencies)
processed.clear()
fun logDependencies(dependencies: Set<ResolvedDependency>) {
dependencies.forEach { dep ->
val depKey = "${dep.moduleGroup}:${dep.moduleName}:${dep.moduleVersion}"
val depId = DependencyIdentifier(dep.moduleGroup, dep.moduleName, dep.moduleVersion)
if (!processed.contains(depKey)) {
processed.add(depKey)
project.logger.debug("Resolved JIJ dependency for JAR: {}", depId)
val jarFile = dep.moduleArtifacts.firstOrNull()?.file
if (jarFile != null && jarFile.exists()) {
val embeddedJars = extractEmbeddedJars(jarFile, project)
embeddedJars.forEach { embeddedDep ->
allEmbeddedDependencies[embeddedDep] = jarFile
}
}
if (isJijTarget(
dep,
allEmbeddedDependencies.keys,
actuallyIncludedDependencies,
project
)
) {
project.logger.debug("Including JIJ dependency in JAR: {}", depId)
actuallyIncludedDependencies.add(depId)
}
logDependencies(dep.children)
}
}
}
logDependencies(resolvedDependencies)
}
}
@@ -0,0 +1,52 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
id("com.gradleup.shadow")
}
val relocate: Boolean by rootProject.extra
// Create a configuration for shading dependencies from common
val shadowCommon: Configuration by project.configurations.creating {
isCanBeResolved = true
isCanBeConsumed = false
extendsFrom(project.configurations.getByName("implementation"))
}
tasks.named<ShadowJar>("shadowJar") {
minimize()
archiveFileName.set("${rootProject.name}-${project.name}-${rootProject.version}.jar")
from(shadowCommon) // Use from() instead of direct assignment
if (relocate) {
relocate(
"io.github.retrooper.packetevents",
"ac.grim.grimac.shaded.io.github.retrooper.packetevents"
)
relocate(
"com.github.retrooper.packetevents",
"ac.grim.grimac.shaded.com.github.retrooper.packetevents"
)
relocate("club.minnced", "ac.grim.grimac.shaded.discord-webhooks")
relocate("org.slf4j", "ac.grim.grimac.shaded.slf4j") // Required by discord-webhooks
relocate("github.scarsz.configuralize", "ac.grim.grimac.shaded.configuralize")
relocate("com.github.puregero", "ac.grim.grimac.shaded.com.github.puregero")
relocate("com.google.code.gson", "ac.grim.grimac.shaded.gson")
relocate("alexh", "ac.grim.grimac.shaded.maps")
relocate("it.unimi.dsi.fastutil", "ac.grim.grimac.shaded.fastutil")
relocate("net.kyori", "ac.grim.grimac.shaded.kyori")
relocate("okhttp3", "ac.grim.grimac.shaded.okhttp3")
relocate("okio", "ac.grim.grimac.shaded.okio")
relocate("org.yaml.snakeyaml", "ac.grim.grimac.shaded.snakeyaml")
relocate("org.json", "ac.grim.grimac.shaded.json")
relocate("org.intellij", "ac.grim.grimac.shaded.intellij")
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
relocate("org.incendo", "ac.grim.grimac.shaded.incendo")
relocate("io.leangen.geantyref", "ac.grim.grimac.shaded.geantyref") // Required by cloud
}
mergeServiceFiles()
}
tasks.named("assemble") {
dependsOn(tasks.named("shadowJar"))
}
+139
View File
@@ -0,0 +1,139 @@
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription.Permission
plugins {
`maven-publish`
grim.`base-conventions`
grim.`shadow-conventions`
id("net.minecrell.plugin-yml.bukkit") version "0.6.0"
}
repositories {
mavenLocal()
maven {
name = "papermc"
url = uri("https://repo.papermc.io/repository/maven-public/")
}
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot
maven("https://jitpack.io/") { // Grim API
content {
includeGroup("com.github.grimanticheat")
}
}
maven("https://repo.viaversion.com") // ViaVersion
maven("https://nexus.scarsz.me/content/repositories/releases") // Configuralize
maven("https://repo.opencollab.dev/maven-snapshots/") // Floodgate
maven("https://repo.opencollab.dev/maven-releases/") // Cumulus (for Floodgate)
maven("https://repo.codemc.io/repository/maven-releases/") // PacketEvents
maven("https://repo.codemc.io/repository/maven-snapshots/")
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // placeholderapi
mavenCentral()
// FastUtil, Discord-Webhooks
}
dependencies {
compileOnly(libs.paper.api)
compileOnly(libs.placeholderapi)
implementation(libs.packetevents.spigot)
implementation(libs.cloud.paper)
implementation(libs.adventure.platform.bukkit)
implementation(project(":common"))
shadow(project(":common"))
}
bukkit {
name = "GrimAC"
author = "GrimAC"
main = "ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin"
website = "https://grim.ac/"
apiVersion = "1.13"
foliaSupported = true
softDepend = listOf(
"ProtocolLib",
"ProtocolSupport",
"Essentials",
"ViaVersion",
"ViaBackwards",
"ViaRewind",
"Geyser-Spigot",
"floodgate",
"FastLogin",
"PlaceholderAPI",
)
permissions {
register("grim.alerts") {
description = "Receive alerts for violations"
default = Permission.Default.OP
}
register("grim.alerts.enable-on-join") {
description = "Enable alerts on join"
default = Permission.Default.OP
}
register("grim.performance") {
description = "Check performance metrics"
default = Permission.Default.OP
}
register("grim.profile") {
description = "Check user profile"
default = Permission.Default.OP
}
register("grim.brand") {
description = "Show client brands on join"
default = Permission.Default.OP
}
register("grim.brand.enable-on-join") {
description = "Enable showing client brands on join"
default = Permission.Default.OP
}
register("grim.sendalert") {
description = "Send cheater alert"
default = Permission.Default.OP
}
register("grim.nosetback") {
description = "Disable setback"
default = Permission.Default.FALSE
}
register("grim.nomodifypacket") {
description = "Disable modifying packets"
default = Permission.Default.FALSE
}
register("grim.exempt") {
description = "Exempt from all checks"
default = Permission.Default.FALSE
}
register("grim.verbose") {
description = "Receive verbose alerts for violations. Requires grim.alerts"
default = Permission.Default.OP
}
register("grim.verbose.enable-on-join") {
description =
"Enable verbose alerts on join. Requires grim.alerts and grim.alerts.enable-on-join"
default = Permission.Default.FALSE
}
}
}
publishing.publications.create<MavenPublication>("maven") {
artifact(tasks["shadowJar"])
}
tasks.shadowJar {
manifest {
attributes["paperweight-mappings-namespace"] = "mojang"
}
}
@@ -0,0 +1,27 @@
package ac.grim.grimac.platform.bukkit;
import ac.grim.grimac.platform.api.PlatformPlugin;
import org.bukkit.plugin.Plugin;
public class BukkitPlatformPlugin implements PlatformPlugin {
private final Plugin plugin;
public BukkitPlatformPlugin(Plugin plugin) {
this.plugin = plugin;
}
@Override
public boolean isEnabled() {
return plugin.isEnabled();
}
@Override
public String getName() {
return plugin.getName();
}
@Override
public String getVersion() {
return plugin.getDescription().getVersion();
}
}
@@ -0,0 +1,37 @@
package ac.grim.grimac.platform.bukkit;
import ac.grim.grimac.platform.api.PlatformServer;
import ac.grim.grimac.platform.api.sender.Sender;
import io.github.retrooper.packetevents.util.SpigotReflectionUtil;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
public class BukkitPlatformServer implements PlatformServer {
@Override
public String getPlatformImplementationString() {
return Bukkit.getVersion();
}
@Override
public void dispatchCommand(Sender sender, String command) {
CommandSender commandSender = GrimACBukkitLoaderPlugin.LOADER.getBukkitSenderFactory().reverse(sender);
Bukkit.dispatchCommand(commandSender, command);
}
@Override
public Sender getConsoleSender() {
return GrimACBukkitLoaderPlugin.LOADER.getBukkitSenderFactory().map(Bukkit.getConsoleSender());
}
@Override
public void registerOutgoingPluginChannel(String bungeeCord) {
GrimACBukkitLoaderPlugin.LOADER.getServer().getMessenger().registerOutgoingPluginChannel(GrimACBukkitLoaderPlugin.LOADER, "BungeeCord");
}
@Override
public double getTPS() {
return SpigotReflectionUtil.getTPS();
}
}
@@ -0,0 +1,195 @@
package ac.grim.grimac.platform.bukkit;
import ac.grim.grimac.api.plugin.BasicGrimPlugin;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.GrimAPIProvider;
import ac.grim.grimac.api.GrimAbstractAPI;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.manager.init.Initable;
import ac.grim.grimac.manager.init.start.ExemptOnlinePlayersOnReload;
import ac.grim.grimac.manager.init.start.StartableInitable;
import ac.grim.grimac.platform.api.Platform;
import ac.grim.grimac.platform.api.PlatformLoader;
import ac.grim.grimac.platform.api.PlatformServer;
import ac.grim.grimac.platform.api.manager.ItemResetHandler;
import ac.grim.grimac.platform.api.manager.MessagePlaceHolderManager;
import ac.grim.grimac.platform.api.manager.ParserDescriptorFactory;
import ac.grim.grimac.platform.api.manager.PermissionRegistrationManager;
import ac.grim.grimac.platform.api.manager.PlatformPluginManager;
import ac.grim.grimac.platform.api.player.PlatformPlayerFactory;
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.api.sender.SenderFactory;
import ac.grim.grimac.platform.bukkit.initables.BukkitBStats;
import ac.grim.grimac.platform.bukkit.initables.BukkitEventManager;
import ac.grim.grimac.platform.bukkit.initables.BukkitTickEndEvent;
import ac.grim.grimac.platform.bukkit.manager.BukkitItemResetHandler;
import ac.grim.grimac.platform.bukkit.manager.BukkitMessagePlaceHolderManager;
import ac.grim.grimac.platform.bukkit.manager.BukkitParserDescriptorFactory;
import ac.grim.grimac.platform.bukkit.manager.BukkitPermissionRegistrationManager;
import ac.grim.grimac.platform.bukkit.manager.BukkitPlatformPluginManager;
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayerFactory;
import ac.grim.grimac.platform.bukkit.scheduler.bukkit.BukkitPlatformScheduler;
import ac.grim.grimac.platform.bukkit.scheduler.folia.FoliaPlatformScheduler;
import ac.grim.grimac.platform.bukkit.sender.BukkitSenderFactory;
import ac.grim.grimac.platform.bukkit.utils.placeholder.PlaceholderAPIExpansion;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import ac.grim.grimac.utils.lazy.LazyHolder;
import com.github.retrooper.packetevents.PacketEventsAPI;
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
import org.incendo.cloud.execution.ExecutionCoordinator;
import org.incendo.cloud.paper.LegacyPaperCommandManager;
import org.jetbrains.annotations.NotNull;
public final class GrimACBukkitLoaderPlugin extends JavaPlugin implements PlatformLoader {
public static GrimACBukkitLoaderPlugin LOADER;
private final LazyHolder<PlatformScheduler> scheduler = LazyHolder.simple(this::createScheduler);
private final LazyHolder<PacketEventsAPI<?>> packetEvents = LazyHolder.simple(() -> SpigotPacketEventsBuilder.build(this));
private final LazyHolder<BukkitSenderFactory> senderFactory = LazyHolder.simple(BukkitSenderFactory::new);
private final LazyHolder<CommandManager<Sender>> commandManager = LazyHolder.simple(this::createCommandManager);
private final LazyHolder<ItemResetHandler> itemResetHandler = LazyHolder.simple(BukkitItemResetHandler::new);
private final PlatformPlayerFactory playerFactory = new BukkitPlatformPlayerFactory();
private final ParserDescriptorFactory parserFactory = new BukkitParserDescriptorFactory();
private final PlatformPluginManager platformPluginManager = new BukkitPlatformPluginManager();
private final GrimPlugin plugin;
private final PlatformServer platformServer = new BukkitPlatformServer();
private final MessagePlaceHolderManager messagePlaceHolderManager = new BukkitMessagePlaceHolderManager();
private final BukkitPermissionRegistrationManager bukkitPermissionRegistrationManager = new BukkitPermissionRegistrationManager();
public GrimACBukkitLoaderPlugin() {
this.plugin = new BasicGrimPlugin(
this.getLogger(),
this.getDataFolder(),
this.getDescription().getVersion(),
this.getDescription().getDescription(),
this.getDescription().getAuthors()
);
}
@Override
public void onLoad() {
LOADER = this;
GrimAPI.INSTANCE.load(this, this.getBukkitInitTasks());
}
private Initable[] getBukkitInitTasks() {
return new Initable[]{
new ExemptOnlinePlayersOnReload(),
new BukkitEventManager(),
new BukkitTickEndEvent(),
new BukkitBStats(),
(StartableInitable) () -> {
if (MessageUtil.hasPlaceholderAPI) {
new PlaceholderAPIExpansion().register();
}
}
};
}
@Override
public void onEnable() {
GrimAPI.INSTANCE.start();
}
@Override
public void onDisable() {
GrimAPI.INSTANCE.stop();
}
@Override
public PlatformScheduler getScheduler() {
return scheduler.get();
}
@Override
public PlatformPlayerFactory getPlatformPlayerFactory() {
return playerFactory;
}
@Override
public ParserDescriptorFactory getParserDescriptorFactory() {
return parserFactory;
}
@Override
public PacketEventsAPI<?> getPacketEvents() {
return packetEvents.get();
}
@Override
public CommandManager<Sender> getCommandManager() {
return commandManager.get();
}
@Override
public ItemResetHandler getItemResetHandler() {
return itemResetHandler.get();
}
@Override
public SenderFactory<CommandSender> getSenderFactory() {
return senderFactory.get();
}
@Override
public GrimPlugin getPlugin() {
return plugin;
}
@Override
public PlatformPluginManager getPluginManager() {
return platformPluginManager;
}
@Override
public PlatformServer getPlatformServer() {
return platformServer;
}
@Override
public void registerAPIService() {
GrimAPIProvider.init(GrimAPI.INSTANCE.getExternalAPI());
Bukkit.getServicesManager().register(GrimAbstractAPI.class, GrimAPI.INSTANCE.getExternalAPI(), GrimACBukkitLoaderPlugin.LOADER, ServicePriority.Normal);
}
@Override
public @NotNull MessagePlaceHolderManager getMessagePlaceHolderManager() {
return messagePlaceHolderManager;
}
@Override
public PermissionRegistrationManager getPermissionManager() {
return bukkitPermissionRegistrationManager;
}
private PlatformScheduler createScheduler() {
return GrimAPI.INSTANCE.getPlatform() == Platform.FOLIA ? new FoliaPlatformScheduler() : new BukkitPlatformScheduler();
}
private CommandManager<Sender> createCommandManager() {
LegacyPaperCommandManager<Sender> manager = new LegacyPaperCommandManager<>(
this,
ExecutionCoordinator.simpleCoordinator(),
senderFactory.get()
);
if (manager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
manager.registerBrigadier();
} else if (manager.hasCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) {
manager.registerAsynchronousCompletions();
}
return manager;
}
public BukkitSenderFactory getBukkitSenderFactory() {
return LOADER.senderFactory.get();
}
}
@@ -0,0 +1,37 @@
package ac.grim.grimac.platform.bukkit.command;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.platform.api.command.PlayerSelector;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.bukkit.sender.BukkitSenderFactory;
import java.util.Collection;
import java.util.Collections;
public class BukkitPlayerSelectorAdapter implements PlayerSelector {
private final org.incendo.cloud.bukkit.data.SinglePlayerSelector bukkitSelector;
public BukkitPlayerSelectorAdapter(org.incendo.cloud.bukkit.data.SinglePlayerSelector bukkitSelector) {
this.bukkitSelector = bukkitSelector;
}
@Override
public boolean isSingle() {
return true;
}
@Override
public Sender getSinglePlayer() {
return ((BukkitSenderFactory) GrimAPI.INSTANCE.getSenderFactory()).map(bukkitSelector.single());
}
@Override
public Collection<Sender> getPlayers() {
return Collections.singletonList(((BukkitSenderFactory) GrimAPI.INSTANCE.getSenderFactory()).map(bukkitSelector.single()));
}
@Override
public String inputString() {
return bukkitSelector.inputString();
}
}
@@ -0,0 +1,28 @@
package ac.grim.grimac.platform.bukkit.command;
import ac.grim.grimac.platform.api.command.AbstractPlayerSelectorParser;
import ac.grim.grimac.platform.api.command.PlayerSelector;
import org.incendo.cloud.bukkit.parser.selector.SinglePlayerSelectorParser;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.parser.ParserDescriptor;
import java.util.concurrent.CompletableFuture;
public class BukkitPlayerSelectorParser<C> extends AbstractPlayerSelectorParser<C> {
@Override
public ParserDescriptor<C, PlayerSelector> descriptor() {
return super.createDescriptor();
}
@Override
protected ParserDescriptor<C, ?> getPlatformSpecificDescriptor() {
return SinglePlayerSelectorParser.singlePlayerSelectorParser();
}
@Override
protected CompletableFuture<PlayerSelector> adaptToCommonSelector(CommandContext<C> context, Object platformSpecificSelector) {
return CompletableFuture.completedFuture(new BukkitPlayerSelectorAdapter((org.incendo.cloud.bukkit.data.SinglePlayerSelector) platformSpecificSelector));
}
}
@@ -0,0 +1,79 @@
package ac.grim.grimac.platform.bukkit.entity;
import ac.grim.grimac.platform.api.entity.GrimEntity;
import ac.grim.grimac.platform.api.world.PlatformWorld;
import ac.grim.grimac.platform.bukkit.utils.convert.BukkitConversionUtils;
import ac.grim.grimac.platform.bukkit.utils.reflection.PaperUtils;
import ac.grim.grimac.platform.bukkit.world.BukkitPlatformWorld;
import ac.grim.grimac.utils.math.Location;
import com.google.common.base.Preconditions;
import org.bukkit.entity.Entity;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class BukkitGrimEntity implements GrimEntity {
private final Entity entity;
private BukkitPlatformWorld bukkitPlatformWorld;
public BukkitGrimEntity(Entity entity) {
Preconditions.checkArgument(entity != null);
this.entity = entity;
}
public Entity getBukkitEntity() {
return this.entity;
}
@Override
public UUID getUniqueId() {
return entity.getUniqueId();
}
@Override
public boolean eject() {
return entity.eject();
}
@Override
public CompletableFuture<Boolean> teleportAsync(Location location) {
org.bukkit.Location bLoc = BukkitConversionUtils.toBukkitLocation(location);
return PaperUtils.teleportAsync(this.entity, bLoc);
}
@Override
@NonNull
public Entity getNative() {
return entity;
}
@Override
public boolean isDead() {
return this.entity.isDead();
}
// TODO replace with PlayerWorldChangeEvent listener instead of checking for equality for better performance
@Override
public PlatformWorld getWorld() {
if (bukkitPlatformWorld == null || !bukkitPlatformWorld.getBukkitWorld().equals(entity.getWorld())) {
bukkitPlatformWorld = new BukkitPlatformWorld(entity.getWorld());
}
return bukkitPlatformWorld;
}
@Override
public Location getLocation() {
org.bukkit.Location location = this.entity.getLocation();
return new Location(
this.getWorld(),
location.getX(),
location.getY(),
location.getZ(),
location.getYaw(),
location.getPitch()
);
}
}
@@ -1,8 +1,8 @@
package ac.grim.grimac.events.bukkit;
package ac.grim.grimac.platform.bukkit.events;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.platform.bukkit.utils.blockstate.BukkitBlockFaceHelper;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.blockstate.helper.BlockFaceHelper;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.PistonData;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
@@ -57,7 +57,7 @@ public class PistonEvent implements Listener {
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
if (player.compensatedWorld.isChunkLoaded(event.getBlock().getX() >> 4, event.getBlock().getZ() >> 4)) {
PistonData data = new PistonData(BlockFaceHelper.fromBukkitFace(event.getDirection()), boxes, player.lastTransactionSent.get(), true, hasSlimeBlock, hasHoneyBlock);
PistonData data = new PistonData(BukkitBlockFaceHelper.fromBukkitFace(event.getDirection()), boxes, player.lastTransactionSent.get(), true, hasSlimeBlock, hasHoneyBlock);
player.latencyUtils.addRealTimeTaskAsync(player.lastTransactionSent.get(), () -> player.compensatedWorld.activePistons.add(data));
}
}
@@ -79,7 +79,7 @@ public class PistonEvent implements Listener {
boolean hasHoneyBlock = false;
List<SimpleCollisionBox> boxes = new ArrayList<>();
BlockFace face = BlockFaceHelper.fromBukkitFace(event.getDirection());
BlockFace face = BukkitBlockFaceHelper.fromBukkitFace(event.getDirection());
// The event was called without blocks and is therefore in the right direction
if (event.getBlocks().isEmpty()) {
@@ -110,7 +110,7 @@ public class PistonEvent implements Listener {
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
if (player.compensatedWorld.isChunkLoaded(event.getBlock().getX() >> 4, event.getBlock().getZ() >> 4)) {
PistonData data = new PistonData(BlockFaceHelper.fromBukkitFace(event.getDirection()), boxes, player.lastTransactionSent.get(), false, hasSlimeBlock, hasHoneyBlock);
PistonData data = new PistonData(BukkitBlockFaceHelper.fromBukkitFace(event.getDirection()), boxes, player.lastTransactionSent.get(), false, hasSlimeBlock, hasHoneyBlock);
player.latencyUtils.addRealTimeTaskAsync(player.lastTransactionSent.get(), () -> player.compensatedWorld.activePistons.add(data));
}
}
@@ -0,0 +1,16 @@
package ac.grim.grimac.platform.bukkit.initables;
import ac.grim.grimac.manager.init.start.StartableInitable;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import io.github.retrooper.packetevents.bstats.bukkit.Metrics;
public class BukkitBStats implements StartableInitable {
@Override
public void start() {
int pluginId = 12820; // <-- Replace with the id of your plugin!
try {
new Metrics(GrimACBukkitLoaderPlugin.LOADER, pluginId);
} catch (Exception ignored) {
}
}
}
@@ -0,0 +1,15 @@
package ac.grim.grimac.platform.bukkit.initables;
import ac.grim.grimac.manager.init.start.StartableInitable;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import ac.grim.grimac.platform.bukkit.events.PistonEvent;
import ac.grim.grimac.utils.anticheat.LogUtil;
import org.bukkit.Bukkit;
public class BukkitEventManager implements StartableInitable {
public void start() {
LogUtil.info("Registering singular bukkit event... (PistonEvent)");
Bukkit.getPluginManager().registerEvents(new PistonEvent(), GrimACBukkitLoaderPlugin.LOADER);
}
}
@@ -0,0 +1,94 @@
package ac.grim.grimac.platform.bukkit.initables;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.manager.init.start.AbstractTickEndEvent;
import ac.grim.grimac.platform.api.Platform;
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayer;
import ac.grim.grimac.platform.bukkit.utils.reflection.PaperUtils;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.lists.HookedListWrapper;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.util.reflection.Reflection;
import io.github.retrooper.packetevents.util.SpigotReflectionUtil;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;
// Copied from: https://github.com/ThomasOM/Pledge/blob/master/src/main/java/dev/thomazz/pledge/inject/ServerInjector.java
@SuppressWarnings(value = {"unchecked", "deprecated"})
public class BukkitTickEndEvent extends AbstractTickEndEvent implements Listener {
@Override
public void start() {
if (!super.shouldInjectEndTick()) {
return;
}
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_11_2) && !Boolean.getBoolean("paper.explicit-flush")) {
LogUtil.warn("Reach.enable-post-packet=true but paper.explicit-flush=false, add \"-Dpaper.explicit-flush=true\" to your server's startup flags for fully functional extra reach accuracy.");
}
// this is necessary for folia
if (GrimAPI.INSTANCE.getPlatform() == Platform.FOLIA) {
PaperUtils.registerTickEndEvent(this, this::tickAllFoliaPlayers);
return;
}
// if it fails to inject, try to use paper's event
if (!injectWithReflection() && !PaperUtils.registerTickEndEvent(this, this::tickAllPlayers)) {
LogUtil.error("Failed to inject into the end of tick event!");
}
}
private void tickAllPlayers() {
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
if (player.disableGrim) continue;
super.onEndOfTick(player);
}
}
private void tickAllFoliaPlayers() {
for (GrimPlayer player : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
if (player.disableGrim) continue;
if (player.platformPlayer == null) continue;
Player p = ((BukkitPlatformPlayer) player.platformPlayer).getNative();
if (!Bukkit.isOwnedByCurrentRegion(p)) continue;
super.onEndOfTick(player);
}
}
private boolean injectWithReflection() {
// Inject so we can add the final transaction pre-flush event
try {
Object connection = SpigotReflectionUtil.getMinecraftServerConnectionInstance();
Field connectionsList = Reflection.getField(connection.getClass(), List.class, 1);
List<Object> endOfTickObject = (List<Object>) connectionsList.get(connection);
// Use a list wrapper to check when the size method is called
// Unsure why synchronized is needed because the object itself gets synchronized
// but whatever. At least plugins can't break it, I guess.
//
// Pledge injects into another list, so we should be safe injecting into this one
List<?> wrapper = Collections.synchronizedList(new HookedListWrapper<>(endOfTickObject) {
@Override
public void onIterator() {
tickAllPlayers();
}
});
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
unsafe.putObject(connection, unsafe.objectFieldOffset(connectionsList), wrapper);
} catch (NoSuchFieldException | IllegalAccessException e) {
LogUtil.exception("Failed to inject into the end of tick event via reflection", e);
return false;
}
return true;
}
}
@@ -0,0 +1,100 @@
package ac.grim.grimac.platform.bukkit.manager;
import ac.grim.grimac.platform.api.manager.ItemResetHandler;
import ac.grim.grimac.platform.api.player.PlatformPlayer;
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayer;
import ac.grim.grimac.platform.bukkit.utils.reflection.PaperUtils;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import lombok.SneakyThrows;
import org.bukkit.Bukkit;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Method;
public class BukkitItemResetHandler implements ItemResetHandler {
// resets item usage, then returns whether the player was using an item
private final @NotNull ItemUsageReset resetItemUsage = createItemUsageResetFunction();
@SneakyThrows
public void resetItemUsage(@Nullable PlatformPlayer player) {
if (player != null) {
resetItemUsage.accept(((BukkitPlatformPlayer) player).getNative());
}
}
@SneakyThrows
private @NotNull ItemUsageReset createItemUsageResetFunction() {
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
if (version.isNewerThan(ServerVersion.V_1_17) && PaperUtils.PAPER) {
if (version.isOlderThan(ServerVersion.V_1_19)) {
return LivingEntity::clearActiveItem;
}
Method setLivingEntityFlag = Class.forName(version.isOlderThan(ServerVersion.V_1_20_5) ? "net.minecraft.world.entity.EntityLiving" : "net.minecraft.world.entity.LivingEntity")
.getDeclaredMethod(version.isOlderThan(ServerVersion.V_1_20_5) ? "c" : "setLivingEntityFlag", int.class, boolean.class);
Method getHandle = (version.isOlderThan(ServerVersion.V_1_20_5)
? Class.forName("org.bukkit.craftbukkit." + Bukkit.getServer().getClass().getPackageName().split("\\.")[3] + ".entity.CraftPlayer")
: Class.forName("org.bukkit.craftbukkit.entity.CraftPlayer")
).getMethod("getHandle");
setLivingEntityFlag.setAccessible(true);
return player -> {
// don't trigger gameevents
setLivingEntityFlag.invoke(getHandle.invoke(player), 1, false);
player.clearActiveItem();
};
}
if (version == ServerVersion.V_1_8_8) {
Class<?> EntityHuman = Class.forName("net.minecraft.server.v1_8_R3.EntityHuman");
Method getHandle = Class.forName("org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer").getMethod("getHandle");
Method clearActiveItem = EntityHuman.getMethod("bV");
Method isUsingItem = EntityHuman.getMethod("bS");
return player -> {
Object handle = getHandle.invoke(player);
clearActiveItem.invoke(handle);
// in 1.8 we need to resync item usage manually,
// only do so if the player was using an item
if ((boolean) isUsingItem.invoke(handle)) {
player.updateInventory();
}
};
}
String nmsPackage = Bukkit.getServer().getClass().getPackageName().split("\\.")[3];
String livingEntityPackage = version.isNewerThan(ServerVersion.V_1_16_5) ? "net.minecraft.world.entity.EntityLiving" : "net.minecraft.server." + nmsPackage + ".EntityLiving";
Method getHandle = Class.forName("org.bukkit.craftbukkit." + nmsPackage + ".entity.CraftPlayer").getMethod("getHandle");
Method clearActiveItem = Class.forName(livingEntityPackage).getMethod(
switch (nmsPackage) {
case "v1_9_R1" -> "cz";
case "v1_9_R2" -> "cA";
case "v1_10_R1" -> "cE";
case "v1_11_R1" -> "cF";
case "v1_12_R1" -> "cN";
case "v1_13_R1", "v1_13_R2" -> "da";
case "v1_14_R1" -> "dp";
case "v1_15_R1" -> "dH";
case "v1_16_R1", "v1_16_R2", "v1_16_R3", "v1_17_R1" -> "clearActiveItem";
case "v1_18_R1" -> "eR";
case "v1_18_R2" -> "eS";
default ->
throw new IllegalStateException("You are using an unsupported server version! (" + version.getReleaseName() + ")");
}
);
return player -> clearActiveItem.invoke(getHandle.invoke(player));
}
private interface ItemUsageReset {
void accept(@NotNull Player player) throws Throwable;
}
}
@@ -0,0 +1,28 @@
package ac.grim.grimac.platform.bukkit.manager;
import ac.grim.grimac.platform.api.manager.MessagePlaceHolderManager;
import ac.grim.grimac.platform.api.player.PlatformPlayer;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import ac.grim.grimac.platform.bukkit.player.BukkitPlatformPlayer;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BukkitMessagePlaceHolderManager implements MessagePlaceHolderManager {
@Override
public @NonNull String replacePlaceholders(@Nullable Sender sender, @NonNull String string) {
if (!MessageUtil.hasPlaceholderAPI) return string;
CommandSender commandSender = sender == null ? null : GrimACBukkitLoaderPlugin.LOADER.getBukkitSenderFactory().unwrap(sender);
return PlaceholderAPI.setPlaceholders(sender instanceof OfflinePlayer ? (OfflinePlayer) commandSender : null, string);
}
@Override
public @NonNull String replacePlaceholders(@Nullable PlatformPlayer object, @NonNull String string) {
if (!MessageUtil.hasPlaceholderAPI) return string;
return PlaceholderAPI.setPlaceholders(((BukkitPlatformPlayer) object).getBukkitPlayer(), string);
}
}
@@ -0,0 +1,17 @@
package ac.grim.grimac.platform.bukkit.manager;
import ac.grim.grimac.platform.api.command.PlayerSelector;
import ac.grim.grimac.platform.api.manager.ParserDescriptorFactory;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.bukkit.command.BukkitPlayerSelectorParser;
import org.incendo.cloud.parser.ParserDescriptor;
public class BukkitParserDescriptorFactory implements ParserDescriptorFactory {
BukkitPlayerSelectorParser<Sender> bukkitPlayerSelectorParser = new BukkitPlayerSelectorParser<>();
@Override
public ParserDescriptor<Sender, PlayerSelector> getSinglePlayer() {
return bukkitPlayerSelectorParser.descriptor();
}
}
@@ -0,0 +1,33 @@
package ac.grim.grimac.platform.bukkit.manager;
import ac.grim.grimac.platform.api.manager.PermissionRegistrationManager;
import ac.grim.grimac.platform.api.permissions.PermissionDefaultValue;
import ac.grim.grimac.platform.bukkit.utils.convert.BukkitConversionUtils;
import org.bukkit.Bukkit;
import org.bukkit.permissions.Permission;
public class BukkitPermissionRegistrationManager implements PermissionRegistrationManager {
/**
* Registers a permission with the specified default value on Bukkit.
* This method is only called for dynamic permissions (e.g., check-specific permissions
* like "grim.exempt.checkname") that are generated at runtime. Most other static permissions
* (e.g., "grim.exempt", "grim.alerts.enable-on-join") are registered with their defaults
* in the `plugin.yml` file, which is defined in the Bukkit Gradle build script.
*
* <p>Dynamic permissions are registered here to ensure they are available for autocomplete
* and permission checks immediately on startup. If the permission already exists, its default
* value is updated to match the specified value.</p>
*
* @param s The permission node to register (e.g., "grim.exempt.checkname").
* @param defaultValue The default value for the permission.
*/
@Override
public void registerPermission(String s, PermissionDefaultValue defaultValue) {
final Permission permission = Bukkit.getPluginManager().getPermission(s);
if (permission == null) {
Bukkit.getPluginManager().addPermission(new Permission(s, BukkitConversionUtils.toBukkitPermissionDefault(defaultValue)));
} else {
permission.setDefault(BukkitConversionUtils.toBukkitPermissionDefault(defaultValue));
}
}
}
@@ -0,0 +1,50 @@
package ac.grim.grimac.platform.bukkit.manager;
import ac.grim.grimac.api.event.EventBus;
import ac.grim.grimac.api.event.GrimEvent;
import ac.grim.grimac.api.event.OptimizedEventBus;
import ac.grim.grimac.platform.api.PlatformPlugin;
import ac.grim.grimac.platform.api.manager.PlatformPluginManager;
import ac.grim.grimac.platform.bukkit.BukkitPlatformPlugin;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.checkerframework.checker.nullness.qual.Nullable;
public class BukkitPlatformPluginManager implements PlatformPluginManager {
private final EventBus eventBus = new OptimizedEventBus();
@Override
public void callEvent(GrimEvent event) {
eventBus.post(event);
}
@Override
public EventBus getEventBus() {
return this.eventBus;
}
@Override
public PlatformPlugin[] getPlugins() {
Plugin[] bukkitPlugins = Bukkit.getPluginManager().getPlugins();
PlatformPlugin[] plugins = new PlatformPlugin[bukkitPlugins.length];
for (int i = 0; i < bukkitPlugins.length; i++) {
plugins[i] = new BukkitPlatformPlugin(bukkitPlugins[i]);
}
return plugins;
}
@Override
public @Nullable PlatformPlugin getPlugin(String pluginName) {
Plugin bukkitPlugin = Bukkit.getPluginManager().getPlugin(pluginName);
return bukkitPlugin == null ? null : new BukkitPlatformPlugin(bukkitPlugin);
}
@Override
public boolean isPluginEnabled(String pluginName) {
PlatformPlugin plugin = getPlugin(pluginName);
return plugin != null && plugin.isEnabled();
}
}
@@ -0,0 +1,66 @@
package ac.grim.grimac.platform.bukkit.player;
import ac.grim.grimac.platform.api.player.PlatformInventory;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import org.bukkit.entity.Player;
public class BukkitPlatformInventory implements PlatformInventory {
private final Player bukkitPlayer;
public BukkitPlatformInventory(Player bukkitPlayer) {
this.bukkitPlayer = bukkitPlayer;
}
@Override
public ItemStack getItemInHand() {
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getItemInHand());
}
@Override
public ItemStack getItemInOffHand() {
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getItemInOffHand());
}
@Override
public ItemStack getStack(int bukkitSlot, int vanillaSlot) {
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getItem(bukkitSlot));
}
@Override
public ItemStack getHelmet() {
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getHelmet());
}
@Override
public ItemStack getChestplate() {
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getHelmet());
}
@Override
public ItemStack getLeggings() {
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getLeggings());
}
@Override
public ItemStack getBoots() {
return SpigotConversionUtil.fromBukkitItemStack(bukkitPlayer.getInventory().getBoots());
}
@Override
public ItemStack[] getContents() {
org.bukkit.inventory.ItemStack[] bukkitItems = bukkitPlayer.getInventory().getContents();
ItemStack[] items = new ItemStack[bukkitItems.length];
for (int i = 0; i < bukkitItems.length; i++) {
if (bukkitItems[i] == null) continue;
items[i] = SpigotConversionUtil.fromBukkitItemStack(bukkitItems[i]);
}
return items;
}
@Override
public String getOpenInventoryKey() {
return bukkitPlayer.getOpenInventory().getType().toString();
}
}
@@ -0,0 +1,156 @@
package ac.grim.grimac.platform.bukkit.player;
import ac.grim.grimac.platform.api.entity.GrimEntity;
import ac.grim.grimac.platform.api.player.PlatformInventory;
import ac.grim.grimac.platform.api.player.PlatformPlayer;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import ac.grim.grimac.platform.bukkit.entity.BukkitGrimEntity;
import ac.grim.grimac.platform.bukkit.utils.anticheat.MultiLibUtil;
import ac.grim.grimac.platform.bukkit.utils.convert.BukkitConversionUtils;
import ac.grim.grimac.platform.bukkit.utils.reflection.PaperUtils;
import ac.grim.grimac.utils.math.Location;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.util.Vector3d;
import lombok.Getter;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class BukkitPlatformPlayer extends BukkitGrimEntity implements PlatformPlayer {
private static final BukkitAudiences audiences = BukkitAudiences.create(GrimACBukkitLoaderPlugin.LOADER);
@Getter
private final Player bukkitPlayer;
private final PlatformInventory inventory;
public BukkitPlatformPlayer(Player bukkitPlayer) {
super(bukkitPlayer);
this.bukkitPlayer = bukkitPlayer;
this.inventory = new BukkitPlatformInventory(bukkitPlayer);
}
@Override
public void kickPlayer(String textReason) {
bukkitPlayer.kickPlayer(textReason);
}
@Override
public boolean hasPermission(String s) {
return bukkitPlayer.hasPermission(s);
}
@Override
public boolean hasPermission(String s, boolean defaultIfUnset) {
return this.bukkitPlayer.hasPermission(new Permission(s, defaultIfUnset ? PermissionDefault.TRUE : PermissionDefault.FALSE));
}
@Override
public boolean isSneaking() {
return bukkitPlayer.isSneaking();
}
@Override
public void setSneaking(boolean isSneaking) {
bukkitPlayer.setSneaking(isSneaking);
}
@Override
public void sendMessage(String message) {
bukkitPlayer.sendMessage(message);
}
@Override
public void sendMessage(Component message) {
audiences.player(bukkitPlayer).sendMessage(message);
}
@Override
public boolean isOnline() {
return bukkitPlayer.isOnline();
}
@Override
public String getName() {
return bukkitPlayer.getName();
}
@Override
public void updateInventory() {
bukkitPlayer.updateInventory();
}
@Override
public Vector3d getPosition() {
org.bukkit.Location location = this.bukkitPlayer.getLocation();
return new Vector3d(location.getX(), location.getY(), location.getZ());
}
@Override
public PlatformInventory getInventory() {
return inventory;
}
@Override
public GrimEntity getVehicle() {
return new BukkitGrimEntity(bukkitPlayer.getVehicle());
}
@Override
public GameMode getGameMode() {
return BukkitConversionUtils.fromBukkitGameMode(bukkitPlayer.getGameMode());
}
@Override
public void setGameMode(GameMode gameMode) {
bukkitPlayer.setGameMode(BukkitConversionUtils.toBukkitGameMode(gameMode));
}
public World getBukkitWorld() {
return bukkitPlayer.getWorld();
}
@Override
public UUID getUniqueId() {
return bukkitPlayer.getUniqueId();
}
@Override
public boolean eject() {
return bukkitPlayer.eject();
}
@Override
public CompletableFuture<Boolean> teleportAsync(Location location) {
org.bukkit.Location bLoc = BukkitConversionUtils.toBukkitLocation(location);
return PaperUtils.teleportAsync(this.bukkitPlayer, bLoc);
}
@Override
public boolean isExternalPlayer() {
return MultiLibUtil.isExternalPlayer(this.bukkitPlayer);
}
@Override
public void sendPluginMessage(String channelName, byte[] byteArray) {
this.bukkitPlayer.sendPluginMessage(GrimACBukkitLoaderPlugin.LOADER, channelName, byteArray);
}
@Override
public Sender getSender() {
return GrimACBukkitLoaderPlugin.LOADER.getBukkitSenderFactory().map(this.bukkitPlayer);
}
@Override
@NonNull
public Player getNative() {
return this.bukkitPlayer;
}
}
@@ -0,0 +1,47 @@
package ac.grim.grimac.platform.bukkit.player;
import ac.grim.grimac.platform.api.player.AbstractPlatformPlayerFactory;
import ac.grim.grimac.platform.api.player.PlatformPlayer;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.UUID;
public class BukkitPlatformPlayerFactory extends AbstractPlatformPlayerFactory<Player> {
@Override
protected Player getNativePlayer(@NotNull UUID uuid) {
return Bukkit.getPlayer(uuid);
}
@Override
protected PlatformPlayer createPlatformPlayer(@NotNull Player nativePlayer) {
return new BukkitPlatformPlayer(nativePlayer);
}
@Override
protected boolean isNativePlayerType(@NotNull Object playerObject) {
return playerObject instanceof Player;
}
@Override
protected UUID getPlayerUUID(@NotNull Player nativePlayer) {
return nativePlayer.getUniqueId();
}
@Override
protected Class<Player> getNativePlayerClass() {
return Player.class;
}
// The cast is safe because Bukkit.getOnlinePlayers() is guaranteed to contain Player or its subtypes,
// and we're only reading from it.
@Override
@SuppressWarnings("unchecked")
protected Collection<Player> getNativeOnlinePlayers() {
// Cast Collection<? extends Player> to Collection<Player>
return (Collection<Player>) Bukkit.getOnlinePlayers();
}
}
@@ -0,0 +1,54 @@
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.scheduler.AsyncScheduler;
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitScheduler;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.TimeUnit;
public class BukkitAsyncScheduler implements AsyncScheduler {
private final BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
@Override
public TaskHandle runNow(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
return new BukkitTaskHandle(bukkitScheduler.runTaskAsynchronously(GrimACBukkitLoaderPlugin.LOADER, task));
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, @NotNull TimeUnit timeUnit) {
return new BukkitTaskHandle(bukkitScheduler.runTaskLaterAsynchronously(GrimACBukkitLoaderPlugin.LOADER,
task,
PlatformScheduler.convertTimeToTicks(delay, timeUnit))
);
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, long period, @NotNull TimeUnit timeUnit) {
return new BukkitTaskHandle(
bukkitScheduler.runTaskTimerAsynchronously(
GrimACBukkitLoaderPlugin.LOADER,
task,
PlatformScheduler.convertTimeToTicks(delay, timeUnit),
PlatformScheduler.convertTimeToTicks(period, timeUnit)
)
);
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
return new BukkitTaskHandle(
bukkitScheduler.runTaskTimerAsynchronously(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks)
);
}
@Override
public void cancel(@NotNull GrimPlugin plugin) {
bukkitScheduler.cancelTasks(GrimACBukkitLoaderPlugin.LOADER);
}
}
@@ -0,0 +1,36 @@
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.entity.GrimEntity;
import ac.grim.grimac.platform.api.scheduler.EntityScheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitScheduler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class BukkitEntityScheduler implements EntityScheduler {
private final BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
@Override
public void execute(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable run, @Nullable Runnable retired, long delay) {
bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, run, delay);
}
@Override
public TaskHandle run(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired) {
return new BukkitTaskHandle(bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, task));
}
@Override
public TaskHandle runDelayed(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long delayTicks) {
return new BukkitTaskHandle(bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, task, delayTicks));
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long initialDelayTicks, long periodTicks) {
return new BukkitTaskHandle(bukkitScheduler.runTaskTimer(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks));
}
}
@@ -0,0 +1,39 @@
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.scheduler.GlobalRegionScheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitScheduler;
import org.jetbrains.annotations.NotNull;
public class BukkitGlobalRegionScheduler implements GlobalRegionScheduler {
private final BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
@Override
public void execute(@NotNull GrimPlugin plugin, @NotNull Runnable run) {
bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, run);
}
@Override
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
return new BukkitTaskHandle(bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, task));
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay) {
return new BukkitTaskHandle(bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, task, delay));
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
return new BukkitTaskHandle(bukkitScheduler.runTaskTimer(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks));
}
@Override
public void cancel(@NotNull GrimPlugin plugin) {
bukkitScheduler.cancelTasks(GrimACBukkitLoaderPlugin.LOADER);
}
}
@@ -0,0 +1,37 @@
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
import ac.grim.grimac.platform.api.scheduler.AsyncScheduler;
import ac.grim.grimac.platform.api.scheduler.EntityScheduler;
import ac.grim.grimac.platform.api.scheduler.GlobalRegionScheduler;
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
import ac.grim.grimac.platform.api.scheduler.RegionScheduler;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.NotNull;
public class BukkitPlatformScheduler implements PlatformScheduler {
private final BukkitAsyncScheduler bukkitAsyncScheduler = new BukkitAsyncScheduler();
private final BukkitGlobalRegionScheduler bukkitGlobalRegionScheduler = new BukkitGlobalRegionScheduler();
private final BukkitEntityScheduler bukkitEntityScheduler = new BukkitEntityScheduler();
private final BukkitRegionScheduler bukkitRegionScheduler = new BukkitRegionScheduler();
@Override
public @NonNull @NotNull AsyncScheduler getAsyncScheduler() {
return bukkitAsyncScheduler;
}
@Override
public @NonNull @NotNull GlobalRegionScheduler getGlobalRegionScheduler() {
return bukkitGlobalRegionScheduler;
}
@Override
public @NonNull @NotNull EntityScheduler getEntityScheduler() {
return bukkitEntityScheduler;
}
@Override
public @NonNull @NotNull RegionScheduler getRegionScheduler() {
return bukkitRegionScheduler;
}
}
@@ -0,0 +1,56 @@
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.scheduler.RegionScheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import ac.grim.grimac.platform.api.world.PlatformWorld;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import ac.grim.grimac.utils.math.Location;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitScheduler;
import org.jetbrains.annotations.NotNull;
public class BukkitRegionScheduler implements RegionScheduler {
private final BukkitScheduler bukkitScheduler = Bukkit.getScheduler();
@Override
public void execute(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable run) {
bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, run);
}
@Override
public void execute(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable run) {
bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, run);
}
@Override
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task) {
return new BukkitTaskHandle(bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, task));
}
@Override
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task) {
return new BukkitTaskHandle(bukkitScheduler.runTask(GrimACBukkitLoaderPlugin.LOADER, task));
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long delayTicks) {
return new BukkitTaskHandle(bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, task, delayTicks));
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long delayTicks) {
return new BukkitTaskHandle(bukkitScheduler.runTaskLater(GrimACBukkitLoaderPlugin.LOADER, task, delayTicks));
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
return new BukkitTaskHandle(bukkitScheduler.runTaskTimer(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks));
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
return new BukkitTaskHandle(bukkitScheduler.runTaskTimer(GrimACBukkitLoaderPlugin.LOADER, task, initialDelayTicks, periodTicks));
}
}
@@ -0,0 +1,28 @@
package ac.grim.grimac.platform.bukkit.scheduler.bukkit;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import org.bukkit.scheduler.BukkitTask;
public class BukkitTaskHandle implements TaskHandle {
private final BukkitTask bukkitTask;
public BukkitTaskHandle(BukkitTask bukkitTask) {
this.bukkitTask = bukkitTask;
}
@Override
public boolean isSync() {
return bukkitTask.isSync();
}
@Override
public boolean getCancelled() {
return bukkitTask.isCancelled();
}
@Override
public void cancel() {
bukkitTask.cancel();
}
}
@@ -0,0 +1,63 @@
package ac.grim.grimac.platform.bukkit.scheduler.folia;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.scheduler.AsyncScheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.TimeUnit;
public class FoliaAsyncScheduler implements AsyncScheduler {
private final io.papermc.paper.threadedregions.scheduler.AsyncScheduler asyncScheduler = Bukkit.getAsyncScheduler();
@Override
public TaskHandle runNow(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
return new FoliaTaskHandle(asyncScheduler.runNow(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run()));
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, @NotNull TimeUnit timeUnit) {
return new FoliaTaskHandle(
asyncScheduler.runDelayed(
GrimACBukkitLoaderPlugin.LOADER,
(ignored) -> task.run(),
delay,
timeUnit
)
);
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay, long period, @NotNull TimeUnit timeUnit) {
return new FoliaTaskHandle(
asyncScheduler.runAtFixedRate(
GrimACBukkitLoaderPlugin.LOADER,
(ignored) -> task.run(),
delay,
period,
timeUnit
)
);
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
return new FoliaTaskHandle(
asyncScheduler.runAtFixedRate(
GrimACBukkitLoaderPlugin.LOADER,
(ignored) -> task.run(),
initialDelayTicks * 50,
periodTicks * 50,
TimeUnit.MILLISECONDS
)
);
}
@Override
public void cancel(@NotNull GrimPlugin plugin) {
asyncScheduler.cancelTasks(GrimACBukkitLoaderPlugin.LOADER);
}
}
@@ -0,0 +1,43 @@
package ac.grim.grimac.platform.bukkit.scheduler.folia;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.entity.GrimEntity;
import ac.grim.grimac.platform.api.scheduler.EntityScheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import ac.grim.grimac.platform.bukkit.entity.BukkitGrimEntity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class FoliaEntityScheduler implements EntityScheduler {
@Override
public void execute(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable run, @Nullable Runnable retired, long delay) {
((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().execute(GrimACBukkitLoaderPlugin.LOADER, run, () -> {
}, delay);
}
@Override
public TaskHandle run(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired) {
return new FoliaTaskHandle(
((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().run(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), () -> {
})
);
}
@Override
public TaskHandle runDelayed(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long delayTicks) {
return new FoliaTaskHandle(
((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().runDelayed(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), () -> {
}, delayTicks)
);
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimEntity entity, @NotNull GrimPlugin plugin, @NotNull Runnable task, @Nullable Runnable retired, long initialDelayTicks, long periodTicks) {
return new FoliaTaskHandle(
((BukkitGrimEntity) entity).getBukkitEntity().getScheduler().runAtFixedRate(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), () -> {
}, initialDelayTicks, periodTicks)
);
}
}
@@ -0,0 +1,38 @@
package ac.grim.grimac.platform.bukkit.scheduler.folia;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.scheduler.GlobalRegionScheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
public class FoliaGlobalRegionScheduler implements GlobalRegionScheduler {
private final io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler globalRegionScheduler = Bukkit.getGlobalRegionScheduler();
@Override
public void execute(@NotNull GrimPlugin plugin, @NotNull Runnable run) {
globalRegionScheduler.execute(GrimACBukkitLoaderPlugin.LOADER, run);
}
@Override
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Runnable task) {
return new FoliaTaskHandle(globalRegionScheduler.run(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run()));
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Runnable task, long delay) {
return new FoliaTaskHandle(globalRegionScheduler.runDelayed(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), delay));
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
return new FoliaTaskHandle(globalRegionScheduler.runAtFixedRate(GrimACBukkitLoaderPlugin.LOADER, (ignored) -> task.run(), initialDelayTicks, periodTicks));
}
@Override
public void cancel(@NotNull GrimPlugin plugin) {
globalRegionScheduler.cancelTasks(GrimACBukkitLoaderPlugin.LOADER);
}
}
@@ -0,0 +1,36 @@
package ac.grim.grimac.platform.bukkit.scheduler.folia;
import ac.grim.grimac.platform.api.scheduler.AsyncScheduler;
import ac.grim.grimac.platform.api.scheduler.EntityScheduler;
import ac.grim.grimac.platform.api.scheduler.GlobalRegionScheduler;
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
import ac.grim.grimac.platform.api.scheduler.RegionScheduler;
import org.checkerframework.checker.nullness.qual.NonNull;
public class FoliaPlatformScheduler implements PlatformScheduler {
private final FoliaAsyncScheduler foliaAsyncScheduler = new FoliaAsyncScheduler();
private final FoliaGlobalRegionScheduler foliaGlobalRegionScheduler = new FoliaGlobalRegionScheduler();
private final FoliaEntityScheduler foliaEntityScheduler = new FoliaEntityScheduler();
private final FoliaRegionScheduler foliaRegionScheduler = new FoliaRegionScheduler();
@Override
public @NonNull AsyncScheduler getAsyncScheduler() {
return foliaAsyncScheduler;
}
@Override
public @NonNull GlobalRegionScheduler getGlobalRegionScheduler() {
return foliaGlobalRegionScheduler;
}
@Override
public @NonNull EntityScheduler getEntityScheduler() {
return foliaEntityScheduler;
}
@Override
public @NonNull RegionScheduler getRegionScheduler() {
return foliaRegionScheduler;
}
}
@@ -0,0 +1,59 @@
package ac.grim.grimac.platform.bukkit.scheduler.folia;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.platform.api.scheduler.RegionScheduler;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import ac.grim.grimac.platform.api.world.PlatformWorld;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import ac.grim.grimac.platform.bukkit.world.BukkitPlatformWorld;
import ac.grim.grimac.utils.math.Location;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
public class FoliaRegionScheduler implements RegionScheduler {
private final io.papermc.paper.threadedregions.scheduler.RegionScheduler regionScheduler = Bukkit.getRegionScheduler();
@Override
public void execute(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable run) {
regionScheduler.execute(GrimACBukkitLoaderPlugin.LOADER, ((BukkitPlatformWorld) world).getBukkitWorld(), chunkX, chunkZ, run);
}
@Override
public void execute(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable run) {
execute(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, run);
}
@Override
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task) {
return new FoliaTaskHandle(regionScheduler.run(GrimACBukkitLoaderPlugin.LOADER, ((BukkitPlatformWorld) world).getBukkitWorld(), chunkX, chunkZ, (ignored) -> task.run()));
}
@Override
public TaskHandle run(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task) {
return run(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task);
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long delayTicks) {
return new FoliaTaskHandle(regionScheduler.runDelayed(GrimACBukkitLoaderPlugin.LOADER,
((BukkitPlatformWorld) world).getBukkitWorld(), chunkX, chunkZ, (ignored) -> task.run(), delayTicks));
}
@Override
public TaskHandle runDelayed(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long delayTicks) {
return runDelayed(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, delayTicks);
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull PlatformWorld world, int chunkX, int chunkZ, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
return new FoliaTaskHandle(regionScheduler.runAtFixedRate(GrimACBukkitLoaderPlugin.LOADER,
((BukkitPlatformWorld) world).getBukkitWorld(), chunkX, chunkZ, (ignored) -> task.run(), initialDelayTicks, periodTicks));
}
@Override
public TaskHandle runAtFixedRate(@NotNull GrimPlugin plugin, @NotNull Location location, @NotNull Runnable task, long initialDelayTicks, long periodTicks) {
return runAtFixedRate(plugin, location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, initialDelayTicks, periodTicks);
}
}
@@ -0,0 +1,28 @@
package ac.grim.grimac.platform.bukkit.scheduler.folia;
import ac.grim.grimac.platform.api.scheduler.TaskHandle;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
public class FoliaTaskHandle implements TaskHandle {
private final ScheduledTask task;
public FoliaTaskHandle(ScheduledTask task) {
this.task = task;
}
@Override
public boolean isSync() {
return false;
}
@Override
public boolean getCancelled() {
return task.isCancelled();
}
@Override
public void cancel() {
task.cancel();
}
}
@@ -0,0 +1,89 @@
package ac.grim.grimac.platform.bukkit.sender;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.platform.api.sender.Sender;
import ac.grim.grimac.platform.api.sender.SenderFactory;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.RemoteConsoleCommandSender;
import org.bukkit.entity.Player;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.SenderMapper;
import java.util.UUID;
public class BukkitSenderFactory extends SenderFactory<CommandSender> implements SenderMapper<CommandSender, Sender> {
private final BukkitAudiences audiences;
public BukkitSenderFactory() {
this.audiences = BukkitAudiences.create(GrimACBukkitLoaderPlugin.LOADER);
}
@Override
protected String getName(CommandSender sender) {
return sender instanceof Player ? sender.getName() : Sender.CONSOLE_NAME;
}
@Override
protected UUID getUniqueId(CommandSender sender) {
return sender instanceof Player ? ((Player) sender).getUniqueId() : Sender.CONSOLE_UUID;
}
@Override
protected void sendMessage(CommandSender sender, String message) {
sender.sendMessage(message);
}
@Override
protected void sendMessage(CommandSender sender, Component message) {
// we can safely send async for players and the console - otherwise, send it sync
if (sender instanceof Player || sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) {
this.audiences.sender(sender).sendMessage(message);
} else {
GrimAPI.INSTANCE.getScheduler().getGlobalRegionScheduler().run(
GrimAPI.INSTANCE.getGrimPlugin(),
() -> this.audiences.sender(sender).sendMessage(message)
);
}
}
@Override
protected boolean hasPermission(CommandSender sender, String node) {
return sender.hasPermission(node);
}
@Override
protected boolean hasPermission(CommandSender sender, String node, boolean defaultIfUnset) {
return sender.hasPermission(new Permission(node, defaultIfUnset ? PermissionDefault.TRUE : PermissionDefault.FALSE));
}
@Override
protected void performCommand(CommandSender sender, String command) {
throw new UnsupportedOperationException();
}
@Override
protected boolean isConsole(CommandSender sender) {
return sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender;
}
@Override
protected boolean isPlayer(CommandSender sender) {
return sender instanceof Player;
}
@Override
public @NonNull Sender map(@NonNull CommandSender base) {
return this.wrap(base);
}
@Override
public @NonNull CommandSender reverse(@NonNull Sender mapped) {
return this.unwrap(mapped);
}
}
@@ -1,4 +1,4 @@
package ac.grim.grimac.utils.anticheat;
package ac.grim.grimac.platform.bukkit.utils.anticheat;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
@@ -9,6 +9,8 @@ import java.lang.reflect.Method;
public class MultiLibUtil {
public final static Method externalPlayerMethod = getMethod(Player.class, "isExternalPlayer");
private static final boolean
IS_PRE_1_18 = PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_18);
public static Method getMethod(Class<?> clazz, String methodName) {
try {
@@ -20,7 +22,7 @@ public class MultiLibUtil {
// TODO: cache external players for better performance, but this only matters for people using multi-lib
public static boolean isExternalPlayer(Player player) {
if (externalPlayerMethod == null || (PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_18))) return false;
if (externalPlayerMethod == null || IS_PRE_1_18) return false;
try {
return (boolean) externalPlayerMethod.invoke(player);
} catch (Exception e) {
@@ -0,0 +1,22 @@
package ac.grim.grimac.platform.bukkit.utils.blockstate;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
public class BukkitBlockFaceHelper {
/**
* For use with bukkit events only
* Grim is not meant to be restrained by bukkit!
*/
@Deprecated
public static BlockFace fromBukkitFace(org.bukkit.block.BlockFace face) {
return switch (face) {
case NORTH -> BlockFace.NORTH;
case SOUTH -> BlockFace.SOUTH;
case WEST -> BlockFace.WEST;
case EAST -> BlockFace.EAST;
case UP -> BlockFace.UP;
case DOWN -> BlockFace.DOWN;
default -> BlockFace.OTHER;
};
}
}
@@ -0,0 +1,62 @@
package ac.grim.grimac.platform.bukkit.utils.convert;
import ac.grim.grimac.platform.api.permissions.PermissionDefaultValue;
import ac.grim.grimac.platform.bukkit.world.BukkitPlatformWorld;
import ac.grim.grimac.utils.math.Location;
import com.github.retrooper.packetevents.protocol.player.GameMode;
public class BukkitConversionUtils {
public static org.bukkit.Location toBukkitLocation(Location location) {
return new org.bukkit.Location(((BukkitPlatformWorld) location.getWorld()).getBukkitWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
}
public static GameMode fromBukkitGameMode(org.bukkit.GameMode gameMode) {
switch (gameMode) {
case CREATIVE:
return GameMode.CREATIVE;
case SURVIVAL:
return GameMode.SURVIVAL;
case ADVENTURE:
return GameMode.ADVENTURE;
case SPECTATOR:
return GameMode.SPECTATOR;
default:
throw new IllegalStateException();
}
}
public static org.bukkit.GameMode toBukkitGameMode(GameMode gameMode) {
switch (gameMode) {
case CREATIVE:
return org.bukkit.GameMode.CREATIVE;
case SURVIVAL:
return org.bukkit.GameMode.SURVIVAL;
case ADVENTURE:
return org.bukkit.GameMode.ADVENTURE;
case SPECTATOR:
return org.bukkit.GameMode.SPECTATOR;
default:
throw new IllegalStateException();
}
}
/**
* Converts this enum to a Bukkit PermissionDefault.
*
* @return The corresponding Bukkit PermissionDefault.
*/
public static org.bukkit.permissions.PermissionDefault toBukkitPermissionDefault(PermissionDefaultValue permissionDefaultValue) {
switch (permissionDefaultValue) {
case TRUE:
return org.bukkit.permissions.PermissionDefault.TRUE;
case FALSE:
return org.bukkit.permissions.PermissionDefault.FALSE;
case OP:
return org.bukkit.permissions.PermissionDefault.OP;
case NOT_OP:
return org.bukkit.permissions.PermissionDefault.NOT_OP;
default:
throw new IllegalStateException();
}
}
}
@@ -0,0 +1,71 @@
package ac.grim.grimac.platform.bukkit.utils.placeholder;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.GrimUser;
import ac.grim.grimac.player.GrimPlayer;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
public class PlaceholderAPIExpansion extends PlaceholderExpansion {
@Override
public @NotNull String getIdentifier() {
return "grim";
}
public @NotNull String getAuthor() {
return String.join(", ", GrimAPI.INSTANCE.getGrimPlugin().getDescription().getAuthors());
}
@Override
public @NotNull String getVersion() {
return GrimAPI.INSTANCE.getExternalAPI().getGrimVersion();
}
@Override
public boolean persist() {
return true;
}
@Override
public @NotNull List<String> getPlaceholders() {
Set<String> placeholders = GrimAPI.INSTANCE.getExternalAPI().getStaticReplacements().keySet();
placeholders.addAll(GrimAPI.INSTANCE.getExternalAPI().getVariableReplacements().keySet());
return List.copyOf(placeholders);
}
@Override
public String onRequest(OfflinePlayer offlinePlayer, @NotNull String params) {
for (Map.Entry<String, String> entry : GrimAPI.INSTANCE.getExternalAPI().getStaticReplacements().entrySet()) {
String key = entry.getKey().equals("%grim_version%")
? "version"
: entry.getKey().replaceAll("%", "");
if (params.equalsIgnoreCase(key)) {
return entry.getValue();
}
}
if (offlinePlayer instanceof Player player) {
GrimPlayer grimPlayer = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(player.getUniqueId());
if (grimPlayer == null) return null;
for (Map.Entry<String, Function<GrimUser, String>> entry : GrimAPI.INSTANCE.getExternalAPI().getVariableReplacements().entrySet()) {
String key = entry.getKey().equals("%player%")
? "player"
: "player_" + entry.getKey().replaceAll("%", "");
if (params.equalsIgnoreCase(key)) {
return entry.getValue().apply(grimPlayer);
}
}
}
return null;
}
}
@@ -0,0 +1,52 @@
package ac.grim.grimac.platform.bukkit.utils.reflection;
import ac.grim.grimac.platform.bukkit.GrimACBukkitLoaderPlugin;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.reflection.ReflectionUtils;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.event.Event;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import java.util.concurrent.CompletableFuture;
public class PaperUtils {
public static final boolean PAPER;
public static final boolean TICK_END_EVENT;
public static final boolean ASYNC_TELEPORT;
static {
PAPER = ReflectionUtils.hasClass("com.destroystokyo.paper.PaperConfig") || ReflectionUtils.hasClass("io.papermc.paper.configuration.Configuration");
TICK_END_EVENT = ReflectionUtils.hasClass("com.destroystokyo.paper.event.server.ServerTickEndEvent");
ASYNC_TELEPORT = ReflectionUtils.hasMethod(Entity.class, "teleportAsync", org.bukkit.Location.class);
}
public static CompletableFuture<Boolean> teleportAsync(final Entity entity, final Location location) {
if (PAPER) {
return entity.teleportAsync(location);
} else {
return CompletableFuture.completedFuture(entity.teleport(location));
}
}
@SuppressWarnings("unchecked")
public static boolean registerTickEndEvent(Listener listener, Runnable runnable) {
if (TICK_END_EVENT) {
try {
Class<?> clazz = ReflectionUtils.getClass("com.destroystokyo.paper.event.server.ServerTickEndEvent");
if (clazz == null) return false;
GrimACBukkitLoaderPlugin.LOADER.getServer().getPluginManager().registerEvent((Class<? extends Event>) clazz,
listener,
EventPriority.NORMAL,
(l, event) -> runnable.run(), GrimACBukkitLoaderPlugin.LOADER);
return true;
} catch (Exception e) {
LogUtil.exception("Failed to register tick end event", e);
}
}
return false;
}
}
@@ -0,0 +1,31 @@
package ac.grim.grimac.platform.bukkit.world;
import ac.grim.grimac.platform.api.world.PlatformChunk;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import org.bukkit.Chunk;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
public class BukkitPlatformChunk implements PlatformChunk {
private static final HashMap<BlockData, Integer> blockDataToId = new HashMap<>();
private static final boolean isFlat = PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13);
private final Chunk chunk;
public BukkitPlatformChunk(@NotNull Chunk chunkAt) {
this.chunk = chunkAt;
}
@Override
public int getBlockID(int x, int y, int z) {
Block block = chunk.getBlock(x, y, z);
return isFlat // Cache blockDataToID because Strings are expensive
? blockDataToId.computeIfAbsent(block.getBlockData(), data -> WrappedBlockState.getByString(PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), data.getAsString(false)).getGlobalId())
: (block.getType().getId() << 4) | block.getData();
}
}
@@ -0,0 +1,53 @@
package ac.grim.grimac.platform.bukkit.world;
import ac.grim.grimac.platform.api.world.PlatformChunk;
import ac.grim.grimac.platform.api.world.PlatformWorld;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
@Getter
public class BukkitPlatformWorld implements PlatformWorld {
private final World bukkitWorld;
public BukkitPlatformWorld(@NotNull World world) {
this.bukkitWorld = world;
}
@Override
public boolean isChunkLoaded(int chunkX, int chunkZ) {
return bukkitWorld.isChunkLoaded(chunkX, chunkZ);
}
@Override
public WrappedBlockState getBlockAt(int x, int y, int z) {
return SpigotConversionUtil.fromBukkitBlockData(bukkitWorld.getBlockAt(x, y, z).getBlockData());
}
@Override
public String getName() {
return bukkitWorld.getName();
}
@Override
public @Nullable UUID getUID() {
return this.bukkitWorld.getUID();
}
@Override
public PlatformChunk getChunkAt(int currChunkX, int currChunkZ) {
return new BukkitPlatformChunk(bukkitWorld.getChunkAt(currChunkX, currChunkZ));
}
@Override
public boolean isLoaded() {
return Bukkit.getWorld(bukkitWorld.getUID()) != null;
}
}
+54
View File
@@ -0,0 +1,54 @@
plugins {
`maven-publish`
grim.`base-conventions`
}
repositories {
mavenLocal()
maven {
name = "papermc"
url = uri("https://repo.papermc.io/repository/maven-public/")
}
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // Spigot
maven("https://jitpack.io/") { // Grim API
content {
includeGroup("com.github.grimanticheat")
}
}
maven("https://repo.viaversion.com") // ViaVersion
maven("https://nexus.scarsz.me/content/repositories/releases") // Configuralize
maven("https://repo.opencollab.dev/maven-snapshots/") // Floodgate
maven("https://repo.opencollab.dev/maven-releases/") // Cumulus (for Floodgate)
maven("https://repo.codemc.io/repository/maven-releases/") // PacketEvents
maven("https://repo.codemc.io/repository/maven-snapshots/")
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
mavenCentral()
// FastUtil, Discord-Webhooks
}
dependencies {
api(libs.packetevents.api)
api(libs.cloud.core)
api("org.incendo:cloud-processors-requirements:1.0.0-rc.1")
api("github.scarsz:configuralize:1.4.1:slim") {
exclude(group = "org.yaml", module = "snakeyaml")
}
// Bump snakeyaml (transitive dep of configuralize) 1.29 -> 2.2 for geyser-fabric
api("org.yaml:snakeyaml:2.2")
api(libs.discord.webhooks)
api(libs.fastutil)
api(libs.adventure.text.minimessage)
api(libs.jetbrains.annotations)
// Used for local testing:
// api("ac.grim.grimac:GrimAPI:1.0")
api("com.github.grimanticheat:grimapi:8507e14a73")
compileOnly(libs.floodgate.api)
compileOnly(libs.via.version.api)
compileOnly(libs.netty)
}
publishing.publications.create<MavenPublication>("maven") {
from(components["java"])
}
@@ -0,0 +1,141 @@
package ac.grim.grimac;
import ac.grim.grimac.api.plugin.GrimPlugin;
import ac.grim.grimac.manager.AlertManagerImpl;
import ac.grim.grimac.manager.DiscordManager;
import ac.grim.grimac.manager.InitManager;
import ac.grim.grimac.manager.SpectateManager;
import ac.grim.grimac.manager.TickManager;
import ac.grim.grimac.manager.config.BaseConfigManager;
import ac.grim.grimac.manager.init.Initable;
import ac.grim.grimac.platform.api.Platform;
import ac.grim.grimac.platform.api.PlatformLoader;
import ac.grim.grimac.platform.api.PlatformServer;
import ac.grim.grimac.platform.api.manager.ItemResetHandler;
import ac.grim.grimac.platform.api.manager.MessagePlaceHolderManager;
import ac.grim.grimac.platform.api.manager.ParserDescriptorFactory;
import ac.grim.grimac.platform.api.manager.PermissionRegistrationManager;
import ac.grim.grimac.platform.api.manager.PlatformPluginManager;
import ac.grim.grimac.platform.api.player.PlatformPlayerFactory;
import ac.grim.grimac.platform.api.scheduler.PlatformScheduler;
import ac.grim.grimac.platform.api.sender.SenderFactory;
import ac.grim.grimac.utils.anticheat.PlayerDataManager;
import ac.grim.grimac.utils.reflection.ReflectionUtils;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@Getter
public final class GrimAPI {
public static final GrimAPI INSTANCE = new GrimAPI();
private final Platform platform = detectPlatform();
private final BaseConfigManager configManager;
private final AlertManagerImpl alertManager;
private final SpectateManager spectateManager;
private final DiscordManager discordManager;
private final PlayerDataManager playerDataManager;
private final TickManager tickManager;
private final GrimExternalAPI externalAPI;
private PlatformLoader loader;
private InitManager initManager;
private boolean initialized = false;
private GrimAPI() {
this.configManager = new BaseConfigManager();
this.alertManager = new AlertManagerImpl();
this.spectateManager = new SpectateManager();
this.discordManager = new DiscordManager();
this.playerDataManager = new PlayerDataManager();
this.tickManager = new TickManager();
this.externalAPI = new GrimExternalAPI(this);
}
private static Platform detectPlatform() {
final Map<String, Platform> platforms = Collections.unmodifiableMap(new HashMap<>() {{
put("io.papermc.paper.threadedregions.RegionizedServer", Platform.FOLIA);
put("org.bukkit.Bukkit", Platform.BUKKIT);
put("net.fabricmc.loader.api.FabricLoader", Platform.FABRIC);
}});
return platforms.entrySet().stream()
.filter(entry -> ReflectionUtils.hasClass(entry.getKey()))
.map(Map.Entry::getValue)
.findFirst()
.orElseThrow(() -> new IllegalStateException("Unknown platform!"));
}
public void load(PlatformLoader platformLoader, Initable... platformSpecificInitables) {
this.loader = platformLoader;
this.initManager = new InitManager(loader.getPacketEvents(), loader::getCommandManager, platformSpecificInitables);
this.initManager.load();
this.initialized = true;
}
public void start() {
checkInitialized();
initManager.start();
}
public void stop() {
checkInitialized();
initManager.stop();
}
public PlatformScheduler getScheduler() {
return loader.getScheduler();
}
public PlatformPlayerFactory getPlatformPlayerFactory() {
return loader.getPlatformPlayerFactory();
}
public ParserDescriptorFactory getParserDescriptors() {
return loader.getParserDescriptorFactory();
}
public InitManager getInitManager() {
return initManager;
}
public GrimPlugin getGrimPlugin() {
return loader.getPlugin();
}
public SenderFactory<?> getSenderFactory() {
return loader.getSenderFactory();
}
public ItemResetHandler getItemResetHandler() {
return loader.getItemResetHandler();
}
public PlatformPluginManager getPluginManager() {
return loader.getPluginManager();
}
public PlatformServer getPlatformServer() {
return loader.getPlatformServer();
}
public @NotNull MessagePlaceHolderManager getMessagePlaceHolderManager() {
return loader.getMessagePlaceHolderManager();
}
private void checkInitialized() {
if (!initialized) {
throw new IllegalStateException("GrimAPI has not been initialized!");
}
}
public PermissionRegistrationManager getPermissionManager() {
return loader.getPermissionManager();
}
public Platform getPlatform() {
return platform;
}
}
@@ -0,0 +1,218 @@
package ac.grim.grimac;
import ac.grim.grimac.api.GrimAbstractAPI;
import ac.grim.grimac.api.plugin.GrimPluginDescription;
import ac.grim.grimac.api.GrimUser;
import ac.grim.grimac.api.alerts.AlertManager;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.api.event.EventBus;
import ac.grim.grimac.api.event.events.GrimReloadEvent;
import ac.grim.grimac.manager.config.ConfigManagerFileImpl;
import ac.grim.grimac.manager.init.start.StartableInitable;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.chat.ChatUtil;
import ac.grim.grimac.utils.common.ConfigReloadObserver;
import com.github.retrooper.packetevents.netty.channel.ChannelHelper;
import lombok.Getter;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
//This is used for grim's external API. It has its own class just for organization.
public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, StartableInitable {
private final GrimAPI api;
@Getter
private final Map<String, Function<GrimUser, String>> variableReplacements = new ConcurrentHashMap<>();
@Getter
private final Map<String, String> staticReplacements = new ConcurrentHashMap<>();
private final Map<String, Function<Object, Object>> functions = new ConcurrentHashMap<>();
private final ConfigManagerFileImpl configManagerFile = new ConfigManagerFileImpl();
private ConfigManager configManager = null;
private boolean started = false;
public GrimExternalAPI(GrimAPI api) {
this.api = api;
}
@Override
public @NonNull EventBus getEventBus() {
return api.getPluginManager().getEventBus();
}
@Override
public @Nullable GrimUser getGrimUser(UUID uuid) {
return api.getPlayerDataManager().getPlayer(uuid);
}
public String replaceVariables(GrimUser user, String content) {
for (Map.Entry<String, String> entry : staticReplacements.entrySet()) {
content = content.replace(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, Function<GrimUser, String>> entry : variableReplacements.entrySet()) {
content = content.replace(entry.getKey(), entry.getValue().apply(user));
}
return content;
}
@Override
public void registerVariable(String string, Function<GrimUser, String> replacement) {
if (replacement == null) {
variableReplacements.remove(string);
} else {
variableReplacements.put(string, replacement);
}
}
@Override
public void registerVariable(String variable, String replacement) {
if (replacement == null) {
staticReplacements.remove(variable);
} else {
staticReplacements.put(variable, replacement);
}
}
@Override
public String getGrimVersion() {
GrimPluginDescription description = GrimAPI.INSTANCE.getGrimPlugin().getDescription();
return description.getVersion();
}
@Override
public void registerFunction(String key, Function<Object, Object> function) {
if (function == null) {
functions.remove(key);
} else {
functions.put(key, function);
}
}
@Override
public Function<Object, Object> getFunction(String key) {
return functions.get(key);
}
@Override
public AlertManager getAlertManager() {
return GrimAPI.INSTANCE.getAlertManager();
}
@Override
public ConfigManager getConfigManager() {
return configManager;
}
@Override
public boolean hasStarted() {
return started;
}
@Override
public int getCurrentTick() {
return GrimAPI.INSTANCE.getTickManager().currentTick;
}
// on load, load the config & register the service
public void load() {
reload(configManagerFile);
api.getLoader().registerAPIService();
}
// handles any config loading that's needed to be done after load
@Override
public void start() {
started = true;
try {
GrimAPI.INSTANCE.getConfigManager().start();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void reload(ConfigManager config) {
if (config.isLoadedAsync() && started) {
GrimAPI.INSTANCE.getScheduler().getAsyncScheduler().runNow(GrimAPI.INSTANCE.getGrimPlugin(),
() -> successfulReload(config));
} else {
successfulReload(config);
}
}
@Override
public CompletableFuture<Boolean> reloadAsync(ConfigManager config) {
if (config.isLoadedAsync() && started) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
GrimAPI.INSTANCE.getScheduler().getAsyncScheduler().runNow(GrimAPI.INSTANCE.getGrimPlugin(),
() -> future.complete(successfulReload(config)));
return future;
}
return CompletableFuture.completedFuture(successfulReload(config));
}
private boolean successfulReload(ConfigManager config) {
try {
config.reload();
GrimAPI.INSTANCE.getConfigManager().load(config);
if (started) GrimAPI.INSTANCE.getConfigManager().start();
onReload(config);
if (started)
GrimAPI.INSTANCE.getScheduler().getAsyncScheduler().runNow(GrimAPI.INSTANCE.getGrimPlugin(),
() -> GrimAPI.INSTANCE.getPluginManager().callEvent(new GrimReloadEvent(true)));
return true;
} catch (Exception e) {
e.printStackTrace();
}
if (started)
GrimAPI.INSTANCE.getScheduler().getAsyncScheduler().runNow(GrimAPI.INSTANCE.getGrimPlugin(),
() -> GrimAPI.INSTANCE.getPluginManager().callEvent(new GrimReloadEvent(false)));
return false;
}
@Override
public void onReload(ConfigManager newConfig) {
if (newConfig == null) {
LogUtil.warn("ConfigManager not set. Using default config file manager.");
configManager = configManagerFile;
} else {
configManager = newConfig;
}
// Update variables
updateVariables();
// Restart
GrimAPI.INSTANCE.getDiscordManager().reload();
GrimAPI.INSTANCE.getSpectateManager().reload();
// Don't reload players if the plugin hasn't started yet
if (!started) return;
// Reload checks for all players
for (GrimPlayer grimPlayer : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
ChannelHelper.runInEventLoop(grimPlayer.user.getChannel(), () -> {
grimPlayer.updatePermissions();
grimPlayer.reload(configManager);
});
}
}
private void updateVariables() {
variableReplacements.putIfAbsent("%player%", GrimUser::getName);
variableReplacements.putIfAbsent("%uuid%", user -> user.getUniqueId().toString());
variableReplacements.putIfAbsent("%ping%", user -> user.getTransactionPing() + "");
variableReplacements.putIfAbsent("%brand%", GrimUser::getBrand);
variableReplacements.putIfAbsent("%h_sensitivity%", user -> ((int) Math.round(user.getHorizontalSensitivity() * 200)) + "");
variableReplacements.putIfAbsent("%v_sensitivity%", user -> ((int) Math.round(user.getVerticalSensitivity() * 200)) + "");
variableReplacements.putIfAbsent("%fast_math%", user -> !user.isVanillaMath() + "");
variableReplacements.putIfAbsent("%tps%", user -> String.format("%.2f", GrimAPI.INSTANCE.getPlatformServer().getTPS()));
variableReplacements.putIfAbsent("%version%", GrimUser::getVersionName);
// static variables
staticReplacements.put("%prefix%", ChatUtil.translateAlternateColorCodes('&', GrimAPI.INSTANCE.getConfigManager().getPrefix()));
staticReplacements.putIfAbsent("%grim_version%", getGrimVersion());
}
}
@@ -0,0 +1,209 @@
package ac.grim.grimac.checks;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.AbstractCheck;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.api.event.events.FlagEvent;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import com.google.common.base.Preconditions;
import lombok.Getter;
import lombok.Setter;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.NotNull;
// Class from https://github.com/Tecnio/AntiCheatBase/blob/master/src/main/java/me/tecnio/anticheat/check/Check.java
@Getter
public class Check extends GrimProcessor implements AbstractCheck {
protected @NonNull final GrimPlayer player;
public double violations;
private double decay;
private double setbackVL;
private String checkName;
private String configName;
private String alternativeName;
private String displayName;
private String description;
private boolean experimental;
private @Setter boolean isEnabled;
private boolean exemptPermission;
private boolean noSetbackPermission;
private boolean noModifyPacketPermission;
private long lastViolationTime;
public Check(final @NotNull GrimPlayer player) {
Preconditions.checkArgument(player != null);
this.player = player;
final CheckData checkData = this.getClass().getAnnotation(CheckData.class);
if (checkData != null) {
this.checkName = checkData.name();
this.configName = checkData.configName();
// Fall back to check name
if (this.configName.equals("DEFAULT")) this.configName = this.checkName;
this.decay = checkData.decay();
this.setbackVL = checkData.setback();
this.alternativeName = checkData.alternativeName();
this.experimental = checkData.experimental();
this.description = checkData.description();
this.displayName = this.checkName;
}
reload();
}
public boolean shouldModifyPackets() {
return isEnabled && !player.disableGrim && !player.noModifyPacketPermission && !exemptPermission;
}
public void updatePermissions() {
if (player.platformPlayer == null || configName == null) return;
GrimAPI.INSTANCE.getScheduler().getEntityScheduler().run(
player.platformPlayer,
GrimAPI.INSTANCE.getGrimPlugin(),
() -> {
final String id = configName.toLowerCase();
exemptPermission = player.platformPlayer.hasPermission("grim.exempt." + id);
noSetbackPermission = player.platformPlayer.hasPermission("grim.nosetback." + id);
noModifyPacketPermission = player.platformPlayer.hasPermission("grim.nomodifypacket." + id);
},
() -> {}
);
}
public final boolean flagAndAlert(String verbose) {
if (flag(verbose)) {
alert(verbose);
return true;
}
return false;
}
public final boolean flagAndAlert() {
return flagAndAlert("");
}
public final boolean flag() {
return flag("");
}
public final boolean flag(String verbose) {
if (player.disableGrim || (experimental && !player.isExperimentalChecks()) || exemptPermission)
return false; // Avoid calling event if disabled
FlagEvent event = new FlagEvent(player, this, verbose);
GrimAPI.INSTANCE.getPluginManager().callEvent(event);
if (event.isCancelled()) return false;
player.punishmentManager.handleViolation(this);
lastViolationTime = System.currentTimeMillis();
violations++;
return true;
}
public final boolean flagWithSetback() {
if (flag()) {
setbackIfAboveSetbackVL();
return true;
}
return false;
}
public final boolean flagAndAlertWithSetback() {
return flagAndAlertWithSetback("");
}
public final boolean flagAndAlertWithSetback(String verbose) {
if (flagAndAlert(verbose)) {
setbackIfAboveSetbackVL();
return true;
}
return false;
}
public final void reward() {
violations = Math.max(0, violations - decay);
}
@Override
public void reload(ConfigManager configuration) {
decay = configuration.getDoubleElse(configName + ".decay", decay);
setbackVL = configuration.getDoubleElse(configName + ".setbackvl", setbackVL);
displayName = configuration.getStringElse(configName + ".displayname", checkName);
description = configuration.getStringElse(configName + ".description", description);
if (setbackVL == -1) setbackVL = Double.MAX_VALUE;
updatePermissions();
onReload(configuration);
}
@Override
public void onReload(ConfigManager config) {
}
public boolean alert(String verbose) {
return player.punishmentManager.handleAlert(player, verbose, this);
}
public boolean setbackIfAboveSetbackVL() {
if (shouldSetback()) {
return player.getSetbackTeleportUtil().executeViolationSetback();
}
return false;
}
public boolean shouldSetback() {
return !noSetbackPermission && violations > setbackVL;
}
public String formatOffset(double offset) {
return offset > 0.001 ? String.format("%.5f", offset) : String.format("%.2E", offset);
}
public boolean isTransaction(PacketTypeCommon packetType) {
return packetType == PacketType.Play.Client.PONG ||
packetType == PacketType.Play.Client.WINDOW_CONFIRMATION;
}
public boolean isFlying(PacketTypeCommon packetType) {
return WrapperPlayClientPlayerFlying.isFlying(packetType);
}
public boolean isUpdate(PacketTypeCommon packetType) {
return isFlying(packetType)
|| packetType == PacketType.Play.Client.CLIENT_TICK_END
|| isTransaction(packetType);
}
public boolean isTickPacket(PacketTypeCommon packetType) {
if (isTickPacketIncludingNonMovement(packetType)) {
if (isFlying(packetType)) {
return !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate;
}
return true;
}
return false;
}
public boolean isTickPacketIncludingNonMovement(PacketTypeCommon packetType) {
// On 1.21.2+ fall back to the TICK_END packet IF the player did not send a movement packet for their tick
// TickTimer checks to see if player did not send a tick end packet before new flying packet is sent
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_2)
&& !player.packetStateData.didSendMovementBeforeTickEnd) {
if (packetType == PacketType.Play.Client.CLIENT_TICK_END) {
return true;
}
}
return isFlying(packetType);
}
}
@@ -0,0 +1,17 @@
package ac.grim.grimac.checks;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.AbstractProcessor;
import ac.grim.grimac.api.config.ConfigReloadable;
import ac.grim.grimac.utils.common.ConfigReloadObserver;
public abstract class GrimProcessor implements AbstractProcessor, ConfigReloadable, ConfigReloadObserver {
// Not everything has to be a check for it to process packets & be configurable
@Override
public void reload() {
reload(GrimAPI.INSTANCE.getConfigManager().getConfig());
}
}
@@ -8,15 +8,15 @@ import ac.grim.grimac.utils.anticheat.update.RotationUpdate;
@CheckData(name = "AimDuplicateLook")
public class AimDuplicateLook extends Check implements RotationCheck {
boolean exempt = false;
public AimDuplicateLook(GrimPlayer playerData) {
super(playerData);
}
boolean exempt = false;
@Override
public void process(final RotationUpdate rotationUpdate) {
if (player.packetStateData.lastPacketWasTeleport || player.packetStateData.lastPacketWasOnePointSeventeenDuplicate || player.compensatedEntities.getSelf().getRiding() != null) {
if (player.packetStateData.lastPacketWasTeleport || player.packetStateData.lastPacketWasOnePointSeventeenDuplicate || player.compensatedEntities.self.getRiding() != null) {
exempt = true;
return;
}
@@ -11,7 +11,8 @@ import ac.grim.grimac.utils.anticheat.update.RotationUpdate;
// It works on clients who % 360 their rotation.
@CheckData(name = "AimModulo360", decay = 0.005)
public class AimModulo360 extends Check implements RotationCheck {
float lastDeltaYaw;
private float lastDeltaYaw;
public AimModulo360(GrimPlayer playerData) {
super(playerData);
@@ -19,12 +20,20 @@ public class AimModulo360 extends Check implements RotationCheck {
@Override
public void process(final RotationUpdate rotationUpdate) {
lastDeltaYaw = rotationUpdate.getDeltaXRot();
if (player.packetStateData.lastPacketWasTeleport) return;
// Exempt for teleport, entering a vehicle due to rotation reset or
// after forced, client-sided rotation change after interacting with a horse (not necessarily mounting it)
if (player.packetStateData.lastPacketWasTeleport || player.vehicleData.wasVehicleSwitch
|| player.packetStateData.horseInteractCausedForcedRotation) {
lastDeltaYaw = rotationUpdate.getDeltaXRot();
return;
}
if (player.xRot < 360 && player.xRot > -360 && Math.abs(rotationUpdate.getDeltaXRot()) > 320 && Math.abs(lastDeltaYaw) < 30) {
flagAndAlert();
} else {
reward();
}
lastDeltaYaw = rotationUpdate.getDeltaXRot();
}
}
@@ -13,26 +13,26 @@ public class AimProcessor extends Check implements RotationCheck {
private static final int SIGNIFICANT_SAMPLES_THRESHOLD = 15;
private static final int TOTAL_SAMPLES_THRESHOLD = 80;
public double sensitivityX;
public double sensitivityY;
public double divisorX;
public double divisorY;
public double modeX, modeY;
public double deltaDotsX, deltaDotsY;
RunningMode xRotMode = new RunningMode(TOTAL_SAMPLES_THRESHOLD);
RunningMode yRotMode = new RunningMode(TOTAL_SAMPLES_THRESHOLD);
float lastXRot;
float lastYRot;
public AimProcessor(GrimPlayer playerData) {
super(playerData);
}
RunningMode xRotMode = new RunningMode(TOTAL_SAMPLES_THRESHOLD);
RunningMode yRotMode = new RunningMode(TOTAL_SAMPLES_THRESHOLD);
float lastXRot;
float lastYRot;
public double sensitivityX;
public double sensitivityY;
public double divisorX;
public double divisorY;
public double modeX, modeY;
public double deltaDotsX, deltaDotsY;
public static double convertToSensitivity(double var13) {
double var11 = var13 / 0.15F / 8.0D;
double var9 = Math.cbrt(var11);
return (var9 - 0.2f) / 0.6f;
}
@Override
public void process(final RotationUpdate rotationUpdate) {
@@ -59,15 +59,15 @@ public class AimProcessor extends Check implements RotationCheck {
if (this.xRotMode.size() > SIGNIFICANT_SAMPLES_THRESHOLD) {
Pair<Double, Integer> modeX = this.xRotMode.getMode();
if (modeX.getSecond() > SIGNIFICANT_SAMPLES_THRESHOLD) {
this.modeX = modeX.getFirst();
if (modeX.second() > SIGNIFICANT_SAMPLES_THRESHOLD) {
this.modeX = modeX.first();
this.sensitivityX = convertToSensitivity(this.modeX);
}
}
if (this.yRotMode.size() > SIGNIFICANT_SAMPLES_THRESHOLD) {
Pair<Double, Integer> modeY = this.yRotMode.getMode();
if (modeY.getSecond() > SIGNIFICANT_SAMPLES_THRESHOLD) {
this.modeY = modeY.getFirst();
if (modeY.second() > SIGNIFICANT_SAMPLES_THRESHOLD) {
this.modeY = modeY.first();
this.sensitivityY = convertToSensitivity(this.modeY);
}
}
@@ -75,10 +75,4 @@ public class AimProcessor extends Check implements RotationCheck {
this.deltaDotsX = deltaXRot / modeX;
this.deltaDotsY = deltaYRot / modeY;
}
public static double convertToSensitivity(double var13) {
double var11 = var13 / 0.15F / 8.0D;
double var9 = Math.cbrt(var11);
return (var9 - 0.2f) / 0.6f;
}
}
}
@@ -8,7 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientHeldItemChange;
@CheckData(name = "BadPacketsA")
@CheckData(name = "BadPacketsA", description = "Sent duplicate slot id")
public class BadPacketsA extends Check implements PacketCheck {
int lastSlot = -1;
@@ -6,9 +6,10 @@ import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
@CheckData(name = "BadPacketsC")
@CheckData(name = "BadPacketsC", description = "Interacted with self")
public class BadPacketsC extends Check implements PacketCheck {
public BadPacketsC(GrimPlayer player) {
super(player);
@@ -17,6 +18,7 @@ public class BadPacketsC extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
if (player.gamemode == GameMode.SPECTATOR) return;
if (new WrapperPlayClientInteractEntity(event).getEntityId() == player.entityID) {
// Instant ban
if (flagAndAlert() && shouldModifyPackets()) {
@@ -8,7 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
@CheckData(name = "BadPacketsD")
@CheckData(name = "BadPacketsD", description = "Impossible pitch")
public class BadPacketsD extends Check implements PacketCheck {
public BadPacketsD(GrimPlayer player) {
super(player);
@@ -4,8 +4,11 @@ import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
@CheckData(name = "BadPacketsE")
@@ -18,12 +21,14 @@ public class BadPacketsE extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
final boolean isViaPleaseStopUsingProtocolHacksOnYourServer = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_2) || PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_21_2);
if (event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION ||
event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION) {
noReminderTicks = 0;
} else if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
noReminderTicks++;
} else if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE) {
} else if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE
|| (isViaPleaseStopUsingProtocolHacksOnYourServer && player.inVehicle())) {
noReminderTicks = 0; // Exempt vehicles
}
@@ -8,7 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
@CheckData(name = "BadPacketsF")
@CheckData(name = "BadPacketsF", description = "Sent duplicate sprinting status")
public class BadPacketsF extends Check implements PacketCheck {
public boolean lastSprinting;
public boolean exemptNext = true; // Support 1.14+ clients starting on either true or false sprinting, we don't know
@@ -8,10 +8,9 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
@CheckData(name = "BadPacketsG")
@CheckData(name = "BadPacketsG", description = "Sent duplicate sneaking status")
public class BadPacketsG extends Check implements PacketCheck {
boolean wasTeleport;
boolean lastSneaking;
private boolean lastSneaking, respawn;
public BadPacketsG(GrimPlayer player) {
super(player);
@@ -19,13 +18,12 @@ public class BadPacketsG extends Check implements PacketCheck {
@Override
public void onPacketReceive(PacketReceiveEvent event) {
wasTeleport = player.packetStateData.lastPacketWasTeleport || wasTeleport;
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
WrapperPlayClientEntityAction packet = new WrapperPlayClientEntityAction(event);
if (packet.getAction() == WrapperPlayClientEntityAction.Action.START_SNEAKING) {
if (lastSneaking && !wasTeleport) {
// The player may send two START_SNEAKING packets if they respawned
if (lastSneaking && !respawn) {
if (flagAndAlert("state=true") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -33,8 +31,9 @@ public class BadPacketsG extends Check implements PacketCheck {
} else {
lastSneaking = true;
}
respawn = false;
} else if (packet.getAction() == WrapperPlayClientEntityAction.Action.STOP_SNEAKING) {
if (!lastSneaking && !wasTeleport) {
if (!lastSneaking && !respawn) {
if (flagAndAlert("state=false") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -42,7 +41,13 @@ public class BadPacketsG extends Check implements PacketCheck {
} else {
lastSneaking = false;
}
respawn = false;
}
}
}
public void handleRespawn() {
// Clients could potentially not send a STOP_SNEAKING packet when they die, so we need to track it
respawn = true;
}
}
@@ -10,9 +10,8 @@ import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
@CheckData(name = "BadPacketsH")
@CheckData(name = "BadPacketsH", description = "Did not swing for attack")
public class BadPacketsH extends Check implements PacketCheck {
// 1.9 packet order: INTERACT -> ANIMATION
@@ -42,9 +41,10 @@ public class BadPacketsH extends Check implements PacketCheck {
// I will simply disable this check for 1.8- clients on 1.9+ servers as I can't be bothered to find a way around this.
// Stop supporting such old clients on modern servers!
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_9)
&& PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_8)) return;
&& PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9))
return;
if (!sentAnimation && flagAndAlert()) {
if (!sentAnimation && flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
@@ -8,7 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerAbilities;
@CheckData(name = "BadPacketsI")
@CheckData(name = "BadPacketsI", description = "Claimed to be flying while unable to fly")
public class BadPacketsI extends Check implements PacketCheck {
public BadPacketsI(GrimPlayer player) {
super(player);
@@ -8,7 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.GameMode;
@CheckData(name = "BadPacketsK")
@CheckData(name = "BadPacketsK", description = "Sent spectate packets while not in spectator mode")
public class BadPacketsK extends Check implements PacketCheck {
public BadPacketsK(GrimPlayer player) {
super(player);
@@ -8,13 +8,11 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
import java.util.Locale;
// checks for impossible dig packets
@CheckData(name = "BadPacketsL")
@CheckData(name = "BadPacketsL", description = "Sent impossible dig packet")
public class BadPacketsL extends Check implements PacketCheck {
public BadPacketsL(GrimPlayer player) {
@@ -26,23 +24,25 @@ public class BadPacketsL extends Check implements PacketCheck {
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
final WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
if (packet.getAction() == DiggingAction.START_DIGGING || packet.getAction() == DiggingAction.FINISHED_DIGGING || packet.getAction() == DiggingAction.CANCELLED_DIGGING) return;
if (packet.getAction() == DiggingAction.START_DIGGING || packet.getAction() == DiggingAction.FINISHED_DIGGING || packet.getAction() == DiggingAction.CANCELLED_DIGGING)
return;
// 1.8 and above clients always send digging packets that aren't used for digging at 0, 0, 0, facing DOWN
// 1.7 and below clients do the same, except use SOUTH for RELEASE_USE_ITEM
final BlockFace expectedFace = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10) && packet.getAction() == DiggingAction.RELEASE_USE_ITEM
? BlockFace.SOUTH : BlockFace.DOWN;
final int expectedFace = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10) && packet.getAction() == DiggingAction.RELEASE_USE_ITEM
? 255 : 0;
if (packet.getBlockFace() != expectedFace
if (packet.getBlockFaceId() != expectedFace
|| packet.getBlockPosition().getX() != 0
|| packet.getBlockPosition().getY() != 0
|| packet.getBlockPosition().getZ() != 0
|| packet.getSequence() != 0
) {
if (flagAndAlert("xyzF="
+ packet.getBlockPosition().getX() + ", " + packet.getBlockPosition().getY() + ", " + packet.getBlockPosition().getZ() + ", " + packet.getBlockFace()
if (flagAndAlert("pos="
+ packet.getBlockPosition().getX() + ", " + packet.getBlockPosition().getY() + ", " + packet.getBlockPosition().getZ()
+ ", face=" + packet.getBlockFace()
+ ", sequence=" + packet.getSequence()
+ ", action=" + packet.getAction().toString().toLowerCase(Locale.ROOT).replace("_", " ") + " v" + player.getVersionName()
+ ", action=" + packet.getAction().toString().toLowerCase(Locale.ROOT)
) && shouldModifyPackets() && packet.getAction() != DiggingAction.RELEASE_USE_ITEM) {
event.setCancelled(true);
player.onPacketCancel();
@@ -11,16 +11,16 @@ import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
@CheckData(name = "BadPacketsM", experimental = true)
@CheckData(name = "BadPacketsM")
public class BadPacketsM extends Check implements PacketCheck {
public BadPacketsM(final GrimPlayer player) {
super(player);
}
// 1.7 players do not send INTERACT_AT, so we cannot check them
private final boolean exempt = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10);
private boolean sentInteractAt = false;
public BadPacketsM(final GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY && !exempt) {
@@ -5,7 +5,7 @@ import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
@CheckData(name = "BadPacketsN")
@CheckData(name = "BadPacketsN", setback = 0)
public class BadPacketsN extends Check implements PacketCheck {
public BadPacketsN(final GrimPlayer player) {
super(player);
@@ -39,7 +39,7 @@ public class BadPacketsO extends Check implements PacketCheck {
boolean hasID = false;
for (Pair<Long, Long> iterator : keepaliveMap) {
if (iterator.getFirst() == id) {
if (iterator.first() == id) {
hasID = true;
break;
}
@@ -55,7 +55,7 @@ public class BadPacketsO extends Check implements PacketCheck {
do {
data = keepaliveMap.poll();
if (data == null) break;
} while (data.getFirst() != id);
} while (data.first() != id);
}
}
}
@@ -8,18 +8,19 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClickWindow;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClickWindow.WindowClickType;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerOpenWindow;
@CheckData(name = "BadPacketsP", experimental = true)
public class BadPacketsP extends Check implements PacketCheck {
private int containerType = -1;
private int containerId = -1;
public BadPacketsP(GrimPlayer playerData) {
super(playerData);
}
private int containerType = -1;
private int containerId = -1;
@Override
public void onPacketSend(final PacketSendEvent event) {
if (event.getPacketType() == PacketType.Play.Server.OPEN_WINDOW) {
@@ -33,35 +34,22 @@ public class BadPacketsP extends Check implements PacketCheck {
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
WrapperPlayClientClickWindow wrapper = new WrapperPlayClientClickWindow(event);
int clickType = wrapper.getWindowClickType().ordinal();
WindowClickType clickType = wrapper.getWindowClickType();
int button = wrapper.getButton();
boolean flag = false;
// TODO: Adjust for containers
boolean flag = switch (clickType) {
case PICKUP, QUICK_MOVE, CLONE -> button > 2 || button < 0;
case SWAP -> (button > 8 || button < 0) && button != 40;
case THROW -> button != 0 && button != 1;
case QUICK_CRAFT -> button == 3 || button == 7 || button > 10 || button < 0;
case PICKUP_ALL -> button != 0;
case UNKNOWN -> false;
};
//TODO: Adjust for containers
switch (clickType) {
case 0:
case 1:
case 4:
if (button != 0 && button != 1) flag = true;
break;
case 2:
if ((button > 8 || button < 0) && button != 40) flag = true;
break;
case 3:
if (button != 2) flag = true;
break;
case 5:
if (button == 3 || button == 7 || button > 10 || button < 0) flag = true;
break;
case 6:
if (button != 0) flag = true;
break;
}
//Allowing this to false flag to debug and find issues faster
// Allowing this to false flag to debug and find issues faster
if (flag) {
if (flagAndAlert("clickType=" + clickType + " button=" + button + (wrapper.getWindowId() == containerId ? " container=" + containerType : "")) && shouldModifyPackets()) {
if (flagAndAlert("clickType=" + clickType.toString().toLowerCase() + ", button=" + button + (wrapper.getWindowId() == containerId ? ", container=" + containerType : "")) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
@@ -19,8 +19,10 @@ public class BadPacketsQ extends Check implements PacketCheck {
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == Client.ENTITY_ACTION) {
WrapperPlayClientEntityAction wrapper = new WrapperPlayClientEntityAction(event);
if (wrapper.getJumpBoost() < 0 || wrapper.getJumpBoost() > 100 || wrapper.getEntityId() != player.entityID || (wrapper.getAction() != Action.START_JUMPING_WITH_HORSE && wrapper.getJumpBoost() != 0)) {
// you are able to send negative jump boost, how and why!?
if (Math.abs(wrapper.getJumpBoost()) > 100
|| wrapper.getEntityId() != player.entityID
|| wrapper.getAction() != Action.START_JUMPING_WITH_HORSE && wrapper.getJumpBoost() != 0) {
if (flagAndAlert("boost=" + wrapper.getJumpBoost() + ", action=" + wrapper.getAction() + ", entity=" + wrapper.getEntityId()) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
@@ -10,23 +10,23 @@ import com.github.retrooper.packetevents.protocol.player.GameMode;
@CheckData(name = "BadPacketsR", decay = 0.25, experimental = true)
public class BadPacketsR extends Check implements PacketCheck {
public BadPacketsR(final GrimPlayer player) {
super(player);
}
private int positions = 0;
private long clock = 0;
private long lastTransTime;
private int oldTransId = 0;
public BadPacketsR(final GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(final PacketReceiveEvent event) {
if (isTransaction(event.getPacketType()) && player.packetStateData.lastTransactionPacketWasValid) {
long ms = (player.getPlayerClockAtLeast() - clock) / 1000000L;
long diff = (System.currentTimeMillis() - lastTransTime);
if (diff > 2000 && ms > 2000) {
if (positions == 0 && clock != 0 && player.gamemode != GameMode.SPECTATOR && !player.compensatedEntities.getSelf().isDead) {
flagAndAlert("time=" + ms + "ms, " + "lst=" + diff + "ms, positions=" + positions);
if (positions == 0 && clock != 0 && player.gamemode != GameMode.SPECTATOR && !player.compensatedEntities.self.isDead) {
flag("time=" + ms + "ms, " + "lst=" + diff + "ms, positions=" + positions);
} else {
reward();
}
@@ -39,9 +39,10 @@ public class BadPacketsR extends Check implements PacketCheck {
}
//
if ((event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION ||
event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION) && !player.compensatedEntities.getSelf().inVehicle()) {
event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION) && !player.inVehicle()) {
positions++;
} else if (event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE && player.compensatedEntities.getSelf().inVehicle()) {
} else if ((event.getPacketType() == PacketType.Play.Client.STEER_VEHICLE || event.getPacketType() == PacketType.Play.Client.VEHICLE_MOVE)
&& player.inVehicle()) {
positions++;
}
}
@@ -14,10 +14,6 @@ import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientIn
@CheckData(name = "BadPacketsT")
public class BadPacketsT extends Check implements PacketCheck {
public BadPacketsT(final GrimPlayer player) {
super(player);
}
// 1.7 and 1.8 seem to have different hitbox "expansion" values than 1.9+
// https://github.com/GrimAnticheat/Grim/pull/1274#issuecomment-1872458702
// https://github.com/GrimAnticheat/Grim/pull/1274#issuecomment-1872533497
@@ -26,6 +22,10 @@ public class BadPacketsT extends Check implements PacketCheck {
private final double minVerticalDisplacement = -0.0001 - (hasLegacyExpansion ? 0.1 : 0);
private final double maxVerticalDisplacement = 1.8001 + (hasLegacyExpansion ? 0.1 : 0);
public BadPacketsT(final GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(final PacketReceiveEvent event) {
if (event.getPacketType().equals(PacketType.Play.Client.INTERACT_ENTITY)) {
@@ -49,7 +49,7 @@ public class BadPacketsT extends Check implements PacketCheck {
// 27/12/2023 - Dynamic values for more than just one entity type?
// 28/12/2023 - Player-only is fine
// 30/12/2023 - Expansions differ in 1.9+
final float scale = (float) packetEntity.getAttributeValue(Attributes.GENERIC_SCALE);
final float scale = (float) packetEntity.getAttributeValue(Attributes.SCALE);
if (targetVector.y > (minVerticalDisplacement * scale) && targetVector.y < (maxVerticalDisplacement * scale)
&& Math.abs(targetVector.x) < (maxHorizontalDisplacement * scale)
&& Math.abs(targetVector.z) < (maxHorizontalDisplacement * scale)) {
@@ -6,7 +6,6 @@ import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.item.ItemStack;
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
@@ -15,7 +14,7 @@ import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerBlockPlacement;
@CheckData(name = "BadPacketsU", experimental = true)
@CheckData(name = "BadPacketsU", description = "Sent impossible use item packet")
public class BadPacketsU extends Check implements PacketCheck {
public BadPacketsU(GrimPlayer player) {
super(player);
@@ -0,0 +1,41 @@
package ac.grim.grimac.checks.impl.badpackets;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
@CheckData(name = "BadPacketsV", description = "Did not move far enough", experimental = true)
public class BadPacketsV extends Check implements PacketCheck {
private int noReminderTicks;
public BadPacketsV(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (!player.canSkipTicks() && isTickPacket(event.getPacketType())) {
if (event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION || event.getPacketType() == PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION) {
int positionAtLeastEveryNTicks = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) ? 20 : 19;
if (noReminderTicks < positionAtLeastEveryNTicks && !player.uncertaintyHandler.lastTeleportTicks.hasOccurredSince(1)) {
final double deltaSq = new WrapperPlayClientPlayerFlying(event).getLocation().getPosition()
.distanceSquared(new Vector3d(player.lastX, player.lastY, player.lastZ));
if (deltaSq <= player.getMovementThreshold() * player.getMovementThreshold()) {
flagAndAlert("delta=" + Math.sqrt(deltaSq));
}
}
noReminderTicks = 0;
} else {
noReminderTicks++;
}
}
}
}
@@ -5,7 +5,7 @@ import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
@CheckData(name = "BadPacketsW", experimental = true)
@CheckData(name = "BadPacketsW", description = "Interacted with non-existent entity", experimental = true)
public class BadPacketsW extends Check implements PacketCheck {
public BadPacketsW(GrimPlayer player) {
super(player);
@@ -0,0 +1,77 @@
package ac.grim.grimac.checks.impl.badpackets;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
@CheckData(name = "BadPacketsX", experimental = true)
public class BadPacketsX extends Check implements PostPredictionCheck {
private boolean sprint;
private boolean sneak;
private int flags;
public BadPacketsX(GrimPlayer player) {
super(player);
}
@Override
public void onPredictionComplete(final PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) {
if (flags > 0) {
setbackIfAboveSetbackVL();
}
flags = 0;
return;
}
if (player.isTickingReliablyFor(3)) {
for (; flags > 0; flags--) {
flagAndAlertWithSetback();
}
}
flags = 0;
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (player.gamemode == GameMode.SPECTATOR || isTickPacket(event.getPacketType())) {
sprint = sneak = false;
return;
}
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
switch (new WrapperPlayClientEntityAction(event).getAction()) {
case START_SNEAKING, STOP_SNEAKING -> {
if (sneak) {
if (player.canSkipTicks() || flagAndAlert()) {
flags++;
}
}
sneak = true;
}
case START_SPRINTING, STOP_SPRINTING -> {
if (player.inVehicle()) {
return;
}
if (sprint) {
if (player.canSkipTicks() || flagAndAlert()) {
flags++;
}
}
sprint = true;
}
}
}
}
}
@@ -8,10 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientHeldItemChange;
/**
* Checks for out of bounds slot changes
*/
@CheckData(name = "BadPacketsY")
@CheckData(name = "BadPacketsY", description = "Sent out of bounds slot id")
public class BadPacketsY extends Check implements PacketCheck {
public BadPacketsY(GrimPlayer player) {
super(player);
@@ -22,7 +19,7 @@ public class BadPacketsY extends Check implements PacketCheck {
if (event.getPacketType() == PacketType.Play.Client.HELD_ITEM_CHANGE) {
final int slot = new WrapperPlayClientHeldItemChange(event).getSlot();
if (slot > 8 || slot < 0) { // ban
if (flagAndAlert("slot="+slot) && shouldModifyPackets()) {
if (flagAndAlert("slot=" + slot) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
@@ -12,12 +12,12 @@ import ac.grim.grimac.utils.math.GrimMath;
// This check has been patched by Baritone for a long time and it also seems to false with cinematic camera now, so it is disabled.
@CheckData(name = "Baritone")
public class Baritone extends Check implements RotationCheck {
private int verbose;
public Baritone(GrimPlayer playerData) {
super(playerData);
}
private int verbose;
@Override
public void process(final RotationUpdate rotationUpdate) {
final HeadRotation from = rotationUpdate.getFrom();
@@ -0,0 +1,71 @@
package ac.grim.grimac.checks.impl.breaking;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import org.checkerframework.checker.nullness.qual.NonNull;
@CheckData(name = "AirLiquidBreak", description = "Breaking a block that cannot be broken")
public class AirLiquidBreak extends Check implements BlockBreakCheck {
public final boolean noFireHitbox = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_15_2);
private int lastTick;
private boolean didLastFlag;
// Initialize to non-null values to prevent NPE when checking for blockType properties and if position equals old position
private @NonNull Vector3i lastBreakLoc = new Vector3i();
private @NonNull StateType lastBlockType = StateTypes.AIR;
public AirLiquidBreak(GrimPlayer player) {
super(player);
}
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (blockBreak.action != DiggingAction.START_DIGGING && blockBreak.action != DiggingAction.FINISHED_DIGGING)
return;
final StateType block = blockBreak.block.getType();
// Fixes false from breaking kelp underwater
// The client sends two start digging packets to the server both in the same tick. AirLiquidBreak gets called twice, doesn't false the first time, but falses the second
// One ends up breaking the kelp, the other ends up doing nothing besides falsing this check because we think they're trying to mine water
// I am explicitly making this patch as narrow and specific as possible to potentially discover other blocks that exhibit similar behaviour
int newTick = GrimAPI.INSTANCE.getTickManager().currentTick;
if (lastTick == newTick
&& lastBreakLoc.equals(blockBreak.position)
&& !didLastFlag
&& lastBlockType.getHardness() == 0.0F
&& lastBlockType.getBlastResistance() == 0.0F
&& block == StateTypes.WATER
) return;
lastTick = newTick;
lastBreakLoc = blockBreak.position;
lastBlockType = block;
// the block does not have a hitbox
boolean invalid = (block == StateTypes.LIGHT && !(player.getInventory().getHeldItem().is(ItemTypes.LIGHT) || player.getInventory().getOffHand().is(ItemTypes.LIGHT)))
|| block.isAir()
|| block == StateTypes.WATER
|| block == StateTypes.LAVA
|| block == StateTypes.BUBBLE_COLUMN
|| block == StateTypes.MOVING_PISTON
|| block == StateTypes.FIRE && noFireHitbox
// or the client claims to have broken an unbreakable block
|| block.getHardness() == -1.0f && blockBreak.action == DiggingAction.FINISHED_DIGGING;
if (invalid && flagAndAlert("block=" + block.getName() + ", type=" + blockBreak.action) && shouldModifyPackets()) {
didLastFlag = true;
blockBreak.cancel();
} else {
didLastFlag = false;
}
}
}
@@ -0,0 +1,46 @@
package ac.grim.grimac.checks.impl.breaking;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.math.Vector3dm;
import ac.grim.grimac.utils.math.VectorUtils;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.player.GameMode;
@CheckData(name = "FarBreak", description = "Breaking blocks too far away", experimental = true)
public class FarBreak extends Check implements BlockBreakCheck {
public FarBreak(GrimPlayer player) {
super(player);
}
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (player.gamemode == GameMode.SPECTATOR || player.inVehicle() || blockBreak.action == DiggingAction.CANCELLED_DIGGING)
return; // falses
double min = Double.MAX_VALUE;
for (double d : player.getPossibleEyeHeights()) {
SimpleCollisionBox box = new SimpleCollisionBox(blockBreak.position);
Vector3dm eyes = new Vector3dm(player.x, player.y + d, player.z);
Vector3dm best = VectorUtils.cutBoxToVector(eyes, box);
min = Math.min(min, eyes.distanceSquared(best));
}
// getPickRange() determines this?
// With 1.20.5+ the new attribute determines creative mode reach using a modifier
double maxReach = player.compensatedEntities.self.getAttributeValue(Attributes.BLOCK_INTERACTION_RANGE);
if (player.packetStateData.didLastMovementIncludePosition || player.canSkipTicks()) {
double threshold = player.getMovementThreshold();
maxReach += Math.hypot(threshold, threshold);
}
if (min > maxReach * maxReach && flagAndAlert(String.format("distance=%.2f", Math.sqrt(min))) && shouldModifyPackets()) {
blockBreak.cancel();
}
}
}
@@ -0,0 +1,121 @@
package ac.grim.grimac.checks.impl.breaking;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.nmsutil.BlockBreakSpeed;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import java.util.Set;
// Based loosely off of Hawk BlockBreakSpeedSurvival
// Also based loosely off of NoCheatPlus FastBreak
// Also based off minecraft wiki: https://minecraft.wiki/w/Breaking#Instant_breaking
@CheckData(name = "FastBreak", description = "Breaking blocks too quickly")
public class FastBreak extends Check implements BlockBreakCheck {
// For some reason these states flag and I don't know why.
// Better to just exempt to not annoy legit players.
private static final Set<StateType> EXEMPT_STATES = Set.of();
public FastBreak(GrimPlayer playerData) {
super(playerData);
}
// The block the player is currently breaking
Vector3i targetBlock = null;
// The maximum amount of damage the player deals to the block
//
double maximumBlockDamage = 0;
// The last time a finish digging packet was sent, to enforce 0.3-second delay after non-instabreak
long lastFinishBreak = 0;
// The time the player started to break the block, to know how long the player waited until they finished breaking the block
long startBreak = 0;
// The buffer to this check
double blockBreakBalance = 0;
double blockDelayBalance = 0;
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (blockBreak.action == DiggingAction.START_DIGGING) {
WrappedBlockState block = blockBreak.block;
// Exempt all blocks that do not exist in the player version
final WrappedBlockState defaultState = WrappedBlockState.getDefaultState(player.getClientVersion(), block.getType());
if (defaultState.getType() == StateTypes.AIR || EXEMPT_STATES.contains(defaultState.getType())) {
return;
}
startBreak = System.currentTimeMillis() - (targetBlock == null ? 50 : 0); // ???
targetBlock = blockBreak.position;
maximumBlockDamage = BlockBreakSpeed.getBlockDamage(player, targetBlock);
double breakDelay = System.currentTimeMillis() - lastFinishBreak;
if (breakDelay >= 275) { // Reduce buffer if "close enough"
blockDelayBalance *= 0.9;
} else { // Otherwise, increase buffer
blockDelayBalance += 300 - breakDelay;
}
if (blockDelayBalance > 1000) { // If more than a second of advantage
if (flagAndAlert("delay=" + breakDelay + "ms, type=" + blockBreak.block.getType()) && shouldModifyPackets()) {
blockBreak.cancel();
}
}
clampBalance();
}
if (blockBreak.action == DiggingAction.FINISHED_DIGGING && targetBlock != null) {
double predictedTime = Math.ceil(1 / maximumBlockDamage) * 50;
double realTime = System.currentTimeMillis() - startBreak;
double diff = predictedTime - realTime;
clampBalance();
if (diff < 25) { // Reduce buffer if "close enough"
blockBreakBalance *= 0.9;
} else { // Otherwise, increase buffer
blockBreakBalance += diff;
}
if (blockBreakBalance > 1000) { // If more than a second of advantage
if (flagAndAlert("diff=" + diff + "ms, balance=" + blockBreakBalance + "ms, type=" + blockBreak.block.getType()) && shouldModifyPackets()) {
blockBreak.cancel();
}
}
// also set start time because the breaking netcode is fucked on 1.14.4+
lastFinishBreak = startBreak = System.currentTimeMillis();
}
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
// Find the most optimal block damage using the animation packet, which is sent at least once a tick when breaking blocks
// On 1.8 clients, via screws with this packet meaning we must fall back to the 1.8 idle flying packet
if ((player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? event.getPacketType() == PacketType.Play.Client.ANIMATION : WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) && targetBlock != null) {
maximumBlockDamage = Math.max(maximumBlockDamage, BlockBreakSpeed.getBlockDamage(player, targetBlock));
}
}
private void clampBalance() {
double balance = Math.max(1000, (player.getTransactionPing()));
blockBreakBalance = GrimMath.clamp(blockBreakBalance, -balance, balance); // Clamp not Math.max in case other logic changes
blockDelayBalance = GrimMath.clamp(blockDelayBalance, -balance, balance);
}
}
@@ -0,0 +1,30 @@
package ac.grim.grimac.checks.impl.breaking;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
@CheckData(name = "InvalidBreak", description = "Sent impossible block face id")
public class InvalidBreak extends Check implements BlockBreakCheck {
public InvalidBreak(GrimPlayer player) {
super(player);
}
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (blockBreak.faceId == 255 && blockBreak.action == DiggingAction.CANCELLED_DIGGING && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10)) {
return;
}
if (blockBreak.faceId < 0 || blockBreak.faceId > 5) {
// ban
if (flagAndAlert("face=" + blockBreak.faceId + ", action=" + blockBreak.action) && shouldModifyPackets()) {
blockBreak.cancel();
}
}
}
}
@@ -0,0 +1,73 @@
package ac.grim.grimac.checks.impl.breaking;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.util.Vector3i;
import java.util.ArrayList;
import java.util.List;
@CheckData(name = "MultiBreak", experimental = true)
public class MultiBreak extends Check implements BlockBreakCheck {
private final List<String> flags = new ArrayList<>();
private boolean hasBroken;
private BlockFace lastFace;
private Vector3i lastPos;
public MultiBreak(GrimPlayer player) {
super(player);
}
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
return;
}
if (hasBroken && (blockBreak.face != lastFace || !blockBreak.position.equals(lastPos))) {
final String verbose = "face=" + blockBreak.face + ", lastFace=" + lastFace
+ ", pos=" + MessageUtil.toUnlabledString(blockBreak.position)
+ ", lastPos=" + MessageUtil.toUnlabledString(lastPos);
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
blockBreak.cancel();
}
} else {
flags.add(verbose);
}
}
lastFace = blockBreak.face;
lastPos = blockBreak.position;
hasBroken = true;
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (player.gamemode == GameMode.SPECTATOR || isTickPacket(event.getPacketType())) {
hasBroken = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
}
flags.clear();
}
}
@@ -0,0 +1,42 @@
package ac.grim.grimac.checks.impl.breaking;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
@CheckData(name = "NoSwingBreak", description = "Did not swing while breaking block", experimental = true)
public class NoSwingBreak extends Check implements BlockBreakCheck {
private boolean sentAnimation;
private boolean sentBreak;
public NoSwingBreak(GrimPlayer playerData) {
super(playerData);
}
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (blockBreak.action != DiggingAction.CANCELLED_DIGGING) {
sentBreak = true;
}
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.ANIMATION) {
sentAnimation = true;
}
if (isTickPacket(event.getPacketType())) {
if (sentBreak && !sentAnimation) {
flagAndAlert();
}
sentAnimation = sentBreak = false;
}
}
}
@@ -0,0 +1,61 @@
package ac.grim.grimac.checks.impl.breaking;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
@CheckData(name = "PositionBreakA")
public class PositionBreakA extends Check implements BlockBreakCheck {
public PositionBreakA(GrimPlayer player) {
super(player);
}
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (player.inVehicle()
|| blockBreak.action == DiggingAction.CANCELLED_DIGGING
|| blockBreak.block.getType() == StateTypes.REDSTONE_WIRE
) return;
SimpleCollisionBox combined = blockBreak.getCombinedBox();
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
double minEyeHeight = Double.MAX_VALUE;
double maxEyeHeight = Double.MIN_VALUE;
for (double height : possibleEyeHeights) {
minEyeHeight = Math.min(minEyeHeight, height);
maxEyeHeight = Math.max(maxEyeHeight, height);
}
SimpleCollisionBox eyePositions = new SimpleCollisionBox(player.x, player.y + minEyeHeight, player.z, player.x, player.y + maxEyeHeight, player.z);
if (!player.packetStateData.didLastMovementIncludePosition || player.canSkipTicks()) {
eyePositions.expand(player.getMovementThreshold());
}
// If the player is inside a block, then they can ray trace through the block and hit the other side of the block
if (eyePositions.isIntersected(combined)) {
return;
}
// So now we have the player's possible eye positions
// So then look at the face that the player has clicked
boolean flag = switch (blockBreak.face) {
case NORTH -> eyePositions.minZ > combined.minZ; // Z- face
case SOUTH -> eyePositions.maxZ < combined.maxZ; // Z+ face
case EAST -> eyePositions.maxX < combined.maxX; // X+ face
case WEST -> eyePositions.minX > combined.minX; // X- face
case UP -> eyePositions.maxY < combined.maxY; // Y+ face
case DOWN -> eyePositions.minY > combined.minY; // Y- face
default -> false;
};
if (flag && flagAndAlert("action=" + blockBreak.action + ", face=" + blockBreak.face) && shouldModifyPackets()) {
blockBreak.cancel();
}
}
}
@@ -0,0 +1,37 @@
package ac.grim.grimac.checks.impl.breaking;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
@CheckData(name = "PositionBreakB", experimental = true)
public class PositionBreakB extends Check implements BlockBreakCheck {
private final int releaseFace = player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) ? 0 : 255;
private BlockFace lastFace;
public PositionBreakB(GrimPlayer player) {
super(player);
}
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (blockBreak.action == DiggingAction.START_DIGGING) {
if (blockBreak.face == lastFace) {
lastFace = null;
}
}
if (lastFace != null) {
flagAndAlert("lastFace=" + lastFace + ", action=" + blockBreak.action);
}
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
lastFace = blockBreak.faceId == releaseFace ? null : blockBreak.face;
}
}
}
@@ -0,0 +1,122 @@
package ac.grim.grimac.checks.impl.breaking;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.Pair;
import ac.grim.grimac.utils.math.Vector3dm;
import ac.grim.grimac.utils.nmsutil.Ray;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3f;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@CheckData(name = "RotationBreak", experimental = true)
public class RotationBreak extends Check implements BlockBreakCheck {
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;
public RotationBreak(GrimPlayer player) {
super(player);
}
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (player.gamemode == GameMode.SPECTATOR)
return; // you don't send flying packets when spectating entities
if (player.inVehicle()) return; // falses
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) return; // falses
if (flagBuffer > 0 && !didRayTraceHit(blockBreak)) {
ignorePost = true;
// If the player hit and has flagged this check recently
if (flagAndAlert("pre-flying, action=" + blockBreak.action) && shouldModifyPackets()) {
blockBreak.cancel();
}
}
}
@Override
public void onPostFlyingBlockBreak(BlockBreak blockBreak) {
if (player.gamemode == GameMode.SPECTATOR)
return; // you don't send flying packets when spectating entities
if (player.inVehicle()) return; // falses
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) return; // falses
// Don't flag twice
if (ignorePost) {
ignorePost = false;
return;
}
if (didRayTraceHit(blockBreak)) {
flagBuffer = Math.max(0, flagBuffer - 0.1);
} else {
flagBuffer = 1;
flagAndAlert("post-flying, action=" + blockBreak.action);
}
}
private boolean didRayTraceHit(BlockBreak blockBreak) {
SimpleCollisionBox box = new SimpleCollisionBox(blockBreak.position);
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
// Start checking if player is in the block
double minEyeHeight = Double.MAX_VALUE;
double maxEyeHeight = Double.MIN_VALUE;
for (double height : possibleEyeHeights) {
minEyeHeight = Math.min(minEyeHeight, height);
maxEyeHeight = Math.max(maxEyeHeight, height);
}
SimpleCollisionBox eyePositions = new SimpleCollisionBox(player.x, player.y + minEyeHeight, player.z, player.x, player.y + maxEyeHeight, player.z);
eyePositions.expand(player.getMovementThreshold());
// If the player is inside a block, then they can ray trace through the block and hit the other side of the block
if (eyePositions.isIntersected(box)) {
return true;
}
// End checking if the player is in the block
List<Vector3f> possibleLookDirs = new ArrayList<>(Arrays.asList(
new Vector3f(player.lastXRot, player.yRot, 0),
new Vector3f(player.xRot, player.yRot, 0)
));
// 1.9+ players could be a tick behind because we don't get skipped ticks
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
possibleLookDirs.add(new Vector3f(player.lastXRot, player.lastYRot, 0));
}
// 1.7 players do not have any of these issues! They are always on the latest look vector
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
possibleLookDirs = Collections.singletonList(new Vector3f(player.xRot, player.yRot, 0));
}
final double distance = player.compensatedEntities.self.getAttributeValue(Attributes.BLOCK_INTERACTION_RANGE);
for (double d : possibleEyeHeights) {
for (Vector3f lookDir : possibleLookDirs) {
Vector3d starting = new Vector3d(player.x, player.y + d, player.z);
Ray trace = new Ray(player, starting.getX(), starting.getY(), starting.getZ(), lookDir.getX(), lookDir.getY());
Pair<Vector3dm, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.first() != null) return true;
}
}
return false;
}
}
@@ -1,29 +1,28 @@
package ac.grim.grimac.checks.impl.badpackets;
package ac.grim.grimac.checks.impl.breaking;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.checks.type.BlockBreakCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import ac.grim.grimac.utils.anticheat.update.BlockBreak;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
import static ac.grim.grimac.events.packets.patch.ResyncWorldUtil.resyncPosition;
import static ac.grim.grimac.utils.nmsutil.BlockBreakSpeed.getBlockDamage;
@CheckData(name = "BadPacketsZ", experimental = true)
public class BadPacketsZ extends Check implements PacketCheck {
public BadPacketsZ(final GrimPlayer player) {
super(player);
}
@CheckData(name = "WrongBreak")
public class WrongBreak extends Check implements BlockBreakCheck {
private final int exemptedY = player.getClientVersion().isOlderThan(ClientVersion.V_1_8) ? 255 : (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_14) ? -1 : 4095);
private boolean lastBlockWasInstantBreak = false;
private Vector3i lastBlock, lastCancelledBlock, lastLastBlock = null;
private final int exemptedY = player.getClientVersion().isOlderThan(ClientVersion.V_1_8) ? 255 : (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_14) ? -1 : 4095);
public WrongBreak(final GrimPlayer player) {
super(player);
}
// The client sometimes sends a wierd cancel packet
private boolean shouldExempt(final Vector3i pos) {
@@ -39,13 +38,10 @@ public class BadPacketsZ extends Check implements PacketCheck {
return player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || getBlockDamage(player, pos) < 1;
}
private String formatted(Vector3i vec) {
return vec == null ? "null" : vec.x + ", " + vec.y + ", " + vec.z;
}
public void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging dig) {
if (dig.getAction() == DiggingAction.START_DIGGING) {
final Vector3i pos = dig.getBlockPosition();
@Override
public void onBlockBreak(BlockBreak blockBreak) {
if (blockBreak.action == DiggingAction.START_DIGGING) {
final Vector3i pos = blockBreak.position;
lastBlockWasInstantBreak = getBlockDamage(player, pos) >= 1;
lastCancelledBlock = null;
@@ -53,24 +49,15 @@ public class BadPacketsZ extends Check implements PacketCheck {
lastBlock = pos;
}
if (dig.getAction() == DiggingAction.CANCELLED_DIGGING) {
final Vector3i pos = dig.getBlockPosition();
if (blockBreak.action == DiggingAction.CANCELLED_DIGGING) {
final Vector3i pos = blockBreak.position;
if (shouldExempt(pos)) {
lastCancelledBlock = null;
lastLastBlock = null;
lastBlock = null;
return;
}
if (!pos.equals(lastBlock)) {
if (!shouldExempt(pos) && !pos.equals(lastBlock)) {
// https://github.com/GrimAnticheat/Grim/issues/1512
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || (!lastBlockWasInstantBreak && pos.equals(lastCancelledBlock))) {
if (flagAndAlert("action=CANCELLED_DIGGING" + ", last=" + formatted(lastBlock) + ", pos=" + formatted(pos))) {
if (flagAndAlert("action=CANCELLED_DIGGING" + ", last=" + MessageUtil.toUnlabledString(lastBlock) + ", pos=" + MessageUtil.toUnlabledString(pos))) {
if (shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
resyncPosition(player, pos);
blockBreak.cancel();
}
}
}
@@ -82,24 +69,21 @@ public class BadPacketsZ extends Check implements PacketCheck {
return;
}
if (dig.getAction() == DiggingAction.FINISHED_DIGGING) {
final Vector3i pos = dig.getBlockPosition();
if (blockBreak.action == DiggingAction.FINISHED_DIGGING) {
final Vector3i pos = blockBreak.position;
// when a player looks away from the mined block, they send a cancel, and if they look at it again, they don't send another start. (thanks mojang!)
if (!pos.equals(lastCancelledBlock) && (!lastBlockWasInstantBreak || player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4)) && !pos.equals(lastBlock)) {
if (flagAndAlert("action=FINISHED_DIGGING" + ", last=" + formatted(lastBlock) + ", pos=" + formatted(pos))) {
if (flagAndAlert("action=FINISHED_DIGGING" + ", last=" + MessageUtil.toUnlabledString(lastBlock) + ", pos=" + MessageUtil.toUnlabledString(pos))) {
if (shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
resyncPosition(player, pos);
blockBreak.cancel();
}
}
}
lastCancelledBlock = null;
// 1.14.4+ clients don't send another start break in protected regions
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4)) {
lastCancelledBlock = null;
lastLastBlock = null;
lastBlock = null;
}
@@ -0,0 +1,13 @@
package ac.grim.grimac.checks.impl.combat;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
@CheckData(name = "Hitboxes", setback = 10)
public class Hitboxes extends Check implements PacketCheck {
public Hitboxes(GrimPlayer player) {
super(player);
}
}
@@ -0,0 +1,68 @@
package ac.grim.grimac.checks.impl.combat;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import java.util.ArrayList;
@CheckData(name = "MultiInteractA", description = "Interacted with multiple entities in the same tick", experimental = true)
public class MultiInteractA extends Check implements PostPredictionCheck {
private final ArrayList<String> flags = new ArrayList<>();
private int lastEntity;
private boolean lastSneaking;
private boolean hasInteracted = false;
public MultiInteractA(final GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
int entity = packet.getEntityId();
boolean sneaking = packet.isSneaking().orElse(false);
if (hasInteracted && entity != lastEntity) {
String verbose = "lastEntity=" + lastEntity + ", entity=" + entity
+ ", lastSneaking=" + lastSneaking + ", sneaking=" + sneaking;
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add(verbose);
}
}
lastEntity = entity;
lastSneaking = sneaking;
hasInteracted = true;
}
if (player.gamemode == GameMode.SPECTATOR || isTickPacket(event.getPacketType())) {
hasInteracted = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
}
flags.clear();
}
}
@@ -0,0 +1,69 @@
package ac.grim.grimac.checks.impl.combat;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import java.util.ArrayList;
@CheckData(name = "MultiInteractB", experimental = true)
public class MultiInteractB extends Check implements PostPredictionCheck {
private final ArrayList<String> flags = new ArrayList<>();
private Vector3f lastPos;
private boolean hasInteracted = false;
public MultiInteractB(final GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
Vector3f pos = new WrapperPlayClientInteractEntity(event).getTarget().orElse(null);
if (pos == null) {
return;
}
if (hasInteracted && !pos.equals(lastPos)) {
String verbose = "pos=" + MessageUtil.toUnlabledString(pos) + ", lastPos=" + MessageUtil.toUnlabledString(lastPos);
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add(verbose);
}
}
lastPos = pos;
hasInteracted = true;
}
if (player.gamemode == GameMode.SPECTATOR || isTickPacket(event.getPacketType())) {
hasInteracted = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
}
flags.clear();
}
}
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package ac.grim.grimac.checks.impl.combat;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
@@ -22,6 +23,7 @@ import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
import ac.grim.grimac.utils.data.packetentity.dragon.PacketEntityEnderDragonPart;
import ac.grim.grimac.utils.math.Vector3dm;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
@@ -32,22 +34,27 @@ import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import org.bukkit.util.Vector;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
// You may not copy the check unless you are licensed under GPL
@CheckData(name = "Reach", configName = "Reach", setback = 10)
@CheckData(name = "Reach", setback = 10)
public class Reach extends Check implements PacketCheck {
// Only one flag per reach attack, per entity, per tick.
// We store position because lastX isn't reliable on teleports.
private final Map<Integer, Vector3d> playerAttackQueue = new HashMap<>();
private static final List<EntityType> blacklisted = Arrays.asList(
EntityTypes.BOAT,
EntityTypes.CHEST_BOAT,
EntityTypes.SHULKER);
private static final CheckResult NONE = new CheckResult(ResultType.NONE, "");
// Only one flag per reach attack, per entity, per tick.
// We store position because lastX isn't reliable on teleports.
private final Int2ObjectMap<Vector3d> playerAttackQueue = new Int2ObjectOpenHashMap<>();
private boolean cancelImpossibleHits;
private double threshold;
private double cancelBuffer; // For the next 4 hits after using reach, we aggressively cancel reach
@@ -80,15 +87,17 @@ public class Reach extends Check implements PacketCheck {
}
return;
}
// Dead entities cause false flags (https://github.com/GrimAnticheat/Grim/issues/546)
if (entity.isDead) return;
// TODO: Remove when in front of via
if (entity.getType() == EntityTypes.ARMOR_STAND && player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) return;
if (entity.getType() == EntityTypes.ARMOR_STAND && player.getClientVersion().isOlderThan(ClientVersion.V_1_8))
return;
if (player.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR) return;
if (player.compensatedEntities.getSelf().inVehicle()) return;
if (player.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR)
return;
if (player.inVehicle()) return;
if (entity.riding != null) return;
boolean tooManyAttacks = playerAttackQueue.size() > 10;
@@ -105,9 +114,7 @@ public class Reach extends Check implements PacketCheck {
}
// If the player set their look, or we know they have a new tick
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) ||
event.getPacketType() == PacketType.Play.Client.PONG ||
event.getPacketType() == PacketType.Play.Client.WINDOW_CONFIRMATION) {
if (isUpdate(event.getPacketType())) {
tickBetterReachCheckWithAngle();
}
}
@@ -125,39 +132,46 @@ public class Reach extends Check implements PacketCheck {
if ((blacklisted.contains(reachEntity.getType()) || !reachEntity.isLivingEntity()) && reachEntity.getType() != EntityTypes.END_CRYSTAL)
return false; // exempt
if (player.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR) return false;
if (player.compensatedEntities.getSelf().inVehicle()) return false;
if (player.gamemode == GameMode.CREATIVE || player.gamemode == GameMode.SPECTATOR)
return false;
if (player.inVehicle()) return false;
// Filter out what we assume to be cheats
if (cancelBuffer != 0) {
return checkReach(reachEntity, new Vector3d(player.x, player.y, player.z), true) != null; // If they flagged
CheckResult result = checkReach(reachEntity, new Vector3d(player.x, player.y, player.z), true);
return result.isFlag(); // If they flagged
} else {
SimpleCollisionBox targetBox = reachEntity.getPossibleCollisionBoxes();
if (reachEntity.getType() == EntityTypes.END_CRYSTAL) {
targetBox = new SimpleCollisionBox(reachEntity.trackedServerPosition.getPos().subtract(1, 0, 1), reachEntity.trackedServerPosition.getPos().add(1, 2, 1));
}
return ReachUtils.getMinReachToBox(player, targetBox) > player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE);
return ReachUtils.getMinReachToBox(player, targetBox) > player.compensatedEntities.self.getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE);
}
}
private void tickBetterReachCheckWithAngle() {
for (Map.Entry<Integer, Vector3d> attack : playerAttackQueue.entrySet()) {
PacketEntity reachEntity = player.compensatedEntities.entityMap.get(attack.getKey().intValue());
if (reachEntity != null) {
String result = checkReach(reachEntity, attack.getValue(), false);
if (result != null) {
if (reachEntity.getType() == EntityTypes.PLAYER) {
flagAndAlert(result);
} else {
flagAndAlert(result + " type=" + reachEntity.getType().getName().getKey());
}
for (Int2ObjectMap.Entry<Vector3d> attack : playerAttackQueue.int2ObjectEntrySet()) {
PacketEntity reachEntity = player.compensatedEntities.entityMap.get(attack.getIntKey());
if (reachEntity == null) continue;
CheckResult result = checkReach(reachEntity, attack.getValue(), false);
switch (result.type()) {
case REACH -> {
String added = reachEntity.getType() == EntityTypes.PLAYER ? "" : ", type=" + reachEntity.getType().getName().getKey();
flagAndAlert(result.verbose() + added);
}
case HITBOX -> {
String added = reachEntity.getType() == EntityTypes.PLAYER ? "" : "type=" + reachEntity.getType().getName().getKey();
player.checkManager.getPacketCheck(Hitboxes.class).flagAndAlert(result.verbose() + added);
}
}
}
playerAttackQueue.clear();
}
private String checkReach(PacketEntity reachEntity, Vector3d from, boolean isPrediction) {
@NotNull
private CheckResult checkReach(PacketEntity reachEntity, Vector3d from, boolean isPrediction) {
SimpleCollisionBox targetBox = reachEntity.getPossibleCollisionBoxes();
if (reachEntity.getType() == EntityTypes.END_CRYSTAL) { // Hardcode end crystal box
@@ -176,13 +190,14 @@ public class Reach extends Check implements PacketCheck {
// Adds some more than 0.03 uncertainty in some cases, but a good trade off for simplicity
//
// Just give the uncertainty on 1.9+ clients as we have no way of knowing whether they had 0.03 movement
if (!player.packetStateData.didLastLastMovementIncludePosition || player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9))
// However, on 1.21.2+ we do know if they had 0.03 movement
if (!player.packetStateData.didLastLastMovementIncludePosition || player.canSkipTicks())
targetBox.expand(player.getMovementThreshold());
double minDistance = Double.MAX_VALUE;
// https://bugs.mojang.com/browse/MC-67665
List<Vector> possibleLookDirs = new ArrayList<>(Collections.singletonList(ReachUtils.getLook(player, player.xRot, player.yRot)));
List<Vector3dm> possibleLookDirs = new ArrayList<>(Collections.singletonList(ReachUtils.getLook(player, player.xRot, player.yRot)));
// If we are a tick behind, we don't know their next look so don't bother doing this
if (!isPrediction) {
@@ -199,14 +214,17 @@ public class Reach extends Check implements PacketCheck {
}
}
final double maxReach = player.compensatedEntities.self.getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE);
// +3 would be 3 + 3 = 6, which is the pre-1.20.5 behaviour, preventing "Missed Hitbox"
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE) + 3;
for (Vector lookVec : possibleLookDirs) {
for (double eye : player.getPossibleEyeHeights()) {
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));
final double distance = maxReach + 3;
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
final Vector3dm eyePos = new Vector3dm(from.getX(), 0, from.getZ());
for (Vector3dm lookVec : possibleLookDirs) {
for (double eye : possibleEyeHeights) {
eyePos.setY(from.getY() + eye);
Vector3dm endReachPos = eyePos.clone().add(new Vector3dm(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance));
Vector intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).getFirst();
Vector3dm intercept = ReachUtils.calculateIntercept(targetBox, eyePos, endReachPos).first();
if (ReachUtils.isVecInside(targetBox, eyePos)) {
minDistance = 0;
@@ -223,22 +241,31 @@ public class Reach extends Check implements PacketCheck {
if ((!blacklisted.contains(reachEntity.getType()) && reachEntity.isLivingEntity()) || reachEntity.getType() == EntityTypes.END_CRYSTAL) {
if (minDistance == Double.MAX_VALUE) {
cancelBuffer = 1;
return "Missed hitbox";
} else if (minDistance > player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE)) {
return new CheckResult(ResultType.HITBOX, "");
} else if (minDistance > maxReach) {
cancelBuffer = 1;
return String.format("%.5f", minDistance) + " blocks";
return new CheckResult(ResultType.REACH, String.format("%.5f", minDistance) + " blocks");
} else {
cancelBuffer = Math.max(0, cancelBuffer - 0.25);
}
}
return null;
return NONE;
}
@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);
}
private enum ResultType {
REACH, HITBOX, NONE
}
private record CheckResult(ResultType type, String verbose) {
public boolean isFlag() {
return type != ResultType.NONE;
}
}
}
@@ -8,7 +8,7 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.GameMode;
@CheckData(name = "CrashB")
@CheckData(name = "CrashB", description = "Sent creative mode inventory click packets while not in creative mode")
public class CrashB extends Check implements PacketCheck {
public CrashB(GrimPlayer player) {
super(player);
@@ -18,7 +18,6 @@ public class CrashB extends Check implements PacketCheck {
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CREATIVE_INVENTORY_ACTION) {
if (player.gamemode != GameMode.CREATIVE) {
player.getSetbackTeleportUtil().executeViolationSetback();
event.setCancelled(true);
player.onPacketCancel();
flagAndAlert(); // Could be transaction split, no need to setback though
Loaded 100 of 658 files, more files were not shown because too many files have changed in this diff. Show more