Compare commits

...
661 Commits
Author SHA1 Message Date
Axionize 328e031c1b Fix 1.8 Villager and Modern Slime {Size: 0} hitboxes 2025-02-26 18:39:43 -05:00
Axionize 0bc781f390 Merge remote-tracking branch 'origin/2.0' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/commands/GrimSpectate.java
2025-02-26 14:46:57 -05:00
Axionize c7f4bd15d2 Merge remote-tracking branch 'origin/2.0' into merge-dev
# Conflicts:
#	.github/workflows/gradle-publish.yml
#	build.gradle.kts
2025-02-19 03:33:51 -05:00
Axionize 9af7a7267e Merge remote-tracking branch 'origin/2.0' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/nmsutil/BukkitNMS.java
2025-02-13 23:45:31 -05:00
Axionize 3ff9e774cd Merge remote-tracking branch 'origin/2.0' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/data/packetentity/PacketEntity.java
#	src/main/java/ac/grim/grimac/utils/nmsutil/GetBoundingBox.java
2025-02-13 13:24:10 -05:00
Axionize 36e5eb9304 Attempt to fix HitboxEntity/Block AssertionError & some more AirLiquidPlace falses 2025-02-13 11:53:14 -05:00
Axionize 0d2940c34a Make painting hitbox code 1.19+ 2025-02-12 15:01:05 -05:00
Axionize a793912337 Get rid of debugging prints 2025-02-12 14:17:31 -05:00
Axionize d1194223ab Temporary workaround to NPE if paintingVariant registry doesn't have paintings for client version 2025-02-12 14:16:30 -05:00
Axionize 0624b117b5 Attempt to fix adventure shading issue with PE in lite mode 2025-02-12 14:15:27 -05:00
Axionize 5f4ec6a1a7 Fix modeling hitbox of Paintings in 1.21 2025-02-11 07:48:20 -05:00
Axionize 3c400f1eeb Dirty hack to fix calculating hitboxes for paintings 2025-02-10 15:04:38 -05:00
Axionize f6dba5ee8e Fix modeling hitbox of Falling Blocks 2025-02-10 12:58:41 -05:00
Axionize 8b3cbab3ad Fix thread exception when accessing bukkit methods from netty threads 2025-02-10 12:50:09 -05:00
Axionize c0e6ae7ec6 Make PacketEventsInit version check use NEWEST_UNSUPPORTED_PE_VERSION instead of hard coding it 2025-02-09 06:26:11 -05:00
Axionize 71d6d9e33f Fix build script 2025-02-09 06:08:27 -05:00
Axionize 0508bd98ba Fix build script 2025-02-09 05:57:50 -05:00
Axionize 5b9efc0ea5 Fix build script 2025-02-09 05:53:11 -05:00
Axionize a3812b2546 Exempt recently changed blocks as a temporary hack for HitboxBlocks 2025-02-09 05:47:41 -05:00
Axionize 05fb233f0e Build two jars, one with PE one ewithout 2025-02-09 04:53:14 -05:00
Axionize e15277d58d Add support for building Grim without shading PE as a build option 2025-02-09 03:45:54 -05:00
Axionize 177ae4cbfa Fix Remy's build mistakes #1 2025-02-09 00:51:33 -05:00
Axionize c1db1479b6 Fix merge issues with updating SprintC 2025-02-08 13:18:12 -05:00
RejomyandRejomy 86f89c010d Fix github actions failing due to incorrect path to the jar. (#53)
Co-authored-by: Rejomy <gg@gg.gg>
2025-02-07 17:41:17 -05:00
Axionize 5de92f28de Merge remote-tracking branch 'origin/2.0' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/sprint/SprintC.java
2025-02-07 17:38:10 -05:00
Axionize 96ab0c3bdf Fix updating upstream 2025-02-05 14:30:17 -05:00
Axionize a4a1397b87 Merge remote-tracking branch 'origin/2.0' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/manager/init/start/CommandRegister.java
#	src/main/java/ac/grim/grimac/player/GrimPlayer.java
#	src/main/resources/config/zh.yml
2025-02-05 13:01:59 -05:00
Axionize 4b5cf2a9a1 Reduce number of rays required to be traced with new getPossibleLookVectors() function 2025-02-05 12:15:48 -05:00
Axionize fa86c87693 Fix HitboxEntity and HitboxReach not working on large custom reach distances 2025-02-05 11:46:41 -05:00
You 6b639048b9 Fix historical reach teleport reach modeling 2025-02-03 11:16:51 -05:00
Axionize 5413484c2a Merge branch 'feat/fix-Folia-LatencyUtils-CME' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/latency/LatencyUtils.java
2025-02-03 10:18:26 -05:00
Axionize 6d6b27dfe2 Merge remote-tracking branch 'origin/2.0' into merge-dev 2025-02-03 02:17:48 -05:00
Axionize fde5efa31f Fix new entity modeling to handle riding entities 2025-02-01 00:04:40 -05:00
Axionize cccc0194d6 Fix upstream Java 8 compatability issue 2025-01-31 22:06:17 -05:00
Axionize d8e7bc8f3e Fix Java 8 compatability break from upstream 2025-01-31 22:02:58 -05:00
Axionize dd37d3407b Enable HitboxEntities by default 2025-01-31 17:38:21 -05:00
Axionize c0c19d1a2d Merge remote-tracking branch 'origin/2.0' into merge-dev 2025-01-31 17:32:10 -05:00
Axionize 59eb669c17 Fix a rare CME in LatencyUtils 2025-01-30 12:46:26 -05:00
Axionize 86cb4af960 Refactor hitbox debugging code 2025-01-30 02:41:12 -05:00
Axionize 056b9f0486 Fix merge conflicts 2025-01-30 02:18:46 -05:00
Axionize afe483c0ad Merge remote-tracking branch 'origin/2.0' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/manager/CheckManager.java
2025-01-30 02:02:38 -05:00
Axionize 5d4c8f6f85 Fix HitboxEntities falses 2025-01-30 01:45:49 -05:00
Axionize a08963e1dc Patches to handling non-target minimum entitiy hitboxes 2025-01-29 08:10:21 -05:00
Axionize 50a2b3af95 Update README.md to note that Java 8 is supported 2025-01-28 23:14:00 -05:00
Axionize 01cd47a6b6 Merge branch 'feat/debug-hitboxes' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/combat/Reach.java
#	src/main/java/ac/grim/grimac/checks/impl/prediction/DebugHandler.java
#	src/main/java/ac/grim/grimac/utils/nmsutil/BlockRayTrace.java
2025-01-28 06:00:06 -05:00
Axionize 7494b995bc Fix checking permission for inventory setbacks 2025-01-28 05:03:22 -05:00
Axionize e4ef877188 Port new Reach modeling to handle generating smallest possible hitboxes 2025-01-25 22:02:24 -05:00
Axionize efa8b750e7 Merge branch 'feat/more-accurate-position-reach-modeling' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/data/ReachInterpolationData.java
2025-01-25 21:51:10 -05:00
Axionize 21d21d2509 Merge remote-tracking branch 'origin/2.0' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/combat/Reach.java
#	src/main/java/ac/grim/grimac/checks/impl/scaffolding/RotationPlace.java
#	src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
#	src/main/java/ac/grim/grimac/predictionengine/PlayerBaseTick.java
#	src/main/java/ac/grim/grimac/predictionengine/UncertaintyHandler.java
#	src/main/java/ac/grim/grimac/predictionengine/predictions/PredictionEngine.java
#	src/main/java/ac/grim/grimac/predictionengine/predictions/rideable/PredictionEngineRideableUtils.java
#	src/main/java/ac/grim/grimac/utils/data/KnownInput.java
#	src/main/java/ac/grim/grimac/utils/data/VectorData.java
#	src/main/java/ac/grim/grimac/utils/nmsutil/BlockProperties.java
2025-01-25 21:34:12 -05:00
Axionize 44011acca2 Make Inventory checks support/respect nosetback permissions 2025-01-25 21:12:53 -05:00
Axionize 71791a1020 Update documentation formatting 2025-01-25 12:44:37 -05:00
Axionize 665a43bd4c Merge remote-tracking branch 'origin/2.0' into feat/more-accurate-position-reach-modeling
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/data/ReachInterpolationData.java
2025-01-25 12:34:44 -05:00
Axionize 5ce81e0fe4 Add documention explaining getPossibleLocationCombined() and getPossibleHitboxCombined() 2025-01-25 12:23:46 -05:00
Axionize 29b6e12cb8 Seperate getting possible locations and possible hitbox to reduce how often expandNonRelative() needs to be called 2025-01-25 12:10:08 -05:00
Axionize 014c5f7670 Mark LineOfSightPlace as experimental cehck 2025-01-25 10:26:32 -05:00
Axionize 9c9316e224 Merge remote-tracking branch 'origin/2.0' into merge-dev 2025-01-23 18:32:51 -05:00
Axionize 9e296cbf5a Merge remote-tracking branch 'origin/2.0' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/badpackets/BadPacketsX.java
#	src/main/java/ac/grim/grimac/utils/collisions/HitboxData.java
#	src/main/resources/config/en.yml
#	src/main/resources/config/es.yml
#	src/main/resources/config/fr.yml
#	src/main/resources/config/it.yml
#	src/main/resources/config/nl.yml
#	src/main/resources/config/pt.yml
#	src/main/resources/config/ru.yml
#	src/main/resources/config/tr.yml
#	src/main/resources/config/zh.yml
2025-01-22 03:20:55 -05:00
Axionize 0af47a1266 Stop using server-side tracked position when attempting to account for teleports not always moving entity client side; expand from client area instead 2025-01-22 00:50:05 -05:00
Axionize 8e6219c597 Stop using server-side tracked position; expand from client area instead 2025-01-20 03:55:57 -05:00
Axionize 9aa555ff78 Fix logic error in new brewing stand hitbox code and optimize CCB size 2025-01-20 02:34:20 -05:00
Axionize 21c0833769 Adapt RaycastData and BlockRayTrace classes to accommodate new HitboxData.getBlockHitbox() parameters format. 2025-01-20 01:44:39 -05:00
Axionize 450642d888 Refactor HitboxData.getBlockHitbox() to include isTargetBlock as parameter
Also fixes a rare NPE
2025-01-20 01:40:38 -05:00
Axionize 4fa3ef68e2 Java 8 compatability fixes 2025-01-15 22:38:17 -05:00
Axionize f477ba4c62 Merge remote-tracking branch 'origin/2.0' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/badpackets/BadPacketsP.java
#	src/main/java/ac/grim/grimac/checks/impl/sprint/SprintB.java
#	src/main/java/ac/grim/grimac/manager/init/start/CommandRegister.java
#	src/main/java/ac/grim/grimac/utils/latency/CompensatedEntities.java
#	src/main/resources/messages/de.yml
#	src/main/resources/punishments/de.yml
#	src/main/resources/punishments/en.yml
#	src/main/resources/punishments/es.yml
#	src/main/resources/punishments/fr.yml
#	src/main/resources/punishments/it.yml
#	src/main/resources/punishments/ja.yml
#	src/main/resources/punishments/nl.yml
#	src/main/resources/punishments/pt.yml
#	src/main/resources/punishments/ru.yml
#	src/main/resources/punishments/tr.yml
#	src/main/resources/punishments/zh.yml
2025-01-15 22:01:06 -05:00
Axionize 4ac58782ac Fix legacy Elder Guardian hitbox 2025-01-05 08:17:53 -05:00
Axionize 2f6242027b Fix calling PacketGuardianEntity constructor and updating metadata; document wiki's errors 2025-01-05 08:17:27 -05:00
Axionize d8c0aef8cc add PacketEntityGuardian for hitbox modeling 2025-01-05 07:48:30 -05:00
Axionize 3f1b4d8472 Merge branch 'merge-dev' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/commands/GrimDump.java
#	src/main/java/ac/grim/grimac/commands/GrimLog.java
#	src/main/java/ac/grim/grimac/commands/GrimVersion.java
#	src/main/java/ac/grim/grimac/manager/init/start/PlaceholderAPIExpansion.java
#	src/main/java/ac/grim/grimac/utils/nmsutil/BlockRayTrace.java
2025-01-02 22:20:51 -05:00
Axionize 0adc332d14 Fix Java 8 Compatability issues 2025-01-01 23:52:56 -05:00
Axionize cda6af1f34 Merge remote-tracking branch 'origin/2.0' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/badpackets/BadPacketsX.java
#	src/main/java/ac/grim/grimac/checks/impl/combat/Reach.java
#	src/main/java/ac/grim/grimac/checks/impl/misc/TransactionOrder.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderB.java
#	src/main/java/ac/grim/grimac/checks/impl/scaffolding/AirLiquidPlace.java
#	src/main/java/ac/grim/grimac/checks/impl/scaffolding/PositionPlace.java
#	src/main/java/ac/grim/grimac/checks/impl/sprint/SprintB.java
#	src/main/java/ac/grim/grimac/commands/GrimVersion.java
#	src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
#	src/main/java/ac/grim/grimac/events/packets/PacketPlayerDigging.java
#	src/main/java/ac/grim/grimac/manager/CheckManager.java
#	src/main/java/ac/grim/grimac/manager/SpectateManager.java
#	src/main/java/ac/grim/grimac/predictionengine/PlayerBaseTick.java
#	src/main/java/ac/grim/grimac/utils/change/PlayerBlockHistory.java
#	src/main/java/ac/grim/grimac/utils/latency/CompensatedInventory.java
#	src/main/java/ac/grim/grimac/utils/math/GrimMath.java
#	src/main/java/ac/grim/grimac/utils/nmsutil/BlockBreakSpeed.java
#	src/main/java/ac/grim/grimac/utils/nmsutil/BoundingBoxSize.java
#	src/main/resources/punishments/de.yml
#	src/main/resources/punishments/en.yml
#	src/main/resources/punishments/es.yml
#	src/main/resources/punishments/fr.yml
#	src/main/resources/punishments/it.yml
#	src/main/resources/punishments/ja.yml
#	src/main/resources/punishments/nl.yml
#	src/main/resources/punishments/pt.yml
#	src/main/resources/punishments/ru.yml
#	src/main/resources/punishments/tr.yml
#	src/main/resources/punishments/zh.yml
2024-12-31 01:16:58 -05:00
Axionize 237f3744d4 Stash debugging code and new hitbox calculation (still wrong?) 2024-12-31 00:26:35 -05:00
Axionize 99b309a0b3 Hitbox Debug Protocol Version Update #1 2024-12-30 18:34:42 -05:00
Axionize ad68a43b83 Style fix 2024-12-28 16:21:06 -05:00
Axionize e7abaf8523 Update upstream more and add debug logging for null hitboxes and PacketOrder 2024-12-28 16:20:22 -05:00
Axionize a508002c48 Update upstream more and add debug logging for null hitboxes 2024-12-28 16:20:05 -05:00
Axionize 259696710f Merge remote-tracking branch 'maninmyvan/packetorder' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderA.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderE.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderF.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderG.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderH.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderI.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderJ.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderK.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderL.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderM.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderN.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderProcessor.java
#	src/main/java/ac/grim/grimac/manager/CheckManager.java
#	src/main/java/ac/grim/grimac/manager/init/start/CommandRegister.java
#	src/main/java/ac/grim/grimac/player/GrimPlayer.java
#	src/main/resources/punishments/de.yml
#	src/main/resources/punishments/en.yml
#	src/main/resources/punishments/es.yml
#	src/main/resources/punishments/fr.yml
#	src/main/resources/punishments/it.yml
#	src/main/resources/punishments/nl.yml
#	src/main/resources/punishments/pt.yml
#	src/main/resources/punishments/ru.yml
#	src/main/resources/punishments/zh.yml
2024-12-28 15:44:17 -05:00
ManInMyVan a47a34e9f9 include more information in verbose 2024-12-28 13:29:53 -07:00
Axionize 4eb5ad4e87 Temporary debugging change + limit used lookVecs 2024-12-28 13:51:24 -05:00
Axionize 46e616107e Fix baby entity hitboxes with dirty hardcoded hack 2024-12-27 22:06:15 -05:00
Axionize dcb72a9efd Complete initial server-side debugging implementation 2024-12-27 21:47:04 -05:00
Axionize b939ba5921 Fix modeling sculk vein hitbox and make SyncedTags compile on Java 8 2024-12-27 18:45:51 -05:00
Axionize 786611aeec Fix modeling sculk vein hitbox 2024-12-27 18:40:56 -05:00
Axionize 44eba3b446 Stash Reach debugging checks 2024-12-27 18:40:32 -05:00
ManInMyVan 0f11cb74b8 don't check the same value twice 2024-12-27 16:24:47 -07:00
ManInMyVan 1cff3e526f fix 1.21.2+ PacketOrderH false 2024-12-26 15:34:32 -07:00
ManInMyVan a09093ee5b don't register PacketOrderProcessor twice 2024-12-26 15:34:32 -07:00
ManInMyVan c1db9edd7d 1.21.2 2024-12-26 15:34:32 -07:00
ManInMyVan 9ac2b4fbb6 fix wrongly resolved merge conflict 2024-12-26 15:32:37 -07:00
ManInMyVan 0b9ba69afc fix falses 2024-12-26 15:32:37 -07:00
ManInMyVan b326c7b961 remove PacketOrderO
depends on too many factors
2024-12-26 15:32:37 -07:00
ManInMyVan f1243073f2 fix more falses 2024-12-26 15:32:37 -07:00
ManInMyVan 4e4f23479a fix falses 2024-12-26 15:32:37 -07:00
ManInMyVan c7a4eeec94 fix false when swapping offhand items 2024-12-26 15:32:37 -07:00
ManInMyVan d1a2dbf6aa fix false when dropping items 2024-12-26 15:32:37 -07:00
ManInMyVan c67258ac13 only setback on item use 2024-12-26 15:32:37 -07:00
ManInMyVan ca7da355f7 remove invalid variable default 2024-12-26 15:32:37 -07:00
ManInMyVan 2a452c7d85 add remaining entity actions to PacketOrderProcessor 2024-12-26 15:32:37 -07:00
ManInMyVan 66776e8163 rename invalidSlots to invalid 2024-12-26 15:32:36 -07:00
ManInMyVan 3089036d43 add PacketOrderO and PacketOrderP 2024-12-26 15:32:36 -07:00
ManInMyVan 447ce3466d add PacketOrderN 2024-12-26 15:32:36 -07:00
ManInMyVan 244113714e Add PacketOrderM 2024-12-26 15:32:36 -07:00
ManInMyVan ae1c47d21f fix a noslow 2024-12-26 15:32:36 -07:00
ManInMyVan 241525c2c2 rename exempt-digging to exempt-placing-while-digging in PacketOrderI
and make it work
2024-12-26 15:32:36 -07:00
ManInMyVan d2b529aceb rename PacketOrderM to PacketOrderA 2024-12-26 15:32:36 -07:00
ManInMyVan 89f0aefe22 add PacketOrderM 2024-12-26 15:32:36 -07:00
ManInMyVan 8d8499d6fc use PacketOrderProcessor in PacketOrderK 2024-12-26 15:32:36 -07:00
ManInMyVan 3bd1673e67 rewrite 2024-12-26 15:32:36 -07:00
ManInMyVan 2ee47a23ea fix falses 2024-12-26 15:32:35 -07:00
ManInMyVan 734d227175 don't cancel the tick 2024-12-26 15:32:35 -07:00
ManInMyVan 1377747bec more PacketOrderC stuff 2024-12-26 15:32:35 -07:00
ManInMyVan 210a9266a4 fixes 2024-12-26 15:32:35 -07:00
ManInMyVan 616c46d97e oops 2024-12-26 15:32:35 -07:00
ManInMyVan aa69b6f69f fix falses 2024-12-26 15:32:35 -07:00
ManInMyVan fae66e9039 Add PacketOrderK 2024-12-26 15:32:35 -07:00
ManInMyVan fb05fcb1fa make PacketOrderE setback
https://github.com/CCBlueX/LiquidBounce/blob/nextgen/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/movement/noslow/modes/blocking/NoSlowBlockingSwitch.kt
2024-12-26 15:32:35 -07:00
ManInMyVan acdcfe8f71 exemptBreaking option in PacketOrdlerL 2024-12-26 15:32:35 -07:00
ManInMyVan e3f5db6f19 fix some PacketOrderF falses 2024-12-26 15:32:34 -07:00
ManInMyVan be48c35eda Add PacketOrderL 2024-12-26 15:32:34 -07:00
ManInMyVan 2ea1d29da5 Check entity in PacketOrderC 2024-12-26 15:32:34 -07:00
ManInMyVan c49e531853 Add PacketOrderJ 2024-12-26 15:32:34 -07:00
ManInMyVan 2eebcfd056 Add PacketOrderI 2024-12-26 15:32:34 -07:00
ManInMyVan f1988e66be Add PacketOrderH 2024-12-26 15:32:34 -07:00
ManInMyVan d7474db60d these are already packet checks 2024-12-26 15:32:34 -07:00
ManInMyVan 97b3781f49 Add PacketOrderG 2024-12-26 15:32:34 -07:00
ManInMyVan a99e0e4947 add PacketOrderF 2024-12-26 15:32:34 -07:00
ManInMyVan ec88893d52 add PacketOrderE 2024-12-26 15:32:33 -07:00
ManInMyVan c1670a7f4e PacketOrder check catagory 2024-12-26 15:32:28 -07:00
Axionize 3e185b6e1e Initial server-side impementation for debugging Hitboxes 2024-12-25 23:05:20 -05:00
Axionize d714211fe6 Merge branch 'merge' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
2024-12-25 19:14:22 -05:00
Axionize 71d524aad0 Fix more Java 8 compatability issues introduced by upstream 2024-12-24 22:58:48 -05:00
Axionize 9bf8eed3d1 - Temporarily undo entity map and iteration order changes in attempt to fix HitboxMiss and HitboxBlock? falses
- Update upstream
- Make PacketOrderC (formerly BadPacketsM) no longer experimental
2024-12-24 22:48:17 -05:00
Axionize 74c8c5ff01 Merge remote-tracking branch 'origin/2.0' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderC.java
#	src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
#	src/main/java/ac/grim/grimac/utils/anticheat/MessageUtil.java
2024-12-24 22:38:12 -05:00
Axionize 935b26ca0c Fix Java 8 Compatability in miniMessage() 2024-12-24 22:19:05 -05:00
Axionize 5e2f889550 Revert entity iteration mapping changes (attempt to fix HitboxMiss and HitboxBlocK? falses) 2024-12-24 22:17:39 -05:00
Axionize b003ec799b Fix Java 8 Compatability in miniMessage() 2024-12-23 22:44:19 -05:00
Axionize 11037cdc85 Fix 1.8 Hitbox modeling for close non-relative teleports 2024-12-23 22:41:16 -05:00
Axionize fffae61f8a Merge branch 'feat/1.8-missed-hitbox-fix' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/events/packets/PacketEntityReplication.java
2024-12-23 22:39:29 -05:00
Axionize 6a56b9bbf0 Merge branch 'merge' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/predictionengine/predictions/rideable/PredictionEngineRideableUtils.java
#	src/main/java/ac/grim/grimac/utils/anticheat/MessageUtil.java
2024-12-23 22:38:28 -05:00
Axionize 4c13a0adec Fix 1.8 Hitbox modeling for close non-relative teleports 2024-12-23 22:06:49 -05:00
Axionize 0932b7062d Merge upstream changes up to commit 1f93dff26c 2024-12-23 21:33:36 -05:00
Axionize 7f61d19f55 Merge remote-tracking branch 'origin/2.0' into merge-dev
# Conflicts:
#	build.gradle.kts
#	src/main/java/ac/grim/grimac/checks/impl/scaffolding/AirLiquidPlace.java
#	src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
#	src/main/java/ac/grim/grimac/manager/CheckManager.java
#	src/main/java/ac/grim/grimac/player/GrimPlayer.java
#	src/main/java/ac/grim/grimac/utils/change/BlockModification.java
#	src/main/java/ac/grim/grimac/utils/change/PlayerBlockHistory.java
2024-12-23 21:12:40 -05:00
Axionize 31396cdd73 Fix NPE that can occur in HitboxEntities check 2024-12-22 21:34:33 -05:00
Axionize ceb6e7932b Merge branch 'merge' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/change/PlayerBlockHistory.java
2024-12-22 21:33:35 -05:00
Axionize 82a755d739 Fix NPE that can occur if there is no hitbox overlap on entity move in reach-entities-check 2024-12-22 21:32:04 -05:00
Axionize 631217a7f4 Fix very rare CME; investigate cause later 2024-12-20 21:35:59 -05:00
Axionize b880f51fbc BadPacketsX, PacketOrder, and LineOfSightPlace improvements
* Refactor and improve numerous PacketOrder checks
* Fix some BadPacketsX falses
* Fix some LineOfSightPlace falses
2024-12-18 16:17:23 -05:00
Axionize 2a86ff4e5f BadPacketsX, and LOSP false fixes 2024-12-18 16:09:59 -05:00
Axionize 3d3a17eea9 Merge remote-tracking branch 'maninmyvan/packetorder' into merge-dev
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderA.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderE.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderF.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderG.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderH.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderI.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderJ.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderK.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderL.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderM.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderN.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderO.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderProcessor.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/TransactionOrder.java
#	src/main/java/ac/grim/grimac/manager/CheckManager.java
#	src/main/java/ac/grim/grimac/player/GrimPlayer.java
#	src/main/resources/punishments/de.yml
#	src/main/resources/punishments/en.yml
#	src/main/resources/punishments/es.yml
#	src/main/resources/punishments/fr.yml
#	src/main/resources/punishments/it.yml
#	src/main/resources/punishments/nl.yml
#	src/main/resources/punishments/pt.yml
#	src/main/resources/punishments/ru.yml
#	src/main/resources/punishments/zh.yml
2024-12-18 14:45:58 -05:00
Axionize ac2607d6cd Merge branch 'merge' into merge-dev 2024-12-18 14:21:57 -05:00
Axionize b4820b5f19 Update punishment files for logging 2024-12-17 19:57:07 -05:00
Axionize 79c70572a8 Code cleanup; re-add grim.verbose.enable-on-join permission 2024-12-17 19:11:55 -05:00
Axionize ced56218d9 Update punishment files for non-en langauges for reach refactor 2024-12-17 19:02:31 -05:00
Axionize 6243fdf605 Refactor and split Reach into 4 checks. Fix some HitboxEntity falses. (#25)
* Temporary hack to fix rapidly changing blocks causing falses
* Refactor reach to flag seperate checks
* Fix verbose double toggling
* Fix check annotations
* Temporary fix
* Temporarily disable removing extra eyeHeight reach iterations; also fix Pink Petals Box
* Stash sectioned entity map
* Replicate vanilla iteration order, primarily for performing entity hitbox blocking checks
2024-12-17 18:53:35 -05:00
AbdisKioskandManInMyVan b40deaa620 Add / grim history (#24)
* Add option to log violations

* Add /grim history command

* Follow coventions

Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>

* Remove unused getters

* Make messages configurable

* make entries per page configurable

* fix subcommand alias

* add command to messages

* synchronize writes to avoid sqlite_misuse error

* add history messages to all lang files

* add mysql compatability to violation database

* add mysql compatability to violation database

* add grim history in help command for all languages

* change colorcodes from § to & for grim history strings

* avoid sync usage of Bukkit.getOfflinePlayer(string)

* add tab completion for online players in grim history

* remove test

* Follow coventions

Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>

* revert file permission change in gradlew

* add 'server' field to grim history

---------

Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-12-17 11:41:19 -05:00
ManInMyVan 571ae73fc5 fix PacketOrderI falses with tick skipping 2024-12-15 12:55:16 -07:00
Axionize 8d2d33f1ea Fixed InventoryD not working due to upstream changes to simulation engine movement data.
ver: 2.3.69-B37
2024-12-15 14:31:52 -05:00
Axionize 738cd44ab9 Fix inventoryD breaking due to new engine changes 2024-12-15 14:30:11 -05:00
ManInMyVan b800699cbf fix 1.21.2+ PacketOrderH false 2024-12-15 12:19:41 -07:00
Axionize d3c82a326a Fix automatically enabling verbose when joining 2024-12-14 20:36:02 -05:00
Axionize e40ba62e5a Merge remote-tracking branch 'origin/2.0' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/movement/NoSlowC.java
#	src/main/java/ac/grim/grimac/checks/impl/movement/NoSlowD.java
#	src/main/java/ac/grim/grimac/checks/impl/movement/NoSlowE.java
#	src/main/java/ac/grim/grimac/checks/impl/post/Post.java
#	src/main/java/ac/grim/grimac/checks/impl/scaffolding/RotationPlace.java
#	src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
#	src/main/java/ac/grim/grimac/manager/CheckManager.java
2024-12-14 19:59:35 -05:00
ManInMyVan bcc9e9be13 don't register PacketOrderProcessor twice 2024-12-13 13:12:47 -07:00
ManInMyVan 40918c9988 remove unused imports 2024-12-13 13:11:58 -07:00
ManInMyVan f493fe3005 1.21.2 2024-12-13 12:38:30 -07:00
ManInMyVan c5dc6d4050 fix wrongly resolved merge conflict 2024-12-12 22:39:31 -07:00
ManInMyVan db8aad3c00 fix falses 2024-12-12 19:52:28 -07:00
ManInMyVan 12cdd2f380 remove PacketOrderO
depends on too many factors
2024-12-12 19:51:17 -07:00
ManInMyVan 6c3657ae40 fix more falses 2024-12-12 19:49:59 -07:00
ManInMyVan ffa21f6f3e fix falses 2024-12-12 19:49:59 -07:00
ManInMyVan 7ce0e2f9ec fix false when swapping offhand items 2024-12-12 19:49:59 -07:00
ManInMyVan 1c3c6a8879 fix false when dropping items 2024-12-12 19:49:59 -07:00
ManInMyVan 75aa7d8f71 only setback on item use 2024-12-12 19:49:59 -07:00
ManInMyVan 33c96893d7 remove invalid variable default 2024-12-12 19:49:59 -07:00
ManInMyVan c3f6fd5c65 add remaining entity actions to PacketOrderProcessor 2024-12-12 19:49:59 -07:00
ManInMyVan 616f3076c9 rename invalidSlots to invalid 2024-12-12 19:49:59 -07:00
ManInMyVan 0898a94104 add PacketOrderO and PacketOrderP 2024-12-12 19:49:59 -07:00
ManInMyVan 48a371dc66 add PacketOrderN 2024-12-12 19:49:39 -07:00
ManInMyVan 5e7fef1572 Add PacketOrderM 2024-12-12 19:49:39 -07:00
ManInMyVan 8701f12f6a fix a noslow 2024-12-12 19:49:39 -07:00
ManInMyVan cbdd5a7a14 rename exempt-digging to exempt-placing-while-digging in PacketOrderI
and make it work
2024-12-12 19:49:39 -07:00
ManInMyVan 48ba546a40 rename PacketOrderM to PacketOrderA 2024-12-12 19:49:39 -07:00
ManInMyVan cdbe983d22 add PacketOrderM 2024-12-12 19:49:39 -07:00
ManInMyVan e2ad24e604 use PacketOrderProcessor in PacketOrderK 2024-12-12 19:49:39 -07:00
ManInMyVan d954784e74 rewrite 2024-12-12 19:49:39 -07:00
ManInMyVan dd0e338588 fix falses 2024-12-12 19:49:39 -07:00
ManInMyVan 73d591907d don't cancel the tick 2024-12-12 19:49:38 -07:00
ManInMyVan 806a13ea25 more PacketOrderC stuff 2024-12-12 19:49:38 -07:00
ManInMyVan 38d64e2cff fixes 2024-12-12 19:49:38 -07:00
ManInMyVan c666d98a9e oops 2024-12-12 19:49:38 -07:00
ManInMyVan c270105c09 fix falses 2024-12-12 19:49:38 -07:00
ManInMyVan 36776a488b Add PacketOrderK 2024-12-12 19:49:38 -07:00
ManInMyVan 5d6c77851a make PacketOrderE setback
https://github.com/CCBlueX/LiquidBounce/blob/nextgen/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/movement/noslow/modes/blocking/NoSlowBlockingSwitch.kt
2024-12-12 19:49:38 -07:00
ManInMyVan 8bb5be493d exemptBreaking option in PacketOrdlerL 2024-12-12 19:49:38 -07:00
ManInMyVan c681a12176 fix some PacketOrderF falses 2024-12-12 19:39:58 -07:00
ManInMyVan ea614f7336 Add PacketOrderL 2024-12-12 19:39:58 -07:00
ManInMyVan fa985fe4fa Check entity in PacketOrderC 2024-12-12 19:39:58 -07:00
ManInMyVan f485b70cbf Add PacketOrderJ 2024-12-12 19:39:58 -07:00
ManInMyVan 36e0974fcf Add PacketOrderI 2024-12-12 19:39:58 -07:00
ManInMyVan a4ee272641 Add PacketOrderH 2024-12-12 19:39:58 -07:00
ManInMyVan fd8507610b these are already packet checks 2024-12-12 19:39:57 -07:00
ManInMyVan 4428af4acc Add PacketOrderG 2024-12-12 19:39:57 -07:00
ManInMyVan a4031c4862 add PacketOrderF 2024-12-12 19:39:57 -07:00
ManInMyVan 7abb8d61b0 add PacketOrderE 2024-12-12 19:39:57 -07:00
ManInMyVan 0b76452fbb PacketOrder check catagory 2024-12-12 19:34:23 -07:00
Axionize 0c8b4c2f3a Update PacketEvents for 1.21.4 support and shadow colors 2024-12-07 03:42:06 -05:00
Axionize 42af76a9ea Merge remote-tracking branch 'origin/2.0' into merge 2024-12-07 02:45:54 -05:00
Axionize 7a0f2b1227 Merge remote-tracking branch 'origin/2.0' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/combat/Reach.java
#	src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
#	src/main/java/ac/grim/grimac/predictionengine/predictions/PredictionEngine.java
2024-12-05 12:36:31 -05:00
Axionize 1789912e14 Improve performance; replace concurrent with nonconcurrent queue 2024-12-05 00:23:56 -05:00
Axionize 6cbedf1f26 Fix Java 8 Compatability 2024-12-04 23:18:17 -05:00
Axionize 2c42a96c3c Merge branch '2.0' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
#	src/main/java/ac/grim/grimac/utils/latency/CompensatedEntities.java
2024-12-03 20:12:24 -05:00
Axionize bc1ab00c3f Merge remote-tracking branch 'origin/2.0' into 2.3.69-b30
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/data/Pair.java
2024-11-30 02:23:24 -05:00
Axionize 34fde514fd Revert "exempt 1.14.2+ clients in NoSlowC and NoSlowD"
This reverts commit f6ef1df29d.
2024-11-30 02:22:24 -05:00
Axionize 26d5d9d9d2 Merge remote-tracking branch 'maninmyvan/multiactions' into 2.3.69-b30
# Conflicts:
#	src/main/java/ac/grim/grimac/manager/CheckManager.java
2024-11-30 02:14:27 -05:00
Axionize f755f2d670 Fix config issue where skip-block-check: true and skip-entity-check: false would cause numerous block falses 2024-11-29 16:23:30 -05:00
Axionize 3004390528 Make LOSP use same direction calculations as Reach check; could fix some falses 2024-11-29 02:01:50 -05:00
Axionize af141e35d3 Put -Dpaper.explicit-flush=true in quotes 2024-11-29 01:07:24 -05:00
Axionize 3a33be168f Warn players who want extra reach accuracy that they need to add paper.explicit-flush=true 2024-11-29 01:07:17 -05:00
Axionize 30994d1279 Shrink blocks for 0.03/0.002 2024-11-29 01:06:06 -05:00
Axionize 9b716b5c58 Add block and reach check skip options 2024-11-29 00:57:01 -05:00
Axionize 714549f79c Merge branch 'reach-check-entities' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/scaffolding/LineOfSightPlace.java
#	src/main/java/ac/grim/grimac/utils/anticheat/update/BlockPlace.java
#	src/main/java/ac/grim/grimac/utils/data/HitData.java
#	src/main/java/ac/grim/grimac/utils/latency/CompensatedEntities.java
#	src/main/java/ac/grim/grimac/utils/nmsutil/BlockRayTrace.java
2024-11-29 00:20:45 -05:00
Axionize d0fcf33255 Fix Armorstand index on 1.13.2 for PacketEntity 2024-11-29 00:09:17 -05:00
Axionize 02553f332f Fix Bow NoSlow 2024-11-28 23:29:24 -05:00
Axionize 1eb12bafd4 Fix evicting queue for riptide entities 2024-11-28 21:17:09 -05:00
Axionize 88883caca8 Fix riptide trident attacks on entiies that are non-pushable or the same team as the attacker 2024-11-28 17:10:32 -05:00
Axionize 5a8e8b320a Add permission to enable verbose on join 2024-11-27 23:45:49 -05:00
Axionize 3723581dc2 split union() in SCB into union() and new encompass() method; fixes Simulation false on walls 2024-11-27 21:48:19 -05:00
Axionize 7ea0d4d24c Make var type in ExploitC explicitly String 2024-11-27 21:47:14 -05:00
Axionize dff5361934 Merge remote-tracking branch 'origin/2.0' into merge 2024-11-27 01:37:11 -05:00
Axionize cd032a51ab Merge remote-tracking branch 'origin/2.0' into merge 2024-11-26 03:41:30 -05:00
Axionize 379fc6601d Merge remote-tracking branch 'origin/2.0' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/manager/init/start/BStats.java
2024-11-25 00:28:02 -05:00
Axionize dd490aa8c2 Merge branch 'fix-modern-cient-legacy-server-walls' into merge 2024-11-25 00:08:31 -05:00
Axionize 42094cbddc Merge branch 'fix-airliquidplace' into merge 2024-11-24 23:49:52 -05:00
Axionize d0562de1e1 Cleanup 2024-11-24 22:22:12 -05:00
Axionize d85979d3ab Merge branch 'fix-airliquidplace' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/badpackets/BadPacketsX.java
#	src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
#	src/main/java/ac/grim/grimac/manager/TickManager.java
#	src/main/java/ac/grim/grimac/utils/collisions/CollisionData.java
#	src/main/java/ac/grim/grimac/utils/collisions/HitboxData.java
#	src/main/java/ac/grim/grimac/utils/collisions/blocks/PistonHeadCollision.java
2024-11-24 22:04:35 -05:00
Axionize 3809aed146 Finish documenting all edge cases that can false AirLiquidPlace and fixing them 2024-11-24 22:02:21 -05:00
Axionize 06210f03ba Remove debug messages 2024-11-24 21:02:05 -05:00
Axionize 97afbd8d77 Move clearing updated blocks logic into an async loop; new ClearRecentlyUpdatedBlocks() class 2024-11-24 20:29:48 -05:00
Axionize df89d15aa6 Cleanup AirLiquidPlace 2024-11-24 20:25:22 -05:00
Axionize 12864dccc5 Only check first value in iterator() in AirLiquidPlace() 2024-11-24 20:17:01 -05:00
Axionize 4c9b07612d Fix AirLiquidPlace false 2024-11-24 20:12:59 -05:00
Axionize 026c2417c9 Add new Data classes to see recently modified blocks 2024-11-24 20:12:34 -05:00
Axionize 9621add16e Fix CCB constructor for DynamicHitboxFence 2024-11-24 02:41:12 -05:00
Axionize 7bd3af3eca Use movementThreshold() instead of 0.03 where appropiate 2024-11-24 01:34:05 -05:00
Axionize dd9d14e195 Style fix 2024-11-24 00:29:24 -05:00
Axionize 8d01e90f11 Mark BadPacketsZ as no longer experimental 2024-11-24 00:03:02 -05:00
Axionize 6ed64d3730 Mark BadPacketsX as no longer experimental 2024-11-23 23:56:22 -05:00
Axionize 8660ff0f60 Fix BadPacketsX falses 2024-11-23 23:56:02 -05:00
Axionize fd889bd26a Merge remote-tracking branch 'maninmyvan/packetorder' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderA.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderE.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderF.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderG.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderH.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderI.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderJ.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderK.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderL.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderM.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderN.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderO.java
#	src/main/java/ac/grim/grimac/checks/impl/packetorder/PacketOrderProcessor.java
#	src/main/java/ac/grim/grimac/manager/CheckManager.java
2024-11-23 11:34:23 -05:00
Axionize 1a7949a477 Revert "Fix rapidly breaking/placing instabreak blocks and lighting tnt falses; currently LOSP no longer stops any illegal placements just flags. Will fix later"
This reverts commit 9f09fcd1
2024-11-22 22:23:10 -05:00
Axionize 0a26d37728 Revert "New buffer system"
This reverts commit ef45df9e
2024-11-22 22:21:37 -05:00
Axionize 73597d9524 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:24:35 -05:00
ManInMyVan 1799a56072 fix falses 2024-11-22 14:28:02 -07:00
ManInMyVan 56e4fa75bf cleanup imports 2024-11-22 14:13:32 -07:00
ManInMyVan b535b28661 rename PacketOrderP to PacketOrderO 2024-11-22 13:46:43 -07:00
ManInMyVan 43634772c7 remove PacketOrderO
depends on too many factors
2024-11-22 13:46:43 -07:00
ManInMyVan aea66feb33 fix more falses 2024-11-22 13:46:43 -07:00
ManInMyVan 11d856ce08 fix falses 2024-11-22 13:46:43 -07:00
ManInMyVan 30a346bd3f fix a noslow 2024-11-22 13:46:43 -07:00
ManInMyVan 5254a376c4 fix false when swapping offhand items 2024-11-22 13:46:43 -07:00
ManInMyVan f79e8c12a5 fix false when dropping items 2024-11-22 13:46:42 -07:00
ManInMyVan af580c4d48 only setback on item use 2024-11-22 13:46:42 -07:00
ManInMyVan be65dc5e51 remove invalid variable default 2024-11-22 13:46:42 -07:00
ManInMyVan 93c1c7b480 remove sent variable 2024-11-22 13:46:42 -07:00
ManInMyVan b0a5dbd07f and use them 2024-11-22 13:46:42 -07:00
ManInMyVan 74cca86bb6 add remaining entity actions to PacketOrderProcessor 2024-11-22 13:46:42 -07:00
ManInMyVan fe4e60c80c rename invalidSlots to invalid 2024-11-22 13:46:42 -07:00
ManInMyVan 22dd134196 add PacketOrderO and PacketOrderP 2024-11-22 13:46:42 -07:00
ManInMyVan e971604565 add PacketOrderN 2024-11-22 13:46:42 -07:00
ManInMyVan 90c59ad4df Add PacketOrderM 2024-11-22 13:46:42 -07:00
ManInMyVan c888256b38 remove unused method 2024-11-22 13:46:41 -07:00
ManInMyVan 72a0ad53dd rename exempt-digging to exempt-placing-while-digging in PAcketOrderI
and make it work
2024-11-22 13:46:41 -07:00
ManInMyVan 2fc13af09d rename PacketOrderM to PacketOrderA 2024-11-22 13:46:41 -07:00
ManInMyVan 57ccbe753e revert renaming post 2024-11-22 13:46:41 -07:00
ManInMyVan d14916c590 add PacketOrderM 2024-11-22 13:46:41 -07:00
ManInMyVan 5b8741ca46 use PacketOrderProcessor in PacketOrderK 2024-11-22 13:46:41 -07:00
ManInMyVan cfcf52f337 rewrite 2024-11-22 13:46:41 -07:00
ManInMyVan ab32f24dc1 fix falses 2024-11-22 13:46:40 -07:00
ManInMyVan a653e17f3c don't cancel the tick 2024-11-22 13:46:40 -07:00
ManInMyVan 809d26307f more PacketOrderC stuff 2024-11-22 13:46:40 -07:00
ManInMyVan d35d326595 fixes 2024-11-22 13:46:40 -07:00
ManInMyVan 81c550e834 oops 2024-11-22 13:46:40 -07:00
ManInMyVan b27cea2385 register PacketOrderL 2024-11-22 13:46:40 -07:00
ManInMyVan 79f1d65713 fix falses 2024-11-22 13:46:40 -07:00
ManInMyVan 737e6c4cfb exemptBreaking -> exempt-breaking 2024-11-22 13:46:40 -07:00
ManInMyVan 44f68a3266 Add PacketOrderK 2024-11-22 13:46:40 -07:00
ManInMyVan 4e69adc548 exemptBreaking option in PacketOrdlerL 2024-11-22 13:46:39 -07:00
ManInMyVan 93d0c38393 make PacketOrderE setback
https://github.com/CCBlueX/LiquidBounce/blob/nextgen/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/movement/noslow/modes/blocking/NoSlowBlockingSwitch.kt
2024-11-22 13:46:39 -07:00
ManInMyVan 81aa8b8d31 check ENTITY_ACTION packets in PacketOrderL 2024-11-22 13:46:39 -07:00
ManInMyVan ce28bb689a fix some PacketOrderF falses 2024-11-22 13:46:39 -07:00
ManInMyVan 487ce68ef6 Add PacketOrderL 2024-11-22 13:46:39 -07:00
ManInMyVan a29f7a2807 nvm it is valid on 1.8 2024-11-22 13:46:39 -07:00
ManInMyVan 80d33f0f11 this packet order is only valid in 1.7 client 2024-11-22 13:46:39 -07:00
ManInMyVan 0bd57102d5 Check entity in PacketOrderC 2024-11-22 13:46:39 -07:00
ManInMyVan c701b22098 these are already packet checks 2024-11-22 13:46:39 -07:00
ManInMyVan 0ad3c58496 Check digging packets in PacketOrderF 2024-11-22 13:46:39 -07:00
ManInMyVan 99e06d6b3b Update PacketOrderI.java 2024-11-22 13:46:39 -07:00
ManInMyVan 4785482543 Add PacketOrderJ 2024-11-22 13:46:38 -07:00
ManInMyVan c06beba53b Add PacketOrderI 2024-11-22 13:46:38 -07:00
ManInMyVan 4b989a15b6 Add PacketOrderH 2024-11-22 13:46:38 -07:00
ManInMyVan 0f10d48519 Add PacketOrderG 2024-11-22 13:46:38 -07:00
ManInMyVan 2e7454de84 add PacketOrderF 2024-11-22 13:46:38 -07:00
ManInMyVan 5faad6b3ba add PacketOrderE 2024-11-22 13:46:38 -07:00
ManInMyVan 75b0f5c344 PacketOrder check catagory 2024-11-22 13:46:38 -07:00
Axionize d0b94bbda5 Merge remote-tracking branch 'origin/update/1.21.3' into merge 2024-11-22 12:15:58 -05:00
Axionize 6f18622643 Merge branch 'flatten-complexcollisionboxes' into merge 2024-11-22 09:14:08 -05:00
Axionize 6b863655f1 Merge remote-tracking branch 'origin/2.0' into flatten-complexcollisionboxes
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/collisions/HitboxData.java
2024-11-22 09:13:17 -05:00
Axionize 631be06ec2 Remove unused calls to makeShapes() 2024-11-22 09:11:04 -05:00
Axionize 1c4361f2c6 Make makeShapes() CCD extra maxIndex explicit; Fix DynamicCollisionWall error 2024-11-22 09:10:04 -05:00
Cristian Milani 2b5016442b Fix race condition and exception when registering check permissions during rapid consecutive player joins on server start 2024-11-21 20:21:59 -05:00
Axionize e389e4b5e1 Fix Pink Petals Hitbox (Coral Fan) for > 1.12.2 and =< 1.19.3 players 2024-11-21 19:21:28 -05:00
Axionize 7d9cdb91b0 Merge branch 'flatten-complexcollisionboxes' into merge 2024-11-21 18:43:20 -05:00
Axionize 83e06bce77 Make CCD length private var 2024-11-21 18:32:33 -05:00
Axionize 42fd3e1cc7 Rename variable for clarity 2024-11-21 17:14:13 -05:00
Axionize 26a771e4da Fix copying CCBs in edge case 2024-11-21 17:12:38 -05:00
Axionize fad1eb5736 Merge branch 'flatten-complexcollisionboxes' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/collisions/CollisionData.java
#	src/main/java/ac/grim/grimac/utils/collisions/HitboxData.java
#	src/main/java/ac/grim/grimac/utils/collisions/blocks/DynamicStair.java
#	src/main/java/ac/grim/grimac/utils/collisions/blocks/PistonHeadCollision.java
#	src/main/java/ac/grim/grimac/utils/collisions/blocks/connecting/DynamicConnecting.java
#	src/main/java/ac/grim/grimac/utils/collisions/blocks/connecting/DynamicHitboxFence.java
#	src/main/java/ac/grim/grimac/utils/collisions/datatypes/ComplexCollisionBox.java
2024-11-21 12:18:11 -05:00
Axionize 1dc4361938 Remove debug print statement 2024-11-21 12:06:03 -05:00
Axionize 3d5491de4f Fix logic error again in CCB constructor 2024-11-21 12:04:04 -05:00
Axionize 75ff92c326 Optimize DynamicHitboxFence 2024-11-21 11:59:19 -05:00
Axionize c530dcfa17 Fix logic error in CCB constructor 2024-11-21 11:58:04 -05:00
Axionize d720b8864f Fix new downCast() for SimpleCollisionBox 2024-11-21 11:41:52 -05:00
Axionize 3e3dbf0f30 Manually size ComplexCollisionBoxes Pt. 2 2024-11-21 11:38:32 -05:00
Axionize 0bd154974b Manually size ComplexCollisionBoxes Pt. 1 2024-11-21 10:28:34 -05:00
Axionize 3f57026960 implement new downCast() API for Dynamic, Simple, and No Collision Boxes 2024-11-21 10:26:46 -05:00
Axionize be9841fb9f Port everything to new internal .downCast() API besides getCollisionBoxes 2024-11-20 12:37:52 -05:00
Axionize d8b529e837 Optimize ComplexCollisionBoxes by using primitives internally; Make new more efficient constructors available 2024-11-20 12:37:01 -05:00
Axionize d01805ad13 Merge remote-tracking branch 'machinebreaker/inventory-checks' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/inventory/InventoryD.java
#	src/main/java/ac/grim/grimac/checks/impl/inventory/InventoryG.java
2024-11-20 12:23:05 -05:00
Axionize f638772c5f Merge remote-tracking branch 'maninmyvan/packetorder' into merge 2024-11-20 12:21:54 -05:00
Axionize b84b21a68f Revert "Remove old .downCast() method for CollisionBoxes"
This reverts commit c91ef450
2024-11-20 12:14:16 -05:00
Axionize da230781e3 Port everything to new internal .downCast() API besides getCollisionBoxes 2024-11-20 12:01:02 -05:00
Axionize c91ef45062 Remove old .downCast() method for CollisionBoxes 2024-11-20 11:23:28 -05:00
Axionize 9a87329618 Optimize ComplexCollisionBoxes by using primitives internally; Make new more efficient constructors available 2024-11-20 11:15:53 -05:00
Axionize 24ee315c0b Merge remote-tracking branch 'origin/2.0' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/combat/Reach.java
2024-11-19 20:15:21 -05:00
ManInMyVan a4decb57f8 fix more falses 2024-11-17 18:03:13 -07:00
ManInMyVan 81feb5be3f fix falses 2024-11-17 17:25:57 -07:00
MachineBreaker 2253fd0ec3 Use correct operator in InventoryF 2024-11-17 19:46:08 -04:00
MachineBreaker db4ad8e16d Remove InventoryG millis check 2024-11-17 19:41:53 -04:00
MachineBreaker 11571a2b8a Implement inventory desync status 2024-11-17 19:40:28 -04:00
MachineBreaker c615c98d09 Clean imports 2024-11-17 19:24:53 -04:00
MachineBreaker 922b134467 Fix more false positives 2024-11-17 19:20:56 -04:00
Axionize 6650e0cece Fix entity metadata parsing for armorstands on 1.14.4 2024-11-17 14:56:18 -05:00
MachineBreaker 8714e0e5a9 Merge remote-tracking branch 'origin/inventory-checks' into inventory-checks 2024-11-17 13:53:44 -04:00
MachineBreaker 24570aa658 Update config version 2024-11-17 13:53:35 -04:00
Axionize 743a2d9cdb Ensure ComplexCollisionBoxes can only contain SimpleCollisionBoxes 2024-11-17 11:45:55 -05:00
Axionize 4b28aa7604 Ensure ComplexCollisionBoxes can only contain SimpleCollisionBoxes 2024-11-17 11:36:10 -05:00
Axionize 50425ada16 Remove debug print statement 2024-11-17 10:34:45 -05:00
MachineBreaker 6d4f3650cc Merge branch 'GrimAnticheat:2.0' into inventory-checks 2024-11-17 10:22:07 -04:00
Axionize de7a5358d2 Armorstand entity metadata in older versions 2024-11-17 08:02:01 -05:00
Axionize 9a0f3a4dd1 Fix hitboxes for armor stands (including small ones) 2024-11-17 07:46:48 -05:00
Axionize bfbde9d8fc Fix falses due to marker armor stands 2024-11-17 07:19:29 -05:00
MachineBreaker a5ced59a35 Clean imports 2024-11-17 08:13:07 -04:00
MachineBreaker e9c6fac17a Apply suggested changes 2024-11-17 08:11:54 -04:00
Axionize 2bc467ac82 Optimize if else in updateEntityMetaData() 2024-11-17 07:05:26 -05:00
Axionize c68f7bd5f8 Finish merging new inventory checks and packetorder checks; backport to Java 8 2024-11-17 05:36:08 -05:00
Axionize 7015a9efa2 Merge remote-tracking branch 'maninmyvan/packetorder' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/manager/CheckManager.java
2024-11-17 05:19:11 -05:00
ManInMyVan 06bd96fcae fix a noslow 2024-11-16 18:29:05 -07:00
ManInMyVan db7bbef9b5 fix false when swapping offhand items 2024-11-16 18:14:50 -07:00
ManInMyVan fa0d147e04 fix false when dropping items 2024-11-16 18:14:31 -07:00
ManInMyVan 39e7cbe9ca only setback on item use 2024-11-16 18:14:04 -07:00
ManInMyVan 84a1641968 remove invalid variable default 2024-11-16 18:13:45 -07:00
ManInMyVan 26acd7b3a5 remove sent variable 2024-11-16 18:13:15 -07:00
ManInMyVan f51e5e4eae and use them 2024-11-16 18:12:40 -07:00
ManInMyVan 636eaf3d5d add remaining entity actions to PacketOrderProcessor 2024-11-16 18:10:13 -07:00
ManInMyVan 5b9fdd00c8 rename invalidSlots to invalid 2024-11-16 16:45:53 -07:00
MachineBreaker bc42035866 Fix some false positives 2024-11-16 19:32:50 -04:00
Axionize 917eb371c8 Merge remote-tracking branch 'machinebreaker/inventory-checks' into inventory-checks 2024-11-16 18:09:23 -05:00
Axionize ef45df9ea3 New buffer system 2024-11-16 16:44:39 -05:00
Axionize 24965108b2 Fix for entities that players can hit through blocking reach/attack ray trace 2024-11-16 16:00:27 -05:00
Axionize 9f09fcd103 Fix rapidly breaking/placing instabreak blocks and lighting tnt falses; currently LOSP no longer stops any illegal placements just flags. Will fix later 2024-11-16 14:41:03 -05:00
MachineBreaker e1baecd32e Resync InventoryE 2024-11-16 15:31:41 -04:00
MachineBreaker 44d66e0e5b Requested changes 2024-11-16 15:26:45 -04:00
MachineBreaker 0368f930b8 Woops change check name 2024-11-16 13:12:40 -04:00
MachineBreaker a83a0c8579 Implement experimental entity action while inventory is open check 2024-11-16 13:07:17 -04:00
MachineBreaker 92b1ad28c2 Fix 1.8 clients never letting 1.9+ server know about their inventory status
(Via hack)
2024-11-16 12:59:15 -04:00
MachineBreaker 5302f15b9d Implement experimental 1.8 click window while inventory not open check 2024-11-16 12:50:09 -04:00
Axionize 6a3eec1960 Add optional success field to HitData used to indicate if raytrace hit intended target 2024-11-16 11:44:38 -05:00
Axionize 11425840ad Add getBlockPlaceCheck() method 2024-11-16 11:21:39 -05:00
Axionize 8515df8224 Early exit optimiztion 2024-11-16 11:08:47 -05:00
Axionize fe5d6e34f2 Initial work to eliminate final LOSP falses by tracking recently changed blocks; improve performance by using primitive array for SimpleCollisionBox 2024-11-16 10:56:37 -05:00
MachineBreaker e3e797e19a Woops fix compilation 2024-11-16 11:55:32 -04:00
MachineBreaker 2293092048 Make an inventory check type 2024-11-16 11:54:58 -04:00
MachineBreaker 147081ccc5 Clean 2024-11-16 11:09:47 -04:00
MachineBreaker b924f65f91 Implement held item change while inventory is open check
Also add verbose for the other inventory checks
2024-11-16 11:01:02 -04:00
MachineBreaker 259dd72f87 Use packets to close player inventory 2024-11-16 10:53:40 -04:00
MachineBreaker ab726bda78 Fix conflicts 2024-11-16 10:47:34 -04:00
MachineBreaker 163bbd7b0e Merge remote-tracking branch 'origin/2.0' into inventory-checks
# Conflicts:
#	src/main/java/ac/grim/grimac/manager/CheckManager.java
#	src/main/resources/config/zh.yml
2024-11-16 10:40:51 -04:00
Axionize 205e169754 Initial work to make Reach raytrace check also check for entities 2024-11-16 08:03:49 -05:00
Axionize 35f7914249 More robust hitData handling of new EntityHitData type in CheckManagerListener 2024-11-16 08:02:10 -05:00
Axionize 31b7fd462f Initial Entity Blocking Hit Checks 2024-11-16 06:55:52 -05:00
Axionize b9812ba2b6 Add better temporary logging to see if new HitData types are used in CheckManagerListener 2024-11-16 05:08:52 -05:00
Axionize fc1d5ff3ae Add new EntityHitData constructors 2024-11-16 01:33:56 -05:00
Axionize 2f983ad316 Refactor HitData in preperation for supporting EntityHitResults 2024-11-15 07:32:20 -05:00
Axionize db23910195 Document why we trace longer than player hit distance on reach ray trace 2024-11-15 06:23:03 -05:00
Axionize 968e166bde Fix Button hitboxes for pre-1.13 players 2024-11-15 03:13:01 -05:00
Axionize efe729c4d1 Add new Reach config option to skip checks against non-player-entities 2024-11-15 01:43:47 -05:00
Axionize d40d19d6e3 Bump packetevents back to 2.6.1 (custom) to fix bugs 2024-11-15 01:06:48 -05:00
Axionize b476b143f4 Spotless changes 2024-11-15 01:06:35 -05:00
Axionize bb54697d9c Make switch cases Java 8 compatible 2024-11-15 01:05:39 -05:00
Axionize 24102c15e6 Bump version number back to 2.3.69 2024-11-15 00:46:20 -05:00
Axionize 5100ef06c8 Build with Java 8 compatibility instead of Java 17 2024-11-15 00:44:54 -05:00
Axionize 9b892eab85 Revert "Java 17 update"
This reverts commit 5a6f87fe
2024-11-15 00:43:05 -05:00
Axionize eab5ca7f6d Merge remote-tracking branch 'origin/2.0' into merge
# Conflicts:
#	build.gradle.kts
#	src/main/java/ac/grim/grimac/checks/impl/scaffolding/RotationPlace.java
#	src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
#	src/main/java/ac/grim/grimac/utils/collisions/HitboxData.java
#	src/main/java/ac/grim/grimac/utils/collisions/blocks/connecting/DynamicHitboxPane.java
#	src/main/java/ac/grim/grimac/utils/collisions/blocks/connecting/DynamicHitboxWall.java
2024-11-15 00:40:09 -05:00
Axionize fd055c163e Use new packetevents metrics class 2024-11-15 00:32:03 -05:00
Axionize ea78d2ff40 Update packetevents (built locally using custom changes) to fix #3 2024-11-15 00:22:52 -05:00
SamB440 6f074513f2 Merge pull request #1787 from Onako2/2.0
Update dependencies so it works on 1.21.3
2024-11-14 16:18:42 +00:00
ManInMyVan 0719c5bdc6 add PacketOrderO and PacketOrderP 2024-11-11 19:19:41 -07:00
ManInMyVan 36a394d142 add PacketOrderN 2024-11-11 19:19:41 -07:00
ManInMyVan 0e08dbc6f2 Add PacketOrderM 2024-11-11 19:19:41 -07:00
ManInMyVan 003aa67a41 remove unused method 2024-11-11 19:19:41 -07:00
ManInMyVan be45a43524 rename exempt-digging to exempt-placing-while-digging in PAcketOrderI
and make it work
2024-11-11 19:19:41 -07:00
ManInMyVan 0d700848f8 rename PacketOrderM to PacketOrderA 2024-11-11 19:19:41 -07:00
ManInMyVan 1ff402036d revert renaming post 2024-11-11 19:19:40 -07:00
ManInMyVan 9d36dbd2b8 add PacketOrderM 2024-11-11 19:19:40 -07:00
ManInMyVan c53c4378d8 use PacketOrderProcessor in PacketOrderK 2024-11-11 19:19:40 -07:00
ManInMyVan eacf176f88 rewrite 2024-11-11 19:19:40 -07:00
ManInMyVan 13afb067bb fix falses 2024-11-11 19:19:39 -07:00
ManInMyVan 7af2f4b2e2 don't cancel the tick 2024-11-11 19:19:39 -07:00
ManInMyVan a1d8bfa6a1 more PacketOrderC stuff 2024-11-11 19:19:39 -07:00
ManInMyVan 47b3fe9ca2 fixes 2024-11-11 19:19:39 -07:00
ManInMyVan 0ce52ea107 oops 2024-11-11 19:19:39 -07:00
ManInMyVan d98fe31412 register PacketOrderL 2024-11-11 19:19:39 -07:00
ManInMyVan d8f338aada fix falses 2024-11-11 19:19:39 -07:00
ManInMyVan f5965c48b3 exemptBreaking -> exempt-breaking 2024-11-11 19:19:39 -07:00
ManInMyVan 0df7077ddb Add PacketOrderK 2024-11-11 19:19:38 -07:00
ManInMyVan 222a9341bf exemptBreaking option in PacketOrdlerL 2024-11-11 19:19:38 -07:00
ManInMyVan 35f6f7870a make PacketOrderE setback
https://github.com/CCBlueX/LiquidBounce/blob/nextgen/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/movement/noslow/modes/blocking/NoSlowBlockingSwitch.kt
2024-11-11 19:19:38 -07:00
ManInMyVan 15b6e0ba27 check ENTITY_ACTION packets in PacketOrderL 2024-11-11 19:19:38 -07:00
ManInMyVan 968754efe0 fix some PacketOrderF falses 2024-11-11 19:19:38 -07:00
ManInMyVan a03c9e0194 Add PacketOrderL 2024-11-11 19:19:38 -07:00
ManInMyVan 734e7cbae8 nvm it is valid on 1.8 2024-11-11 19:19:38 -07:00
ManInMyVan 52fe6691ac this packet order is only valid in 1.7 client 2024-11-11 19:19:38 -07:00
ManInMyVan acd8d1192c Check entity in PacketOrderC 2024-11-11 19:19:38 -07:00
ManInMyVan 8fc309cb76 these are already packet checks 2024-11-11 19:19:37 -07:00
ManInMyVan 45f16ec10f Check digging packets in PacketOrderF 2024-11-11 19:19:37 -07:00
ManInMyVan 5ff8cb21c8 Update PacketOrderI.java 2024-11-11 19:19:37 -07:00
ManInMyVan f8997b8739 Add PacketOrderJ 2024-11-11 19:19:37 -07:00
ManInMyVan ed21464c3a Add PacketOrderI 2024-11-11 19:19:37 -07:00
ManInMyVan 7954575216 Add PacketOrderH 2024-11-11 19:19:37 -07:00
ManInMyVan 1a11d3e733 Add PacketOrderG 2024-11-11 19:19:37 -07:00
ManInMyVan 487aa45a27 add PacketOrderF 2024-11-11 19:19:37 -07:00
ManInMyVan b7f9aeab06 add PacketOrderE 2024-11-11 19:19:36 -07:00
ManInMyVan 6aaee382a6 PacketOrder check catagory 2024-11-11 19:19:30 -07:00
Onako2 8c84c506bf Update dependencies for 1.21.3 support 2024-11-11 22:03:35 +01:00
Axionize 0622f92cf1 Revert "Remove unncessary NO_COLLISION entry for torchcrop"
This reverts commit e149ca6be8.
2024-11-03 18:14:12 -05:00
Axionize a8f81c141a Revert "Remove unncessary NO_COLLISION entries"
This reverts commit 1761d853de.
2024-11-03 18:14:11 -05:00
Axionize efffceb9f2 Fix scaffolding hitbox for pre-1.14 clients 2024-11-03 07:05:40 -05:00
Axionize 75d1fc32c8 Enable checks against scaffolding 2024-11-03 06:58:37 -05:00
Axionize e087e93e2a Fix Weeping Vines and Vine Plant for all versions; Fix Weeping + Twisted for pre 1.16 players 2024-11-03 06:34:04 -05:00
Axionize e83c9967b4 Fix pitcher crop for pre-1.20 players 2024-11-03 05:51:34 -05:00
Axionize 2b1896020d Fix sniffer egg for pre 1.20 players 2024-11-03 05:46:06 -05:00
Axionize 61b17907ee Fix frogspawn for pre-1.19 players 2024-11-03 05:45:50 -05:00
Axionize 339fb42f37 Fix Sculk Shrieker hit box for all versions and collision box for pre 1.18.2 2024-11-03 05:33:50 -05:00
Axionize 7985275697 Fix Spore Blossom hitbox on < 1.17 2024-11-03 05:18:42 -05:00
Axionize 661b60d07c Fix glow lichen and sculk vein boxes 2024-11-03 05:15:31 -05:00
Axionize d4f647e18b Fix Cauldron Hit/Collision Box 2024-11-03 03:51:39 -05:00
Axionize 1761d853de Remove unncessary NO_COLLISION entries 2024-11-03 02:59:10 -05:00
Axionize 42a6543f9b Fix Pink Petals Boxes 2024-11-03 02:51:23 -05:00
Axionize 9356c6c323 Add new union() function to collision boxes 2024-11-03 02:41:27 -05:00
Axionize a7a92f7e10 Fix Coral Fan Collision box 2024-11-03 01:44:04 -04:00
Axionize e149ca6be8 Remove unncessary NO_COLLISION entry for torchcrop 2024-11-03 01:17:36 -04:00
Axionize d44493743d Cleanup and documnet why 2nd rayTrace in getNearestReachHitResult is intentionally non-optimal 2024-11-03 00:48:51 -04:00
Axionize 7eb030de7d Remove unsued getFacing() from vector code 2024-11-02 22:34:03 -04:00
Axionize 8fd4a4a87d Fix falses on blocks with 'insides/internal walls' (different Raycast block placement shape then HitBox shape) like Cauldrons, Hoppers, and Composters 2024-11-02 22:33:08 -04:00
Axionize 8f71a427fd Annotate LOSP functions 2024-11-02 04:36:56 -04:00
Axionize 8b9bc356f2 Merge remote-tracking branch 'origin/2.0' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/scaffolding/RotationPlace.java
#	src/main/java/ac/grim/grimac/player/GrimPlayer.java
2024-11-01 21:31:23 -04:00
Axionize 89b6c8306e Fix falses on dead corals 2024-11-01 21:25:08 -04:00
Axionize 32a09aa36b Merge remote-tracking branch 'origin/2.0' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/player/GrimPlayer.java
2024-10-27 04:31:43 -04:00
Axionize 3ea716c580 Merge remote-tracking branch 'origin/2.0' into merge 2024-10-20 03:01:42 -04:00
Axionize 328d347845 Merge remote-tracking branch 'origin/2.0' into merge 2024-10-14 13:05:26 -04:00
Axionize d394c3d67c Revert Java 17 changes 2024-10-10 23:59:36 -04:00
Axionize 17b6b8a4e7 Merge branch 'los-containers' into merge 2024-10-10 23:54:56 -04:00
Axionize 980226fab9 Update LOSP to work with new grim config 2024-10-10 23:54:19 -04:00
Axionize 0f726a0f34 Merge remote-tracking branch 'origin/2.0' into los-containers 2024-10-10 23:53:39 -04:00
Axionize 91ee057f4a Merge remote-tracking branch 'origin/2.0' into merge
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/combat/Reach.java
2024-10-10 23:38:40 -04:00
Axionize c26afbc0af Merge branch 'GrimAnticheat:2.0' into merge 2024-10-08 00:08:05 -04:00
Axionize be56e28009 Merge branch 'fix-attribute-clamp' into merge 2024-10-05 17:35:57 -04:00
Axionize 0697c425ca Document SimpleCollisionBox and HexCollisionBox with Javadoc 2024-10-03 03:40:32 -04:00
Axionize ca0ca471fb Document SimpleCollisionBox and HexCollisionBox with Javadoc 2024-10-03 03:38:58 -04:00
Axionize 7b2aac3874 Version Bump 2024-10-03 02:25:59 -04:00
Axionize fbe8376ca0 Remove experimental check flag from Reach 2024-10-03 02:15:33 -04:00
Axionize 22bc18859b Modernize reach check 2024-10-03 01:29:18 -04:00
Axionize 25f9608d58 Merge branch 'reach-wall-hit' into LOSP-reach-wall-check
# Conflicts:
#	src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
#	src/main/java/ac/grim/grimac/utils/nmsutil/BlockRayTrace.java
2024-10-03 01:26:45 -04:00
Axionize 428f213e15 Migrate reach-related functions to new BlockRayTrace util class 2024-10-03 01:23:39 -04:00
AxionizeandManInMyVan 593d48a6e6 Button Styling Change
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:15 -04:00
AxionizeandManInMyVan 3dcf3c931a Sapling Styling Change
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:15 -04:00
AxionizeandManInMyVan 8cc45ddba3 TALL_FLOWER Styling Change
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:14 -04:00
AxionizeandManInMyVan 6f23122657 Redstone Wire Comment Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:14 -04:00
AxionizeandManInMyVan c0b0759ed0 Inline Hitbox Calculation
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:14 -04:00
AxionizeandManInMyVan 00252f3b97 getPropaguleMinHeight Spacing
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:13 -04:00
AxionizeandManInMyVan 531c49011b Small Flower Line Spacing/Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:13 -04:00
AxionizeandManInMyVan dea22454f7 Coral Fan Line Spacing/Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:13 -04:00
AxionizeandManInMyVan 12bda63785 Banner Line Spacing/Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:12 -04:00
AxionizeandManInMyVan c65e17cf0c Simplify TALL_FLOWERS handling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:12 -04:00
AxionizeandManInMyVan 753ca0e6ad Rails Styling
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:12 -04:00
AxionizeandManInMyVan 8b85e1711d Mark function as Deprecated
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-10-03 00:10:12 -04:00
Axionize 12b0dfd19d Fix spelling mistake 2024-10-03 00:07:51 -04:00
Axionize 8c05d41423 Replace RuntimeException in HitBox.java with IllegalStateException 2024-10-03 00:07:26 -04:00
Axionize c5ab0f5440 Merge remote-tracking branch 'origin/2.0' into los-containers
# Conflicts:
#	src/main/java/ac/grim/grimac/utils/collisions/CollisionData.java
2024-10-02 21:01:12 -04:00
ManInMyVan d92f5ef375 fix chains for pre-1.16 players 2024-10-02 21:00:18 -04:00
Axionize c313d6203a Compact all NO_COLLISION states together 2024-10-02 20:51:10 -04:00
Axionize 070f92aea2 Fix 1.11 Ascending rails hitboxes 2024-09-28 01:53:38 -04:00
Axionize 4e3c5894b5 Fix HitBox of ascending powered rail on 1.9 2024-09-28 01:37:43 -04:00
Axionize 8cfb9f0f17 Fix HitBox of ascending powered rails on 1.7.10 2024-09-28 01:14:49 -04:00
Axionize 4e135e3f92 Make result player.getPossibleEyeHeights() of final in checks and remove unused imports 2024-09-28 00:21:33 -04:00
Axionize 938522974b Replace RotationPlace with LOSP in Turkish config 2024-09-26 21:23:08 -04:00
Axionize 6994975387 Merge remote-tracking branch 'origin/2.0' into los-containers
# Conflicts:
#	src/main/java/ac/grim/grimac/checks/impl/scaffolding/RotationPlace.java
2024-09-26 21:20:07 -04:00
Axionize 6d3a172466 Removing unneeded special case handling 2024-09-26 17:12:07 -04:00
Axionize 3aaa185617 Readability/documentation improvements 2024-09-25 00:51:50 -04:00
Axionize 980cd92333 1.8 Players 2024-09-25 00:28:59 -04:00
Axionize 89da2942c7 Handle player joining on new version -> scale changing -> old version 2024-09-25 00:01:52 -04:00
Axionize 8ea905e053 Optimize returned array for crawling 2024-09-25 00:01:09 -04:00
Axionize 885e959cdb fix conditionall check 2024-09-24 23:22:22 -04:00
Axionize 02904a3dce Only rewrite player possibleEyeHeights when player scale changes 2024-09-24 23:03:10 -04:00
Axionize e8d4bb2376 Don't bother updating scale attribute if no change is made 2024-09-23 21:16:24 -04:00
Axionize 7695167578 Fix intializing array 2024-09-23 20:34:50 -04:00
Axionize 94e5f63a65 Simplify logic and handle caching even when scale changes 2024-09-23 20:19:05 -04:00
Axionize 9fa0f773d5 Cache eyeHeights where possible 2024-09-22 17:41:54 -04:00
Axionize 88111e6f7e make getPossibleEyeHeights return most likely heights 2024-09-22 17:17:25 -04:00
Axionize 9a5c16fe6a Merge branch '2.0' into los-containers 2024-09-21 23:04:16 -04:00
Axionize 4efaf8d497 Fix Array matching error and block
The lower level ArraySupport.mismatch() function doesn't work on Java 8 and requires access modification in modern Java. Repalced with Arrays.equals()

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

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

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

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

Added new CollisionBox and set to NoCollisionBox for
- Potatoes
2024-08-31 21:05:24 -04:00
Axionize 3a145cb615 Fix banners 2024-08-31 20:03:34 -04:00
Axionize 837516ea86 Fix syntax error 2024-08-31 14:57:07 -04:00
Axionize 66228f59be Add lever hitboxes and fix banner hitboxes 2024-08-31 14:55:33 -04:00
Axionize 800c79a898 Document Hex vs Simple CollisionBox purpose 2024-08-31 14:55:16 -04:00
Axionize 2177b12bcf Print out target block when flagged - help find falses from constant flagging on non-standard blocks 2024-08-30 14:44:22 -04:00
Axionize 050c22ce27 Clean up 2024-08-29 17:02:29 -04:00
Axionize ded614f30f MVP commit 2024-08-29 17:02:28 -04:00
Axionize 88e439ebfd Improve temporary fix - delete unncessary code 2024-08-29 02:55:40 -04:00
AxionizeandManInMyVan a027355c7d Update src/main/java/ac/grim/grimac/events/packets/CheckManagerListener.java
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-08-29 02:53:48 -04:00
AxionizeandManInMyVan 8a351ec928 Update src/main/java/ac/grim/grimac/utils/collisions/datatypes/ComplexCollisionBox.java
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-08-29 02:52:53 -04:00
AxionizeandManInMyVan b2fa4974ef Update src/main/java/ac/grim/grimac/utils/collisions/HitboxData.java
Co-authored-by: ManInMyVan <113963219+ManInMyVan@users.noreply.github.com>
2024-08-29 02:52:29 -04:00
Axionize 9c2a034b43 Temporary Hacky Fix to demonstrate cause of fence false flag 2024-08-29 02:35:29 -04:00
Axionize 45ba746300 Comment cleanup 2024-08-26 01:22:07 -04:00
Axionize 483f317f83 Remove unneeded entry in punishments.yml 2024-08-26 01:16:26 -04:00
Axionize dee3268bce Make variables private 2024-08-26 01:14:30 -04:00
Axionize 2a88d3eef4 Account for player being inside of target block 2024-08-26 00:39:00 -04:00
Axionize 2898fed15a 1.9+ tick behind and 1.7 ticking behaviour compensation 2024-08-26 00:20:40 -04:00
Axionize d2721077c9 Remove print statements and cleanup comments 2024-08-26 00:13:54 -04:00
Axionize dd7bb81b46 Rework whitelist to use HashSet 2024-08-26 00:13:04 -04:00
Axionize 4515d21023 Seperate LOS-block-place checks from Sam's LOS reach checks 2024-08-26 00:01:14 -04:00
Axionize 3315e3c148 Revert "Merge reach wall hit check"
This reverts commit b5990080
2024-08-25 23:58:36 -04:00
Axionize 2b552680a7 Fix styling 2024-08-25 13:44:26 -04:00
Axionize f78c80f04d Temporarily comment out system.out.println 2024-08-25 03:18:17 -04:00
Axionize bc239a7994 Fix block whitelist 2024-08-25 03:15:00 -04:00
Axionize a508ec2279 0.03/0.0002 changes, cleanup code, add comments 2024-08-24 23:15:46 -04:00
Axionize cccecbacbc Remove RotationPlace, replacec with LineOfSightPlace 2024-08-24 23:09:06 -04:00
Axionize 177a8b0527 Add config options for check and enable it by adding to punishments 2024-08-24 23:08:41 -04:00
Axionize d869ff959f Add config options for check and enable it by adding to punishments 2024-08-24 23:05:04 -04:00
Axionize 772ba562e6 Rename check 2024-08-24 23:04:50 -04:00
Axionize 1786360d7c Clean up Code and add code for blockTypeWhitelist to BlockLOS checks for performance. 2024-08-24 22:24:23 -04:00
Axionize 328596f01f Expand hitbox of target block by 0.03/0.0002 to account for known MC bug 2024-08-24 19:18:43 -04:00
Axionize 6a13c9f822 Expand hitbox of target block by 0.03/0.0002 to account for known MC bug 2024-08-24 19:18:41 -04:00
Axionize 3c78a63719 Workable check 2024-08-24 19:18:41 -04:00
Axionize 8b645b75df Stash commits - loop alternate possible scenarios 2024-08-24 19:18:41 -04:00
Axionize ae3ea30c92 Stash commits - compensated everything 2024-08-24 19:18:40 -04:00
Axionize 01bd2c0c11 Stash commits - compensated world 2024-08-24 19:18:40 -04:00
Axionize e91721299a Container LOS initial commit 2024-08-24 19:18:39 -04:00
Axionize 4e08ec9fca Deobfuscate and document purpose of misunderstood code in traverseBlocks() 2024-08-24 19:18:39 -04:00
Axionize b599008040 Merge reach wall hit check
(cherry picked from commit 335c33b109)
2024-08-24 19:18:39 -04:00
SamB440 831f68b00c Check for hitting through walls 2024-06-29 18:11:05 +01:00
MachineBreaker bccda6cb9e Merge branch 'GrimAnticheat:2.0' into inventory-checks 2023-11-04 00:17:56 -04:00
MachineBreaker d0e77d2959 InventoryD: Exempt last block place use item if < 50L 2023-11-03 09:06:48 -04:00
MachineBreaker 441ff72e1e Merge branch 'GrimAnticheat:2.0' into inventory-checks 2023-11-03 09:05:45 -04:00
MachineBreaker aff131394e Don't handle InventoryD predictions if slowed down by a item. 2023-10-17 04:25:06 -04:00
MachineBreaker 7a6f758853 Merge branch 'GrimAnticheat:2.0' into inventory-checks 2023-10-17 04:24:24 -04:00
MachineBreaker eef8f538bc Merge branch 'GrimAnticheat:2.0' into inventory-checks 2023-09-25 19:55:46 -04:00
MachineBreaker 42d79ea01f Exempt teleports for InventoryD
Fixes a false positive
2023-09-18 17:42:08 -04:00
MachineBreaker df2c92555f Update fr.yml 2023-09-18 17:40:42 -04:00
MachineBreaker 380f6b5581 Update fr.yml 2023-09-18 17:40:12 -04:00
MachineBreaker fb6450fb72 Merge branch '2.0' into inventory-checks 2023-09-18 17:38:59 -04:00
Alejandro Martinez bb01c25605 Close inventory synchronously 2023-05-25 19:32:55 -04:00
Alejandro Martinez d812e7dd8b Don't setback for inventory checks 2023-05-21 13:20:28 -04:00
Alejandro Martinez 60f3a765f3 Fix section typo 2023-05-21 11:26:10 -04:00
Alejandro Martinez 31d6bd3664 Bump config version & add missing config upgrade 2023-05-21 11:24:49 -04:00
MachineBreaker 4c0018b04c Merge branch 'GrimAnticheat:2.0' into inventory-checks 2023-05-21 10:49:06 -04:00
MachineBreaker 4b0b3df9d2 Merge pull request #2 from UserNugget/inventory-checks-hotfix
Make transaction id "NONE" really impossible
2023-04-05 06:05:47 -06:00
UserNugget f699be1a65 Make transaction id "NONE" really impossible 2023-04-05 14:39:43 +03:00
MachineBreaker b6496b31f0 Merge pull request #1 from UserNugget/inventory-checks
InventoryWalk check
2023-04-05 05:17:56 -06:00
UserNugget 1e601c3de9 Remove pointless optimization 2023-04-05 10:57:39 +03:00
MachineBreaker 00b39fec38 Merge branch 'GrimAnticheat:2.0' into inventory-checks 2023-04-04 20:50:49 -06:00
UserNugget 9224ab8a76 Correct some comments 2023-04-05 05:03:29 +03:00
UserNugget 5307aebbf5 Some small fixes 2023-04-04 23:00:34 +03:00
UserNugget e7d8d613aa Most likely fixed false flags 2023-04-04 22:56:22 +03:00
UserNugget f469b08505 Close inventory to prevent infinity setbacks 2023-04-04 22:34:48 +03:00
UserNugget 60b2a07659 Initial InventoryD rewrite 2023-04-04 15:28:46 +03:00
MachineBreaker 8d6d448073 Merge branch 'GrimAnticheat:2.0' into inventory-checks 2023-04-02 17:17:22 -06:00
Alejandro Martinez 798156fedc Merge branch 'inventory-checks' of https://github.com/MachineBreaker/Grim into inventory-checks
 Conflicts:
	src/main/java/ac/grim/grimac/utils/latency/CompensatedInventory.java
2023-03-19 08:23:30 -06:00
MachineBreaker e18510fc6b Merge branch 'GrimAnticheat:2.0' into inventory-checks 2023-03-19 08:23:09 -06:00
Alejandro Martinez 0fe96bf32d Implement InventoryD (Clicking inventory while moving) 2023-03-19 08:22:04 -06:00
noobi 6d1f491b80 Fix InventoryC missing setback vls 2023-03-19 00:27:49 +01:00
noobi 07ac8b99f0 Implement InventoryC (Placing while inventory is open) 2023-03-19 00:16:05 +01:00
Alejandro Martinez 622c35e935 Implement InventoryB (Digging while inventory is open) 2023-03-18 17:03:00 -06:00
Alejandro Martinez c6adad5992 Make code more readable 2023-03-18 16:24:23 -06:00
Alejandro Martinez 211722a8a7 Properly exempt beacon inventory 2023-03-18 16:22:51 -06:00
Alejandro Martinez a0082a4ce7 Merge remote-tracking branch 'origin/inventory-checks' into inventory-checks 2023-03-18 16:17:42 -06:00
Alejandro Martinez a4eb540d23 Implement InventoryA (Attack while inventory is open) 2023-03-18 16:16:51 -06:00
MachineBreaker 2d427d6c47 Merge branch 'GrimAnticheat:2.0' into inventory-checks 2023-03-18 14:19:25 -06:00
Alejandro Martinez 0d00168aaf Initial work of Inventory Checks 2023-03-17 04:25:35 -06:00
169 changed files with 7329 additions and 875 deletions

No files matched your search

+78 -17
View File
@@ -15,24 +15,85 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
contents: write # Allows the workflow to create or update references (tags)
packages: write
actions: write
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: Build with Gradle
uses: gradle/actions/setup-gradle@v3
with:
arguments: build
- name: Upload a Build Artifact
uses: actions/upload-artifact@v4
with:
path: /home/runner/work/Grim/Grim/build/libs/**.jar
- name: Extract Version from build.gradle.kts
id: extract-version
run: |
# Extract the version from build.gradle.kts using grep and sed
VERSION=$(grep "^version\s*=" build.gradle.kts | sed 's/version\s*=\s*"\(.*\)"/\1/')
echo "VERSION: $VERSION"
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Build Lite Jar with Gradle
uses: gradle/actions/setup-gradle@v3
with:
arguments: build -PshadePE=false
- name: Upload Lite Artifact
uses: actions/upload-artifact@v4
with:
name: grimac-lite
path: ${{ github.workspace }}/build/libs/grimac-${{ env.VERSION }}-lite.jar
- name: Build Main Jar with Gradle
uses: gradle/actions/setup-gradle@v3
with:
arguments: build
- name: Upload Main Artifact
uses: actions/upload-artifact@v4
with:
name: grimac-main
path: ${{ github.workspace }}/build/libs/grimac-${{ env.VERSION }}.jar
- name: Generate build number
if: contains(fromJSON('["merge", "release", "main"]'), github.ref_name)
id: buildnumber
uses: onyxmueller/build-tag-number@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Publish to Modrinth
if: contains(fromJSON('["merge", "release", "main"]'), github.ref_name)
uses: Kir-Antipov/mc-publish@v3.3
with:
modrinth-id: ${{ vars.MODRINTH_ID }}
modrinth-featured: true
modrinth-unfeature-mode: subset
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
files: |
${{ github.workspace }}/build/libs/grimac-${{ env.VERSION }}.jar
${{ github.workspace }}/build/libs/grimac-${{ env.VERSION }}-lite.jar
name: Lightning Grim Anticheat ${{ env.VERSION }}-b${{ steps.buildnumber.outputs.build_number }}
version: ${{ env.VERSION }}-b${{ steps.buildnumber.outputs.build_number }}
version-type: release
loaders: |
bukkit
spigot
paper
folia
purpur
game-versions: |
>=1.7
retry-attempts: 2
retry-delay: 10000
fail-mode: fail
+1 -2
View File
@@ -11,8 +11,7 @@ This project is considered feature complete for the 2.0 (open-source) branch of
- *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).
- Java 8 is fully supported.
- Paper, Spigot, and Folia are currently supported.
- If you use Geyser, place Floodgate on the backend server so grim can exempt bedrock players. Grim cannot access the Floodgate API if it is on the proxy.
- If you use ViaVersion, it should be on the backend server as movement is highly dependent on client version.
+29 -6
View File
@@ -28,6 +28,8 @@ spotless {
group = "ac.grim.grimac"
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
@@ -36,7 +38,14 @@ val relocate: Boolean = project.findProperty("relocate")?.toString()?.toBoolean(
?: System.getenv("RELOCATE_JAR")?.toBoolean()
?: true
// Whether or not to shade PE into the jar, some servers may not want this if they use other plugins
// With PE; this prevents duplicate listening and reduces RAM usage by ~80-100 MB
val shadePE: Boolean = project.findProperty("shadePE")?.toString()?.toBoolean()
?: System.getenv("SHADE_PE")?.toBoolean()
?: true
repositories {
mavenLocal()
maven {
name = "papermc"
url = uri("https://repo.papermc.io/repository/maven-public/")
@@ -62,11 +71,17 @@ repositories {
dependencies {
compileOnly("io.papermc.paper:paper-api:1.20.6-R0.1-SNAPSHOT")
implementation("com.github.retrooper:packetevents-spigot:2.7.1-SNAPSHOT")
// PE dependency is now conditional
if (shadePE) {
implementation("com.github.retrooper:packetevents-spigot:2.7.1-SNAPSHOT")
} else {
compileOnly("com.github.retrooper:packetevents-spigot:2.7.1-SNAPSHOT")
}
implementation("co.aikar:acf-paper:0.5.1-SNAPSHOT")
implementation("club.minnced:discord-webhooks:0.8.0") // Newer versions include kotlin-stdlib, which leads to incompatibility with plugins that use Kotlin
implementation("it.unimi.dsi:fastutil:8.5.15")
implementation("github.scarsz:configuralize:1.4.0")
implementation("com.zaxxer:HikariCP:4.0.3")
// Used for local testing:
@@ -91,6 +106,10 @@ bukkit {
apiVersion = "1.13"
foliaSupported = true
if (!shadePE) {
depend = listOf("packetevents") + (depend ?: emptyList())
}
softDepend = listOf(
"ProtocolLib",
"ProtocolSupport",
@@ -174,7 +193,6 @@ tasks.build {
tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
options.release.set(17)
}
java {
@@ -182,6 +200,7 @@ java {
disableAutoTargetJvm()
}
publishing.publications.create<MavenPublication>("maven") {
artifact(tasks["shadowJar"])
}
@@ -192,10 +211,14 @@ tasks.shadowJar {
}
minimize()
archiveFileName.set("${project.name}-${project.version}.jar")
archiveFileName.set("${project.name}-${project.version}${if (shadePE) "" else "-lite"}.jar")
if (relocate) {
relocate("io.github.retrooper.packetevents", "ac.grim.grimac.shaded.io.github.retrooper.packetevents")
relocate("com.github.retrooper.packetevents", "ac.grim.grimac.shaded.com.github.retrooper.packetevents")
// Only relocate PE if we're shading it
if (shadePE) {
relocate("io.github.retrooper.packetevents", "ac.grim.grimac.shaded.io.github.retrooper.packetevents")
relocate("com.github.retrooper.packetevents", "ac.grim.grimac.shaded.com.github.retrooper.packetevents")
relocate("net.kyori", "ac.grim.grimac.shaded.kyori") // use PE's built-in adventure instead when not shading
}
relocate("co.aikar.commands", "ac.grim.grimac.shaded.acf")
relocate("co.aikar.locale", "ac.grim.grimac.shaded.locale")
relocate("club.minnced", "ac.grim.grimac.shaded.discord-webhooks")
@@ -204,12 +227,12 @@ tasks.shadowJar {
relocate("com.google.code.gson", "ac.grim.grimac.shaded.gson")
relocate("alexh", "ac.grim.grimac.shaded.maps")
relocate("it.unimi.dsi.fastutil", "ac.grim.grimac.shaded.fastutil")
relocate("net.kyori", "ac.grim.grimac.shaded.kyori")
relocate("okhttp3", "ac.grim.grimac.shaded.okhttp3")
relocate("okio", "ac.grim.grimac.shaded.okio")
relocate("org.yaml.snakeyaml", "ac.grim.grimac.shaded.snakeyaml")
relocate("org.json", "ac.grim.grimac.shaded.json")
relocate("org.intellij", "ac.grim.grimac.shaded.intellij")
relocate("org.jetbrains", "ac.grim.grimac.shaded.jetbrains")
relocate("com.zaxxer", "ac.grim.gimac.shaded.zaxxer")
}
}
+23 -3
View File
@@ -2,8 +2,11 @@ package ac.grim.grimac;
import ac.grim.grimac.manager.*;
import ac.grim.grimac.manager.config.BaseConfigManager;
import ac.grim.grimac.manager.violationdatabase.ViolationDatabaseManager;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.anticheat.PlayerDataManager;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
@Getter
@@ -17,22 +20,39 @@ public enum GrimAPI {
private final PlayerDataManager playerDataManager = new PlayerDataManager();
private final TickManager tickManager = new TickManager();
private final GrimExternalAPI externalAPI = new GrimExternalAPI(this);
private ViolationDatabaseManager violationDatabaseManager;
private InitManager initManager;
private JavaPlugin plugin;
private boolean criticalLoadFailure = false; // Track critical failures
public void load(final JavaPlugin plugin) {
this.plugin = plugin;
this.violationDatabaseManager = new ViolationDatabaseManager(plugin);
initManager = new InitManager();
initManager.load();
initManager.load(); // Load all initializers
}
public void start(final JavaPlugin plugin) {
this.plugin = plugin;
initManager.start();
if (initManager != null) {
initManager.start();
}
if (criticalLoadFailure) {
LogUtil.error("GrimAC encountered one or more critical error(s) during initialization.");
Bukkit.getPluginManager().disablePlugin(plugin);
}
}
public void stop(final JavaPlugin plugin) {
this.plugin = plugin;
initManager.stop();
if (initManager != null) {
initManager.stop();
}
}
// Method to signal a critical failure
public void signalCriticalFailure() {
criticalLoadFailure = true;
}
}
@@ -0,0 +1,23 @@
package ac.grim.grimac.checks.debug;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.player.GrimPlayer;
import org.bukkit.entity.Player;
public abstract class AbstractDebugHandler extends Check {
protected final GrimPlayer grimPlayer;
public AbstractDebugHandler(GrimPlayer grimPlayer) {
super(grimPlayer);
this.grimPlayer = grimPlayer;
}
public GrimPlayer getPlayer() {
return grimPlayer;
}
public abstract void toggleListener(Player player);
public abstract boolean toggleConsoleOutput();
}
@@ -0,0 +1,198 @@
package ac.grim.grimac.checks.debug;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.NoCollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.Pair;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPluginMessage;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Handles debug visualization of hitboxes and reach calculations for GrimAC.
* Sends debug data to clients through plugin messages that can be visualized by compatible clients.
*/
public class HitboxDebugHandler extends AbstractDebugHandler {
/**
* Set of players currently listening to hitbox debug data
*/
private final Set<Player> listeners = new CopyOnWriteArraySet<>(new HashSet<>());
/**
* Creates a new HitboxDebugHandler for the specified player
*
* @param grimPlayer The GrimAC player instance to debug
*/
public HitboxDebugHandler(GrimPlayer grimPlayer) {
super(grimPlayer);
}
/**
* Toggles whether a player receives hitbox debug visualization data.
* If the player is already listening, they will be removed. If not, they will be added.
*
* @param player The player to toggle debug visualization for
*/
@Override
public void toggleListener(Player player) {
if (!listeners.remove(player)) listeners.add(player);
}
@Override
public boolean toggleConsoleOutput() {
throw new UnsupportedOperationException();
}
/**
* Sends debug visualization data for reach calculations to all listening players.
* The data includes hitboxes, target entities, look vectors, and eye heights used in reach calculations.
*
* @param hitboxes Map of entity IDs to their collision boxes
* @param targetEntities Set of entity IDs that are considered targets
* @param lookVecsAndEyeHeights List of pairs containing look vectors and their corresponding eye heights
* @param basePos Base position before eye height adjustments
* @param isPrediction Whether these hitboxes are from a prediction calculation
*
* Packet Format (Version 1):
* - Byte: Version (0)
* - Byte: Global flags
* - Bit 0: isPrediction
* - Bits 1-7: Reserved
* - Double: Player reach/interact distance
* - Vector3d: Base position (3 doubles)
* - VarInt: Number of ray traces
* - For each ray trace:
* - Double: Eye height delta
* - Vector3d: Look vector (3 doubles)
* - VarInt: Number of hitboxes
* - For each hitbox:
* - VarInt: Entity ID
* - Byte: Flags
* - Bit 0: Is target entity
* - Bit 1: Is no collision
* - Bits 2-7: Reserved
* - If not NoCollisionBox:
* - Double: minX
* - Double: minY
* - Double: minZ
* - Double: maxX
* - Double: maxY
* - Double: maxZ
*/
public void sendHitboxData(Map<Integer, CollisionBox> hitboxes, Set<Integer> targetEntities,
List<Pair<Vector, Double>> lookVecsAndEyeHeights, Vector basePos,
boolean isPrediction, double reachDistance) {
if (!isEnabled()) return;
ByteBuf buffer = Unpooled.buffer();
try {
// Version Header
buffer.writeByte(1);
// Global Flags Header
// Pack boolean flags into a single byte
byte global_flags = 0;
global_flags |= (isPrediction ? 1 : 0); // Bit 0: are the hitboxes from a prediction?
// Bits 2-7 reserved for future use
buffer.writeByte(global_flags);
// Write reach distance
buffer.writeDouble(reachDistance);
// Write base position
writeVector(buffer, basePos);
// Write number of ray traces
ByteBufHelper.writeVarInt(buffer, lookVecsAndEyeHeights.size());
// Write all possible ray traces
for (Pair<Vector, Double> pair : lookVecsAndEyeHeights) {
Vector lookVec = pair.first();
double eyeHeight = pair.second();
// Write eye height delta and look vector
// we make them 3 meters shorter because all of the vectors passed into here are made 3 meters longer
// then they need to be so grim can report correct reach distance for too far away hits
buffer.writeDouble(eyeHeight);
writeVector(buffer, lookVec);
}
// Write number of hitboxes
ByteBufHelper.writeVarInt(buffer, hitboxes.size());
// Write hitbox data
for (Map.Entry<Integer, CollisionBox> entry : hitboxes.entrySet()) {
int entityId = entry.getKey();
CollisionBox box = entry.getValue();
// Write entity ID
ByteBufHelper.writeVarInt(buffer, entityId);
// Pack boolean flags into a single byte
byte flags = 0;
flags |= (targetEntities.contains(entityId) ? 1 : 0); // Bit 0: Is target
flags |= (box == NoCollisionBox.INSTANCE ? 2 : 0); // Bit 1: Is no collision
// Bits 2-7 reserved for future use
buffer.writeByte(flags);
// Write box coordinates if it's not a NoCollisionBox
if ((flags & 2) == 0) {
SimpleCollisionBox simpleCollisionBox = (SimpleCollisionBox) box;
buffer.writeDouble(simpleCollisionBox.minX);
buffer.writeDouble(simpleCollisionBox.minY);
buffer.writeDouble(simpleCollisionBox.minZ);
buffer.writeDouble(simpleCollisionBox.maxX);
buffer.writeDouble(simpleCollisionBox.maxY);
buffer.writeDouble(simpleCollisionBox.maxZ);
}
}
// Convert buffer to byte array
byte[] data = new byte[buffer.readableBytes()];
buffer.readBytes(data);
// Create and send packet
WrapperPlayServerPluginMessage packet = new WrapperPlayServerPluginMessage(
"grim:debug_hitbox",
data
);
// Send to all listeners
for (Player listener : listeners) {
if (listener != null) {
PacketEvents.getAPI().getPlayerManager().sendPacket(listener, packet);
}
}
} finally {
// Release buffer to prevent memory leaks
buffer.release();
}
}
public boolean isEnabled() {
return !listeners.isEmpty();
}
/**
* Helper method to write a Vector to the ByteBuf
* @param buffer The buffer to write to
* @param vector The vector to write
*/
private void writeVector(ByteBuf buffer, Vector vector) {
buffer.writeDouble(vector.getX());
buffer.writeDouble(vector.getY());
buffer.writeDouble(vector.getZ());
}
}
@@ -38,14 +38,31 @@ public class BadPacketsP extends Check implements PacketCheck {
int button = wrapper.getButton();
// 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;
};
boolean flag;
switch (clickType) {
case PICKUP:
case QUICK_MOVE:
case CLONE:
flag = button > 2 || button < 0;
break;
case SWAP:
flag = (button > 8 || button < 0) && button != 40;
break;
case THROW:
flag = button != 0 && button != 1;
break;
case QUICK_CRAFT:
flag = button == 3 || button == 7 || button > 10 || button < 0;
break;
case PICKUP_ALL:
flag = button != 0;
break;
case UNKNOWN:
flag = false;
break;
default:
throw new IllegalStateException("Impossible clickType; Compiler does not know this is unreachable!");
}
// Allowing this to false flag to debug and find issues faster
if (flag) {
@@ -48,17 +48,20 @@ public class BadPacketsX extends Check implements PostPredictionCheck {
}
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
switch (new WrapperPlayClientEntityAction(event).getAction()) {
case START_SNEAKING, STOP_SNEAKING -> {
WrapperPlayClientEntityAction wrapper = new WrapperPlayClientEntityAction(event);
switch (wrapper.getAction()) {
case START_SNEAKING:
case STOP_SNEAKING:
if (sneak) {
if (player.canSkipTicks() || flagAndAlert()) {
flags++;
}
}
sneak = true;
}
case START_SPRINTING, STOP_SPRINTING -> {
break;
case START_SPRINTING:
case STOP_SPRINTING:
if (player.inVehicle()) {
return;
}
@@ -68,9 +71,12 @@ public class BadPacketsX extends Check implements PostPredictionCheck {
flags++;
}
}
sprint = true;
}
break;
default:
// Handle other cases if necessary
break;
}
}
}
@@ -17,6 +17,7 @@ import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import java.util.Collections;
import java.util.Set;
// Based loosely off of Hawk BlockBreakSpeedSurvival
@@ -27,7 +28,7 @@ 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(StateTypes.TRIAL_SPAWNER);
private static final Set<StateType> EXEMPT_STATES = Collections.singleton(StateTypes.TRIAL_SPAWNER);
public FastBreak(GrimPlayer playerData) {
super(playerData);
@@ -44,15 +44,30 @@ public class PositionBreakA extends Check implements BlockBreakCheck {
// 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;
};
boolean flag;
switch (blockBreak.face) {
case NORTH:
flag = eyePositions.minZ > combined.minZ; // Z- face
break;
case SOUTH:
flag = eyePositions.maxZ < combined.maxZ; // Z+ face
break;
case EAST:
flag = eyePositions.maxX < combined.maxX; // X+ face
break;
case WEST:
flag = eyePositions.minX > combined.minX; // X- face
break;
case UP:
flag = eyePositions.maxY < combined.maxY; // Y+ face
break;
case DOWN:
flag = eyePositions.minY > combined.minY; // Y- face
break;
default:
flag = false;
break;
}
if (flag && flagAndAlert("action=" + blockBreak.action + ", face=" + blockBreak.face) && shouldModifyPackets()) {
blockBreak.cancel();
@@ -0,0 +1,13 @@
package ac.grim.grimac.checks.impl.combat;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
@CheckData(name = "HitboxBlock", configName = "HitboxBlock", setback = 20)
public class HitboxBlock extends Check implements PacketCheck {
public HitboxBlock(GrimPlayer player) {
super(player);
}
}
@@ -0,0 +1,13 @@
package ac.grim.grimac.checks.impl.combat;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
@CheckData(name = "HitboxEntity", configName = "HitboxEntity", setback = 30)
public class HitboxEntity extends Check implements PacketCheck {
public HitboxEntity(GrimPlayer player) {
super(player);
}
}
@@ -5,9 +5,9 @@ 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) {
@CheckData(name = "HitboxMiss", configName = "HitboxMiss", setback = 10)
public class HitboxMiss extends Check implements PacketCheck {
public HitboxMiss(GrimPlayer player) {
super(player);
}
}
@@ -18,10 +18,18 @@ package ac.grim.grimac.checks.impl.combat;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.debug.HitboxDebugHandler;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.NoCollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.BlockHitData;
import ac.grim.grimac.utils.data.EntityHitData;
import ac.grim.grimac.utils.data.HitData;
import ac.grim.grimac.utils.data.Pair;
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
import ac.grim.grimac.utils.nmsutil.BlockRayTrace;
import ac.grim.grimac.utils.data.packetentity.dragon.PacketEntityEnderDragonPart;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
@@ -31,11 +39,15 @@ import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3i;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@@ -47,13 +59,19 @@ public class Reach extends Check implements PacketCheck {
// Only one flag per reach attack, per entity, per tick.
// We store position because lastX isn't reliable on teleports.
private final Int2ObjectMap<Vector3d> playerAttackQueue = new Int2ObjectOpenHashMap<>();
// Used to prevent falses in the wall hit check
private final Set<Vector3i> blocksChangedThisTick = new HashSet<>();
public static final double extraSearchDistance = 3; // extra distance to raytrace beyond reach distance so we know far beyond the legit distance a cheater hit
private static final List<EntityType> blacklisted = Arrays.asList(
EntityTypes.BOAT,
EntityTypes.CHEST_BOAT,
EntityTypes.SHULKER);
private boolean ignoreNonPlayerTargets;
private boolean cancelImpossibleHits;
private double threshold;
public double reachThreshold;
private double cancelBuffer; // For the next 4 hits after using reach, we aggressively cancel reach
public Reach(GrimPlayer player) {
@@ -85,6 +103,10 @@ public class Reach extends Check implements PacketCheck {
return;
}
if (ignoreNonPlayerTargets && !entity.getType().equals(EntityTypes.PLAYER)) {
return;
}
// Dead entities cause false flags (https://github.com/GrimAnticheat/Grim/issues/546)
if (entity.isDead) return;
@@ -109,8 +131,9 @@ public class Reach extends Check implements PacketCheck {
}
// If the player set their look, or we know they have a new tick
final boolean isFlying = WrapperPlayClientPlayerFlying.isFlying(event.getPacketType());
if (isUpdate(event.getPacketType())) {
tickBetterReachCheckWithAngle();
tickBetterReachCheckWithAngle(isFlying);
}
}
@@ -132,8 +155,7 @@ public class Reach extends Check implements PacketCheck {
// Filter out what we assume to be cheats
if (cancelBuffer != 0) {
CheckResult result = checkReach(reachEntity, new Vector3d(player.x, player.y, player.z), true);
return result.isFlag(); // If they flagged
return checkReach(reachEntity, new Vector3d(player.x, player.y, player.z), true) != NONE; // If they flagged
} else {
SimpleCollisionBox targetBox = reachEntity.getPossibleCollisionBoxes();
if (reachEntity.getType() == EntityTypes.END_CRYSTAL) {
@@ -143,25 +165,37 @@ public class Reach extends Check implements PacketCheck {
}
}
private void tickBetterReachCheckWithAngle() {
private void tickBetterReachCheckWithAngle(boolean isFlying) {
for (Int2ObjectMap.Entry<Vector3d> attack : playerAttackQueue.int2ObjectEntrySet()) {
PacketEntity reachEntity = player.compensatedEntities.entityMap.get(attack.getIntKey());
if (reachEntity == null) continue;
CheckResult result = checkReach(reachEntity, attack.getValue(), false);
String added;
switch (result.type()) {
case REACH -> {
String added = reachEntity.getType() == EntityTypes.PLAYER ? "" : ", type=" + reachEntity.getType().getName().getKey();
case REACH:
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);
}
break;
case HITBOX:
added = reachEntity.getType() == EntityTypes.PLAYER ? "" : "type=" + reachEntity.getType().getName().getKey();
player.checkManager.getPacketCheck(HitboxMiss.class).flagAndAlert(result.verbose() + added);
break;
case BLOCK:
added = reachEntity.getType() == EntityTypes.PLAYER ? "" : "type=" + reachEntity.getType().getName().getKey();
player.checkManager.getPacketCheck(HitboxBlock.class).flagAndAlert(result.verbose() + added);
break;
case ENTITY:
added = reachEntity.getType() == EntityTypes.PLAYER ? "" : "type=" + reachEntity.getType().getName().getKey();
player.checkManager.getPacketCheck(HitboxEntity.class).flagAndAlert(result.verbose() + added);
break;
}
}
playerAttackQueue.clear();
// We can't use transactions for this because of this problem:
// transaction -> block changed applied -> 2nd transaction -> list cleared -> attack packet -> flying -> reach block hit checked, falses
if (isFlying) blocksChangedThisTick.clear();
}
@NotNull
@@ -178,7 +212,7 @@ public class Reach extends Check implements PacketCheck {
targetBox.expand(0.1f);
}
targetBox.expand(threshold);
targetBox.expand(reachThreshold);
// This is better than adding to the reach, as 0.03 can cause a player to miss their target
// Adds some more than 0.03 uncertainty in some cases, but a good trade off for simplicity
@@ -190,28 +224,17 @@ public class Reach extends Check implements PacketCheck {
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)));
// If we are a tick behind, we don't know their next look so don't bother doing this
if (!isPrediction) {
possibleLookDirs.add(ReachUtils.getLook(player, player.lastXRot, player.yRot));
// 1.9+ players could be a tick behind because we don't get skipped ticks
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
possibleLookDirs.add(ReachUtils.getLook(player, player.lastXRot, player.lastYRot));
}
// 1.7 players do not have any of these issues! They are always on the latest look vector
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
possibleLookDirs = Collections.singletonList(ReachUtils.getLook(player, player.xRot, player.yRot));
}
}
// will store all lookVecsAndEyeHeight pairs that landed a hit on the target entity
// We only need to check for blocking intersections for these
List<Pair<Vector, Double>> lookVecsAndEyeHeights = new ArrayList<>();
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 = maxReach + 3;
// We raytrace for > the player's reach distance so in the case a player is hacking
// We can return in the flag the distance of the reach hit instead of a generic "player failed reach check"
// +3 would be 3 + extraSearchDistance = 6, which is the pre-1.20.5 behaviour, preventing "Missed Hitbox"
final double distance = maxReach + extraSearchDistance;
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
final Vector[] possibleLookDirs = player.getPossibleLookVectors(isPrediction);
final Vector eyePos = new Vector(from.getX(), 0, from.getZ());
for (Vector lookVec : possibleLookDirs) {
for (double eye : possibleEyeHeights) {
@@ -227,16 +250,47 @@ public class Reach extends Check implements PacketCheck {
if (intercept != null) {
minDistance = Math.min(eyePos.distance(intercept), minDistance);
lookVecsAndEyeHeights.add(new Pair<>(lookVec, eye));
}
}
}
if (hitboxDebuggingEnabled())
sendHitboxDebugData(reachEntity, from, lookVecsAndEyeHeights, isPrediction);
HitData foundHitData = null;
// If the entity is within range of the player (we'll flag anyway if not, so no point checking blocks in this case)
// Ignore when could be hitting through a moving shulker, piston blocks. They are just too glitchy/uncertain to check.
if (minDistance <= distance - extraSearchDistance && !player.compensatedWorld.isNearHardEntity(player.boundingBox.copy().expand(4))) {
// we can optimize didRayTraceHit more to only rayTrace up to the maximize distance of all rays that hit to the target...
// I'm too lazy to do that and we don't need to optimize that much yet so...
final @Nullable Pair<Double, HitData> hitResult = didRayTraceHit(reachEntity, lookVecsAndEyeHeights, from);
HitData hitData = hitResult.second();
// If the returned hit result was NOT the target entity we flag the check
if (hitData instanceof EntityHitData &&
player.compensatedEntities.getPacketEntityID(((EntityHitData) hitData).getEntity()) != player.compensatedEntities.getPacketEntityID(reachEntity)) {
minDistance = Double.MIN_VALUE;
foundHitData = hitData;
// until I fix block modeling exempt any blocks changed this tick
} else if (hitData instanceof BlockHitData && !blocksChangedThisTick.contains(((BlockHitData) hitData).getPosition())) {
minDistance = Double.MIN_VALUE;
foundHitData = hitData;
}
}
// if the entity is not exempt and the entity is alive
if ((!blacklisted.contains(reachEntity.getType()) && reachEntity.isLivingEntity()) || reachEntity.getType() == EntityTypes.END_CRYSTAL) {
if (minDistance == Double.MAX_VALUE) {
if (minDistance == Double.MIN_VALUE && foundHitData != null) {
cancelBuffer = 1;
if (foundHitData instanceof BlockHitData) {
return new CheckResult(ResultType.BLOCK, "Hit block=" + ((BlockHitData) foundHitData).getState().getType().getName() + " ");
} else { // entity hit data
return new CheckResult(ResultType.ENTITY, "Hit entity=" + ((EntityHitData) foundHitData).getEntity().getType().getName() + " ");
}
} else if (minDistance == Double.MAX_VALUE) {
cancelBuffer = 1;
return new CheckResult(ResultType.HITBOX, "");
} else if (minDistance > maxReach) {
} else if (minDistance > player.compensatedEntities.self.getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE)) {
cancelBuffer = 1;
return new CheckResult(ResultType.REACH, String.format("%.5f", minDistance) + " blocks");
} else {
@@ -249,19 +303,138 @@ public class Reach extends Check implements PacketCheck {
private static final CheckResult NONE = new CheckResult(ResultType.NONE, "");
private record CheckResult(ResultType type, String verbose) {
private static class CheckResult {
private final ResultType type;
private final String verbose;
public CheckResult(ResultType type, String verbose) {
this.type = type;
this.verbose = verbose;
}
public ResultType type() {
return type;
}
public String verbose() {
return verbose;
}
public boolean isFlag() {
return type != ResultType.NONE;
}
}
private enum ResultType {
REACH, HITBOX, NONE
REACH, HITBOX, BLOCK, ENTITY, NONE
}
public void handleBlockChange(Vector3i vector3i, WrappedBlockState state) {
if (blocksChangedThisTick.size() >= 40) return; // Don't let players freeze movement packets to grow this
// Only do this for nearby blocks
if (new Vector(vector3i.x, vector3i.y, vector3i.z).distanceSquared(new Vector(player.x, player.y, player.z)) > 6) return;
// Only do this if the state really had any world impact
if (state.equals(player.compensatedWorld.getBlock(vector3i))) return;
blocksChangedThisTick.add(vector3i);
}
// Checks if it was possible to hit a target entity
// TODO refactor to return list of rays and why each of them didn't hit instead of closest obstruction
// NOTE: It should be impossible for the returned Pair to be null
// because all of the possibleLookVecsAndEyeHeights passed in should be ones that hit the target entity
// in previous parts of this check when we didn't check for any obstructions like blocks/entities
private @NotNull Pair<@NotNull Double, @NotNull HitData> didRayTraceHit(PacketEntity targetEntity,
List<Pair<Vector, Double>> possibleLookVecsAndEyeHeights,
Vector3d from) {
HitData firstObstruction = null;
double firstObstructionDistanceSq = 0;
// Check every possible look direction and every possible eye height
for (Pair<Vector, Double> vectorDoublePair : possibleLookVecsAndEyeHeights) {
Vector lookVec = vectorDoublePair.first();
double eye = vectorDoublePair.second();
Vector eyes = new Vector(from.getX(), from.getY() + eye, from.getZ());
// this function is completely 0.03 aware
final HitData hitResult = BlockRayTrace.getNearestHitResult(player, targetEntity, eyes, lookVec);
// If we hit the target entity, it's a valid hit
if (hitResult instanceof EntityHitData && ((EntityHitData) hitResult).getEntity().equals(targetEntity)) {
double distanceSquared = eyes.distanceSquared(hitResult.getBlockHitLocation());
return new Pair<>(distanceSquared, hitResult); // Legitimate hit
} else if (hitResult != null && firstObstruction == null) {
// Store the first obstruction only
firstObstruction = hitResult;
firstObstructionDistanceSq = eyes.distanceSquared(hitResult.getBlockHitLocation());
}
}
// Return the first obstruction if no valid hit found
// Since we sort eye heights by likeniness, we should in effect return the most likely (first) obstruction
assert firstObstruction != null;
return new Pair<>(firstObstructionDistanceSq, firstObstruction);
}
private boolean hitboxDebuggingEnabled() {
return player.checkManager.getCheck(HitboxDebugHandler.class).isEnabled();
}
private void sendHitboxDebugData(PacketEntity reachEntity, Vector3d from, List<Pair<Vector, Double>> lookVecsAndEyeHeights, boolean isPrediction) {
Map<Integer, CollisionBox> hitboxes = new HashMap<>();
for (Int2ObjectMap.Entry<PacketEntity> entry : player.compensatedEntities.entityMap.int2ObjectEntrySet()) {
PacketEntity entity = entry.getValue();
if (!entity.canHit()) continue;
CollisionBox box;
if (entity.equals(reachEntity)) {
// Target entity gets expanded hitbox
box = entity.getPossibleCollisionBoxes();
SimpleCollisionBox sBox = (SimpleCollisionBox) box;
sBox.expand(player.checkManager.getPacketCheck(Reach.class).reachThreshold);
// Add movement threshold uncertainty for 1.9+ or non-position updates
if (!player.packetStateData.didLastLastMovementIncludePosition
|| player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
sBox.expand(player.getMovementThreshold());
}
} else {
// Non-target entities
box = entity.getMinimumPossibleCollisionBoxes();
if (box instanceof NoCollisionBox) {
hitboxes.put(entry.getIntKey(), NoCollisionBox.INSTANCE);
continue;
} else if (box instanceof SimpleCollisionBox) {
SimpleCollisionBox sBox = (SimpleCollisionBox) box;
sBox.expand(-player.checkManager.getPacketCheck(Reach.class).reachThreshold);
// Shrink non-target entities by movement threshold when applicable
if (!player.packetStateData.didLastLastMovementIncludePosition
|| player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
sBox.expand(-player.getMovementThreshold());
}
}
}
// Add 1.8 and below extra hitbox size
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_9)
&& box instanceof SimpleCollisionBox) {
((SimpleCollisionBox) box).expand(0.1f);
}
hitboxes.put(entry.getIntKey(), box);
}
player.checkManager.getCheck(HitboxDebugHandler.class).sendHitboxData(hitboxes,
Collections.singleton(player.compensatedEntities.getPacketEntityID(reachEntity)),
lookVecsAndEyeHeights,
new Vector(from.getX(), from.getY(), from.getZ()),
isPrediction, player.compensatedEntities.self.getAttributeValue(Attributes.ENTITY_INTERACTION_RANGE));
}
@Override
public void onReload(ConfigManager config) {
this.ignoreNonPlayerTargets = config.getBooleanElse("Reach.ignore-non-player-targets", false);
this.cancelImpossibleHits = config.getBooleanElse("Reach.block-impossible-hits", true);
this.threshold = config.getDoubleElse("Reach.threshold", 0.0005);
this.reachThreshold = config.getDoubleElse("Reach.threshold", 0.0005);
}
}
@@ -38,7 +38,6 @@ public class CrashH extends Check implements PacketCheck {
player.onPacketCancel();
}
flagAndAlert("(invalid) length=" + length);
return;
}
}
}
@@ -34,7 +34,8 @@ public class ExploitC extends Check implements PacketCheck {
if (event.getPacketType() == PacketType.Play.Client.CHAT_COMMAND_UNSIGNED) {
String command = "/" + new WrapperPlayClientChatCommandUnsigned(event).getCommand();
if (!command.stripTrailing().equals(command)) {
String strippedCommand = command.replaceAll("\\s+$", ""); // Remove trailing whitespace
if (!strippedCommand.equals(command)) {
if (flagAndAlert("command=" + command)) {
event.setCancelled(true);
player.onPacketCancel();
@@ -0,0 +1,42 @@
package ac.grim.grimac.checks.impl.inventory;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.InventoryCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity.InteractAction;
@CheckData(name = "InventoryA", setback = 3, description = "Attacked an entity while inventory is open")
public class InventoryA extends InventoryCheck {
public InventoryA(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
super.onPacketReceive(event);
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
WrapperPlayClientInteractEntity wrapper = new WrapperPlayClientInteractEntity(event);
if (wrapper.getAction() != InteractAction.ATTACK) return;
// Is not possible to attack while the inventory is open.
if (player.hasInventoryOpen) {
if (flagAndAlert()) {
// Cancel the packet
if (shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
if (!isNoSetbackPermission())
closeInventory();
}
} else {
reward();
}
}
}
}
@@ -0,0 +1,35 @@
package ac.grim.grimac.checks.impl.inventory;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.InventoryCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
@CheckData(name = "InventoryB", setback = 3, description = "Started digging blocks while inventory is open")
public class InventoryB extends InventoryCheck {
public InventoryB(GrimPlayer player) {
super(player);
}
public void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging wrapper) {
if (wrapper.getAction() != DiggingAction.START_DIGGING) return;
// Is not possible to start digging a block while the inventory is open.
if (player.hasInventoryOpen) {
if (flagAndAlert()) {
// Cancel the packet
if (shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
if (!isNoSetbackPermission()) {
closeInventory();
}
}
} else {
reward();
}
}
}
@@ -0,0 +1,30 @@
package ac.grim.grimac.checks.impl.inventory;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.InventoryCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
@CheckData(name = "InventoryC", setback = 3, description = "Placed a block while inventory is open")
public class InventoryC extends InventoryCheck {
public InventoryC(GrimPlayer player) {
super(player);
}
public void onBlockPlace(final BlockPlace place) {
// It is not possible to place a block while the inventory is open
if (player.hasInventoryOpen) {
if (flagAndAlert()) {
if (shouldModifyPackets()) {
place.resync();
}
if (!isNoSetbackPermission()) {
closeInventory();
}
}
} else {
reward();
}
}
}
@@ -0,0 +1,85 @@
package ac.grim.grimac.checks.impl.inventory;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.InventoryCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.data.VectorData.MoveVectorData;
import ac.grim.grimac.utils.data.VehicleData;
import java.util.StringJoiner;
@CheckData(name = "InventoryD", setback = 1, decay = 0.25)
public class InventoryD extends InventoryCheck {
private int horseJumpVerbose;
public InventoryD(GrimPlayer player) {
super(player);
}
@Override
public void onPredictionComplete(final PredictionComplete predictionComplete) {
if (!predictionComplete.isChecked() ||
predictionComplete.getData().isTeleport() ||
player.getSetbackTeleportUtil().blockOffsets ||
player.packetStateData.lastPacketWasTeleport ||
player.packetStateData.isSlowedByUsingItem() ||
System.currentTimeMillis() - player.lastBlockPlaceUseItem < 50L) {
return;
}
if (player.hasInventoryOpen) {
boolean inVehicle = player.inVehicle();
boolean isJumping, isMoving;
if (inVehicle) {
VehicleData vehicle = player.vehicleData;
// Will flag once if player open anything with pressed space bar
isJumping = vehicle.nextHorseJump > 0 && horseJumpVerbose++ >= 1;
isMoving = vehicle.nextVehicleForward != 0 || vehicle.nextVehicleHorizontal != 0;
} else {
MoveVectorData move = findMovement(player.predictedVelocity);
isJumping = player.predictedVelocity.isJump();
isMoving = move != null && (move.x != 0 || move.z != 0);
}
if (!isMoving && !isJumping) {
reward();
return;
}
if (flag()) {
if (!isNoSetbackPermission())
closeInventory();
StringJoiner joiner = new StringJoiner(" ");
if (isMoving) joiner.add("moving");
if (isJumping) joiner.add("jumping");
if (inVehicle) joiner.add("inVehicle");
alert(joiner.toString());
}
} else {
horseJumpVerbose = 0;
}
}
private MoveVectorData findMovement(VectorData vectorData) {
if (vectorData instanceof MoveVectorData) {
return (MoveVectorData) vectorData;
}
while (vectorData != null) {
vectorData = vectorData.lastVector;
if (vectorData instanceof MoveVectorData) {
return (MoveVectorData) vectorData;
}
}
return null;
}
}
@@ -0,0 +1,50 @@
package ac.grim.grimac.checks.impl.inventory;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.InventoryCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
@CheckData(name = "InventoryE", setback = 3, description = "Sent a held item change packet while inventory is open")
public class InventoryE extends InventoryCheck {
private long lastTransaction = Long.MAX_VALUE; // Impossible transaction ID
public InventoryE(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
super.onPacketReceive(event);
if (event.getPacketType() == PacketType.Play.Client.HELD_ITEM_CHANGE) {
// It is not possible to change hotbar slots with held item change while the inventory is open
// A container click packet would be sent instead
if (player.hasInventoryOpen) {
if (this.lastTransaction < player.lastTransactionReceived.get()
&& flagAndAlert()) {
// Cancel the packet
if (shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
player.getInventory().needResend = true;
}
if (!isNoSetbackPermission()) {
closeInventory();
}
}
} else {
reward();
}
}
}
@Override
public void onPacketSend(PacketSendEvent event) {
if (event.getPacketType() == PacketType.Play.Server.HELD_ITEM_CHANGE) {
this.lastTransaction = player.lastTransactionSent.get();
}
}
}
@@ -0,0 +1,46 @@
package ac.grim.grimac.checks.impl.inventory;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.InventoryCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.inventory.InventoryDesyncStatus;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
@CheckData(name = "InventoryF", setback = 3, description = "Sent a click window packet without a open inventory", experimental = true)
public class InventoryF extends InventoryCheck {
public InventoryF(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
// Exempt on 1.9+ server version due to the Via hack done in PacketPlayerWindow, the exemption can be deleted
// once we are ahead of ViaVersion
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)
|| player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) return;
super.onPacketReceive(event);
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
if (!player.hasInventoryOpen && player.inventoryDesyncStatus == InventoryDesyncStatus.NOT_DESYNCED) {
if (flagAndAlert()) {
// Cancel the packet
if (shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
if (!isNoSetbackPermission()) {
closeInventory();
}
}
} else {
reward();
}
}
}
}
@@ -0,0 +1,40 @@
package ac.grim.grimac.checks.impl.inventory;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.InventoryCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
@CheckData(name = "InventoryG", setback = 3, description = "Sent a entity action packet while inventory is open", experimental = true)
public class InventoryG extends InventoryCheck {
public InventoryG(GrimPlayer player) {
super(player);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (player.packetStateData.lastPacketWasTeleport) return;
super.onPacketReceive(event);
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
WrapperPlayClientEntityAction wrapper = new WrapperPlayClientEntityAction(event);
WrapperPlayClientEntityAction.Action action = wrapper.getAction();
if (action == WrapperPlayClientEntityAction.Action.STOP_SNEAKING
|| action == WrapperPlayClientEntityAction.Action.STOP_SPRINTING) {
return;
}
if (player.hasInventoryOpen) {
if (flagAndAlert() && !isNoSetbackPermission()) {
closeInventory();
}
} else {
reward();
}
}
}
}
@@ -0,0 +1,52 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClickWindow;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClickWindow.WindowClickType;
@CheckData(name = "PacketOrderA", experimental = true)
public class PacketOrderA extends Check implements PostPredictionCheck {
public PacketOrderA(final GrimPlayer player) {
super(player);
}
private int invalid;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
final WindowClickType clickType = new WrapperPlayClientClickWindow(event).getWindowClickType();
if ((clickType == WindowClickType.PICKUP || clickType == WindowClickType.PICKUP_ALL) && player.packetOrderProcessor.isQuickMoveClicking()
|| clickType == WindowClickType.QUICK_MOVE && player.packetOrderProcessor.isPickUpClicking()) {
if (!player.canSkipTicks()) {
if (flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
invalid++;
}
}
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (; invalid >= 1; invalid--) {
flagAndAlert();
}
}
invalid = 0;
}
}
@@ -1,4 +1,4 @@
package ac.grim.grimac.checks.impl.badpackets;
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
@@ -9,25 +9,33 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
@CheckData(name = "BadPacketsM")
public class BadPacketsM extends Check implements PacketCheck {
public BadPacketsM(final GrimPlayer player) {
@CheckData(name = "PacketOrderC")
public class PacketOrderC extends Check implements PacketCheck {
public PacketOrderC(final GrimPlayer player) {
super(player);
}
// 1.7 players do not send INTERACT_AT, so we cannot check them
private final boolean exempt = player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10);
private boolean sentInteractAt = false;
private int requiredEntity;
private InteractionHand requiredHand;
private boolean requiredSneaking;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY && !exempt) {
if (exempt) {
return;
}
final WrapperPlayClientInteractEntity wrapper = new WrapperPlayClientInteractEntity(event);
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
final WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
final PacketEntity entity = player.compensatedEntities.entityMap.get(wrapper.getEntityId());
final PacketEntity entity = player.compensatedEntities.entityMap.get(packet.getEntityId());
// For armor stands, vanilla clients send:
// - when renaming the armor stand or in spectator mode: INTERACT_AT + INTERACT
@@ -35,27 +43,49 @@ public class BadPacketsM extends Check implements PacketCheck {
// Just exempt armor stands to be safe
if (entity != null && entity.getType() == EntityTypes.ARMOR_STAND) return;
switch (wrapper.getAction()) {
final boolean sneaking = packet.isSneaking().orElse(false);
switch (packet.getAction()) {
// INTERACT_AT then INTERACT
case INTERACT:
if (!sentInteractAt) {
if (flagAndAlert("Missed Interact-At") && shouldModifyPackets()) {
if (flagAndAlert("Skipped Interact-At") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else if (packet.getEntityId() != requiredEntity || packet.getHand() != requiredHand || sneaking != requiredSneaking) {
String verbose = "requiredEntity=" + requiredEntity + ", entity=" + packet.getEntityId()
+ ", requiredHand=" + requiredHand + ", hand=" + packet.getHand()
+ ", requiredSneaking=" + requiredSneaking + ", sneaking=" + sneaking;
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
sentInteractAt = false;
break;
case INTERACT_AT:
if (sentInteractAt) {
if (flagAndAlert("Missed Interact") && shouldModifyPackets()) {
if (flagAndAlert("Skipped Interact") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
requiredHand = packet.getHand();
requiredEntity = packet.getEntityId();
requiredSneaking = sneaking;
sentInteractAt = true;
break;
}
}
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
if (sentInteractAt) {
sentInteractAt = false;
flagAndAlert("Skipped Interact (Tick)");
}
}
}
}
@@ -0,0 +1,13 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
@CheckData(name = "PacketOrderD")
public class PacketOrderD extends Check implements PacketCheck {
public PacketOrderD(GrimPlayer player) {
super(player);
}
}
@@ -0,0 +1,76 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import java.util.ArrayDeque;
@CheckData(name = "PacketOrderE", experimental = true)
public class PacketOrderE extends Check implements PostPredictionCheck {
public PacketOrderE(final GrimPlayer player) {
super(player);
}
private final ArrayDeque<String> flags = new ArrayDeque<>();
private boolean setback;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.HELD_ITEM_CHANGE) {
if (player.packetOrderProcessor.isAttacking()
|| player.packetOrderProcessor.isRightClicking()
|| player.packetOrderProcessor.isOpeningInventory()
|| player.packetOrderProcessor.isReleasing()
|| player.packetOrderProcessor.isSneaking()
|| player.packetOrderProcessor.isSprinting()
|| player.packetOrderProcessor.isLeavingBed()
|| player.packetOrderProcessor.isStartingToGlide()
|| player.packetOrderProcessor.isJumpingWithMount()
) {
String verbose = "attacking=" + player.packetOrderProcessor.isAttacking()
+ ", rightClicking=" + player.packetOrderProcessor.isRightClicking()
+ ", openingInventory=" + player.packetOrderProcessor.isOpeningInventory()
+ ", releasing=" + player.packetOrderProcessor.isReleasing()
+ ", sneaking=" + player.packetOrderProcessor.isSneaking()
+ ", sprinting=" + player.packetOrderProcessor.isSprinting()
+ ", bed=" + player.packetOrderProcessor.isLeavingBed()
+ ", sprinting=" + player.packetOrderProcessor.isSprinting()
+ ", gliding=" + player.packetOrderProcessor.isStartingToGlide()
+ ", mountJumping=" + player.packetOrderProcessor.isJumpingWithMount();
if (player.canSkipTicks() && flags.add(verbose) || flagAndAlert(verbose)) {
if (player.packetOrderProcessor.isUsing()) {
setback = true;
}
}
}
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) {
if (setback) {
setback = false;
setbackIfAboveSetbackVL();
}
return;
}
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
if (flagAndAlert(verbose) && setback) {
setback = false;
setbackIfAboveSetbackVL();
}
}
}
setback = false;
flags.clear();
}
}
@@ -0,0 +1,69 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClientStatus;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
import java.util.ArrayDeque;
@CheckData(name = "PacketOrderF", experimental = true)
public class PacketOrderF extends Check implements PostPredictionCheck {
public PacketOrderF(GrimPlayer player) {
super(player);
}
private final ArrayDeque<String> flags = new ArrayDeque<>();
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY
|| event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT
|| event.getPacketType() == PacketType.Play.Client.USE_ITEM
|| event.getPacketType() == PacketType.Play.Client.PICK_ITEM
|| event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING
|| (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS
&& new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT)
) if (player.packetOrderProcessor.isSprinting() || player.packetOrderProcessor.isSneaking()) {
String verbose = "action=" + (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY ? "interact"
: event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT ? "place"
: event.getPacketType() == PacketType.Play.Client.USE_ITEM ? "use"
: event.getPacketType() == PacketType.Play.Client.PICK_ITEM ? "pick"
: event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING ? "dig"
: "openInventory")
+ ", sprinting=" + player.packetOrderProcessor.isSprinting()
+ ", sneaking=" + player.packetOrderProcessor.isSneaking();
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING
&& new WrapperPlayClientPlayerDigging(event).getAction() == DiggingAction.RELEASE_USE_ITEM
) return; // don't cause a noslow
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add(verbose);
}
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
}
flags.clear();
}
}
@@ -0,0 +1,74 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClientStatus;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
import java.util.ArrayDeque;
@CheckData(name = "PacketOrderG", experimental = true)
public class PacketOrderG extends Check implements PostPredictionCheck {
public PacketOrderG(GrimPlayer player) {
super(player);
}
private final ArrayDeque<String> flags = new ArrayDeque<>();
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING || (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS
&& new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT)) {
DiggingAction action = null;
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
action = new WrapperPlayClientPlayerDigging(event).getAction();
if (action == DiggingAction.RELEASE_USE_ITEM
|| action == DiggingAction.START_DIGGING
|| action == DiggingAction.CANCELLED_DIGGING
|| action == DiggingAction.FINISHED_DIGGING
) return;
}
if (player.packetOrderProcessor.isAttacking()
|| player.packetOrderProcessor.isReleasing()
|| player.packetOrderProcessor.isRightClicking()
|| player.packetOrderProcessor.isPicking()
|| player.packetOrderProcessor.isDigging()
) {
String verbose = "action=" + (action == null ? "openInventory" : action == DiggingAction.SWAP_ITEM_WITH_OFFHAND ? "swap" : "drop")
+ ", attacking=" + player.packetOrderProcessor.isAttacking()
+ ", releasing=" + player.packetOrderProcessor.isReleasing()
+ ", rightClicking=" + player.packetOrderProcessor.isRightClicking()
+ ", picking=" + player.packetOrderProcessor.isPicking()
+ ", digging=" + player.packetOrderProcessor.isDigging();
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add(verbose);
}
}
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
}
flags.clear();
}
}
@@ -0,0 +1,62 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientEntityAction;
@CheckData(name = "PacketOrderH", experimental = true)
public class PacketOrderH extends Check implements PostPredictionCheck {
public PacketOrderH(final GrimPlayer player) {
super(player);
}
private int invalid;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.ENTITY_ACTION) {
switch (new WrapperPlayClientEntityAction(event).getAction()) {
case START_SPRINTING:
case STOP_SPRINTING:
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_21_2) && player.packetOrderProcessor.isSneaking()) {
if (!player.canSkipTicks()) {
flagAndAlert();
} else {
invalid++;
}
}
break;
case START_SNEAKING:
case STOP_SNEAKING:
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_21_2) && player.packetOrderProcessor.isSprinting()) {
if (!player.canSkipTicks()) {
flagAndAlert();
} else {
invalid++;
}
}
break;
}
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (; invalid >= 1; invalid--) {
flagAndAlert();
}
}
invalid = 0;
}
}
@@ -0,0 +1,142 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import ac.grim.grimac.utils.nmsutil.BlockBreakSpeed;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
import java.util.ArrayDeque;
@CheckData(name = "PacketOrderI", experimental = true)
public class PacketOrderI extends Check implements PostPredictionCheck {
public PacketOrderI(final GrimPlayer player) {
super(player);
}
private boolean exemptPlacingWhileDigging;
private boolean setback;
private boolean digging; // for placing
private final ArrayDeque<String> flags = new ArrayDeque<>();
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
if (new WrapperPlayClientInteractEntity(event).getAction() == WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
if (player.packetOrderProcessor.isRightClicking() || player.packetOrderProcessor.isPicking() || player.packetOrderProcessor.isReleasing() || player.packetOrderProcessor.isDigging()) {
String verbose = "type=attack, rightClicking=" + player.packetOrderProcessor.isRightClicking()
+ ", picking=" + player.packetOrderProcessor.isPicking()
+ ", releasing=" + player.packetOrderProcessor.isReleasing()
+ ", digging=" + player.packetOrderProcessor.isDigging();
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add(verbose);
}
}
} else if (player.packetOrderProcessor.isReleasing() || player.packetOrderProcessor.isDigging()) {
String verbose = "type=interact, releasing=" + player.packetOrderProcessor.isReleasing() + ", digging=" + player.packetOrderProcessor.isDigging();
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add(verbose);
}
}
}
if (event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT || event.getPacketType() == PacketType.Play.Client.USE_ITEM) {
if (player.packetOrderProcessor.isReleasing() || digging) {
String verbose = "type=place/use, releasing=" + player.packetOrderProcessor.isReleasing() + ", digging=" + digging;
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add(verbose);
}
}
}
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
switch (packet.getAction()) {
case RELEASE_USE_ITEM:
if (player.packetOrderProcessor.isAttacking() || player.packetOrderProcessor.isRightClicking() || player.packetOrderProcessor.isPicking() || player.packetOrderProcessor.isDigging()) {
String verbose = "type=release, attacking=" + player.packetOrderProcessor.isAttacking()
+ ", rightClicking=" + player.packetOrderProcessor.isRightClicking()
+ ", picking=" + player.packetOrderProcessor.isPicking()
+ ", digging=" + player.packetOrderProcessor.isDigging();
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose)) {
setback = true;
}
} else {
flags.add(verbose);
setback = true;
}
}
break;
case START_DIGGING:
double damage = BlockBreakSpeed.getBlockDamage(player, packet.getBlockPosition());
if (damage >= 1 || damage <= 0 && player.gamemode == GameMode.CREATIVE) {
return;
}
case CANCELLED_DIGGING:
case FINISHED_DIGGING:
if (exemptPlacingWhileDigging || player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_7_10)) {
return;
}
digging = true;
}
}
if (isTickPacket(event.getPacketType())) {
digging = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) {
if (setback) {
setbackIfAboveSetbackVL();
setback = false;
}
return;
}
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
if (flagAndAlert(verbose) && setback) {
setbackIfAboveSetbackVL();
setback = false;
}
}
}
flags.clear();
setback = false;
}
@Override
public void onReload(ConfigManager config) {
exemptPlacingWhileDigging = config.getBooleanElse(getConfigName() + ".exempt-placing-while-digging", false);
}
}
@@ -0,0 +1,47 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
@CheckData(name = "PacketOrderJ", experimental = true)
public class PacketOrderJ extends Check implements PostPredictionCheck {
public PacketOrderJ(final GrimPlayer player) {
super(player);
}
private int invalid;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT || event.getPacketType() == PacketType.Play.Client.USE_ITEM) {
if (player.packetOrderProcessor.isAttacking() && !player.packetOrderProcessor.isInteracting()) {
if (!player.canSkipTicks()) {
if (flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
invalid++;
}
}
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (; invalid >= 1; invalid--) {
flagAndAlert();
}
}
invalid = 0;
}
}
@@ -0,0 +1,64 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClientStatus;
import java.util.ArrayDeque;
@CheckData(name = "PacketOrderK", experimental = true)
public class PacketOrderK extends Check implements PostPredictionCheck {
public PacketOrderK(final GrimPlayer player) {
super(player);
}
private final ArrayDeque<String> flags = new ArrayDeque<>();
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS) {
if (new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT) {
if (player.packetOrderProcessor.isClickingInInventory() || player.packetOrderProcessor.isClosingInventory()) {
String verbose = "open, clicking=" + player.packetOrderProcessor.isClickingInInventory() + ", closing=" + player.packetOrderProcessor.isClosingInventory();
if (!player.canSkipTicks()) {
flagAndAlert(verbose);
} else {
flags.add(verbose);
}
}
}
}
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW || event.getPacketType() == PacketType.Play.Client.CLOSE_WINDOW) {
if (player.packetOrderProcessor.isOpeningInventory()) {
String verbose = event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW ? "click" : "close";
if (!player.canSkipTicks()) {
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add(verbose);
}
}
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (String verbose : flags) {
flagAndAlert(verbose);
}
}
flags.clear();
}
}
@@ -0,0 +1,69 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.DiggingAction;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClientStatus;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerDigging;
import java.util.ArrayDeque;
@CheckData(name = "PacketOrderL", experimental = true)
public class PacketOrderL extends Check implements PostPredictionCheck {
public PacketOrderL(final GrimPlayer player) {
super(player);
}
private final ArrayDeque<String> flags = new ArrayDeque<>();
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS) {
if (new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT) {
if (player.packetOrderProcessor.isDropping()) {
if (!player.canSkipTicks()) {
if (flagAndAlert("inventory") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add("inventory");
}
}
}
}
if (event.getPacketType() == PacketType.Play.Client.PLAYER_DIGGING) {
if (new WrapperPlayClientPlayerDigging(event).getAction() == DiggingAction.SWAP_ITEM_WITH_OFFHAND) {
if (player.packetOrderProcessor.isDropping()) {
if (!player.canSkipTicks()) {
if (flagAndAlert("swap") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
flags.add("swap");
}
}
}
}
}
@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,68 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerBlockPlacement;
@CheckData(name = "PacketOrderM", experimental = true)
public class PacketOrderM extends Check implements PostPredictionCheck {
public PacketOrderM(final GrimPlayer player) {
super(player);
}
private int invalid;
private boolean usingWithoutInteract, interacting;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) {
if (new WrapperPlayClientInteractEntity(event).getAction() != WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
interacting = true;
if (usingWithoutInteract) {
if (!player.canSkipTicks()) {
if (flagAndAlert() && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
} else {
invalid++;
}
}
}
}
if (event.getPacketType() == PacketType.Play.Client.USE_ITEM
|| event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT
&& new WrapperPlayClientPlayerBlockPlacement(event).getFace() == BlockFace.OTHER) {
if (!interacting) {
usingWithoutInteract = true;
}
interacting = false;
}
if (isTickPacket(event.getPacketType())) {
usingWithoutInteract = interacting = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (; invalid >= 1; invalid--) {
flagAndAlert();
}
}
invalid = 0;
}
}
@@ -0,0 +1,65 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.BlockPlaceCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerBlockPlacement;
@CheckData(name = "PacketOrderN", experimental = true)
public class PacketOrderN extends BlockPlaceCheck {
public PacketOrderN(final GrimPlayer player) {
super(player);
}
private int invalid;
private boolean usingWithoutPlacing, placing;
@Override
public void onBlockPlace(BlockPlace place) {
placing = true;
if (usingWithoutPlacing) {
if (!player.canSkipTicks()) {
if (flagAndAlert() && shouldModifyPackets() && shouldCancel()) {
place.resync();
}
} else {
invalid++;
}
}
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.USE_ITEM
|| event.getPacketType() == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT
&& new WrapperPlayClientPlayerBlockPlacement(event).getFace() == BlockFace.OTHER) {
if (!placing) {
usingWithoutPlacing = true;
}
placing = false;
}
if (isTickPacket(event.getPacketType())) {
usingWithoutPlacing = placing = false;
}
}
@Override
public void onPredictionComplete(PredictionComplete predictionComplete) {
if (!player.canSkipTicks()) return;
if (player.isTickingReliablyFor(3)) {
for (; invalid >= 1; invalid--) {
flagAndAlert();
}
}
invalid = 0;
}
}
@@ -0,0 +1,62 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity.InteractAction;
@CheckData(name = "PacketOrderO", experimental = true)
public class PacketOrderO extends Check implements PacketCheck {
public PacketOrderO(final GrimPlayer player) {
super(player);
}
private boolean sentMainhand;
private int requiredEntity;
private boolean requiredSneaking;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
final WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
InteractAction action = packet.getAction();
if (action != InteractAction.ATTACK) {
final boolean sneaking = packet.isSneaking().orElse(false);
final int entity = packet.getEntityId();
if (packet.getHand() == InteractionHand.OFF_HAND) {
if (action == InteractAction.INTERACT) {
if (!sentMainhand) {
if (flagAndAlert("Skipped Mainhand") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
sentMainhand = false;
} else if (sneaking != requiredSneaking || entity != requiredEntity) {
String verbose = "requiredEntity=" + requiredEntity + ", entity=" + entity
+ ", requiredSneaking=" + requiredSneaking + ", sneaking=" + sneaking;
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
} else {
requiredEntity = entity;
requiredSneaking = sneaking;
sentMainhand = true;
}
}
}
if (isTickPacket(event.getPacketType())) {
sentMainhand = false;
}
}
}
@@ -0,0 +1,63 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.PacketCheck;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.InteractionHand;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity.InteractAction;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
@CheckData(name = "PacketOrderP", experimental = true)
public class PacketOrderP extends Check implements PacketCheck {
public PacketOrderP(final GrimPlayer player) {
super(player);
}
private boolean sentMainhand;
private int requiredEntity;
private boolean requiredSneaking;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
final WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
InteractAction action = packet.getAction();
if (action != InteractAction.ATTACK) {
final boolean sneaking = packet.isSneaking().orElse(false);
final int entity = packet.getEntityId();
if (packet.getHand() == InteractionHand.OFF_HAND) {
if (action == InteractAction.INTERACT) {
if (!sentMainhand) {
if (flagAndAlert("Skipped Mainhand") && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
sentMainhand = false;
} else if (sneaking != requiredSneaking || entity != requiredEntity) {
String verbose = "requiredEntity=" + requiredEntity + ", entity=" + entity
+ ", requiredSneaking=" + requiredSneaking + ", sneaking=" + sneaking;
if (flagAndAlert(verbose) && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
}
}
} else {
requiredEntity = entity;
requiredSneaking = sneaking;
sentMainhand = true;
}
}
}
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && !player.packetStateData.lastPacketWasTeleport && !player.packetStateData.lastPacketWasOnePointSeventeenDuplicate) {
sentMainhand = false;
}
}
}
@@ -0,0 +1,165 @@
package ac.grim.grimac.checks.impl.packetorder;
import ac.grim.grimac.checks.Check;
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.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.wrapper.play.client.*;
import lombok.Getter;
import org.jetbrains.annotations.Contract;
@Getter
public final class PacketOrderProcessor extends Check implements PacketCheck {
public PacketOrderProcessor(final GrimPlayer player) {
super(player);
}
private boolean openingInventory; // only pre 1.9 clients on pre 1.9 servers
private boolean swapping;
private boolean dropping;
private boolean interacting;
private boolean attacking;
private boolean releasing;
private boolean digging;
private boolean sprinting;
private boolean sneaking;
private boolean placing;
private boolean using;
private boolean picking;
private boolean clickingInInventory;
private boolean closingInventory;
private boolean quickMoveClicking;
private boolean pickUpClicking;
private boolean leavingBed;
private boolean startingToGlide;
private boolean jumpingWithMount;
@Override
public void onPacketReceive(PacketReceiveEvent event) {
final PacketTypeCommon packetType = event.getPacketType();
if (packetType == PacketType.Play.Client.CLIENT_STATUS) {
if (new WrapperPlayClientClientStatus(event).getAction() == WrapperPlayClientClientStatus.Action.OPEN_INVENTORY_ACHIEVEMENT) {
openingInventory = true;
}
}
if (packetType == PacketType.Play.Client.INTERACT_ENTITY) {
if (new WrapperPlayClientInteractEntity(event).getAction() == WrapperPlayClientInteractEntity.InteractAction.ATTACK) {
attacking = true;
} else {
interacting = true;
}
}
if (packetType == PacketType.Play.Client.PLAYER_DIGGING) {
switch (new WrapperPlayClientPlayerDigging(event).getAction()) {
case SWAP_ITEM_WITH_OFFHAND:
swapping = true;
break;
case DROP_ITEM:
case DROP_ITEM_STACK:
dropping = true;
break;
case RELEASE_USE_ITEM:
releasing = true;
break;
case FINISHED_DIGGING:
case CANCELLED_DIGGING:
case START_DIGGING:
digging = true;
break;
}
}
if (packetType == PacketType.Play.Client.ENTITY_ACTION) {
switch (new WrapperPlayClientEntityAction(event).getAction()) {
case START_SPRINTING:
case STOP_SPRINTING:
sprinting = true;
break;
case STOP_SNEAKING:
case START_SNEAKING:
sneaking = true;
break;
case LEAVE_BED:
leavingBed = true;
break;
case START_FLYING_WITH_ELYTRA:
startingToGlide = true;
break;
case OPEN_HORSE_INVENTORY:
openingInventory = true;
break;
case START_JUMPING_WITH_HORSE:
case STOP_JUMPING_WITH_HORSE:
jumpingWithMount = true;
break;
}
}
if (packetType == PacketType.Play.Client.USE_ITEM) {
using = true;
}
if (packetType == PacketType.Play.Client.PLAYER_BLOCK_PLACEMENT) {
if (new WrapperPlayClientPlayerBlockPlacement(event).getFace() == BlockFace.OTHER) {
using = true;
} else {
placing = true;
}
}
if (packetType == PacketType.Play.Client.PICK_ITEM) {
picking = true;
}
if (packetType == PacketType.Play.Client.CLICK_WINDOW) {
clickingInInventory = true;
switch (new WrapperPlayClientClickWindow(event).getWindowClickType()) {
case QUICK_MOVE:
quickMoveClicking = true;
break;
case PICKUP:
case PICKUP_ALL:
pickUpClicking = true;
break;
}
}
if (packetType == PacketType.Play.Client.CLOSE_WINDOW) {
closingInventory = true;
}
if (isTickPacket(packetType)) {
openingInventory = false;
swapping = false;
dropping = false;
attacking = false;
interacting = false;
releasing = false;
digging = false;
placing = false;
using = false;
picking = false;
sprinting = false;
sneaking = false;
clickingInInventory = false;
closingInventory = false;
quickMoveClicking = false;
pickUpClicking = false;
leavingBed = false;
startingToGlide = false;
jumpingWithMount = false;
}
}
@Contract(pure = true)
public boolean isRightClicking() {
return placing || using || interacting;
}
}
@@ -1,8 +1,8 @@
package ac.grim.grimac.checks.impl.prediction;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.type.PostPredictionCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.checks.debug.AbstractDebugHandler;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
import ac.grim.grimac.utils.lists.EvictingQueue;
@@ -14,7 +14,7 @@ import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
public class DebugHandler extends Check implements PostPredictionCheck {
public class DebugHandler extends AbstractDebugHandler implements PostPredictionCheck {
Set<Player> listeners = new CopyOnWriteArraySet<>(new HashSet<>());
boolean outputToConsole = false;
@@ -66,7 +66,9 @@ public class AirLiquidPlace extends BlockPlaceCheck {
// But for such tiny differences in legitness its not worth it.
Iterable<BlockModification> blockModifications = player.blockHistory.getRecentModifications((blockModification) -> currentTick - blockModification.tick() < 2
&& blockPos.equals(blockModification.location())
&& (blockModification.cause() == BlockModification.Cause.START_DIGGING || blockModification.cause() == BlockModification.Cause.HANDLE_NETTY_SYNC_TRANSACTION));
&& (blockModification.cause() == BlockModification.Cause.START_DIGGING
|| blockModification.cause() == BlockModification.Cause.HANDLE_NETTY_SYNC_TRANSACTION
|| blockModification.cause() == BlockModification.Cause.FINISHED_DIGGING));
// Check if old block from instant breaking in same tick as the current placement was valid
// There should only be one block here for legit clients
@@ -0,0 +1,194 @@
package ac.grim.grimac.checks.impl.scaffolding;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.checks.CheckData;
import ac.grim.grimac.checks.type.BlockPlaceCheck;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.BlockHitData;
import ac.grim.grimac.utils.nmsutil.BlockRayTrace;
import ac.grim.grimac.utils.nmsutil.ReachUtilsPrimitives;
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.player.GameMode;
import com.github.retrooper.packetevents.protocol.world.BlockFace;
import com.github.retrooper.packetevents.protocol.world.states.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.viaversion.viaversion.util.Triple;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@CheckData(name = "LineOfSightPlace", experimental = true)
public class LineOfSightPlace extends BlockPlaceCheck {
private double flagBuffer = 0; // If the player flags once, force them to play legit, or we will cancel the tick before.
private boolean ignorePost = false;
private boolean useBlockWhitelist;
private HashSet<StateType> blockWhitelist;
// 15 is the maximum set of Collision boxes that will be used in the ray trace check
// it corresponds to the size of the collision boxes from the modern Cauldron
// Since this is used per-player we can avoid calling new[] by allocating it per-player in the check
private final SimpleCollisionBox[] collisionBoxBuffer = new SimpleCollisionBox[15];
public final Set<Triple<Vector3i, WrappedBlockState, Byte>> blocksChangedList = ConcurrentHashMap.newKeySet();
public LineOfSightPlace(GrimPlayer player) {
super(player);
}
@Override
public void onBlockPlace(final BlockPlace place) {
if (checkIfShouldSkip(place)) return;
if (flagBuffer > 0 && !didRayTraceHit(place)) {
ignorePost = true;
// If the player hit and has flagged this check recently
if (flagAndAlert("pre-flying: " + player.compensatedWorld.getBlock(place.getPlacedAgainstBlockLocation()).getType()) && shouldModifyPackets() && shouldCancel()) {
place.resync(); // Deny the block placement.
}
}
}
// Use post flying because it has the correct rotation, and can't false easily.
@Override
public void onPostFlyingBlockPlace(BlockPlace place) {
if (checkIfShouldSkip(place)) return;
// Don't flag twice
if (ignorePost) {
ignorePost = false;
return;
}
// Ray trace to try and hit the target block.
boolean hit = didRayTraceHit(place);
// This can false with rapidly moving yaw in 1.8+ clients
if (!hit) {
flagBuffer = 1;
flagAndAlert("post-flying: " + player.compensatedWorld.getBlock(place.getPlacedAgainstBlockLocation()).getType());
} else {
flagBuffer = Math.max(0, flagBuffer - 0.1);
}
}
private boolean checkIfShouldSkip(BlockPlace place) {
StateType targetBlockStateType = player.compensatedWorld.getBlock(place.getPlacedAgainstBlockLocation()).getType();
if (player.gamemode == GameMode.SPECTATOR) return true; // A waste to check creative mode players
if (targetBlockStateType == StateTypes.REDSTONE_WIRE) return true; // Redstone too buggy
if (player.compensatedWorld.isNearHardEntity(player.boundingBox.copy().expand(4))) return true; // Shulkers and Pistons are too buggy
if (useBlockWhitelist) {
return !isBlockTypeWhitelisted(targetBlockStateType);
}
return false;
}
private boolean didRayTraceHit(BlockPlace place) {
double[] possibleEyeHeights = player.getPossibleEyeHeights();
// Start checking if player is in the block
double minEyeHeight = Double.MAX_VALUE;
double maxEyeHeight = Double.MIN_VALUE;
for (double height : possibleEyeHeights) {
minEyeHeight = Math.min(minEyeHeight, height);
maxEyeHeight = Math.max(maxEyeHeight, height);
}
double movementThreshold = player.getMovementThreshold();
SimpleCollisionBox eyePositions = new SimpleCollisionBox(player.x, player.y + minEyeHeight, player.z, player.x, player.y + maxEyeHeight, player.z);
eyePositions.expand(movementThreshold);
int[] interactBlockVec = new int[]{place.blockPosition.x, place.blockPosition.y, place.blockPosition.z};
BlockFace expectedBlockFace = place.getDirection();
// If the player is inside a block, then they can ray trace through the block and hit the other side of the block
// This may potentially be exploitable as a minor bypass
if (eyePositions.isIntersected(new SimpleCollisionBox(interactBlockVec[0], interactBlockVec[1], interactBlockVec[2]))) {
return true;
}
// End checking if the player is in the block
float[][] possibleLookDirs;
// 1.9+ players could be a tick behind because we don't get skipped ticks
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) {
possibleLookDirs = new float[][]{
{player.xRot, player.yRot},
{player.lastXRot, player.lastYRot},
{player.lastXRot, player.yRot}
};
} else if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
// 1.7 players do not have any of these issues! They are always on the latest look vector
possibleLookDirs = new float[][]{{player.xRot, player.yRot}};
} else {
possibleLookDirs = new float[][]{
{player.xRot, player.yRot},
{player.lastXRot, player.yRot}
};
}
// We do not need to add 0.03/0.0002 to maxDistance to ensure our raytrace hits blocks
// Since we expand the hitboxes of the expectedTargetBlock by 0.03/0.002 already later
double maxDistance = player.compensatedEntities.self.getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
// Define possible offsets
// TODO, vectorize this with SIMD or AVX for performance
double[][] offsets = {
{0, 0, 0},
{movementThreshold, 0, 0},
{-movementThreshold, 0, 0},
{0, movementThreshold, 0},
{0, -movementThreshold, 0},
{0, 0, movementThreshold},
{0, 0, -movementThreshold}
};
double[] eyePosition = new double[3];
double[] eyeLookDir = new double[3];
for (double eyeHeight : possibleEyeHeights) {
for (float[] lookDir : possibleLookDirs) {
for (double[] offset : offsets) {
eyePosition[0] = player.x + offset[0];
eyePosition[1] = player.y + eyeHeight + offset[1];
eyePosition[2] = player.z + offset[2];
ReachUtilsPrimitives.getLook(player, lookDir[0], lookDir[1], eyeLookDir);
if (didRayTraceHitTargetBlock(eyePosition, eyeLookDir, maxDistance, interactBlockVec, expectedBlockFace)) {
return true; // If any possible face matches the client-side placement, assume it's legitimate
}
}
}
}
return false; // No matching face found
}
private boolean didRayTraceHitTargetBlock(double[] eyePos, double[] eyeDir, double maxDistance, int[] targetBlockVec, BlockFace expectedBlockFace) {
BlockHitData hitData = BlockRayTrace.getNearestHitResult(player, eyePos, eyeDir, maxDistance, maxDistance, targetBlockVec, expectedBlockFace, collisionBoxBuffer, false);
// we check for hitdata != null because of being in expanded hitbox, or there was no result, do we still need this?
return hitData != null && hitData.success;
}
private boolean isBlockTypeWhitelisted(StateType type) {
return blockWhitelist.contains(type);
}
@Override
public void onReload(ConfigManager config) {
useBlockWhitelist = config.getBooleanElse("LineOfSightPlace.use-block-whitelist", false);
blockWhitelist = new HashSet<>();
List<String> blocks = config.getStringList("LineOfSightPlace.block-whitelist");
for (String block : blocks) {
blockWhitelist.add(StateTypes.getByName(block));
}
}
}
@@ -46,15 +46,27 @@ public class PositionPlace extends BlockPlaceCheck {
// So now we have the player's possible eye positions
// So then look at the face that the player has clicked
boolean flag = switch (place.getDirection()) {
case NORTH -> eyePositions.minZ > combined.minZ; // Z- face
case SOUTH -> eyePositions.maxZ < combined.maxZ; // Z+ face
case EAST -> eyePositions.maxX < combined.maxX; // X+ face
case WEST -> eyePositions.minX > combined.minX; // X- face
case UP -> eyePositions.maxY < combined.maxY; // Y+ face
case DOWN -> eyePositions.minY > combined.minY; // Y- face
default -> false;
};
boolean flag = false;
switch (place.getDirection()) {
case NORTH: // Z- face
flag = eyePositions.minZ > combined.minZ;
break;
case SOUTH: // Z+ face
flag = eyePositions.maxZ < combined.maxZ;
break;
case EAST: // X+ face
flag = eyePositions.maxX < combined.maxX;
break;
case WEST: // X- face
flag = eyePositions.minX > combined.minX;
break;
case UP: // Y+ face
flag = eyePositions.maxY < combined.maxY;
break;
case DOWN: // Y- face
flag = eyePositions.minY > combined.minY;
break;
}
if (flag && flagAndAlert() && shouldModifyPackets() && shouldCancel()) {
place.resync();
@@ -0,0 +1,67 @@
package ac.grim.grimac.checks.type;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientCloseWindow;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerCloseWindow;
import org.jetbrains.annotations.MustBeInvokedByOverriders;
public class InventoryCheck extends BlockPlaceCheck implements PacketCheck {
// Impossible transaction ID
protected static final long NONE = Long.MAX_VALUE;
protected long closeTransaction = NONE;
protected int closePacketsToSkip;
public InventoryCheck(GrimPlayer player) {
super(player);
}
@Override
@MustBeInvokedByOverriders
public void onPacketReceive(final PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
// Disallow any clicks if inventory is closing
if (closeTransaction != NONE && shouldModifyPackets()) {
event.setCancelled(true);
player.onPacketCancel();
player.getInventory().needResend = true;
}
} else if (event.getPacketType() == PacketType.Play.Client.CLOSE_WINDOW) {
// Players with high ping can close inventory faster than send transaction back
if (closeTransaction != NONE && closePacketsToSkip-- <= 0) {
closeTransaction = NONE;
}
}
}
public void closeInventory() {
if (closeTransaction != NONE) {
return;
}
int windowId = player.getInventory().openWindowID;
player.user.writePacket(new WrapperPlayServerCloseWindow(windowId));
// Force close inventory on server side
closePacketsToSkip = 1; // Sending close packet to itself, so skip it
PacketEvents.getAPI().getProtocolManager().receivePacket(
player.user.getChannel(), new WrapperPlayClientCloseWindow(windowId)
);
player.sendTransaction();
int transaction = player.lastTransactionSent.get();
closeTransaction = transaction;
player.latencyUtils.addRealTimeTask(transaction, () -> {
if (closeTransaction == transaction) {
closeTransaction = NONE;
}
});
player.user.flushPackets();
}
}
@@ -1,6 +1,7 @@
package ac.grim.grimac.commands;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.checks.debug.HitboxDebugHandler;
import ac.grim.grimac.player.GrimPlayer;
import co.aikar.commands.BaseCommand;
import co.aikar.commands.annotation.*;
@@ -70,4 +71,17 @@ public class GrimDebug extends BaseCommand {
sender.sendMessage("Console output for " + (grimPlayer.bukkitPlayer == null ? grimPlayer.user.getProfile().getName() : grimPlayer.bukkitPlayer.getName()) + " is now " + isOutput);
}
@Subcommand("hitboxdebug")
@CommandPermission("grim.hitboxdebug")
@CommandCompletion("@players")
public void onHitboxDebug(CommandSender sender, @Optional OnlinePlayer target) {
Player player = null;
if (sender instanceof Player) player = (Player) sender;
GrimPlayer grimPlayer = parseTarget(sender, player, target);
if (grimPlayer == null) return;
grimPlayer.checkManager.getCheck(HitboxDebugHandler.class).toggleListener(player);
}
}
@@ -0,0 +1,86 @@
package ac.grim.grimac.commands;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.manager.violationdatabase.Violation;
import ac.grim.grimac.manager.violationdatabase.ViolationDatabaseManager;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import co.aikar.commands.BaseCommand;
import co.aikar.commands.annotation.*;
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
@CommandAlias("grim|grimac")
public class GrimHistory extends BaseCommand {
@Subcommand("history|hist")
@CommandPermission("grim.history")
@CommandAlias("gh")
@CommandCompletion("@players")
public void onLogs(CommandSender sender, String target, @Optional Integer page) {
int entriesPerPage = GrimAPI.INSTANCE.getConfigManager().getConfig().getIntElse("history.entries-per-page", 15);
String header = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("grim-history-header",
"%prefix% &bShowing logs for &f%player% (&f%page%&b/&f%maxPages%&f)");
String logFormat = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("grim-history-entry",
"%prefix% &8[&f%server%&8] &bFailed &f%check% (x&c%vl%&f) &7%verbose% (&b%timeago% ago&7)");
FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(), __ -> {
OfflinePlayer targetPlayer = Bukkit.getOfflinePlayer(target);
int notNullPage = page == null ? 1 : page;
ViolationDatabaseManager violations = GrimAPI.INSTANCE.getViolationDatabaseManager();
int logCount = violations.getLogCount(targetPlayer.getUniqueId());
List<Violation> logs = violations.getViolations(targetPlayer.getUniqueId(), notNullPage, entriesPerPage);
int maxPages = (int) Math.ceil((float) logCount / entriesPerPage);
MessageUtil.sendMessage(sender, MessageUtil.miniMessage(MessageUtil.replacePlaceholders(sender, header
.replace("%player%", targetPlayer.getName())
.replace("%page%", String.valueOf(notNullPage))
.replace("%maxPages%", String.valueOf(maxPages))
)));
for (int i = logs.size() - 1; i >= 0; i--) {
Violation log = logs.get(i);
MessageUtil.sendMessage(sender, MessageUtil.miniMessage(MessageUtil.replacePlaceholders(sender, logFormat
.replace("%player%", targetPlayer.getName())
.replace("%check%", log.getCheckName())
.replace("%verbose%", log.getVerbose())
.replace("%vl%", String.valueOf(log.getVl()))
.replace("%timeago%", getTimeAgo(log.getCreatedAt()))
.replace("%server%", log.getServerName())
)));
}
});
}
protected String getTimeAgo(Date date) {
long durationMillis = new Date().getTime() - date.getTime();
long days = TimeUnit.MILLISECONDS.toDays(durationMillis);
durationMillis -= TimeUnit.DAYS.toMillis(days);
long hours = TimeUnit.MILLISECONDS.toHours(durationMillis);
durationMillis -= TimeUnit.HOURS.toMillis(hours);
long minutes = TimeUnit.MILLISECONDS.toMinutes(durationMillis);
durationMillis -= TimeUnit.MINUTES.toMillis(minutes);
long seconds = TimeUnit.MILLISECONDS.toSeconds(durationMillis);
StringBuilder result = new StringBuilder();
if (days > 0) result.append(days).append("d ");
if (hours > 0) result.append(hours).append("h ");
if (minutes > 0) result.append(minutes).append("m ");
if (seconds > 0) result.append(seconds).append("s");
return result.toString().trim();
}
}
@@ -19,7 +19,8 @@ public class GrimSpectate extends BaseCommand {
@CommandPermission("grim.spectate")
@CommandCompletion("@players")
public void onSpectate(CommandSender sender, @Optional Player target) {
if (!(sender instanceof Player player)) return;
if (!(sender instanceof Player)) return;
Player player = (Player) sender;
if (target != null && target.getUniqueId().equals(player.getUniqueId())) {
String message = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("cannot-run-on-self", "%prefix% &cYou cannot use this command on yourself!");
@@ -12,17 +12,18 @@ import co.aikar.commands.annotation.Subcommand;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Collections;
@CommandAlias("grim|grimac")
public class GrimStopSpectating extends BaseCommand {
public static final CommandCompletionHandler<BukkitCommandCompletionContext> completionHandler = context -> context.getSender().hasPermission("grim.spectate.stophere") ? List.of("here") : List.of();
public static final CommandCompletionHandler<BukkitCommandCompletionContext> completionHandler = context -> context.getSender().hasPermission("grim.spectate.stophere") ? Collections.singletonList("here") : Collections.emptyList();
@Subcommand("stopspectating")
@CommandPermission("grim.spectate")
@CommandCompletion("@stopspectating")
public void onStopSpectate(CommandSender sender, String[] args) {
if (!(sender instanceof Player player)) return;
if (!(sender instanceof Player)) return;
Player player = (Player) sender;
String string = args.length > 0 ? args[0] : null;
if (GrimAPI.INSTANCE.getSpectateManager().isSpectating(player.getUniqueId())) {
boolean teleportBack = string == null || !string.equalsIgnoreCase("here") || !sender.hasPermission("grim.spectate.stophere");
@@ -16,13 +16,11 @@ import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.command.CommandSender;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Objects;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.atomic.AtomicReference;
@CommandAlias("grim|grimac")
@@ -37,8 +35,6 @@ public class GrimVersion extends BaseCommand {
private static long lastCheck;
private static final AtomicReference<Component> updateMessage = new AtomicReference<>();
private static final HttpClient HTTP_CLIENT = HttpClient.newHttpClient();
public static void checkForUpdatesAsync(CommandSender sender) {
String current = GrimAPI.INSTANCE.getExternalAPI().getGrimVersion();
MessageUtil.sendMessage(sender, Component.text()
@@ -60,47 +56,78 @@ public class GrimVersion extends BaseCommand {
@SuppressWarnings("deprecation")
private static void checkForUpdates(CommandSender sender) {
String current = GrimAPI.INSTANCE.getExternalAPI().getGrimVersion();
HttpURLConnection connection = null;
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.modrinth.com/v2/project/LJNGWSvH/version"))
.GET()
.header("User-Agent", "GrimAnticheat/Grim/" + GrimAPI.INSTANCE.getExternalAPI().getGrimVersion())
.header("Content-Type", "application/json")
.timeout(Duration.of(5, ChronoUnit.SECONDS))
.build();
// Create the URL object
URL url = new URL("https://api.modrinth.com/v2/project/LJNGWSvH/version");
HttpResponse<String> response = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
// Open the connection
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("User-Agent", "GrimAnticheat/Grim/" + GrimAPI.INSTANCE.getExternalAPI().getGrimVersion());
connection.setRequestProperty("Content-Type", "application/json");
connection.setConnectTimeout(5000); // Set timeout to 5 seconds
connection.setReadTimeout(5000); // Set read timeout to 5 seconds
// Get the response code
int responseCode = connection.getResponseCode();
if (responseCode != 200) {
Component msg = updateMessage.get();
MessageUtil.sendMessage(sender, Objects.requireNonNullElseGet(msg, () -> Component.text()
.append(Component.text("Failed to check latest version.").color(NamedTextColor.RED))
.build()));
LogUtil.error("Failed to check latest GrimAC version. Response code: " + response.statusCode());
if (msg == null) {
msg = Component.text()
.append(Component.text("Failed to check latest version.").color(NamedTextColor.RED))
.build();
}
MessageUtil.sendMessage(sender, msg);
LogUtil.error("Failed to check latest GrimAC version. Response code: " + responseCode);
return;
}
// Using old JsonParser method, as old versions of Gson don't include the static one
JsonObject object = new JsonParser().parse(response.body()).getAsJsonArray().get(0).getAsJsonObject();
String latest = object.get("version_number").getAsString();
Status status = compareVersions(current, latest);
Component msg = switch (status) {
case AHEAD ->
Component.text("You are using a development version of GrimAC").color(NamedTextColor.LIGHT_PURPLE);
case UPDATED ->
Component.text("You are using the latest version of GrimAC").color(NamedTextColor.GREEN);
case OUTDATED -> Component.text()
.append(Component.text("New GrimAC version found!").color(NamedTextColor.AQUA))
.append(Component.text(" Version ").color(NamedTextColor.GRAY))
.append(Component.text(latest).color(NamedTextColor.GRAY).decorate(TextDecoration.ITALIC))
.append(Component.text(" is available to be downloaded here: ").color(NamedTextColor.GRAY))
.append(Component.text("https://modrinth.com/plugin/grimac").color(NamedTextColor.GRAY).decorate(TextDecoration.UNDERLINED)
.clickEvent(ClickEvent.openUrl("https://modrinth.com/plugin/grimac")))
.build();
};
updateMessage.set(msg);
MessageUtil.sendMessage(sender, msg);
} catch (Exception ignored) {
// Read the response body
try (InputStream inputStream = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
// Parse the response JSON
JsonObject object = JsonParser.parseString(response.toString()).getAsJsonArray().get(0).getAsJsonObject();
String latest = object.get("version_number").getAsString();
// Compare versions
Status status = compareVersions(current, latest);
Component msg = null;
switch (status) {
case AHEAD:
msg = Component.text("You are using a development version of GrimAC").color(NamedTextColor.LIGHT_PURPLE);
break;
case UPDATED:
msg = Component.text("You are using the latest version of GrimAC").color(NamedTextColor.GREEN);
break;
case OUTDATED:
msg = Component.text()
.append(Component.text("New GrimAC version found!").color(NamedTextColor.AQUA))
.append(Component.text(" Version ").color(NamedTextColor.GRAY))
.append(Component.text(latest).color(NamedTextColor.GRAY).decorate(TextDecoration.ITALIC))
.append(Component.text(" is available to be downloaded here: ").color(NamedTextColor.GRAY))
.append(Component.text("https://modrinth.com/plugin/grimac").color(NamedTextColor.GRAY).decorate(TextDecoration.UNDERLINED)
.clickEvent(ClickEvent.openUrl("https://modrinth.com/plugin/grimac")))
.build();
break;
}
updateMessage.set(msg);
MessageUtil.sendMessage(sender, msg);
}
} catch (Exception e) {
MessageUtil.sendMessage(sender, Component.text("Failed to check latest version.").color(NamedTextColor.RED));
LogUtil.error("Failed to check latest GrimAC version.", ignored);
LogUtil.error("Failed to check latest GrimAC version.", e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
@@ -1,6 +1,7 @@
package ac.grim.grimac.events.packets;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.checks.impl.inventory.InventoryB;
import ac.grim.grimac.events.packets.patch.ResyncWorldUtil;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.anticheat.update.*;
@@ -14,7 +15,6 @@ import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.*;
import ac.grim.grimac.utils.inventory.Inventory;
import ac.grim.grimac.utils.latency.CompensatedWorld;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.math.VectorUtils;
import ac.grim.grimac.utils.nmsutil.*;
import com.github.retrooper.packetevents.PacketEvents;
@@ -52,88 +52,18 @@ import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import static ac.grim.grimac.utils.nmsutil.BlockRayTrace.traverseBlocks;
public class CheckManagerListener extends PacketListenerAbstract {
public CheckManagerListener() {
super(PacketListenerPriority.LOW);
}
// Copied from MCP...
// Returns null if there isn't anything.
//
// I do have to admit that I'm starting to like bifunctions/new java 8 things more than I originally did.
// although I still don't understand Mojang's obsession with streams in some of the hottest methods... that kills performance
public static HitData traverseBlocks(GrimPlayer player, Vector3d start, Vector3d end, BiFunction<WrappedBlockState, Vector3i, HitData> predicate) {
// I guess go back by the collision epsilon?
double endX = GrimMath.lerp(-1.0E-7D, end.x, start.x);
double endY = GrimMath.lerp(-1.0E-7D, end.y, start.y);
double endZ = GrimMath.lerp(-1.0E-7D, end.z, start.z);
double startX = GrimMath.lerp(-1.0E-7D, start.x, end.x);
double startY = GrimMath.lerp(-1.0E-7D, start.y, end.y);
double startZ = GrimMath.lerp(-1.0E-7D, start.z, end.z);
int floorStartX = GrimMath.floor(startX);
int floorStartY = GrimMath.floor(startY);
int floorStartZ = GrimMath.floor(startZ);
if (start.equals(end)) return null;
WrappedBlockState state = player.compensatedWorld.getBlock(floorStartX, floorStartY, floorStartZ);
HitData apply = predicate.apply(state, new Vector3i(floorStartX, floorStartY, floorStartZ));
if (apply != null) {
return apply;
}
double xDiff = endX - startX;
double yDiff = endY - startY;
double zDiff = endZ - startZ;
double xSign = Math.signum(xDiff);
double ySign = Math.signum(yDiff);
double zSign = Math.signum(zDiff);
double posXInverse = xSign == 0 ? Double.MAX_VALUE : xSign / xDiff;
double posYInverse = ySign == 0 ? Double.MAX_VALUE : ySign / yDiff;
double posZInverse = zSign == 0 ? Double.MAX_VALUE : zSign / zDiff;
double d12 = posXInverse * (xSign > 0 ? 1.0D - GrimMath.frac(startX) : GrimMath.frac(startX));
double d13 = posYInverse * (ySign > 0 ? 1.0D - GrimMath.frac(startY) : GrimMath.frac(startY));
double d14 = posZInverse * (zSign > 0 ? 1.0D - GrimMath.frac(startZ) : GrimMath.frac(startZ));
// Can't figure out what this code does currently
while (d12 <= 1.0D || d13 <= 1.0D || d14 <= 1.0D) {
if (d12 < d13) {
if (d12 < d14) {
floorStartX += xSign;
d12 += posXInverse;
} else {
floorStartZ += zSign;
d14 += posZInverse;
}
} else if (d13 < d14) {
floorStartY += ySign;
d13 += posYInverse;
} else {
floorStartZ += zSign;
d14 += posZInverse;
}
state = player.compensatedWorld.getBlock(floorStartX, floorStartY, floorStartZ);
apply = predicate.apply(state, new Vector3i(floorStartX, floorStartY, floorStartZ));
if (apply != null) {
return apply;
}
}
return null;
}
private static void placeWaterLavaSnowBucket(GrimPlayer player, ItemStack held, StateType toPlace, InteractionHand hand) {
HitData data = getNearestHitResult(player, StateTypes.AIR, false, true, true);
BlockHitData data = getNearestHitResult(player, StateTypes.AIR, false, true, true);
if (data != null) {
BlockPlace blockPlace = new BlockPlace(player, hand, data.getPosition(), data.getClosestDirection().getFaceValue(), data.getClosestDirection(), held, data);
@@ -262,8 +192,9 @@ public class CheckManagerListener extends PacketListenerAbstract {
private static void handleBlockPlaceOrUseItem(PacketWrapper<?> packet, GrimPlayer player) {
// Legacy "use item" packet
if (packet instanceof WrapperPlayClientPlayerBlockPlacement place &&
if (packet instanceof WrapperPlayClientPlayerBlockPlacement &&
PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9)) {
WrapperPlayClientPlayerBlockPlacement place = (WrapperPlayClientPlayerBlockPlacement) packet;
if (player.gamemode == GameMode.SPECTATOR || player.gamemode == GameMode.ADVENTURE) return;
@@ -278,7 +209,9 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
}
if (packet instanceof WrapperPlayClientUseItem place) {
if (packet instanceof WrapperPlayClientUseItem) {
WrapperPlayClientUseItem place = (WrapperPlayClientUseItem) packet;
if (player.gamemode == GameMode.SPECTATOR || player.gamemode == GameMode.ADVENTURE) return;
ItemStack placedWith = player.getInventory().getHeldItem();
@@ -290,7 +223,9 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
// Check for interactable first (door, etc)
if (packet instanceof WrapperPlayClientPlayerBlockPlacement place) {
if (packet instanceof WrapperPlayClientPlayerBlockPlacement) {
WrapperPlayClientPlayerBlockPlacement place = (WrapperPlayClientPlayerBlockPlacement) packet;
ItemStack placedWith = player.getInventory().getHeldItem();
ItemStack offhand = player.getInventory().getOffHand();
@@ -327,7 +262,8 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
}
if (packet instanceof WrapperPlayClientPlayerBlockPlacement place) {
if (packet instanceof WrapperPlayClientPlayerBlockPlacement) {
WrapperPlayClientPlayerBlockPlacement place = (WrapperPlayClientPlayerBlockPlacement) packet;
if (player.gamemode == GameMode.SPECTATOR || player.gamemode == GameMode.ADVENTURE) return;
Vector3i blockPosition = place.getBlockPosition();
@@ -497,6 +433,8 @@ public class CheckManagerListener extends PacketListenerAbstract {
final WrapperPlayClientPlayerDigging packet = new WrapperPlayClientPlayerDigging(event);
final DiggingAction action = packet.getAction();
player.checkManager.getPacketCheck(InventoryB.class).handle(event, packet);
if (action == DiggingAction.START_DIGGING || action == DiggingAction.FINISHED_DIGGING || action == DiggingAction.CANCELLED_DIGGING) {
final BlockBreak blockBreak = new BlockBreak(player, packet.getBlockPosition(), packet.getBlockFace(), packet.getBlockFaceId(), action, player.compensatedWorld.getBlock(packet.getBlockPosition()));
@@ -511,6 +449,15 @@ public class CheckManagerListener extends PacketListenerAbstract {
if (action == DiggingAction.FINISHED_DIGGING && BREAKABLE.apply(blockBreak.block.getType())) {
player.compensatedWorld.startPredicting();
player.blockHistory.add(
new BlockModification(
player.compensatedWorld.getBlock(blockBreak.position),
WrappedBlockState.getByGlobalId(0),
blockBreak.position,
GrimAPI.INSTANCE.getTickManager().currentTick,
BlockModification.Cause.FINISHED_DIGGING
)
);
player.compensatedWorld.updateBlock(blockBreak.position.x, blockBreak.position.y, blockBreak.position.z, 0);
player.compensatedWorld.stopPredicting(packet);
}
@@ -643,7 +590,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
private static void placeBucket(GrimPlayer player, InteractionHand hand) {
HitData data = getNearestHitResult(player, null, true, false, true);
BlockHitData data = getNearestHitResult(player, null, true, false, true);
if (data != null) {
BlockPlace blockPlace = new BlockPlace(player, hand, data.getPosition(), data.getClosestDirection().getFaceValue(), data.getClosestDirection(), ItemStack.EMPTY, data);
@@ -814,7 +761,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
private static void placeLilypad(GrimPlayer player, InteractionHand hand) {
HitData data = getNearestHitResult(player, null, true, false, true);
BlockHitData data = getNearestHitResult(player, null, true, false, true);
if (data != null) {
// A lilypad cannot replace a fluid
@@ -844,7 +791,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
}
private static HitData getNearestHitResult(GrimPlayer player, StateType heldItem, boolean sourcesHaveHitbox, boolean fluidPlacement, boolean itemUsePlacement) {
private static BlockHitData getNearestHitResult(GrimPlayer player, StateType heldItem, boolean sourcesHaveHitbox, boolean fluidPlacement, boolean itemUsePlacement) {
Vector3d startingPos = new Vector3d(player.x, player.y + player.getEyeHeight(), player.z);
Vector startingVec = new Vector(startingPos.getX(), startingPos.getY(), startingPos.getZ());
Ray trace = new Ray(player, startingPos.getX(), startingPos.getY(), startingPos.getZ(), player.xRot, player.yRot);
@@ -852,7 +799,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
Vector endVec = trace.getPointAtDistance(distance);
Vector3d endPos = new Vector3d(endVec.getX(), endVec.getY(), endVec.getZ());
return traverseBlocks(player, startingPos, endPos, (block, vector3i) -> {
return (BlockHitData) traverseBlocks(player, startingPos, endPos, (block, vector3i) -> {
if (fluidPlacement && player.getClientVersion().isOlderThan(ClientVersion.V_1_13) && CollisionData.getData(block.getType())
.getMovementCollisionBox(player, player.getClientVersion(), block, vector3i.getX(), vector3i.getY(), vector3i.getZ()).isNull()) {
return null;
@@ -879,7 +826,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
}
}
if (bestHitLoc != null) {
return new HitData(vector3i, bestHitLoc, bestFace, block);
return new BlockHitData(vector3i, bestHitLoc, bestFace, block, true);
}
if (sourcesHaveHitbox &&
@@ -892,7 +839,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
Pair<Vector, BlockFace> intercept = ReachUtils.calculateIntercept(box, trace.getOrigin(), trace.getPointAtDistance(distance));
if (intercept.first() != null) {
return new HitData(vector3i, intercept.first(), intercept.second(), block);
return new BlockHitData(vector3i, intercept.first(), intercept.second(), block, true);
}
}
@@ -237,8 +237,9 @@ public class PacketEntityReplication extends Check implements PacketCheck {
if (status.getStatus() == 31) {
PacketEntity hook = player.compensatedEntities.getEntity(status.getEntityId());
if (!(hook instanceof PacketEntityHook hookEntity)) return;
if (!(hook instanceof PacketEntityHook)) return;
PacketEntityHook hookEntity = (PacketEntityHook) hook;
if (hookEntity.attached == player.entityID) {
player.sendTransaction();
// We don't transaction sandwich this, it's too rare to be a real problem.
@@ -443,6 +444,7 @@ public class PacketEntityReplication extends Check implements PacketCheck {
return;
}
// player.compensatedEntities.entityMap.updateEntityPosition(player.compensatedEntities.entityMap.get(entityId), new Vector3d(data.getX() + deltaX, data.getY() + deltaY, data.getZ() + deltaZ));
data.setX(data.getX() + deltaX);
data.setY(data.getY() + deltaY);
data.setZ(data.getZ() + deltaZ);
@@ -468,7 +470,8 @@ public class PacketEntityReplication extends Check implements PacketCheck {
player.latencyUtils.addRealTimeTask(lastTrans, () -> {
PacketEntity entity = player.compensatedEntities.getEntity(entityId);
if (entity == null) return;
if (entity instanceof PacketEntityTrackXRot xRotEntity && yaw != null) {
if (entity instanceof PacketEntityTrackXRot && yaw != null) {
PacketEntityTrackXRot xRotEntity = (PacketEntityTrackXRot) entity;
xRotEntity.packetYaw = yaw;
xRotEntity.steps = entity.isBoat() ? 10 : 3;
}
@@ -113,17 +113,15 @@ public class PacketPlayerDigging extends PacketListenerAbstract {
// Players in survival can't use a bow without an arrow
// Crossbow charge checked previously
if (material == ItemTypes.BOW || material == ItemTypes.CROSSBOW) {
/*player.packetStateData.slowedByUsingItem = player.gamemode == GameMode.CREATIVE ||
player.getInventory().hasItemType(ItemTypes.ARROW) ||
player.getInventory().hasItemType(ItemTypes.TIPPED_ARROW) ||
player.getInventory().hasItemType(ItemTypes.SPECTRAL_ARROW);
player.packetStateData.eatingHand = place.getHand();*/
boolean isSlowedByUsingItem = player.gamemode == GameMode.CREATIVE ||
player.getInventory().hasAnyOfItemType(ItemTypes.ARROW, ItemTypes.TIPPED_ARROW, ItemTypes.SPECTRAL_ARROW);
player.packetStateData.eatingHand = hand;
// TODO: How do we lag compensate arrows? Mojang removed idle packet.
// I think we may have to cancel the bukkit event if the player isn't slowed
// On 1.8, it wouldn't be too bad to handle bows correctly
// But on 1.9+, no idle packet and clients/servers don't agree on bow status
// Mojang pls fix
player.packetStateData.setSlowedByUsingItem(false);
player.packetStateData.setSlowedByUsingItem(isSlowedByUsingItem);
}
if (material == ItemTypes.SPYGLASS && player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_17)) {
@@ -221,6 +219,8 @@ public class PacketPlayerDigging extends PacketListenerAbstract {
final ItemStack item = hand == InteractionHand.MAIN_HAND ?
player.getInventory().getHeldItem() : player.getInventory().getOffHand();
final boolean wasSlow = player.packetStateData.isSlowedByUsingItem();
handleUseItem(player, item, hand);
}
}
@@ -0,0 +1,163 @@
package ac.grim.grimac.events.packets;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.data.packetentity.PacketEntitySelf;
import ac.grim.grimac.utils.inventory.InventoryDesyncStatus;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClientStatus;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientClientStatus.Action;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerOpenWindow;
public class PacketPlayerWindow extends PacketListenerAbstract {
public PacketPlayerWindow() {
super(PacketListenerPriority.LOWEST);
}
@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && !event.isCancelled()) {
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
if (player.hasInventoryOpen && isNearNetherPortal(player)) {
handleInventoryClose(player, InventoryDesyncStatus.NETHER_PORTAL);
}
}
// Client Status is sent in 1.7-1.8
if (event.getPacketType() == PacketType.Play.Client.CLIENT_STATUS) {
WrapperPlayClientClientStatus wrapper = new WrapperPlayClientClientStatus(event);
if (wrapper.getAction() == Action.OPEN_INVENTORY_ACHIEVEMENT) {
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
handleInventoryOpen(player);
}
}
// We need to do this due to 1.9 not sending anymore the inventory action in the Client Status
if (event.getPacketType() == PacketType.Play.Client.CLICK_WINDOW) {
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
// TODO: Remove this check after we finish the before ViaVersion injection
// Explanation: On 1.7 and 1.8 we have OPEN_INVENTORY_ACHIEVEMENT on CLIENT_STATUS packet
// but after Via translation this information gets lost
// This is a workaround to atleast make our inventory checks work "decently" in 1.8 clients for 1.9+ servers
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)
&& player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) {
handleInventoryOpen(player);
}
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8)) {
handleInventoryOpen(player);
}
}
if (event.getPacketType() == PacketType.Play.Client.CLOSE_WINDOW) {
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
handleInventoryClose(player, InventoryDesyncStatus.NOT_DESYNCED);
}
}
@Override
public void onPacketSend(PacketSendEvent event) {
if (event.getPacketType() == PacketType.Play.Server.RESPAWN) {
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
player.sendTransaction();
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(),
() -> handleInventoryClose(player, InventoryDesyncStatus.NOT_DESYNCED));
} else if (event.getPacketType() == PacketType.Play.Server.OPEN_WINDOW) {
WrapperPlayServerOpenWindow wrapper = new WrapperPlayServerOpenWindow(event);
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
player.sendTransaction();
String legacyType = wrapper.getLegacyType();
int modernType = wrapper.getType();
InventoryDesyncStatus inventoryDesyncStatus = getContainerDesyncStatus(player, legacyType, modernType);
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(),
() -> {
if (inventoryDesyncStatus == InventoryDesyncStatus.NOT_DESYNCED) {
handleInventoryOpen(player);
} else {
handleInventoryClose(player, inventoryDesyncStatus);
}
});
} else if (event.getPacketType() == PacketType.Play.Server.OPEN_HORSE_WINDOW) {
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
player.sendTransaction();
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(),
() -> handleInventoryOpen(player));
} else if (event.getPacketType() == PacketType.Play.Server.CLOSE_WINDOW) {
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;
player.sendTransaction();
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(),
() -> handleInventoryClose(player, InventoryDesyncStatus.NOT_DESYNCED));
}
}
private void handleInventoryOpen(GrimPlayer player) {
if (!player.hasInventoryOpen) {
player.lastInventoryOpen = System.currentTimeMillis();
}
player.hasInventoryOpen = true;
}
private void handleInventoryClose(GrimPlayer player, InventoryDesyncStatus desyncStatus) {
player.hasInventoryOpen = false;
player.inventoryDesyncStatus = desyncStatus;
}
public InventoryDesyncStatus getContainerDesyncStatus(GrimPlayer player, String legacyType, int modernType) {
// Closing beacon with the cross button cause desync in 1.7-1.8
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) &&
("minecraft:beacon".equals(legacyType) || modernType == 8)) {
return player.inventoryDesyncStatus = InventoryDesyncStatus.BEACON;
}
if (isNearNetherPortal(player)) {
return player.inventoryDesyncStatus = InventoryDesyncStatus.NETHER_PORTAL;
}
return player.inventoryDesyncStatus = InventoryDesyncStatus.NOT_DESYNCED;
}
public boolean isNearNetherPortal(GrimPlayer player) {
// Going inside nether portal with opened inventory cause desync, fixed in 1.12.2
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_12_1) &&
player.pointThreeEstimator.isNearNetherPortal) {
PacketEntitySelf playerEntity = player.compensatedEntities.self;
// Client ignore nether portal if player has passengers or riding an entity
return !playerEntity.inVehicle() && playerEntity.passengers.isEmpty();
}
return false;
}
}
@@ -15,7 +15,7 @@ import java.util.BitSet;
public class PacketWorldReaderEight extends BasePacketWorldReader {
@Override
public void handleMapChunkBulk(final GrimPlayer player, final PacketSendEvent event) {
PacketWrapper<?> wrapper = new PacketWrapper<>(event);
PacketWrapper wrapper = new PacketWrapper(event);
ByteBuf buffer = (ByteBuf) wrapper.getBuffer();
boolean skylight = wrapper.readBoolean();
@@ -47,7 +47,7 @@ public class PacketWorldReaderEight extends BasePacketWorldReader {
@Override
public void handleMapChunk(final GrimPlayer player, final PacketSendEvent event) {
PacketWrapper<?> wrapper = new PacketWrapper<>(event);
PacketWrapper wrapper = new PacketWrapper(event);
final int chunkX = wrapper.readInt();
final int chunkZ = wrapper.readInt();
@@ -1,26 +1,26 @@
package ac.grim.grimac.manager;
import ac.grim.grimac.api.AbstractCheck;
import ac.grim.grimac.checks.debug.HitboxDebugHandler;
import ac.grim.grimac.checks.impl.aim.AimDuplicateLook;
import ac.grim.grimac.checks.impl.aim.AimModulo360;
import ac.grim.grimac.checks.impl.aim.processor.AimProcessor;
import ac.grim.grimac.checks.impl.badpackets.*;
import ac.grim.grimac.checks.impl.breaking.*;
import ac.grim.grimac.checks.impl.combat.Hitboxes;
import ac.grim.grimac.checks.impl.combat.MultiInteractA;
import ac.grim.grimac.checks.impl.combat.MultiInteractB;
import ac.grim.grimac.checks.impl.combat.Reach;
import ac.grim.grimac.checks.impl.combat.*;
import ac.grim.grimac.checks.impl.crash.*;
import ac.grim.grimac.checks.impl.elytra.*;
import ac.grim.grimac.checks.impl.exploit.ExploitA;
import ac.grim.grimac.checks.impl.exploit.ExploitB;
import ac.grim.grimac.checks.impl.exploit.ExploitC;
import ac.grim.grimac.checks.impl.groundspoof.NoFall;
import ac.grim.grimac.checks.impl.inventory.*;
import ac.grim.grimac.checks.impl.misc.ClientBrand;
import ac.grim.grimac.checks.impl.misc.GhostBlockMitigation;
import ac.grim.grimac.checks.impl.misc.TransactionOrder;
import ac.grim.grimac.checks.impl.movement.*;
import ac.grim.grimac.checks.impl.multiactions.*;
import ac.grim.grimac.checks.impl.packetorder.*;
import ac.grim.grimac.checks.impl.post.Post;
import ac.grim.grimac.checks.impl.prediction.DebugHandler;
import ac.grim.grimac.checks.impl.prediction.GroundSpoof;
@@ -80,8 +80,11 @@ public class CheckManager {
public CheckManager(GrimPlayer player) {
// Include post checks in the packet check too
packetChecks = new ImmutableClassToInstanceMap.Builder<PacketCheck>()
.put(Hitboxes.class, new Hitboxes(player))
.put(PacketOrderProcessor.class, player.packetOrderProcessor)
.put(Reach.class, new Reach(player))
.put(HitboxMiss.class, new HitboxMiss(player))
.put(HitboxBlock.class, new HitboxBlock(player))
.put(HitboxEntity.class, new HitboxEntity(player))
.put(PacketEntityReplication.class, new PacketEntityReplication(player))
.put(PacketChangeGameState.class, new PacketChangeGameState(player))
.put(CompensatedInventory.class, new CompensatedInventory(player))
@@ -102,7 +105,6 @@ public class CheckManager {
.put(BadPacketsI.class, new BadPacketsI(player))
.put(BadPacketsK.class, new BadPacketsK(player))
.put(BadPacketsL.class, new BadPacketsL(player))
.put(BadPacketsM.class, new BadPacketsM(player))
.put(BadPacketsN.class, new BadPacketsN(player))
.put(BadPacketsP.class, new BadPacketsP(player))
.put(BadPacketsQ.class, new BadPacketsQ(player))
@@ -113,11 +115,19 @@ public class CheckManager {
.put(BadPacketsV.class, new BadPacketsV(player))
.put(BadPacketsW.class, new BadPacketsW(player))
.put(BadPacketsY.class, new BadPacketsY(player))
.put(InventoryA.class, new InventoryA(player))
.put(InventoryB.class, new InventoryB(player))
.put(InventoryE.class, new InventoryE(player))
.put(InventoryF.class, new InventoryF(player))
.put(InventoryG.class, new InventoryG(player))
.put(MultiActionsA.class, new MultiActionsA(player))
.put(MultiActionsB.class, new MultiActionsB(player))
.put(MultiActionsC.class, new MultiActionsC(player))
.put(MultiActionsD.class, new MultiActionsD(player))
.put(MultiActionsE.class, new MultiActionsE(player))
.put(PacketOrderC.class, new PacketOrderC(player))
.put(PacketOrderD.class, new PacketOrderD(player))
.put(PacketOrderO.class, new PacketOrderO(player))
.put(TransactionOrder.class, new TransactionOrder(player))
.put(SprintA.class, new SprintA(player))
.put(VehicleA.class, new VehicleA(player))
@@ -145,8 +155,19 @@ public class CheckManager {
.put(ExplosionHandler.class, new ExplosionHandler(player))
.put(KnockbackHandler.class, new KnockbackHandler(player))
.put(GhostBlockDetector.class, new GhostBlockDetector(player))
.put(InventoryD.class, new InventoryD(player))
.put(Phase.class, new Phase(player))
.put(Post.class, new Post(player))
.put(PacketOrderA.class, new PacketOrderA(player))
.put(PacketOrderE.class, new PacketOrderE(player))
.put(PacketOrderF.class, new PacketOrderF(player))
.put(PacketOrderG.class, new PacketOrderG(player))
.put(PacketOrderH.class, new PacketOrderH(player))
.put(PacketOrderI.class, new PacketOrderI(player))
.put(PacketOrderJ.class, new PacketOrderJ(player))
.put(PacketOrderK.class, new PacketOrderK(player))
.put(PacketOrderL.class, new PacketOrderL(player))
.put(PacketOrderM.class, new PacketOrderM(player))
.put(GroundSpoof.class, new GroundSpoof(player))
.put(OffsetHandler.class, new OffsetHandler(player))
.put(SuperDebug.class, new SuperDebug(player))
@@ -176,6 +197,7 @@ public class CheckManager {
.build();
blockPlaceCheck = new ImmutableClassToInstanceMap.Builder<BlockPlaceCheck>()
.put(InventoryC.class, new InventoryC(player))
.put(InvalidPlaceA.class, new InvalidPlaceA(player))
.put(InvalidPlaceB.class, new InvalidPlaceB(player))
.put(AirLiquidPlace.class, new AirLiquidPlace(player))
@@ -185,7 +207,9 @@ public class CheckManager {
.put(FabricatedPlace.class, new FabricatedPlace(player))
.put(PositionPlace.class, new PositionPlace(player))
.put(RotationPlace.class, new RotationPlace(player))
.put(PacketOrderN.class, new PacketOrderN(player))
.put(DuplicateRotPlace.class, new DuplicateRotPlace(player))
.put(LineOfSightPlace.class, new LineOfSightPlace(player))
.put(GhostBlockMitigation.class, new GhostBlockMitigation(player))
.build();
@@ -219,6 +243,11 @@ public class CheckManager {
.put(PositionBreakB.class, new PositionBreakB(player))
.build();
// TODO put all modules with no listeners here
ClassToInstanceMap<AbstractCheck> noneModules = new ImmutableClassToInstanceMap.Builder<AbstractCheck>()
.put(HitboxDebugHandler.class, new HitboxDebugHandler(player))
.build();
allChecks = new ImmutableClassToInstanceMap.Builder<AbstractCheck>()
.putAll(packetChecks)
.putAll(positionCheck)
@@ -228,6 +257,7 @@ public class CheckManager {
.putAll(blockPlaceCheck)
.putAll(prePredictionChecks)
.putAll(blockBreakChecks)
.putAll(noneModules)
.build();
init();
@@ -338,6 +368,10 @@ public class CheckManager {
}
}
public <T extends AbstractCheck> T getCheck(Class<T> check) {
return (T) allChecks.get(check);
}
public void onPostFlyingBlockBreak(final BlockBreak blockBreak) {
for (BlockBreakCheck check : blockBreakChecks.values()) {
check.onPostFlyingBlockBreak(blockBreak);
@@ -353,6 +387,11 @@ public class CheckManager {
return (T) packetChecks.get(check);
}
@SuppressWarnings("unchecked")
public <T extends BlockPlaceCheck> T getBlockPlaceCheck(Class<T> check) {
return (T) blockPlaceCheck.get(check);
}
@SuppressWarnings("unchecked")
public <T extends PacketCheck> T getPrePredictionCheck(Class<T> check) {
return (T) prePredictionChecks.get(check);
@@ -5,10 +5,14 @@ import ac.grim.grimac.manager.init.Initable;
import ac.grim.grimac.manager.init.load.PacketEventsInit;
import ac.grim.grimac.manager.init.start.*;
import ac.grim.grimac.manager.init.stop.TerminatePacketEvents;
import ac.grim.grimac.utils.anticheat.LogUtil;
import ac.grim.grimac.utils.anticheat.MessageUtil;
import com.google.common.collect.ImmutableList;
import lombok.Getter;
import java.io.PrintWriter;
import java.io.StringWriter;
public class InitManager {
private final ImmutableList<Initable> initializersOnLoad;
@@ -38,6 +42,7 @@ public class InitManager {
.add(new PacketLimiter())
.add(GrimAPI.INSTANCE.getDiscordManager())
.add(GrimAPI.INSTANCE.getSpectateManager())
.add(GrimAPI.INSTANCE.getViolationDatabaseManager())
.add(new JavaVersion())
.add(new ViaVersion())
.add(new TAB())
@@ -72,7 +77,12 @@ public class InitManager {
try {
initable.start();
} catch (Exception e) {
e.printStackTrace();
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String stackTrace = sw.toString();
LogUtil.error("Failed to stop initializer: " + initable.getClass().getName() + stackTrace);
}
}
@@ -143,6 +143,10 @@ public class PunishmentManager implements ConfigReloadable {
if (command.command.equals("[webhook]")) {
GrimAPI.INSTANCE.getDiscordManager().sendAlert(player, verbose, check.getDisplayName(), vl);
} else if (command.command.equals("[log]")) {
int vls = (int) group.violations.values().stream().filter((e) -> e == check).count();
String verboseWithoutGl = verbose.replaceAll(" /gl .*", "");
GrimAPI.INSTANCE.getViolationDatabaseManager().logAlert(player, verboseWithoutGl, check.getDisplayName(), vls);
} else if (command.command.equals("[proxy]")) {
ProxyAlertMessenger.sendPluginMessage(replaceAlertPlaceholders(command.command, vl, check, proxyAlertString, verbose));
} else {
@@ -111,8 +111,7 @@ public class SetbackTeleportUtil extends Check implements PostPredictionCheck {
// Setbacks aren't allowed
if (player.disableGrim) return true;
// Player has permission to cheat, permission not given to OP by default.
if (player.bukkitPlayer != null && player.noSetbackPermission) return true;
return false;
return player.bukkitPlayer != null && player.noSetbackPermission;
}
private void simulateFriction(Vector vector) {
@@ -88,5 +88,14 @@ public class SpectateManager implements Initable {
spectatingPlayers.remove(uuid);
}
private record PreviousState(org.bukkit.GameMode gameMode, Location location) {}
private static class PreviousState {
public PreviousState(org.bukkit.GameMode gameMode, Location location) {
this.gameMode = gameMode;
this.location = location;
}
private final org.bukkit.GameMode gameMode;
private final Location location;
}
}
@@ -34,6 +34,7 @@ public class ConfigManagerFileImpl implements ConfigManager, BasicReloadable {
GrimAPI.INSTANCE.getPlugin().getDataFolder().mkdirs();
if (!initialized) {
initialized = true;
upgrade();
config.addSource(GrimAC.class, "config", getConfigFile("config.yml"));
config.addSource(GrimAC.class, "messages", getConfigFile("messages.yml"));
config.addSource(GrimAC.class, "discord", getConfigFile("discord.yml"));
@@ -83,7 +84,7 @@ public class ConfigManagerFileImpl implements ConfigManager, BasicReloadable {
configVersion = Integer.parseInt(configStringVersion);
// TODO: Do we have to hardcode this?
configString = configString.replaceAll("config-version: " + configStringVersion, "config-version: 9");
configString = configString.replaceAll("config-version: " + configStringVersion, "config-version: 10");
Files.write(config.toPath(), configString.getBytes());
upgradeModernConfig(config, configString, configVersion);
@@ -125,6 +126,9 @@ public class ConfigManagerFileImpl implements ConfigManager, BasicReloadable {
if (configVersion < 9) {
newOffsetHandlingAntiKB(config, configString);
}
if (configVersion < 10) {
addInventoryPunishments();
}
}
private void removeLegacyTwoPointOne(File config) throws IOException {
@@ -175,6 +179,28 @@ public class ConfigManagerFileImpl implements ConfigManager, BasicReloadable {
}
}
private void addInventoryPunishments() {
File config = new File(GrimAPI.INSTANCE.getPlugin().getDataFolder(), "punishments.yml");
String configString;
if (config.exists()) {
try {
configString = new String(Files.readAllBytes(config.toPath()));
// If it works, it isn't stupid. Only replace it if it exactly matches the default config.
String reachSection = " Reach:";
String inventorySection = " Inventory:\n remove-violations-after: 300\n checks:\n - \"Inventory\"\n commands:\n - \"10:10 [alert]\"\n - \"20:20 [webhook]\"\n - \"20:20 [proxy]\"\n";
int index = configString.indexOf(reachSection);
if (index != -1) {
configString = configString.substring(0, index) + inventorySection + configString.substring(index);
}
Files.write(config.toPath(), configString.getBytes());
} catch (IOException ignored) {
}
}
}
private void fixBadPacketsAndAdjustPingConfig(File config, String configString) {
try {
configString = configString.replaceAll("max-ping: \\d+", "max-transaction-time: 60");
@@ -11,15 +11,31 @@ import com.github.retrooper.packetevents.protocol.item.enchantment.type.Enchantm
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.particle.type.ParticleTypes;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.PEVersion;
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
import java.util.concurrent.Executors;
public class PacketEventsInit implements Initable {
PEVersion NEWEST_UNSUPPORTED_PE_VERSION = new PEVersion(2, 7, 0);
@Override
public void start() {
LogUtil.info("Loading PacketEvents...");
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(GrimAPI.INSTANCE.getPlugin()));
if (!checkPacketEventsVersion()) {
GrimAPI.INSTANCE.signalCriticalFailure();
throw new RuntimeException("\n" +
"******************************************************\n" +
"GrimAC requires PacketEvents > " + NEWEST_UNSUPPORTED_PE_VERSION + "\n" +
"Please update PacketEvents to a compatible version.\n" +
"This is a critical error. GrimAC will be disabled.\n" +
"*****************************************************");
}
PacketEvents.getAPI().getSettings()
.fullStackTrace(true)
.kickOnPacketException(true)
@@ -27,6 +43,7 @@ public class PacketEventsInit implements Initable {
.reEncodeByDefault(false)
.debug(false);
PacketEvents.getAPI().load();
// This may seem useless, but it causes java to start loading stuff async before we need it
Executors.defaultThreadFactory().newThread(() -> {
StateTypes.AIR.getName();
@@ -38,4 +55,9 @@ public class PacketEventsInit implements Initable {
ParticleTypes.DUST.getName();
}).start();
}
private boolean checkPacketEventsVersion() {
PEVersion peVersion = PacketEvents.getAPI().getVersion();
return peVersion.isNewerThan(NEWEST_UNSUPPORTED_PE_VERSION);
}
}
@@ -4,7 +4,6 @@ import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.commands.*;
import ac.grim.grimac.manager.init.Initable;
import co.aikar.commands.PaperCommandManager;
import org.bukkit.Bukkit;
public class CommandRegister implements Initable {
@Override
@@ -27,11 +26,8 @@ public class CommandRegister implements Initable {
commandManager.registerCommand(new GrimVersion());
commandManager.registerCommand(new GrimDump());
commandManager.registerCommand(new GrimBrands());
commandManager.registerCommand(new GrimHistory());
commandManager.getCommandCompletions().registerCompletion("stopspectating", GrimStopSpectating.completionHandler);
if (GrimAPI.INSTANCE.getConfigManager().getConfig().getBooleanElse("check-for-updates", true)) {
GrimVersion.checkForUpdatesAsync(Bukkit.getConsoleSender());
}
}
}
@@ -18,6 +18,7 @@ public class PacketManager implements Initable {
PacketEvents.getAPI().getEventManager().registerListener(new PacketPlayerJoinQuit());
PacketEvents.getAPI().getEventManager().registerListener(new PacketPingListener());
PacketEvents.getAPI().getEventManager().registerListener(new PacketPlayerWindow());
PacketEvents.getAPI().getEventManager().registerListener(new PacketPlayerDigging());
PacketEvents.getAPI().getEventManager().registerListener(new PacketPlayerAttack());
PacketEvents.getAPI().getEventManager().registerListener(new PacketEntityAction());
@@ -8,9 +8,7 @@ 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.*;
import java.util.function.Function;
public class PlaceholderAPIExpansion extends PlaceholderExpansion {
@@ -37,7 +35,7 @@ public class PlaceholderAPIExpansion extends PlaceholderExpansion {
public @NotNull List<String> getPlaceholders() {
Set<String> placeholders = GrimAPI.INSTANCE.getExternalAPI().getStaticReplacements().keySet();
placeholders.addAll(GrimAPI.INSTANCE.getExternalAPI().getVariableReplacements().keySet());
return List.copyOf(placeholders);
return Collections.unmodifiableList(new ArrayList<>(placeholders));
}
@Override
@@ -51,7 +49,8 @@ public class PlaceholderAPIExpansion extends PlaceholderExpansion {
}
}
if (offlinePlayer instanceof Player player) {
if (offlinePlayer instanceof Player) {
Player player = (Player) offlinePlayer;
GrimPlayer grimPlayer = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(player);
if (grimPlayer == null) return null;
@@ -76,7 +76,7 @@ public class TickEndEvent implements Initable, Listener {
// 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) {
List<?> wrapper = Collections.synchronizedList(new HookedListWrapper<Object>(endOfTickObject) {
@Override
public void onIterator() {
tickAllPlayers();
@@ -13,9 +13,15 @@ public class ExemptElytraFeature extends GrimFeature {
@Override
public void setState(GrimPlayer player, ConfigManager config, FeatureState state) {
switch (state) {
case ENABLED -> player.setExemptElytra(true);
case DISABLED -> player.setExemptElytra(false);
default -> player.setExemptElytra(isEnabledInConfig(player, config));
case ENABLED:
player.setExemptElytra(true);
break;
case DISABLED:
player.setExemptElytra(false);
break;
default:
player.setExemptElytra(isEnabledInConfig(player, config));
break;
}
}
@@ -13,9 +13,15 @@ public class ExperimentalChecksFeature extends GrimFeature {
@Override
public void setState(GrimPlayer player, ConfigManager config, FeatureState state) {
switch (state) {
case ENABLED -> player.setExperimentalChecks(true);
case DISABLED -> player.setExperimentalChecks(false);
default -> player.setExperimentalChecks(isEnabledInConfig(player, config));
case ENABLED:
player.setExperimentalChecks(true);
break;
case DISABLED:
player.setExperimentalChecks(false);
break;
default:
player.setExperimentalChecks(isEnabledInConfig(player, config));
break;
}
}
@@ -6,7 +6,7 @@ import ac.grim.grimac.player.GrimPlayer;
public class ClearRecentlyUpdatedBlocks implements Tickable {
private static final int maxTickAge = 2;
private static final int maxTickAge = 3;
@Override
public void tick() {
@@ -0,0 +1,121 @@
package ac.grim.grimac.manager.violationdatabase;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.player.GrimPlayer;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.bukkit.plugin.Plugin;
import java.sql.*;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
public class MySQLViolationDatabase implements ViolationDatabase {
private final Plugin plugin;
private HikariDataSource dataSource;
public MySQLViolationDatabase(Plugin plugin, String url, String database, String username, String password) {
this.plugin = plugin;
setupDataSource(url, database, username, password);
}
private void setupDataSource(String url, String database, String username, String password) {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://" + url + "/" + database);
config.setUsername(username);
config.setPassword(password);
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
config.setMaximumPoolSize(10);
config.setAutoCommit(true);
dataSource = new HikariDataSource(config);
}
@Override
public void connect() {
try (Connection connection = dataSource.getConnection()) {
connection.prepareStatement(
"CREATE TABLE IF NOT EXISTS violations(" +
"id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, " +
"server VARCHAR(255) NOT NULL, " +
"uuid CHAR(36) NOT NULL, " +
"check_name TEXT NOT NULL, " +
"verbose TEXT NOT NULL, " +
"vl INTEGER NOT NULL, " +
"created_at BIGINT NOT NULL" +
")"
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_violations_uuid ON violations(uuid);"
).execute();
} catch (SQLException ex) {
plugin.getLogger().log(Level.SEVERE, "Failed to generate violations database:", ex);
}
}
@Override
public synchronized void logAlert(GrimPlayer player, String verbose, String checkName, int vls) {
try (Connection connection = dataSource.getConnection();
PreparedStatement insertAlert = connection.prepareStatement(
"INSERT INTO violations (server, uuid, check_name, verbose, vl, created_at) VALUES (?, ?, ?, ?, ?, ?)"
)
) {
insertAlert.setString(1, GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("history.server-name", "Prison"));
insertAlert.setString(2, player.getUniqueId().toString());
insertAlert.setString(3, checkName);
insertAlert.setString(4, verbose);
insertAlert.setInt(5, vls);
insertAlert.setLong(6, System.currentTimeMillis());
insertAlert.execute();
} catch (SQLException ex) {
plugin.getLogger().log(Level.SEVERE, "Failed to log alert", ex);
}
}
@Override
public synchronized int getLogCount(UUID player) {
try (Connection connection = dataSource.getConnection();
PreparedStatement countLogs = connection.prepareStatement(
"SELECT COUNT(*) FROM violations WHERE uuid = ?"
)
) {
countLogs.setString(1, player.toString());
ResultSet result = countLogs.executeQuery();
if (result.next()) {
return result.getInt(1);
}
} catch (SQLException ex) {
plugin.getLogger().log(Level.SEVERE, "Failed to count logs", ex);
}
return 0;
}
@Override
public synchronized List<Violation> getViolations(UUID player, int page, int limit) {
try (Connection connection = dataSource.getConnection();
PreparedStatement fetchLogs = connection.prepareStatement(
"SELECT server, uuid, check_name, verbose, vl, created_at FROM violations" +
" WHERE uuid = ? ORDER BY created_at DESC LIMIT ? OFFSET ?"
)
) {
fetchLogs.setString(1, player.toString());
fetchLogs.setInt(2, limit);
fetchLogs.setInt(3, (page - 1) * limit);
return Violation.fromResultSet(fetchLogs.executeQuery());
} catch (SQLException ex) {
plugin.getLogger().log(Level.SEVERE, "Failed to fetch logs", ex);
return null;
}
}
@Override
public void disconnect() {
if (dataSource != null && !dataSource.isClosed()) {
dataSource.close();
}
}
}
@@ -0,0 +1,135 @@
package ac.grim.grimac.manager.violationdatabase;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.player.GrimPlayer;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
public class SQLiteViolationDatabase implements ViolationDatabase {
private final Plugin plugin;
private Connection openConnection;
public SQLiteViolationDatabase(@NotNull Plugin plugin) {
this.plugin = plugin;
}
@Override
public void connect() {
try {
// Init sqlite
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
plugin.getLogger().log(Level.SEVERE, "Could not load SQLite driver", e);
}
try (Connection connection = getConnection()) {
connection.prepareStatement(
"CREATE TABLE IF NOT EXISTS violations(" +
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " +
"server VARCHAR(255) NOT NULL, " +
"uuid CHARACTER(36) NOT NULL, " +
"check_name TEXT NOT NULL, " +
"verbose TEXT NOT NULL, " +
"vl INTEGER NOT NULL, " +
"created_at BIGINT NOT NULL" +
")"
).execute();
connection.prepareStatement(
"CREATE INDEX IF NOT EXISTS idx_violations_uuid ON violations(uuid)"
).execute();
} catch (SQLException ex) {
plugin.getLogger().log(Level.SEVERE, "Failed to generate violations database:", ex);
}
}
@Override
public synchronized void logAlert(GrimPlayer player, String verbose, String checkName, int vls) {
try (
Connection connection = getConnection();
PreparedStatement insertLog = connection.prepareStatement(
"INSERT INTO violations (server, uuid, check_name, verbose, vl, created_at) VALUES (?, ?, ?, ?, ?, ?)"
)
) {
insertLog.setString(1, GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("history.server-name", "Prison"));
insertLog.setString(2, player.getUniqueId().toString());
insertLog.setString(3, verbose);
insertLog.setString(4, checkName);
insertLog.setInt(5, vls);
insertLog.setLong(6, System.currentTimeMillis());
insertLog.executeUpdate();
} catch (SQLException ex) {
plugin.getLogger().log(Level.SEVERE, "Failed to insert violation:", ex);
}
}
public synchronized int getLogCount(UUID player) {
try (
Connection connection = getConnection();
PreparedStatement fetchLogs = connection.prepareStatement(
"SELECT COUNT(*) FROM violations WHERE uuid = ?"
)
) {
fetchLogs.setString(1, player.toString());
ResultSet resultSet = fetchLogs.executeQuery();
if (resultSet.next()) {
return resultSet.getInt(1);
}
} catch (SQLException ex) {
plugin.getLogger().log(Level.SEVERE, "Failed to fetch number of violations:", ex);
}
return 0;
}
@Override
public synchronized List<Violation> getViolations(UUID player, int page, int limit) {
List<Violation> violations = new ArrayList<>();
try (
Connection connection = getConnection();
PreparedStatement fetchLogs = connection.prepareStatement(
"SELECT server, uuid, check_name, verbose, vl, created_at FROM violations" +
" WHERE uuid = ? ORDER BY created_at DESC LIMIT ? OFFSET ?"
)
) {
fetchLogs.setString(1, player.toString());
fetchLogs.setInt(2, limit);
fetchLogs.setInt(3, (page - 1) * limit);
return Violation.fromResultSet(fetchLogs.executeQuery());
} catch (SQLException ex) {
plugin.getLogger().log(Level.SEVERE, "Failed to fetch violations:", ex);
}
return violations;
}
@Override
public void disconnect() {
try {
if (openConnection != null && !openConnection.isClosed()) {
openConnection.close();
}
} catch (SQLException ex) {
plugin.getLogger().log(Level.SEVERE, "Failed to close connection", ex);
}
}
protected synchronized Connection getConnection() throws SQLException {
if (openConnection == null || openConnection.isClosed()) {
openConnection = openConnection();
}
return openConnection;
}
protected Connection openConnection() throws SQLException {
return DriverManager.getConnection("jdbc:sqlite:" + plugin.getDataFolder().getAbsolutePath() + File.separator + "violations.sqlite");}
}
@@ -0,0 +1,38 @@
package ac.grim.grimac.manager.violationdatabase;
import lombok.Data;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
@Data
public class Violation {
private final String serverName;
private final UUID playerUUID;
private final String checkName;
private final String verbose;
private final int vl;
private final Date createdAt;
public static List<Violation> fromResultSet(ResultSet resultSet) throws SQLException {
List<Violation> violations = new ArrayList<>();
while(resultSet.next()) {
String server = resultSet.getString("server");
UUID player = UUID.fromString(resultSet.getString("uuid"));
String checkName = resultSet.getString("check_name");
String verbose = resultSet.getString("verbose");
int vl = resultSet.getInt("vl");
Date createdAt = new Date(resultSet.getLong("created_at"));
violations.add(new Violation(server, player, checkName, verbose, vl, createdAt));
}
return violations;
}
}
@@ -0,0 +1,20 @@
package ac.grim.grimac.manager.violationdatabase;
import ac.grim.grimac.player.GrimPlayer;
import java.util.List;
import java.util.UUID;
public interface ViolationDatabase {
void connect();
void logAlert(GrimPlayer player, String verbose, String checkName, int vls);
int getLogCount(UUID player);
List<Violation> getViolations(UUID player, int page, int limit);
void disconnect();
}
@@ -0,0 +1,58 @@
package ac.grim.grimac.manager.violationdatabase;
import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.api.config.ConfigManager;
import ac.grim.grimac.manager.init.Initable;
import ac.grim.grimac.player.GrimPlayer;
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
import org.bukkit.plugin.Plugin;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
public class ViolationDatabaseManager implements Initable {
private final Plugin plugin;
private ViolationDatabase database;
public ViolationDatabaseManager(Plugin plugin) {
this.plugin = plugin;
}
@Override
public void start() {
ConfigManager config = GrimAPI.INSTANCE.getConfigManager().getConfig();
String dbType = config.getStringElse("history.database.type", "SQLITE").toUpperCase();
if (dbType.equals("SQLITE")) {
this.database = new SQLiteViolationDatabase(plugin);
} else if (dbType.equals("MYSQL")) {
String url = config.getStringElse("history.database.host", "jdbc:mysql://localhost:3306/");
String database = config.getStringElse("history.database.database", "grimac");
String username = config.getStringElse("history.database.username", "root");
String password = config.getStringElse("history.database.password", "password");
this.database = new MySQLViolationDatabase(plugin, url, database, username, password);
} else {
this.database = new SQLiteViolationDatabase(plugin);
plugin.getLogger().log(Level.SEVERE, "Invalid database type: " + dbType + ". Defaulting to SQLite");
}
this.database.connect();
}
public void logAlert(GrimPlayer player, String verbose, String checkName, int vls) {
FoliaScheduler.getAsyncScheduler().runNow(plugin, __ -> database.logAlert(player, verbose, checkName, vls));
}
public int getLogCount(UUID player) {
return database.getLogCount(player);
}
public List<Violation> getViolations(UUID player, int page, int limit) {
return database.getViolations(player, page, limit);
}
}
@@ -9,7 +9,8 @@ import ac.grim.grimac.api.handler.ResyncHandler;
import ac.grim.grimac.checks.Check;
import ac.grim.grimac.checks.impl.aim.processor.AimProcessor;
import ac.grim.grimac.checks.impl.misc.ClientBrand;
import ac.grim.grimac.checks.impl.misc.TransactionOrder;
import ac.grim.grimac.checks.impl.packetorder.PacketOrderD;
import ac.grim.grimac.checks.impl.packetorder.PacketOrderProcessor;
import ac.grim.grimac.events.packets.CheckManagerListener;
import ac.grim.grimac.manager.*;
import ac.grim.grimac.manager.player.features.FeatureManagerImpl;
@@ -28,11 +29,13 @@ import ac.grim.grimac.utils.data.packetentity.PacketEntitySelf;
import ac.grim.grimac.utils.data.tags.SyncedTags;
import ac.grim.grimac.utils.enums.FluidTag;
import ac.grim.grimac.utils.enums.Pose;
import ac.grim.grimac.utils.inventory.InventoryDesyncStatus;
import ac.grim.grimac.utils.latency.*;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.math.TrigHandler;
import ac.grim.grimac.utils.nmsutil.BlockProperties;
import ac.grim.grimac.utils.nmsutil.GetBoundingBox;
import ac.grim.grimac.utils.nmsutil.ReachUtils;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
@@ -106,6 +109,7 @@ public class GrimPlayer implements GrimUser {
// End manager like classes
public Vector clientVelocity = new Vector();
PacketTracker packetTracker;
public final PacketOrderProcessor packetOrderProcessor = new PacketOrderProcessor(this);
private long transactionPing = 0;
public long lastTransSent = 0;
public long lastTransReceived = 0;
@@ -221,6 +225,9 @@ public class GrimPlayer implements GrimUser {
// possibleEyeHeights[0] = Standing eye heights, [1] = Sneaking. [2] = Elytra, Swimming, and Riptide Trident which only exists in 1.9+
public double[][] possibleEyeHeights = new double[3][];
public int totalFlyingPacketsSent;
public boolean hasInventoryOpen;
public long lastInventoryOpen;
public InventoryDesyncStatus inventoryDesyncStatus;
public Queue<BlockPlaceSnapshot> placeUseItemPackets = new LinkedBlockingQueue<>();
public Queue<BlockBreak> queuedBreaks = new LinkedBlockingQueue<>();
public PlayerBlockHistory blockHistory = new PlayerBlockHistory();
@@ -360,7 +367,7 @@ public class GrimPlayer implements GrimUser {
if (packetTracker != null) packetTracker.setIntervalPackets(packetTracker.getIntervalPackets() - 1);
if (skipped > 0 && System.currentTimeMillis() - joinTime > 5000)
checkManager.getPacketCheck(TransactionOrder.class).flagAndAlert("skipped: " + skipped);
checkManager.getPacketCheck(PacketOrderD.class).flagAndAlert("skipped: " + skipped);
do {
data = transactionsSent.poll();
@@ -466,7 +473,8 @@ public class GrimPlayer implements GrimUser {
public void disconnect(Component reason) {
String textReason;
if (reason instanceof TranslatableComponent translatableComponent) {
if (reason instanceof TranslatableComponent) {
TranslatableComponent translatableComponent = (TranslatableComponent) reason;
textReason = translatableComponent.key();
} else {
textReason = LegacyComponentSerializer.legacySection().serialize(reason);
@@ -571,7 +579,7 @@ public class GrimPlayer implements GrimUser {
public ClientVersion getClientVersion() {
ClientVersion ver = user.getClientVersion();
// If temporarily null, assume server version...
return Objects.requireNonNullElseGet(ver, () -> ClientVersion.getById(PacketEvents.getAPI().getServerManager().getVersion().getProtocolVersion()));
return ver != null ? ver : ClientVersion.getById(PacketEvents.getAPI().getServerManager().getVersion().getProtocolVersion());
}
// Alright, someone at mojang decided to not send a flying packet every tick with 1.9
@@ -607,15 +615,60 @@ public class GrimPlayer implements GrimUser {
return this.isSneaking ? this.possibleEyeHeights[1] : this.possibleEyeHeights[0];
} else {
// 1.8 players just have their pose set to standing all the time
return switch (pose) {
case FALL_FLYING, // Elytra gliding
SPIN_ATTACK, // Riptide trident
SWIMMING -> // Swimming (includes crawling in 1.14+)
this.possibleEyeHeights[2]; // [swimming/gliding/riptide height, standing height, sneaking height]
case NINE_CROUCHING, CROUCHING -> this.possibleEyeHeights[1]; // [sneaking height, standing height, swimming/gliding/riptide height]
default -> this.possibleEyeHeights[0]; // [standing height, sneaking height, swimming/gliding/riptide height]
switch (pose) {
case FALL_FLYING: // Elytra gliding
case SPIN_ATTACK: // Riptide trident
case SWIMMING: // Swimming (includes crawling in 1.14+)
return this.possibleEyeHeights[2]; // [swimming/gliding/riptide height, standing height, sneaking height]
case NINE_CROUCHING:
case CROUCHING:
return this.possibleEyeHeights[1]; // [sneaking height, standing height, swimming/gliding/riptide height]
default:
return this.possibleEyeHeights[0]; // [standing height, sneaking height, swimming/gliding/riptide height]
}
}
}
// 1.8-1.10.2 specific mouse delay fix (MC-67665)
// https://bugs.mojang.com/browse/MC-67665
// 1.9-1.21.1 specific desync due to skipped ticks
// Players can be a tick behind on both pitch and yaw together
// 1.21.2+ added end tick input packet, fixing skipped tick issues
public Vector[] getPossibleLookVectors(boolean isPrediction) {
// If we are a tick behind, we don't know their next look so only use current
if (isPrediction) {
return new Vector[]{ReachUtils.getLook(this, this.xRot, this.yRot)};
}
// 1.9-1.10.2: All three vectors (normal, mouse delay, tick desync)
if (this.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) &&
this.getClientVersion().isOlderThan(ClientVersion.V_1_11)) {
return new Vector[]{
ReachUtils.getLook(this, this.xRot, this.yRot),
ReachUtils.getLook(this, this.lastXRot, this.yRot),
ReachUtils.getLook(this, this.lastXRot, this.lastYRot)
};
}
// 1.11-1.21.1: Two vectors (normal, tick desync)
else if (this.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_11) &&
this.getClientVersion().isOlderThan(ClientVersion.V_1_21_2)) {
return new Vector[]{
ReachUtils.getLook(this, this.xRot, this.yRot),
ReachUtils.getLook(this, this.lastXRot, this.lastYRot)
};
}
// 1.8: Two vectors (normal, mouse delay)
else if (this.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_8) &&
this.getClientVersion().isOlderThan(ClientVersion.V_1_9)) {
return new Vector[]{
ReachUtils.getLook(this, this.xRot, this.yRot),
ReachUtils.getLook(this, this.lastXRot, this.yRot)
};
}
// 1.7 and 1.21.2+: Just normal vector
else {
return new Vector[]{ReachUtils.getLook(this, this.xRot, this.yRot)};
}
}
@Override
@@ -260,7 +260,8 @@ public class MovementCheckRunner extends Check implements PositionCheck {
// When in control of the entity, the player sets the entity position to their current position
riding.setPositionRaw(player, new SimpleCollisionBox(player.x, player.y, player.z, player.x, player.y, player.z));
if (riding instanceof PacketEntityTrackXRot boat) {
if (riding instanceof PacketEntityTrackXRot) {
PacketEntityTrackXRot boat = (PacketEntityTrackXRot) riding;
boat.packetYaw = player.xRot;
boat.interpYaw = player.xRot;
boat.steps = 0;
@@ -17,6 +17,7 @@ import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes;
import org.bukkit.util.Vector;
import java.util.NoSuchElementException;
import java.util.Optional;
public final class PlayerBaseTick {
@@ -142,11 +143,12 @@ public final class PlayerBaseTick {
// Pre-1.17 clients don't have powder snow and therefore don't desync
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_16_4)) return;
final ValuedAttribute playerSpeed = player.compensatedEntities.self.getAttribute(Attributes.MOVEMENT_SPEED).orElseThrow();
final ValuedAttribute playerSpeed = player.compensatedEntities.self.getAttribute(Attributes.MOVEMENT_SPEED).orElseThrow(() -> new NoSuchElementException("No value present"));
// Might be null after respawn?
final Optional<WrapperPlayServerUpdateAttributes.Property> property = playerSpeed.property();
if (property.isEmpty()) return;
if (!property.isPresent()) return;
// The client first desync's this attribute
property.get().getModifiers().removeIf(modifier -> modifier.getUUID().equals(CompensatedEntities.SNOW_MODIFIER_UUID) || modifier.getName().getKey().equals("powder_snow"));
@@ -356,12 +358,22 @@ public final class PlayerBaseTick {
double d7 = direction2 == BlockFace.WEST || direction2 == BlockFace.EAST ? relativeXMovement : relativeZMovement;
d6 = direction2 == BlockFace.EAST || direction2 == BlockFace.SOUTH ? 1.0 - d7 : d7;
// d7 and d6 flip the movement direction based on desired movement direction
boolean doesSuffocate = switch (direction2) {
case EAST -> suffocatesAt(player, blockX + 1, blockZ);
case WEST -> suffocatesAt(player, blockX - 1, blockZ);
case NORTH -> suffocatesAt(player, blockX, blockZ - 1);
default -> suffocatesAt(player, blockX, blockZ + 1);
};
boolean doesSuffocate;
switch (direction2) {
case EAST:
doesSuffocate = suffocatesAt(player, blockX + 1, blockZ);
break;
case WEST:
doesSuffocate = suffocatesAt(player, blockX - 1, blockZ);
break;
case NORTH:
doesSuffocate = suffocatesAt(player, blockX, blockZ - 1);
break;
case SOUTH:
default:
doesSuffocate = suffocatesAt(player, blockX, blockZ + 1);
break;
}
if (d6 >= lowestValue || doesSuffocate) continue;
lowestValue = d6;
@@ -1,5 +1,6 @@
package ac.grim.grimac.predictionengine;
import ac.grim.grimac.checks.impl.combat.Reach;
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.predictionengine.predictions.PredictionEngine;
import ac.grim.grimac.utils.collisions.CollisionData;
@@ -16,6 +17,7 @@ import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.util.Vector3i;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.util.Vector;
@@ -104,6 +106,7 @@ public class PointThreeEstimator {
private boolean isNearHorizontalFlowingLiquid = false; // We can't calculate the direction, only a toggle
private boolean isNearVerticalFlowingLiquid = false; // We can't calculate exact values, once again a toggle
private boolean isNearBubbleColumn = false; // We can't calculate exact values once again
public boolean isNearNetherPortal = false; // We can't calculate exact values once again
private int maxPositiveLevitation = Integer.MIN_VALUE; // Positive potion effects [0, 128]
private int minNegativeLevitation = Integer.MAX_VALUE; // Negative potion effects [-127, -1]r
@@ -152,6 +155,9 @@ public class PointThreeEstimator {
isNearFluid = true;
}
player.checkManager.getPacketCheck(Reach.class).handleBlockChange(new Vector3i(x, y, z), state);
if (pointThreeBox.isIntersected(new SimpleCollisionBox(x, y, z))) {
// https://github.com/MWHunter/Grim/issues/613
int controllingEntityId = player.inVehicle() ? player.getRidingVehicleId() : player.entityID;
@@ -247,6 +253,7 @@ public class PointThreeEstimator {
isNearClimbable = false;
isNearBubbleColumn = false;
isNearFluid = false;
isNearNetherPortal = false;
// Check for flowing water
Collisions.hasMaterial(player, pointThreeBox, (pair) -> {
@@ -268,6 +275,10 @@ public class PointThreeEstimator {
isNearFluid = true;
}
if (state.getType() == StateTypes.NETHER_PORTAL) {
isNearNetherPortal = true;
}
return false;
});
}
@@ -305,7 +305,8 @@ public class UncertaintyHandler {
// This is the end of that section.
// I can't figure out how the client exactly tracks boost time
if (player.compensatedEntities.self.getRiding() instanceof PacketEntityRideable vehicle) {
if (player.compensatedEntities.self.getRiding() instanceof PacketEntityRideable) {
PacketEntityRideable vehicle = (PacketEntityRideable) player.compensatedEntities.self.getRiding();
if (vehicle.currentBoostTime < vehicle.boostTimeMax + 20)
offset -= 0.01;
}
@@ -14,6 +14,7 @@ import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUp
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.NoSuchElementException;
public class MovementTickerStrider extends MovementTickerRideable {
@@ -61,7 +62,7 @@ public class MovementTickerStrider extends MovementTickerRideable {
// Client desyncs the attribute
// Again I don't know when this was changed, or whether it always existed, so I will just put it behind 1.20+
final ValuedAttribute movementSpeedAttr = strider.getAttribute(Attributes.MOVEMENT_SPEED).orElseThrow();
final ValuedAttribute movementSpeedAttr = strider.getAttribute(Attributes.MOVEMENT_SPEED).orElseThrow(() -> new NoSuchElementException("Attribute not found"));
float updatedMovementSpeed = (float) movementSpeedAttr.get();
if (newSpeed) {
final WrapperPlayServerUpdateAttributes.Property lastProperty = movementSpeedAttr.property().orElse(null);
@@ -424,52 +424,63 @@ public class PredictionEngine {
// Order priority (to avoid false positives and false flagging future predictions):
// Knockback and explosions
// 0.03 ticks
// Movement without input
// Normal movement
// First bread knockback and explosions
// Flagging groundspoof
// Flagging flip items
if (a.isExplosion())
aScore -= 5;
aScore -= 10;
if (a.isKnockback())
aScore -= 5;
aScore -= 10;
if (b.isExplosion())
bScore -= 5;
bScore -= 10;
if (b.isKnockback())
bScore -= 5;
bScore -= 10;
if (a.isFirstBreadExplosion())
aScore += 1;
aScore += 2;
if (b.isFirstBreadExplosion())
bScore += 1;
bScore += 2;
if (a.isFirstBreadKb())
aScore += 1;
aScore += 2;
if (b.isFirstBreadKb())
bScore += 1;
bScore += 2;
if (a.isFlipItem())
aScore += 3;
aScore += 6;
if (b.isFlipItem())
bScore += 3;
bScore += 6;
if (a.isZeroPointZeroThree())
aScore -= 1;
aScore -= 2;
if (b.isZeroPointZeroThree())
bScore -= 2;
if (a.isWithInput() || a.isJump())
aScore += 1;
else
aScore -= 1;
if (b.isWithInput() || b.isJump())
bScore += 1;
else
bScore -= 1;
// If the player is on the ground but the vector leads the player off the ground
if ((player.inVehicle() ? player.clientControlledVerticalCollision : player.onGround) && a.vector.getY() >= 0)
aScore += 2;
aScore += 4;
if ((player.inVehicle() ? player.clientControlledVerticalCollision : player.onGround) && b.vector.getY() >= 0)
bScore += 2;
bScore += 4;
if (aScore != bScore)
return Integer.compare(aScore, bScore);
@@ -756,9 +767,9 @@ public class PredictionEngine {
if (loopSlowed == 1 && !possibleLastTickOutput.isZeroPointZeroThree()) continue;
for (int strafe = strafeMin; strafe <= strafeMax; strafe++) {
for (int forward = forwardMin; forward <= forwardMax; forward++) {
VectorData result = new VectorData(possibleLastTickOutput.vector.clone()
VectorData result = new VectorData.MoveVectorData(possibleLastTickOutput.vector.clone()
.add(getMovementResultFromInput(player, transformInputsToVector(player, new Vector(strafe, 0, forward)), speed, player.xRot)),
possibleLastTickOutput, VectorData.VectorType.InputResult);
possibleLastTickOutput, VectorData.VectorType.InputResult, forward, strafe);
result = result.returnNewModified(result.vector.clone().multiply(player.stuckSpeedMultiplier), VectorData.VectorType.StuckMultiplier);
result = result.returnNewModified(handleOnClimbable(result.vector.clone(), player), VectorData.VectorType.Climbable);
// Signal that we need to flip sneaking bounding box
@@ -51,7 +51,7 @@ public class PredictionEngineNormal extends PredictionEngine {
// And 0.03 didn't affect onGround status
// The player cannot jump
final OptionalInt jumpBoost = player.compensatedEntities.getPotionLevelForPlayer(PotionTypes.JUMP_BOOST);
if (((jumpBoost.isEmpty() || jumpBoost.getAsInt() >= 0) && player.onGround) || !player.lastOnGround)
if (((!jumpBoost.isPresent() || jumpBoost.getAsInt() >= 0) && player.onGround) || !player.lastOnGround)
return;
JumpPower.jumpFromGround(player, jump);
@@ -22,9 +22,12 @@ import java.util.Set;
public final class PredictionEngineRideableUtils {
public static Set<VectorData> handleJumps(GrimPlayer player, Set<VectorData> possibleVectors) {
if (!(player.compensatedEntities.self.getRiding() instanceof PacketEntityHorse horse)) return possibleVectors;
if (!(player.compensatedEntities.self.getRiding() instanceof PacketEntityHorse)) return possibleVectors;
if (horse instanceof PacketEntityCamel camel) {
PacketEntityHorse horse = (PacketEntityHorse) player.compensatedEntities.self.getRiding();
if (horse instanceof PacketEntityCamel) {
PacketEntityCamel camel = (PacketEntityCamel) horse;
handleCamelDash(player, possibleVectors, camel);
} else {
handleHorseJumping(player, possibleVectors, horse);
@@ -40,7 +40,12 @@ public class MessageUtil {
public @NotNull String replacePlaceholders(@Nullable Object object, @NotNull String string) {
if (!hasPlaceholderAPI) return string;
return PlaceholderAPI.setPlaceholders(object instanceof OfflinePlayer player ? player : null, string);
OfflinePlayer player = null;
if (object instanceof OfflinePlayer) {
player = (OfflinePlayer) object;
}
return PlaceholderAPI.setPlaceholders(player, string);
}
public @NotNull Component replacePlaceholders(@NotNull GrimPlayer player, @NotNull Component component) {
@@ -57,13 +62,14 @@ public class MessageUtil {
// hex codes
Matcher matcher = HEX_PATTERN.matcher(string);
StringBuilder sb = new StringBuilder(string.length());
StringBuffer sb = new StringBuffer(string.length()); // this is synchronized but doesn't need to be; its easier for upstream compat though
while (matcher.find()) {
matcher.appendReplacement(sb, "<#" + matcher.group(0).replaceAll("[&§#x]", "") + ">");
}
string = matcher.appendTail(sb).toString();
matcher.appendTail(sb);
string = sb.toString();
// MiniMessage doesn't like legacy formatting codes
string = ChatColor.translateAlternateColorCodes('&', string)
@@ -9,7 +9,7 @@ import ac.grim.grimac.utils.collisions.blocks.DoorHandler;
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.ComplexCollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.HitData;
import ac.grim.grimac.utils.data.BlockHitData;
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
import ac.grim.grimac.utils.latency.CompensatedWorld;
import ac.grim.grimac.utils.math.GrimMath;
@@ -46,7 +46,7 @@ public class BlockPlace {
private static final BlockFace[] BY_2D = { BlockFace.SOUTH, BlockFace.WEST, BlockFace.NORTH, BlockFace.EAST };
static final BlockFace[] BY_3D = { BlockFace.DOWN, BlockFace.UP, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST, BlockFace.EAST };
@Setter
Vector3i blockPosition;
public Vector3i blockPosition;
@Getter
InteractionHand hand;
@Getter
@@ -60,7 +60,7 @@ public class BlockPlace {
@Getter
StateType material;
@Getter
@Nullable HitData hitData;
@Nullable BlockHitData hitData;
@Getter
int faceId;
BlockFace face;
@@ -76,7 +76,7 @@ public class BlockPlace {
// Allocated once instead of in functions to reduce new[] calls that need to be made. Since per-instance BlockPlace is always dealt with on the same thread we can use 1 buffer array
private final SimpleCollisionBox[] collisions = new SimpleCollisionBox[ComplexCollisionBox.DEFAULT_MAX_COLLISION_BOX_SIZE];
public BlockPlace(GrimPlayer player, InteractionHand hand, Vector3i blockPosition, int faceId, BlockFace face, ItemStack itemStack, HitData hitData) {
public BlockPlace(GrimPlayer player, InteractionHand hand, Vector3i blockPosition, int faceId, BlockFace face, ItemStack itemStack, BlockHitData hitData) {
this.player = player;
this.hand = hand;
this.blockPosition = blockPosition;
@@ -540,14 +540,21 @@ public class BlockPlace {
}
public Vector3i getNormalBlockFace() {
return switch (face) {
case DOWN -> new Vector3i(0, -1, 0);
case SOUTH -> new Vector3i(0, 0, 1);
case NORTH -> new Vector3i(0, 0, -1);
case WEST -> new Vector3i(-1, 0, 0);
case EAST -> new Vector3i(1, 0, 0);
default -> new Vector3i(0, 1, 0);
};
switch (face) {
default:
case UP:
return new Vector3i(0, 1, 0);
case DOWN:
return new Vector3i(0, -1, 0);
case SOUTH:
return new Vector3i(0, 0, 1);
case NORTH:
return new Vector3i(0, 0, -1);
case WEST:
return new Vector3i(-1, 0, 0);
case EAST:
return new Vector3i(1, 0, 0);
}
}
public void set(StateType material) {
@@ -24,6 +24,7 @@ import com.github.retrooper.packetevents.util.Vector3i;
import org.bukkit.util.Vector;
import java.util.*;
import java.util.stream.Collectors;
public enum BlockPlaceResult {
@@ -374,7 +375,7 @@ public enum BlockPlaceResult {
place.set();
}
}, ItemTypes.values().stream().filter(mat -> mat.getName().getKey().contains("candle_cake"))
.toList().toArray(new ItemType[0])),
.collect(Collectors.toList()).toArray(new ItemType[0])),
PISTON_BASE((player, place) -> {
WrappedBlockState piston = place.getMaterial().createBlockState(CompensatedWorld.blockVersion);
@@ -107,11 +107,17 @@ public class ConsumesBlockPlace {
Attachment attachment = bell.getAttachment();
BlockFace dir2 = BlockFace.valueOf(direction.name());
return switch (attachment) {
case FLOOR -> AxisUtil.isSameAxis(dir, dir2);
case SINGLE_WALL, DOUBLE_WALL -> !AxisUtil.isSameAxis(dir, dir2);
case CEILING -> true;
};
switch (attachment) {
case FLOOR:
return AxisUtil.isSameAxis(dir, dir2);
case SINGLE_WALL:
case DOUBLE_WALL:
return !AxisUtil.isSameAxis(dir, dir2);
case CEILING:
return true;
default:
return false;
}
} else {
return false;
}
@@ -18,42 +18,64 @@ public class BlockFaceHelper {
*/
@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;
};
switch (face) {
case NORTH:
return BlockFace.NORTH;
case SOUTH:
return BlockFace.SOUTH;
case WEST:
return BlockFace.WEST;
case EAST:
return BlockFace.EAST;
case UP:
return BlockFace.UP;
case DOWN:
return BlockFace.DOWN;
default:
return BlockFace.OTHER;
}
}
public static BlockFace getClockWise(BlockFace face) {
return switch (face) {
case NORTH -> BlockFace.EAST;
case SOUTH -> BlockFace.WEST;
case WEST -> BlockFace.NORTH;
default -> BlockFace.SOUTH;
};
switch (face) {
case NORTH:
return BlockFace.EAST;
case SOUTH:
return BlockFace.WEST;
case WEST:
return BlockFace.NORTH;
case EAST:
default:
return BlockFace.SOUTH;
}
}
public static BlockFace getPEClockWise(BlockFace face) {
return switch (face) {
case NORTH -> BlockFace.EAST;
case SOUTH -> BlockFace.WEST;
case WEST -> BlockFace.NORTH;
default -> BlockFace.SOUTH;
};
switch (face) {
case NORTH:
return BlockFace.EAST;
case SOUTH:
return BlockFace.WEST;
case WEST:
return BlockFace.NORTH;
case EAST:
default:
return BlockFace.SOUTH;
}
}
public static BlockFace getCounterClockwise(BlockFace face) {
return switch (face) {
case NORTH -> BlockFace.WEST;
case SOUTH -> BlockFace.EAST;
case WEST -> BlockFace.SOUTH;
default -> BlockFace.NORTH;
};
switch (face) {
case NORTH:
return BlockFace.WEST;
case SOUTH:
return BlockFace.EAST;
case WEST:
return BlockFace.SOUTH;
case EAST:
default:
return BlockFace.NORTH;
}
}
public Vector offset(Vector toOffset, BlockFace face) {
@@ -3,9 +3,42 @@ package ac.grim.grimac.utils.change;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.util.Vector3i;
public record BlockModification(WrappedBlockState oldBlockContents, WrappedBlockState newBlockContents,
Vector3i location, int tick,
Cause cause) {
public class BlockModification {
private final WrappedBlockState oldBlockContents;
private final WrappedBlockState newBlockContents;
private final Vector3i location;
private final int tick;
private final Cause cause;
private final long lastTransasction = -1;
public BlockModification(WrappedBlockState oldBlockContents, WrappedBlockState newBlockContents,
Vector3i location, int tick, Cause cause) {
this.oldBlockContents = oldBlockContents;
this.newBlockContents = newBlockContents;
this.location = location;
this.tick = tick;
this.cause = cause;
}
public WrappedBlockState oldBlockContents() {
return oldBlockContents;
}
public WrappedBlockState newBlockContents() {
return newBlockContents;
}
public Vector3i location() {
return location;
}
public int tick() {
return tick;
}
public Cause cause() {
return cause;
}
@Override
public String toString() {
@@ -19,6 +52,7 @@ public record BlockModification(WrappedBlockState oldBlockContents, WrappedBlock
START_DIGGING,
APPLY_BLOCK_CHANGES,
HANDLE_NETTY_SYNC_TRANSACTION,
FINISHED_DIGGING,
OTHER
}
}
@@ -1,20 +1,27 @@
package ac.grim.grimac.utils.change;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import java.util.Deque;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Tracks block modifications made by a player over time.
*/
public class PlayerBlockHistory {
private final ConcurrentLinkedDeque<BlockModification> blockHistory = new ConcurrentLinkedDeque<>();
// TODO, figure out how its possible for this to CME!
public final Deque<BlockModification> modificationQueue = new ConcurrentLinkedDeque<>();
/**
* Adds a new block modification to the history.
* @param modification The block modification to add
*/
public void add(BlockModification modification) {
blockHistory.add(modification);
modificationQueue.add(modification);
}
/**
@@ -22,8 +29,29 @@ public class PlayerBlockHistory {
* @param filter Predicate to filter modifications
* @return Filtered list of block modifications
*/
public Iterable<BlockModification> getRecentModifications(Predicate<BlockModification> filter) {
return blockHistory.stream().filter(filter).toList();
public List<BlockModification> getRecentModifications(Predicate<BlockModification> filter) {
return modificationQueue.stream().filter(filter).collect(Collectors.toList()); // Java 8+ compatible
}
public List<WrappedBlockState> getBlockStates(Predicate<BlockModification> filter) {
return modificationQueue.stream()
.filter(filter)
.flatMap(mod -> Stream.of(mod.oldBlockContents(), mod.newBlockContents()))
.collect(Collectors.toList());// Java 8+ compatible
}
public List<WrappedBlockState> getPreviousBlockStates(Predicate<BlockModification> filter) {
return modificationQueue.stream()
.filter(filter)
.map(BlockModification::oldBlockContents)
.collect(Collectors.toList());
}
public List<WrappedBlockState> getResultingBlockStates(Predicate<BlockModification> filter) {
return modificationQueue.stream()
.filter(filter)
.map(BlockModification::newBlockContents)
.collect(Collectors.toList());
}
/**
@@ -31,16 +59,18 @@ public class PlayerBlockHistory {
* @param maxTick The maximum tick age to keep
*/
public void cleanup(int maxTick) {
while (!blockHistory.isEmpty() && maxTick - blockHistory.peekFirst().tick() > 0) {
blockHistory.removeFirst();
while (!modificationQueue.isEmpty() && maxTick - modificationQueue.peekFirst().tick() > 0) {
modificationQueue.removeFirst();
}
}
// Get the size of the block history
public int size() {
return blockHistory.size();
return modificationQueue.size();
}
// Clear all block modifications
public void clear() {
blockHistory.clear();
modificationQueue.clear();
}
}
@@ -3,13 +3,51 @@ package ac.grim.grimac.utils.chunks;
import com.github.retrooper.packetevents.protocol.world.chunk.BaseChunk;
public record Column(int x, int z, BaseChunk[] chunks, int transaction) {
public class Column {
private final int x;
private final int z;
private final BaseChunk[] chunks;
private final int transaction;
// This ability was removed in 1.17 because of the extended world height
// Therefore, the size of the chunks are ALWAYS 16!
// Constructor
public Column(int x, int z, BaseChunk[] chunks, int transaction) {
this.x = x;
this.z = z;
this.chunks = chunks;
this.transaction = transaction;
}
// Getters
public int x() {
return x;
}
public int z() {
return z;
}
public BaseChunk[] chunks() {
return chunks;
}
public int transaction() {
return transaction;
}
// Method to merge chunks
public void mergeChunks(BaseChunk[] toMerge) {
for (int i = 0; i < 16; i++) {
if (toMerge[i] != null) chunks[i] = toMerge[i];
if (toMerge[i] != null) {
chunks[i] = toMerge[i];
}
}
}
@Override
public String toString() {
return String.format(
"Column{x=%d, z=%d, chunks=%s, transaction=%d}",
x, z, java.util.Arrays.toString(chunks), transaction
);
}
}
@@ -54,22 +54,36 @@ public enum AxisUtil {
}
public static AxisSelect getAxis(BlockFace face) {
return switch (face) {
case EAST -> EAST.select;
case WEST -> WEST.select;
case NORTH -> NORTH.select;
case SOUTH -> SOUTH.select;
case UP -> UP.select;
default -> DOWN.select;
};
switch (face) {
case EAST:
return EAST.select;
case WEST:
return WEST.select;
case NORTH:
return NORTH.select;
case SOUTH:
return SOUTH.select;
case UP:
return UP.select;
case DOWN:
default:
return DOWN.select;
}
}
public static boolean isSameAxis(BlockFace one, BlockFace two) {
return switch (one) {
case WEST, EAST -> two == BlockFace.WEST || two == BlockFace.EAST;
case NORTH, SOUTH -> two == BlockFace.NORTH || two == BlockFace.SOUTH;
case UP, DOWN -> two == BlockFace.UP || two == BlockFace.DOWN;
default -> false;
};
switch (one) {
case WEST:
case EAST:
return two == BlockFace.WEST || two == BlockFace.EAST;
case NORTH:
case SOUTH:
return two == BlockFace.NORTH || two == BlockFace.SOUTH;
case UP:
case DOWN:
return two == BlockFace.UP || two == BlockFace.DOWN;
default:
return false;
}
}
}
@@ -174,22 +174,30 @@ public enum CollisionData {
// Overwrite previous SKULL enum for legacy, where head and wall skull isn't separate
WALL_SKULL((player, version, data, x, y, z) -> {
return switch (data.getFacing()) {
case SOUTH -> new SimpleCollisionBox(0.25F, 0.25F, 0.0F, 0.75F, 0.75F, 0.5F, false);
case WEST -> new SimpleCollisionBox(0.5F, 0.25F, 0.25F, 1.0F, 0.75F, 0.75F, false);
case EAST -> new SimpleCollisionBox(0.0F, 0.25F, 0.25F, 0.5F, 0.75F, 0.75F, false);
default -> new SimpleCollisionBox(0.25F, 0.25F, 0.5F, 0.75F, 0.75F, 1.0F, false);
};
switch (data.getFacing()) {
case SOUTH:
return new SimpleCollisionBox(0.25F, 0.25F, 0.0F, 0.75F, 0.75F, 0.5F, false);
case WEST:
return new SimpleCollisionBox(0.5F, 0.25F, 0.25F, 1.0F, 0.75F, 0.75F, false);
case EAST:
return new SimpleCollisionBox(0.0F, 0.25F, 0.25F, 0.5F, 0.75F, 0.75F, false);
default:
return new SimpleCollisionBox(0.25F, 0.25F, 0.5F, 0.75F, 0.75F, 1.0F, false);
}
}, StateTypes.CREEPER_WALL_HEAD, StateTypes.DRAGON_WALL_HEAD, StateTypes.PLAYER_WALL_HEAD, StateTypes.ZOMBIE_WALL_HEAD,
StateTypes.SKELETON_WALL_SKULL, StateTypes.WITHER_SKELETON_WALL_SKULL),
PIGLIN_WALL_HEAD((player, version, data, x, y, z) -> {
return switch (data.getFacing()) {
case SOUTH -> new HexCollisionBox(3.0D, 4.0D, 0.0D, 13.0D, 12.0D, 8.0D);
case EAST -> new HexCollisionBox(0.0D, 4.0D, 3.0D, 8.0D, 12.0D, 13.0D);
case WEST -> new HexCollisionBox(8.0D, 4.0D, 3.0D, 16.0D, 12.0D, 13.0D);
default -> new HexCollisionBox(3.0D, 4.0D, 8.0D, 13.0D, 12.0D, 16.0D);
};
switch (data.getFacing()) {
case SOUTH:
return new HexCollisionBox(3.0D, 4.0D, 0.0D, 13.0D, 12.0D, 8.0D);
case EAST:
return new HexCollisionBox(0.0D, 4.0D, 3.0D, 8.0D, 12.0D, 13.0D);
case WEST:
return new HexCollisionBox(8.0D, 4.0D, 3.0D, 16.0D, 12.0D, 13.0D);
default:
return new HexCollisionBox(3.0D, 4.0D, 8.0D, 13.0D, 12.0D, 16.0D);
}
}, StateTypes.PIGLIN_WALL_HEAD),
DOOR(new DoorHandler(), BlockTags.DOORS.getStates().toArray(new StateType[0])),
@@ -245,9 +253,7 @@ public enum CollisionData {
return new SimpleCollisionBox(eatenPosition, 0, 0.0625, 1 - 0.0625, height, 1 - 0.0625, false);
}, StateTypes.CAKE),
COCOA_BEANS((player, version, data, x, y, z) -> {
return getCocoa(version, data.getAge(), data.getFacing());
}, StateTypes.COCOA),
COCOA_BEANS((player, version, data, x, y, z) -> getCocoa(version, data.getAge(), data.getFacing()), StateTypes.COCOA),
STONE_CUTTER((player, version, data, x, y, z) -> {
if (version.isOlderThanOrEquals(ClientVersion.V_1_13_2))
@@ -350,12 +356,16 @@ public enum CollisionData {
if (version.isOlderThanOrEquals(ClientVersion.V_1_8))
width = 2;
return switch (data.getFacing()) {
case NORTH -> new HexCollisionBox(0.0D, 0.0D, 16.0D - width, 16.0D, 16.0D, 16.0D);
case SOUTH -> new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, width);
case WEST -> new HexCollisionBox(16.0D - width, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D);
default -> new HexCollisionBox(0.0D, 0.0D, 0.0D, width, 16.0D, 16.0D);
};
switch (data.getFacing()) {
case NORTH:
return new HexCollisionBox(0.0D, 0.0D, 16.0D - width, 16.0D, 16.0D, 16.0D);
case SOUTH:
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, width);
case WEST:
return new HexCollisionBox(16.0D - width, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D);
default:
return new HexCollisionBox(0.0D, 0.0D, 0.0D, width, 16.0D, 16.0D);
}
}, StateTypes.LADDER),
CAMPFIRE((player, version, data, x, y, z) -> {
@@ -532,12 +542,16 @@ public enum CollisionData {
if (data.isOpen())
return NoCollisionBox.INSTANCE;
return switch (data.getFacing()) {
case NORTH, SOUTH -> new SimpleCollisionBox(0.0F, 0.0F, 0.375F, 1.0F, 1.5F, 0.625F, false);
case WEST, EAST -> new SimpleCollisionBox(0.375F, 0.0F, 0.0F, 0.625F, 1.5F, 1.0F, false);
default -> // This code is unreachable but the compiler does not know this
NoCollisionBox.INSTANCE;
};
switch (data.getFacing()) {
case NORTH:
case SOUTH:
return new SimpleCollisionBox(0.0F, 0.0F, 0.375F, 1.0F, 1.5F, 0.625F, false);
case WEST:
case EAST:
return new SimpleCollisionBox(0.375F, 0.0F, 0.0F, 0.625F, 1.5F, 1.0F, false);
default: // This code is unreachable but the compiler does not know this
return NoCollisionBox.INSTANCE;
}
}, BlockTags.FENCE_GATES.getStates().toArray(new StateType[0])),
FENCE(new DynamicCollisionFence(), BlockTags.FENCES.getStates().toArray(new StateType[0])),
@@ -680,9 +694,7 @@ public enum CollisionData {
0.625, 0.625, 0.625, false),
StateTypes.STRUCTURE_VOID),
END_ROD((player, version, data, x, y, z) -> {
return getEndRod(version, data.getFacing());
}, StateTypes.END_ROD, StateTypes.LIGHTNING_ROD),
END_ROD((player, version, data, x, y, z) -> getEndRod(version, data.getFacing()), StateTypes.END_ROD, StateTypes.LIGHTNING_ROD),
CAULDRON((player, version, data, x, y, z) -> {
if (version.isNewerThan(ClientVersion.V_1_13_2)) { // changed in 19w13a, 1.14 Snapshot
@@ -728,9 +740,7 @@ public enum CollisionData {
SOULSAND(new SimpleCollisionBox(0, 0, 0, 1, 0.875, 1, false),
StateTypes.SOUL_SAND),
PICKLE((player, version, data, x, y, z) -> {
return getPicklesBox(version, data.getPickles());
}, StateTypes.SEA_PICKLE),
PICKLE((player, version, data, x, y, z) -> getPicklesBox(version, data.getPickles()), StateTypes.SEA_PICKLE),
TURTLEEGG((player, version, data, x, y, z) -> {
// ViaVersion replacement block (West facing cocoa beans)
@@ -757,27 +767,34 @@ public enum CollisionData {
BlockTags.FLOWER_POTS.getStates().toArray(new StateType[0])),
WALL_SIGN((player, version, data, x, y, z) -> {
return switch (data.getFacing()) {
case NORTH -> new HexCollisionBox(0.0D, 4.5D, 14.0D, 16.0D, 12.5D, 16.0D);
case SOUTH -> new HexCollisionBox(0.0D, 4.5D, 0.0D, 16.0D, 12.5D, 2.0D);
case WEST -> new HexCollisionBox(14.0D, 4.5D, 0.0D, 16.0D, 12.5D, 16.0D);
case EAST -> new HexCollisionBox(0.0D, 4.5D, 0.0D, 2.0D, 12.5D, 16.0D);
default -> NoCollisionBox.INSTANCE;
};
switch (data.getFacing()) {
case NORTH:
return new HexCollisionBox(0.0D, 4.5D, 14.0D, 16.0D, 12.5D, 16.0D);
case SOUTH:
return new HexCollisionBox(0.0D, 4.5D, 0.0D, 16.0D, 12.5D, 2.0D);
case WEST:
return new HexCollisionBox(14.0D, 4.5D, 0.0D, 16.0D, 12.5D, 16.0D);
case EAST:
return new HexCollisionBox(0.0D, 4.5D, 0.0D, 2.0D, 12.5D, 16.0D);
default:
return NoCollisionBox.INSTANCE;
}
}, BlockTags.WALL_SIGNS.getStates().toArray(new StateType[0])),
WALL_FAN((player, version, data, x, y, z) -> {
return switch (data.getFacing()) {
case NORTH -> new HexCollisionBox(0.0D, 4.0D, 5.0D, 16.0D, 12.0D, 16.0D);
case SOUTH -> new HexCollisionBox(0.0D, 4.0D, 0.0D, 16.0D, 12.0D, 11.0D);
case WEST -> new HexCollisionBox(5.0D, 4.0D, 0.0D, 16.0D, 12.0D, 16.0D);
default -> new HexCollisionBox(0.0D, 4.0D, 0.0D, 11.0D, 12.0D, 16.0D);
};
switch (data.getFacing()) {
case NORTH:
return new HexCollisionBox(0.0D, 4.0D, 5.0D, 16.0D, 12.0D, 16.0D);
case SOUTH:
return new HexCollisionBox(0.0D, 4.0D, 0.0D, 16.0D, 12.0D, 11.0D);
case WEST:
return new HexCollisionBox(5.0D, 4.0D, 0.0D, 16.0D, 12.0D, 16.0D);
default:
return new HexCollisionBox(0.0D, 4.0D, 0.0D, 11.0D, 12.0D, 16.0D);
}
}, BlockTags.WALL_CORALS.getStates().toArray(new StateType[0])),
CORAL_PLANT((player, version, data, x, y, z) -> {
return new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 15.0D, 14.0D);
}, Stream.concat(
CORAL_PLANT((player, version, data, x, y, z) -> new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 15.0D, 14.0D), Stream.concat(
Arrays.stream(BlockTags.CORAL_PLANTS.getStates().toArray(new StateType[0])),
Stream.of(StateTypes.DEAD_HORN_CORAL, StateTypes.DEAD_TUBE_CORAL, StateTypes.DEAD_BRAIN_CORAL,
StateTypes.DEAD_BUBBLE_CORAL, StateTypes.DEAD_FIRE_CORAL)
@@ -821,37 +838,50 @@ public enum CollisionData {
}, StateTypes.TRIPWIRE),
TRIPWIRE_HOOK((player, version, data, x, y, z) -> {
return switch (data.getFacing()) {
case NORTH -> new HexCollisionBox(5.0D, 0.0D, 10.0D, 11.0D, 10.0D, 16.0D);
case SOUTH -> new HexCollisionBox(5.0D, 0.0D, 0.0D, 11.0D, 10.0D, 6.0D);
case WEST -> new HexCollisionBox(10.0D, 0.0D, 5.0D, 16.0D, 10.0D, 11.0D);
default -> new HexCollisionBox(0.0D, 0.0D, 5.0D, 6.0D, 10.0D, 11.0D);
};
switch (data.getFacing()) {
case NORTH:
return new HexCollisionBox(5.0D, 0.0D, 10.0D, 11.0D, 10.0D, 16.0D);
case SOUTH:
return new HexCollisionBox(5.0D, 0.0D, 0.0D, 11.0D, 10.0D, 6.0D);
case WEST:
return new HexCollisionBox(10.0D, 0.0D, 5.0D, 16.0D, 10.0D, 11.0D);
default:
return new HexCollisionBox(0.0D, 0.0D, 5.0D, 6.0D, 10.0D, 11.0D);
}
}, StateTypes.TRIPWIRE_HOOK),
TORCH(new HexCollisionBox(6.0D, 0.0D, 6.0D, 10.0D, 10.0D, 10.0D),
StateTypes.TORCH, StateTypes.REDSTONE_TORCH),
WALL_TORCH((player, version, data, x, y, z) -> {
return switch (data.getFacing()) {
case NORTH -> new HexCollisionBox(5.5D, 3.0D, 11.0D, 10.5D, 13.0D, 16.0D);
case SOUTH -> new HexCollisionBox(5.5D, 3.0D, 0.0D, 10.5D, 13.0D, 5.0D);
case WEST -> new HexCollisionBox(11.0D, 3.0D, 5.5D, 16.0D, 13.0D, 10.5D);
case EAST -> new HexCollisionBox(0.0D, 3.0D, 5.5D, 5.0D, 13.0D, 10.5D);
switch (data.getFacing()) {
case NORTH:
return new HexCollisionBox(5.5D, 3.0D, 11.0D, 10.5D, 13.0D, 16.0D);
case SOUTH:
return new HexCollisionBox(5.5D, 3.0D, 0.0D, 10.5D, 13.0D, 5.0D);
case WEST:
return new HexCollisionBox(11.0D, 3.0D, 5.5D, 16.0D, 13.0D, 10.5D);
case EAST:
return new HexCollisionBox(0.0D, 3.0D, 5.5D, 5.0D, 13.0D, 10.5D);
// 1.13 separates wall and normal torches, 1.12 does not
default -> new HexCollisionBox(6.0D, 0.0D, 6.0D, 10.0D, 10.0D, 10.0D);
};
default:
return new HexCollisionBox(6.0D, 0.0D, 6.0D, 10.0D, 10.0D, 10.0D);
}
}, StateTypes.WALL_TORCH, StateTypes.REDSTONE_WALL_TORCH),
// 1.17 blocks
CANDLE((player, version, data, x, y, z) -> {
if (version.isNewerThanOrEquals(ClientVersion.V_1_17)) {
return switch (data.getCandles()) {
case 1 -> new HexCollisionBox(7.0, 0.0, 7.0, 9.0, 6.0, 9.0);
case 2 -> new HexCollisionBox(5.0, 0.0, 6.0, 11.0, 6.0, 9.0);
case 3 -> new HexCollisionBox(5.0, 0.0, 6.0, 10.0, 6.0, 11.0);
default -> new HexCollisionBox(5.0, 0.0, 5.0, 11.0, 6.0, 10.0);
};
switch (data.getCandles()) {
case 1:
return new HexCollisionBox(7.0, 0.0, 7.0, 9.0, 6.0, 9.0);
case 2:
return new HexCollisionBox(5.0, 0.0, 6.0, 11.0, 6.0, 9.0);
case 3:
return new HexCollisionBox(5.0, 0.0, 6.0, 10.0, 6.0, 11.0);
default:
return new HexCollisionBox(5.0, 0.0, 5.0, 11.0, 6.0, 10.0);
}
}
return getPicklesBox(version, data.getCandles());
@@ -941,27 +971,17 @@ public enum CollisionData {
return new HexCollisionBox(6.0D, 0.0D, 0.0D, 10.0D, 16.0D, 16.0D);
}, StateTypes.NETHER_PORTAL),
AZALEA((player, version, data, x, y, z) -> {
return new ComplexCollisionBox(2,
AZALEA((player, version, data, x, y, z) -> new ComplexCollisionBox(2,
new HexCollisionBox(0.0, 8.0, 0.0, 16.0, 16.0, 16.0),
new HexCollisionBox(6.0, 0.0, 6.0, 10.0, 8.0, 10.0));
}, StateTypes.AZALEA, StateTypes.FLOWERING_AZALEA),
new HexCollisionBox(6.0, 0.0, 6.0, 10.0, 8.0, 10.0)), StateTypes.AZALEA, StateTypes.FLOWERING_AZALEA),
AMETHYST_CLUSTER((player, version, data, x, y, z) -> {
return getAmethystBox(version, data.getFacing(), 7, 3);
}, StateTypes.AMETHYST_CLUSTER),
AMETHYST_CLUSTER((player, version, data, x, y, z) -> getAmethystBox(version, data.getFacing(), 7, 3), StateTypes.AMETHYST_CLUSTER),
SMALL_AMETHYST_BUD((player, version, data, x, y, z) -> {
return getAmethystBox(version, data.getFacing(), 3, 4);
}, StateTypes.SMALL_AMETHYST_BUD),
SMALL_AMETHYST_BUD((player, version, data, x, y, z) -> getAmethystBox(version, data.getFacing(), 3, 4), StateTypes.SMALL_AMETHYST_BUD),
MEDIUM_AMETHYST_BUD((player, version, data, x, y, z) -> {
return getAmethystBox(version, data.getFacing(), 4, 3);
}, StateTypes.MEDIUM_AMETHYST_BUD),
MEDIUM_AMETHYST_BUD((player, version, data, x, y, z) -> getAmethystBox(version, data.getFacing(), 4, 3), StateTypes.MEDIUM_AMETHYST_BUD),
LARGE_AMETHYST_BUD((player, version, data, x, y, z) -> {
return getAmethystBox(version, data.getFacing(), 5, 3);
}, StateTypes.LARGE_AMETHYST_BUD),
LARGE_AMETHYST_BUD((player, version, data, x, y, z) -> getAmethystBox(version, data.getFacing(), 5, 3), StateTypes.LARGE_AMETHYST_BUD),
MUD_BLOCK((player, version, data, x, y, z) -> {
if (version.isNewerThanOrEquals(ClientVersion.V_1_19)) {
@@ -974,13 +994,18 @@ public enum CollisionData {
if (!data.isHanging()) {
return new HexCollisionBox(7.0D, 0.0D, 7.0D, 9.0D, 16.0D, 9.0D);
}
return switch (data.getAge()) {
case 0 -> new HexCollisionBox(7.0D, 13.0D, 7.0D, 9.0D, 16.0D, 9.0D);
case 1 -> new HexCollisionBox(7.0D, 10.0D, 7.0D, 9.0D, 16.0D, 9.0D);
case 2 -> new HexCollisionBox(7.0D, 7.0D, 7.0D, 9.0D, 16.0D, 9.0D);
case 3 -> new HexCollisionBox(7.0D, 3.0D, 7.0D, 9.0D, 16.0D, 9.0D);
default -> new HexCollisionBox(7.0D, 0.0D, 7.0D, 9.0D, 16.0D, 9.0D);
};
switch (data.getAge()) {
case 0:
return new HexCollisionBox(7.0D, 13.0D, 7.0D, 9.0D, 16.0D, 9.0D);
case 1:
return new HexCollisionBox(7.0D, 10.0D, 7.0D, 9.0D, 16.0D, 9.0D);
case 2:
return new HexCollisionBox(7.0D, 7.0D, 7.0D, 9.0D, 16.0D, 9.0D);
case 3:
return new HexCollisionBox(7.0D, 3.0D, 7.0D, 9.0D, 16.0D, 9.0D);
default:
return new HexCollisionBox(7.0D, 0.0D, 7.0D, 9.0D, 16.0D, 9.0D);
}
}, StateTypes.MANGROVE_PROPAGULE),
SCULK_SHRIKER((player, version, data, x, y, z) -> {
@@ -1015,11 +1040,16 @@ public enum CollisionData {
}, StateTypes.PITCHER_CROP),
WALL_HANGING_SIGNS((player, version, data, x, y, z) -> {
return switch (data.getFacing()) {
case NORTH, SOUTH -> new HexCollisionBox(0.0, 14.0, 6.0, 16.0, 16.0, 10.0);
case WEST, EAST -> new HexCollisionBox(6.0, 14.0, 0.0, 10.0, 16.0, 16.0);
default -> NoCollisionBox.INSTANCE;
};
switch (data.getFacing()) {
case NORTH:
case SOUTH:
return new HexCollisionBox(0.0, 14.0, 6.0, 16.0, 16.0, 10.0);
case WEST:
case EAST:
return new HexCollisionBox(6.0, 14.0, 0.0, 10.0, 16.0, 16.0);
default:
return NoCollisionBox.INSTANCE;
}
}, BlockTags.WALL_HANGING_SIGNS.getStates().toArray(new StateType[0])),
DEFAULT(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.STONE);
@@ -1057,14 +1087,20 @@ public enum CollisionData {
if (version.isOlderThanOrEquals(ClientVersion.V_1_16_4))
return NoCollisionBox.INSTANCE;
return switch (facing) {
case DOWN -> new HexCollisionBox(param_1, 16 - param_0, param_1, 16 - param_1, 16.0, 16 - param_1);
case NORTH -> new HexCollisionBox(param_1, param_1, 16 - param_0, 16 - param_1, 16 - param_1, 16.0);
case SOUTH -> new HexCollisionBox(param_1, param_1, 0.0, 16 - param_1, 16 - param_1, param_0);
case EAST -> new HexCollisionBox(0.0, param_1, param_1, param_0, 16 - param_1, 16 - param_1);
case WEST -> new HexCollisionBox(16 - param_0, param_1, param_1, 16.0, 16 - param_1, 16 - param_1);
default -> new HexCollisionBox(param_1, 0.0, param_1, 16 - param_1, param_0, 16 - param_1);
};
switch (facing) {
case DOWN:
return new HexCollisionBox(param_1, 16 - param_0, param_1, 16 - param_1, 16.0, 16 - param_1);
case NORTH:
return new HexCollisionBox(param_1, param_1, 16 - param_0, 16 - param_1, 16 - param_1, 16.0);
case SOUTH:
return new HexCollisionBox(param_1, param_1, 0.0, 16 - param_1, 16 - param_1, param_0);
case EAST:
return new HexCollisionBox(0.0, param_1, param_1, param_0, 16 - param_1, 16 - param_1);
case WEST:
return new HexCollisionBox(16 - param_0, param_1, param_1, 16.0, 16 - param_1, 16 - param_1);
default:
return new HexCollisionBox(param_1, 0.0, param_1, 16 - param_1, param_0, 16 - param_1);
}
}
private static CollisionBox getPicklesBox(ClientVersion version, int pickles) {
@@ -1073,13 +1109,18 @@ public enum CollisionData {
return getCocoa(version, pickles, BlockFace.WEST);
}
return switch (pickles) {
case 1 -> new HexCollisionBox(6.0D, 0.0D, 6.0D, 10.0D, 6.0D, 10.0D);
case 2 -> new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 6.0D, 13.0D);
case 3 -> new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 6.0D, 14.0D);
case 4 -> new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 7.0D, 14.0D);
default -> NoCollisionBox.INSTANCE;
};
switch (pickles) {
case 1:
return new HexCollisionBox(6.0D, 0.0D, 6.0D, 10.0D, 6.0D, 10.0D);
case 2:
return new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 6.0D, 13.0D);
case 3:
return new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 6.0D, 14.0D);
case 4:
return new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 7.0D, 14.0D);
default:
return NoCollisionBox.INSTANCE;
}
}
public static CollisionBox getCocoa(ClientVersion version, int age, BlockFace direction) {
@@ -1134,11 +1175,16 @@ public enum CollisionData {
if (version.isOlderThan(ClientVersion.V_1_9))
return NoCollisionBox.INSTANCE;
return switch (face) {
case NORTH, SOUTH -> new HexCollisionBox(6.0D, 6.0D, 0.0D, 10.0D, 10.0D, 16.0D);
case EAST, WEST -> new HexCollisionBox(0.0D, 6.0D, 6.0D, 16.0D, 10.0D, 10.0D);
default -> new HexCollisionBox(6.0D, 0.0D, 6.0D, 10.0D, 16.0D, 10.0);
};
switch (face) {
case NORTH:
case SOUTH:
return new HexCollisionBox(6.0D, 6.0D, 0.0D, 10.0D, 10.0D, 16.0D);
case EAST:
case WEST:
return new HexCollisionBox(0.0D, 6.0D, 6.0D, 16.0D, 10.0D, 10.0D);
default:
return new HexCollisionBox(6.0D, 0.0D, 6.0D, 10.0D, 16.0D, 10.0);
}
}
// Would pre-computing all states be worth the memory cost? I doubt it
@@ -20,29 +20,32 @@ import java.util.*;
public enum HitboxData {
RAILS((player, item, version, data, isTargetBlock, x, y, z) -> {
return switch (data.getShape()) {
case ASCENDING_NORTH, ASCENDING_SOUTH, ASCENDING_EAST, ASCENDING_WEST -> {
switch (data.getShape()) {
case ASCENDING_NORTH:
case ASCENDING_SOUTH:
case ASCENDING_EAST:
case ASCENDING_WEST:
if (version.isOlderThan(ClientVersion.V_1_8)) {
StateType railType = data.getType();
// Activator rails always appear as flat detector rails in 1.7.10 because of ViaVersion
// Ascending power rails in 1.7 have flat rail hitbox https://bugs.mojang.com/browse/MC-9134
if (railType == StateTypes.ACTIVATOR_RAIL || (railType == StateTypes.POWERED_RAIL && data.isPowered())) {
yield new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F, false);
return new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F, false);
}
yield new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F, false);
return new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F, false);
} else if (version.isOlderThan(ClientVersion.V_1_9)) {
yield new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F, false);
return new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F, false);
} else if (version.isNewerThanOrEquals(ClientVersion.V_1_9) && version.isOlderThan(ClientVersion.V_1_10)) {
// https://bugs.mojang.com/browse/MC-89552 sloped rails in 1.9 - it is slightly taller than a regular rail
yield new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.1875F, 1.0F, false);
return new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.1875F, 1.0F, false);
} else if (version.isOlderThan(ClientVersion.V_1_11)) {
// https://bugs.mojang.com/browse/MC-102638 All sloped rails are full blocks in 1.10
yield new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
}
yield new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D);
}
default -> new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D);
};
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D);
default:
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D);
}
}, BlockTags.RAILS.getStates().toArray(new StateType[0])),
END_PORTAL((player, item, version, data, isTargetBlock, x, y, z) -> {
@@ -106,31 +109,35 @@ public enum HitboxData {
}
}
return switch (face) {
case FLOOR -> {
switch (face) {
case FLOOR:
// X-AXIS
if (facing == BlockFace.EAST || facing == BlockFace.WEST) {
yield new SimpleCollisionBox(0.25, 0.0, 0.3125, 0.75, 0.375, 0.6875, false);
return new SimpleCollisionBox(0.25, 0.0, 0.3125, 0.75, 0.375, 0.6875, false);
}
// Z-AXIS
yield new SimpleCollisionBox(0.3125, 0.0, 0.25, 0.6875, 0.375, 0.75, false);
// Z-AXIS
}
case WALL -> switch (facing) {
case EAST -> new SimpleCollisionBox(0.0, 0.25, 0.3125, 0.375, 0.75, 0.6875, false);
case WEST -> new SimpleCollisionBox(0.625, 0.25, 0.3125, 1.0, 0.75, 0.6875, false);
case SOUTH -> new SimpleCollisionBox(0.3125, 0.25, 0.0, 0.6875, 0.75, 0.375, false);
default -> new SimpleCollisionBox(0.3125, 0.25, 0.625, 0.6875, 0.75, 1.0, false);
};
default -> {
return new SimpleCollisionBox(0.3125, 0.0, 0.25, 0.6875, 0.375, 0.75, false);
case WALL:
switch (facing) {
case EAST:
return new SimpleCollisionBox(0.0, 0.25, 0.3125, 0.375, 0.75, 0.6875, false);
case WEST:
return new SimpleCollisionBox(0.625, 0.25, 0.3125, 1.0, 0.75, 0.6875, false);
case SOUTH:
return new SimpleCollisionBox(0.3125, 0.25, 0.0, 0.6875, 0.75, 0.375, false);
case NORTH:
default:
return new SimpleCollisionBox(0.3125, 0.25, 0.625, 0.6875, 0.75, 1.0, false);
}
case CEILING:
default:
// X-AXIS
if (facing == BlockFace.EAST || facing == BlockFace.WEST) {
yield new SimpleCollisionBox(0.25, 0.625, 0.3125, 0.75, 1.0, 0.6875, false);
return new SimpleCollisionBox(0.25, 0.625, 0.3125, 0.75, 1.0, 0.6875, false);
}
// Z-Axis
yield new SimpleCollisionBox(0.3125, 0.625, 0.25, 0.6875, 1.0, 0.75, false);
}
};
return new SimpleCollisionBox(0.3125, 0.625, 0.25, 0.6875, 1.0, 0.75, false);
}
}), StateTypes.LEVER),
BUTTON((player, item, version, data, isTargetBlock, x, y, z) -> {
@@ -164,17 +171,27 @@ public enum HitboxData {
switch (face) {
case WALL:
return switch (facing) {
case EAST ->
powered ? new HexCollisionBox(0.0, 6.0, 5.0, 1.0, 10.0, 11.0) : new HexCollisionBox(0.0, 6.0, 5.0, 2.0, 10.0, 11.0);
case WEST ->
powered ? new HexCollisionBox(15.0, 6.0, 5.0, 16.0, 10.0, 11.0) : new HexCollisionBox(14.0, 6.0, 5.0, 16.0, 10.0, 11.0);
case SOUTH ->
powered ? new HexCollisionBox(5.0, 6.0, 0.0, 11.0, 10.0, 1.0) : new HexCollisionBox(5.0, 6.0, 0.0, 11.0, 10.0, 2.0);
case NORTH, UP, DOWN ->
powered ? new HexCollisionBox(5.0, 6.0, 15.0, 11.0, 10.0, 16.0) : new HexCollisionBox(5.0, 6.0, 14.0, 11.0, 10.0, 16.0);
default -> NoCollisionBox.INSTANCE;
};
CollisionBox shape;
switch (facing) {
case EAST:
shape = powered ? new HexCollisionBox(0.0, 6.0, 5.0, 1.0, 10.0, 11.0) : new HexCollisionBox(0.0, 6.0, 5.0, 2.0, 10.0, 11.0);
break;
case WEST:
shape = powered ? new HexCollisionBox(15.0, 6.0, 5.0, 16.0, 10.0, 11.0) : new HexCollisionBox(14.0, 6.0, 5.0, 16.0, 10.0, 11.0);
break;
case SOUTH:
shape = powered ? new HexCollisionBox(5.0, 6.0, 0.0, 11.0, 10.0, 1.0) : new HexCollisionBox(5.0, 6.0, 0.0, 11.0, 10.0, 2.0);
break;
case NORTH:
case UP:
case DOWN:
shape = powered ? new HexCollisionBox(5.0, 6.0, 15.0, 11.0, 10.0, 16.0) : new HexCollisionBox(5.0, 6.0, 14.0, 11.0, 10.0, 16.0);
break;
default:
shape = NoCollisionBox.INSTANCE;
}
return shape;
case CEILING:
// ViaVersion shows lever
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
@@ -205,24 +222,32 @@ public enum HitboxData {
WALL(new DynamicHitboxWall(), BlockTags.WALLS.getStates().toArray(new StateType[0])),
WALL_SIGN((player, item, version, data, isTargetBlock, x, y, z) -> {
return switch (data.getFacing()) {
case NORTH -> new HexCollisionBox(0.0, 4.5, 14.0, 16.0, 12.5, 16.0);
case SOUTH -> new HexCollisionBox(0.0, 4.5, 0.0, 16.0, 12.5, 2.0);
case EAST -> new HexCollisionBox(0.0, 4.5, 0.0, 2.0, 12.5, 16.0);
case WEST -> new HexCollisionBox(14.0, 4.5, 0.0, 16.0, 12.5, 16.0);
default -> NoCollisionBox.INSTANCE;
};
switch (data.getFacing()) {
case NORTH:
return new HexCollisionBox(0.0, 4.5, 14.0, 16.0, 12.5, 16.0);
case SOUTH:
return new HexCollisionBox(0.0, 4.5, 0.0, 16.0, 12.5, 2.0);
case EAST:
return new HexCollisionBox(0.0, 4.5, 0.0, 2.0, 12.5, 16.0);
case WEST:
return new HexCollisionBox(14.0, 4.5, 0.0, 16.0, 12.5, 16.0);
default:
return NoCollisionBox.INSTANCE;
}
}, BlockTags.WALL_SIGNS.getStates().toArray(new StateType[0])),
WALL_HANGING_SIGN((player, item, version, data, isTargetBlock, x, y, z) -> {
return switch (data.getFacing()) {
case NORTH, SOUTH -> new ComplexCollisionBox(2,
switch (data.getFacing()) {
case NORTH:
case SOUTH:
return new ComplexCollisionBox(2,
new HexCollisionBox(0.0D, 14.0D, 6.0D, 16.0D, 16.0D, 10.0D),
new HexCollisionBox(1.0D, 0.0D, 7.0D, 15.0D, 10.0D, 9.0D));
default -> new ComplexCollisionBox(2,
new HexCollisionBox(1.0D, 0.0D, 7.0D, 15.0D, 10.0D, 9.0D));
default:
return new ComplexCollisionBox(2,
new HexCollisionBox(6.0D, 14.0D, 0.0D, 10.0D, 16.0D, 16.0D),
new HexCollisionBox(7.0D, 0.0D, 1.0D, 9.0D, 10.0D, 15.0D));
};
new HexCollisionBox(7.0D, 0.0D, 1.0D, 9.0D, 10.0D, 15.0D));
}
}, BlockTags.WALL_HANGING_SIGNS.getStates().toArray(new StateType[0])),
STANDING_SIGN((player, item, version, data, isTargetBlock, x, y, z) ->
@@ -247,13 +272,18 @@ public enum HitboxData {
return WALL_SIGN.dynamic.fetch(player, item, version, data, isTargetBlock, x, y, z);
}
return switch (data.getFacing()) {
case NORTH -> new HexCollisionBox(0.0, 0.0, 14.0, 16.0, 12.5, 16.0);
case EAST -> new HexCollisionBox(0.0, 0.0, 0.0, 2.0, 12.5, 16.0);
case WEST -> new HexCollisionBox(14.0, 0.0, 0.0, 16.0, 12.5, 16.0);
case SOUTH -> new HexCollisionBox(0.0, 0.0, 0.0, 16.0, 12.5, 2.0);
default -> throw new IllegalStateException("Impossible Banner Facing State; Something very wrong is going on");
};
switch (data.getFacing()) {
case NORTH:
return new HexCollisionBox(0.0, 0.0, 14.0, 16.0, 12.5, 16.0);
case EAST:
return new HexCollisionBox(0.0, 0.0, 0.0, 2.0, 12.5, 16.0);
case WEST:
return new HexCollisionBox(14.0, 0.0, 0.0, 16.0, 12.5, 16.0);
case SOUTH:
return new HexCollisionBox(0.0, 0.0, 0.0, 16.0, 12.5, 2.0);
default:
throw new IllegalStateException("Impossible Banner Facing State; Something very wrong is going on");
}
}, StateTypes.WHITE_WALL_BANNER, StateTypes.ORANGE_WALL_BANNER, StateTypes.MAGENTA_WALL_BANNER,
StateTypes.LIGHT_BLUE_WALL_BANNER, StateTypes.YELLOW_WALL_BANNER, StateTypes.LIME_WALL_BANNER,
StateTypes.PINK_WALL_BANNER, StateTypes.GRAY_WALL_BANNER, StateTypes.LIGHT_GRAY_WALL_BANNER,
@@ -405,12 +435,17 @@ public enum HitboxData {
if (version.isOlderThan(ClientVersion.V_1_13))
return new HexCollisionBox(7.0D, 0.0D, 7.0D, 9.0D, 16.0D, 9.0D);
return switch (data.getFacing()) {
case SOUTH -> new HexCollisionBox(6.0D, 0.0D, 6.0D, 10.0D, 10.0D, 16.0D);
case WEST -> new HexCollisionBox(0.0D, 0.0D, 6.0D, 10.0D, 10.0D, 10.0D);
case NORTH -> new HexCollisionBox(6.0D, 0.0D, 0.0D, 10.0D, 10.0D, 10.0D);
default -> new HexCollisionBox(6.0D, 0.0D, 6.0D, 16.0D, 10.0D, 10.0D);
};
switch (data.getFacing()) {
case SOUTH:
return new HexCollisionBox(6.0D, 0.0D, 6.0D, 10.0D, 10.0D, 16.0D);
case WEST:
return new HexCollisionBox(0.0D, 0.0D, 6.0D, 10.0D, 10.0D, 10.0D);
case NORTH:
return new HexCollisionBox(6.0D, 0.0D, 0.0D, 10.0D, 10.0D, 10.0D);
case EAST:
default:
return new HexCollisionBox(6.0D, 0.0D, 6.0D, 16.0D, 10.0D, 10.0D);
}
}, StateTypes.ATTACHED_MELON_STEM, StateTypes.ATTACHED_PUMPKIN_STEM),
PUMPKIN_STEM((player, item, version, data, isTargetBlock, x, y, z) -> {
@@ -645,11 +680,16 @@ public enum HitboxData {
}
private static int getPropaguleMinHeight(int age) {
return switch (age) {
case 0, 1, 2 -> 13 - age * 3;
case 3, 4 -> (4 - age) * 3;
default -> throw new IllegalStateException("Impossible Propagule Height");
};
switch (age) {
case 0:
case 1:
case 2:
return 13 - age * 3;
case 3:
case 4:
return (4 - age) * 3;
}
throw new IllegalStateException("Impossible Propagule Height");
}
private static CollisionBox getVineCollisionBox(ClientVersion version, boolean isWeeping, boolean isBlock) {
@@ -673,13 +713,19 @@ public enum HitboxData {
}
private static int getHorizontalID(BlockFace facing) {
return switch (facing) {
case DOWN, UP -> -1;
case NORTH -> 2;
case SOUTH -> 0;
case WEST -> 1;
case EAST -> 3;
default -> throw new IllegalStateException("Impossible blockface for getHorizontalID");
};
switch (facing) {
case DOWN:
case UP:
return -1;
case NORTH:
return 2;
case SOUTH:
return 0;
case WEST:
return 1;
case EAST:
return 3;
}
throw new IllegalStateException("Impossible blockface for getHorizontalID");
}
}
@@ -0,0 +1,97 @@
package ac.grim.grimac.utils.collisions;
/*
*/
import ac.grim.grimac.player.GrimPlayer;
import ac.grim.grimac.utils.collisions.datatypes.*;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import org.jetbrains.annotations.Nullable;
import java.util.*;
// Expansion to the CollisionData class, which is different than regular ray tracing hitboxes
public enum RaycastData {
HOPPER((player, item, version, data, isTarget, x, y, z) -> {
HexCollisionBox insideShape = new HexCollisionBox(2.0, 11.0, 2.0, 14.0, 16.0, 14.0);
switch (data.getFacing()) {
case NORTH:
new ComplexCollisionBox(insideShape, new HexCollisionBox(6.0, 8.0, 0.0, 10.0, 10.0, 4.0));
case SOUTH:
new ComplexCollisionBox(insideShape, new HexCollisionBox(6.0, 8.0, 12.0, 10.0, 10.0, 16.0));
case WEST:
new ComplexCollisionBox(insideShape, new HexCollisionBox(0.0, 8.0, 6.0, 4.0, 10.0, 10.0));
case EAST:
new ComplexCollisionBox(insideShape, new HexCollisionBox(12.0, 8.0, 6.0, 16.0, 10.0, 10.0));
default:
return insideShape;
}
}, StateTypes.HOPPER),
CAULDRON((player, item, version, data, isTarget, x, y, z) -> {
return new HexCollisionBox(2.0, 4.0, 2.0, 14.0, 16.0, 14.0);
}, BlockTags.CAULDRONS.getStates().toArray(new StateType[0])),
FULL_BLOCK((player, item, version, data, isTarget, x, y, z) -> {
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
}, StateTypes.COMPOSTER, StateTypes.SCAFFOLDING);
private static final Map<StateType, RaycastData> lookup = new HashMap<>();
static {
for (RaycastData data : RaycastData.values()) {
for (StateType type : data.materials) {
lookup.put(type, data);
}
}
}
private final StateType[] materials;
private CollisionBox box;
private HitBoxFactory dynamic;
RaycastData(CollisionBox box, StateType... materials) {
this.box = box;
Set<StateType> mList = new HashSet<>(Arrays.asList(materials));
mList.remove(null); // Sets can contain one null
this.materials = mList.toArray(new StateType[0]);
}
RaycastData(HitBoxFactory dynamic, StateType... materials) {
this.dynamic = dynamic;
Set<StateType> mList = new HashSet<>(Arrays.asList(materials));
mList.remove(null); // Sets can contain one null
this.materials = mList.toArray(new StateType[0]);
}
public static RaycastData getData(StateType material) {
return lookup.get(material);
}
@Nullable
public static CollisionBox getBlockHitbox(GrimPlayer player, StateType heldItem, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
RaycastData data = getData(block.getType());
if (data == null) {
// We explicitly do not want to fallback on HitBoxData or CollisionBox
// Because we only ever use this as a 2nd ray trace
return NoCollisionBox.INSTANCE;
}
// Simple collision box to override
if (data.box != null)
return data.box.copy().offset(x, y, z);
// Allow this class to override collision boxes when they aren't the same as regular boxes
HitBoxFactory hitBoxFactory = data.dynamic;
CollisionBox collisionBox = hitBoxFactory.fetch(player, heldItem, version, block, false, x, y, z);
collisionBox.offset(x, y, z);
return collisionBox;
}
}
@@ -21,14 +21,18 @@ public class DoorHandler implements CollisionFactory {
@Override
public CollisionBox fetch(GrimPlayer player, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
return switch (fetchDirection(player, version, block, x, y, z)) {
case NORTH -> NORTH_AABB.copy();
case SOUTH -> SOUTH_AABB.copy();
case EAST -> EAST_AABB.copy();
case WEST -> WEST_AABB.copy();
default -> NoCollisionBox.INSTANCE;
};
switch (fetchDirection(player, version, block, x, y, z)) {
case NORTH:
return NORTH_AABB.copy();
case SOUTH:
return SOUTH_AABB.copy();
case EAST:
return EAST_AABB.copy();
case WEST:
return WEST_AABB.copy();
}
return NoCollisionBox.INSTANCE;
}
public BlockFace fetchDirection(GrimPlayer player, ClientVersion version, WrappedBlockState door, int x, int y, int z) {
@@ -76,11 +80,16 @@ public class DoorHandler implements CollisionFactory {
isRightHinge = door.getHinge() == Hinge.RIGHT;
}
return switch (facingDirection) {
case SOUTH -> isClosed ? BlockFace.SOUTH : (isRightHinge ? BlockFace.EAST : BlockFace.WEST);
case WEST -> isClosed ? BlockFace.WEST : (isRightHinge ? BlockFace.SOUTH : BlockFace.NORTH);
case NORTH -> isClosed ? BlockFace.NORTH : (isRightHinge ? BlockFace.WEST : BlockFace.EAST);
default -> isClosed ? BlockFace.EAST : (isRightHinge ? BlockFace.NORTH : BlockFace.SOUTH);
};
switch (facingDirection) {
case EAST:
default:
return isClosed ? BlockFace.EAST : (isRightHinge ? BlockFace.NORTH : BlockFace.SOUTH);
case SOUTH:
return isClosed ? BlockFace.SOUTH : (isRightHinge ? BlockFace.EAST : BlockFace.WEST);
case WEST:
return isClosed ? BlockFace.WEST : (isRightHinge ? BlockFace.SOUTH : BlockFace.NORTH);
case NORTH:
return isClosed ? BlockFace.NORTH : (isRightHinge ? BlockFace.WEST : BlockFace.EAST);
}
}
}
@@ -74,12 +74,17 @@ public class DynamicStair implements CollisionFactory {
}
private static BlockFace rotateYCCW(BlockFace face) {
return switch (face) {
case EAST -> BlockFace.NORTH;
case SOUTH -> BlockFace.EAST;
case WEST -> BlockFace.SOUTH;
default -> BlockFace.WEST;
};
switch (face) {
default:
case NORTH:
return BlockFace.WEST;
case EAST:
return BlockFace.NORTH;
case SOUTH:
return BlockFace.EAST;
case WEST:
return BlockFace.SOUTH;
}
}
private static CollisionBox[] makeShapes(SimpleCollisionBox p_199779_0_, SimpleCollisionBox p_199779_1_, SimpleCollisionBox p_199779_2_, SimpleCollisionBox p_199779_3_, SimpleCollisionBox p_199779_4_) {
@@ -126,23 +131,36 @@ public class DynamicStair implements CollisionFactory {
}
private int directionToValue(BlockFace face) {
return switch (face) {
case NORTH -> 2;
case SOUTH -> 0;
case WEST -> 1;
case EAST -> 3;
default -> -1;
};
switch (face) {
default:
case UP:
case DOWN:
return -1;
case NORTH:
return 2;
case SOUTH:
return 0;
case WEST:
return 1;
case EAST:
return 3;
}
}
private EnumShape toEnumShape(Shape shape) {
return switch (shape) {
case INNER_LEFT -> EnumShape.INNER_LEFT;
case INNER_RIGHT -> EnumShape.INNER_RIGHT;
case OUTER_LEFT -> EnumShape.OUTER_LEFT;
case OUTER_RIGHT -> EnumShape.OUTER_RIGHT;
default -> EnumShape.STRAIGHT;
};
switch (shape) {
default:
case STRAIGHT:
return EnumShape.STRAIGHT;
case INNER_LEFT:
return EnumShape.INNER_LEFT;
case INNER_RIGHT:
return EnumShape.INNER_RIGHT;
case OUTER_LEFT:
return EnumShape.OUTER_LEFT;
case OUTER_RIGHT:
return EnumShape.OUTER_RIGHT;
}
}
enum EnumShape {
@@ -14,13 +14,20 @@ public class PistonBaseCollision implements CollisionFactory {
public CollisionBox fetch(GrimPlayer player, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
if (!block.isExtended()) return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
return switch (block.getFacing()) {
case UP -> new HexCollisionBox(0, 0, 0, 16, 12, 16);
case NORTH -> new HexCollisionBox(0, 0, 4, 16, 16, 16);
case SOUTH -> new HexCollisionBox(0, 0, 0, 16, 16, 12);
case WEST -> new HexCollisionBox(4, 0, 0, 16, 16, 16);
case EAST -> new HexCollisionBox(0, 0, 0, 12, 16, 16);
default -> new HexCollisionBox(0, 4, 0, 16, 16, 16);
};
switch (block.getFacing()) {
default:
case DOWN:
return new HexCollisionBox(0, 4, 0, 16, 16, 16);
case UP:
return new HexCollisionBox(0, 0, 0, 16, 12, 16);
case NORTH:
return new HexCollisionBox(0, 0, 4, 16, 16, 16);
case SOUTH:
return new HexCollisionBox(0, 0, 0, 16, 16, 12);
case WEST:
return new HexCollisionBox(4, 0, 0, 16, 16, 16);
case EAST:
return new HexCollisionBox(0, 0, 0, 12, 16, 16);
}
}
}
@@ -38,43 +38,46 @@ public class PistonHeadCollision implements CollisionFactory {
longAmount = 0;
return switch (block.getFacing()) {
case UP -> new ComplexCollisionBox(2,
switch (block.getFacing()) {
case DOWN:
default:
return new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 0, 16, 4, 16),
new HexCollisionBox(6, 4, 6, 10, 16 + longAmount, 10));
case UP:
return new ComplexCollisionBox(2,
new HexCollisionBox(0, 12, 0, 16, 16, 16),
new HexCollisionBox(6, 0 - longAmount, 6, 10, 12, 10));
case NORTH -> new ComplexCollisionBox(2,
new HexCollisionBox(6, 0 - longAmount, 6, 10, 12, 10));
case NORTH:
return new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 0, 16, 16, 4),
new HexCollisionBox(6, 6, 4, 10, 10, 16 + longAmount));
case SOUTH -> {
new HexCollisionBox(6, 6, 4, 10, 10, 16 + longAmount));
case SOUTH:
// SOUTH piston is glitched in 1.7 and 1.8, fixed in 1.9
// Don't bother with short piston boxes as 1.7/1.8 clients don't have them
if (version.isOlderThanOrEquals(ClientVersion.V_1_8))
yield new ComplexCollisionBox(2,
return new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 12, 16, 16, 16),
new HexCollisionBox(4, 6, 0, 12, 10, 12));
yield new ComplexCollisionBox(2,
return new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 12, 16, 16, 16),
new HexCollisionBox(6, 6, 0 - longAmount, 10, 10, 12));
}
case WEST -> {
case WEST:
// WEST piston is glitched in 1.7 and 1.8, fixed in 1.9
// Don't bother with short piston boxes as 1.7/1.8 clients don't have them
if (version.isOlderThanOrEquals(ClientVersion.V_1_8))
yield new ComplexCollisionBox(2,
return new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 0, 4, 16, 16),
new HexCollisionBox(6, 4, 4, 10, 12, 16));
yield new ComplexCollisionBox(2,
return new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 0, 4, 16, 16),
new HexCollisionBox(4, 6, 6, 16 + longAmount, 10, 10));
}
case EAST -> new ComplexCollisionBox(2,
new HexCollisionBox(12, 0, 0, 16, 16, 16),
new HexCollisionBox(0 - longAmount, 6, 4, 12, 10, 12));
default -> new ComplexCollisionBox(2,
new HexCollisionBox(0, 0, 0, 16, 4, 16),
new HexCollisionBox(6, 4, 6, 10, 16 + longAmount, 10));
};
case EAST:
return new ComplexCollisionBox(2,
new HexCollisionBox(12, 0, 0, 16, 16, 16),
new HexCollisionBox(0 - longAmount, 6, 4, 12, 10, 12));
}
}
}
@@ -9,7 +9,7 @@ import java.util.HashSet;
public class OffsetCollisionBox extends SimpleCollisionBox {
public static enum OffsetType {
public enum OffsetType {
NONE,
XZ,
XYZ,
Loaded 100 of 169 files, more files were not shown because too many files have changed in this diff. Show more