Skip to content

Commit 9b11eb3

Browse files
authored
Merge branch 'GrimAnticheat:2.0' into 2.0
2 parents 54a1528 + a1fcc7f commit 9b11eb3

File tree

32 files changed

+561
-88
lines changed

32 files changed

+561
-88
lines changed

build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ repositories {
2525
maven("https://repo.opencollab.dev/maven-snapshots/") // Floodgate
2626
maven("https://repo.opencollab.dev/maven-releases/") // Cumulus (for Floodgate)
2727
maven("https://repo.codemc.io/repository/maven-releases/") // PacketEvents
28+
maven("https://repo.codemc.io/repository/maven-snapshots/")
2829
mavenCentral()
2930
// FastUtil, Discord-Webhooks
3031
}
3132

3233
dependencies {
33-
implementation("com.github.retrooper.packetevents:spigot:2.3.0")
34+
implementation("com.github.retrooper.packetevents:spigot:2.3.1-SNAPSHOT")
3435
implementation("co.aikar:acf-paper:0.5.1-SNAPSHOT")
3536
implementation("club.minnced:discord-webhooks:0.8.0") // Newer versions include kotlin-stdlib, which leads to incompatibility with plugins that use Kotlin
3637
implementation("it.unimi.dsi:fastutil:8.5.13")

src/main/java/ac/grim/grimac/checks/impl/combat/Reach.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ private boolean isKnownInvalid(PacketEntity reachEntity) {
131131
} else {
132132
SimpleCollisionBox targetBox = reachEntity.getPossibleCollisionBoxes();
133133
if (reachEntity.getType() == EntityTypes.END_CRYSTAL) {
134-
targetBox = new SimpleCollisionBox(reachEntity.desyncClientPos.subtract(1, 0, 1), reachEntity.desyncClientPos.add(1, 2, 1));
134+
targetBox = new SimpleCollisionBox(reachEntity.trackedServerPosition.getPos().subtract(1, 0, 1), reachEntity.trackedServerPosition.getPos().add(1, 2, 1));
135135
}
136136
return ReachUtils.getMinReachToBox(player, targetBox) > player.compensatedEntities.getSelf().getEntityInteractRange();
137137
}
@@ -159,7 +159,7 @@ private String checkReach(PacketEntity reachEntity, Vector3d from, boolean isPre
159159
SimpleCollisionBox targetBox = reachEntity.getPossibleCollisionBoxes();
160160

161161
if (reachEntity.getType() == EntityTypes.END_CRYSTAL) { // Hardcode end crystal box
162-
targetBox = new SimpleCollisionBox(reachEntity.desyncClientPos.subtract(1, 0, 1), reachEntity.desyncClientPos.add(1, 2, 1));
162+
targetBox = new SimpleCollisionBox(reachEntity.trackedServerPosition.getPos().subtract(1, 0, 1), reachEntity.trackedServerPosition.getPos().add(1, 2, 1));
163163
}
164164

165165
// 1.7 and 1.8 players get a bit of extra hitbox (this is why you should use 1.8 on cross version servers)

src/main/java/ac/grim/grimac/checks/impl/scaffolding/FarPlace.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ public void onBlockPlace(final BlockPlace place) {
3434

3535
// getPickRange() determines this?
3636
// With 1.20.5+ the new attribute determines creative mode reach using a modifier
37-
double maxReach = player.gamemode == GameMode.CREATIVE && !player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20_5)
38-
? 6.0
39-
: player.compensatedEntities.getSelf().getBlockInteractRange();
37+
double maxReach = player.compensatedEntities.getSelf().getBlockInteractRange();
4038
double threshold = player.getMovementThreshold();
4139
maxReach += Math.hypot(threshold, threshold);
4240

src/main/java/ac/grim/grimac/checks/impl/velocity/ExplosionHandler.java

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@
99
import ac.grim.grimac.utils.data.VelocityData;
1010
import com.github.retrooper.packetevents.event.PacketSendEvent;
1111
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
12+
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
13+
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
14+
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
15+
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
16+
import com.github.retrooper.packetevents.protocol.world.states.type.StateValue;
1217
import com.github.retrooper.packetevents.util.Vector3f;
1318
import com.github.retrooper.packetevents.util.Vector3i;
1419
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerExplosion;
1520
import lombok.Getter;
1621
import org.bukkit.Bukkit;
1722
import org.bukkit.util.Vector;
23+
import org.jetbrains.annotations.Nullable;
1824

1925
import java.util.Deque;
2026
import java.util.LinkedList;
@@ -43,12 +49,35 @@ public void onPacketSend(final PacketSendEvent event) {
4349

4450
Vector3f velocity = explosion.getPlayerMotion();
4551

46-
if (!explosion.getRecords().isEmpty()) {
52+
final @Nullable WrapperPlayServerExplosion.BlockInteraction blockInteraction = explosion.getBlockInteraction();
53+
final boolean shouldDestroy = blockInteraction != WrapperPlayServerExplosion.BlockInteraction.KEEP_BLOCKS;
54+
if (!explosion.getRecords().isEmpty() && shouldDestroy) {
4755
player.sendTransaction();
4856

4957
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> {
50-
for (Vector3i records : explosion.getRecords()) {
51-
player.compensatedWorld.updateBlock(records.x, records.y, records.z, 0);
58+
for (Vector3i record : explosion.getRecords()) {
59+
// Null OR not flip redstone blocks, then set to air
60+
if (blockInteraction != WrapperPlayServerExplosion.BlockInteraction.TRIGGER_BLOCKS) {
61+
player.compensatedWorld.updateBlock(record.x, record.y, record.z, 0);
62+
} else {
63+
// We need to flip redstone blocks, or do special things with other blocks
64+
final WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(record);
65+
final StateType type = state.getType();
66+
if (BlockTags.CANDLES.contains(type) || BlockTags.CANDLE_CAKES.contains(type)) {
67+
state.setLit(false);
68+
continue;
69+
} else if (type == StateTypes.BELL) {
70+
// Does this affect anything? I don't know, I don't see anything that relies on whether a bell is ringing.
71+
continue;
72+
}
73+
74+
// Otherwise try and flip/open it.
75+
final Object poweredValue = state.getInternalData().get(StateValue.POWERED);
76+
final boolean canFlip = (poweredValue != null && !(Boolean) poweredValue) || type == StateTypes.LEVER;
77+
if (canFlip) {
78+
player.compensatedWorld.tickOpenable(record.x, record.y, record.z);
79+
}
80+
}
5281
}
5382
});
5483
}

src/main/java/ac/grim/grimac/events/packets/PacketPlayerRespawn.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ public PacketPlayerRespawn() {
5454
private static final byte KEEP_ALL = 3;
5555

5656
private boolean hasFlag(WrapperPlayServerRespawn respawn, byte flag) {
57+
// This packet was added in 1.16
58+
// On versions older than 1.16, via keeps all data.
59+
if (PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_16)) {
60+
return true;
61+
}
5762
return (respawn.getKeptData() & flag) != 0;
5863
}
5964

@@ -177,8 +182,8 @@ public void onPacketSend(PacketSendEvent event) {
177182
player.compensatedWorld.setDimension(respawn.getDimension(), event.getUser());
178183
}
179184

180-
// TODO this needs to be done for other client versions as well. And there should probably be some attribute holder that we can just call reset() on.
181-
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_20_5) && !this.hasFlag(respawn, KEEP_ATTRIBUTES)) {
185+
// TODO And there should probably be some attribute holder that we can just call reset() on.
186+
if (player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_16) && !this.hasFlag(respawn, KEEP_ATTRIBUTES)) {
182187
// Reset attributes if not kept
183188
final PacketEntitySelf self = player.compensatedEntities.getSelf();
184189
self.gravityAttribute = 0.08d;

src/main/java/ac/grim/grimac/manager/SetbackTeleportUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ public TeleportAcceptData checkTeleportQueue(double x, double y, double z) {
280280

281281
// There seems to be a version difference in teleports past 30 million... just clamp the vector
282282
Vector3d clamped = VectorUtils.clampVector(new Vector3d(trueTeleportX, trueTeleportY, trueTeleportZ));
283-
double threshold = teleportPos.isRelativeX() ? player.getMovementThreshold() : 0;
283+
double threshold = teleportPos.isRelative() ? player.getMovementThreshold() : 0;
284284
boolean closeEnoughY = Math.abs(clamped.getY() - y) <= 1e-7 + threshold; // 1.7 rounding
285285

286286
if (player.lastTransactionReceived.get() == teleportPos.getTransaction() && Math.abs(clamped.getX() - x) <= threshold && closeEnoughY && Math.abs(clamped.getZ() - z) <= threshold) {

src/main/java/ac/grim/grimac/predictionengine/MovementCheckRunner.java

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import ac.grim.grimac.utils.anticheat.update.PredictionComplete;
1818
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
1919
import ac.grim.grimac.utils.data.VectorData;
20+
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
2021
import ac.grim.grimac.utils.data.packetentity.PacketEntityHorse;
2122
import ac.grim.grimac.utils.data.packetentity.PacketEntityRideable;
2223
import ac.grim.grimac.utils.data.packetentity.PacketEntityTrackXRot;
@@ -55,19 +56,14 @@ public void processAndCheckMovementPacket(PositionUpdate data) {
5556
// This teleport wasn't valid as the player STILL hasn't loaded this damn chunk.
5657
// Keep re-teleporting until they load the chunk!
5758
if (player.getSetbackTeleportUtil().insideUnloadedChunk()) {
58-
player.lastOnGround = player.clientClaimsLastOnGround; // Stop a false on join
59-
6059
// The player doesn't control this vehicle, we don't care
61-
if (player.compensatedEntities.getSelf().inVehicle() &&
60+
final boolean invalidVehicle = player.compensatedEntities.getSelf().inVehicle() &&
6261
(PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9) ||
63-
player.getClientVersion().isOlderThan(ClientVersion.V_1_9))) {
64-
return;
65-
}
62+
player.getClientVersion().isOlderThan(ClientVersion.V_1_9));
6663

67-
if (!data.isTeleport()) {
64+
if (!invalidVehicle && !data.isTeleport()) {
6865
// Teleport the player back to avoid players being able to simply ignore transactions
6966
player.getSetbackTeleportUtil().executeForceResync();
70-
return;
7167
}
7268
}
7369

@@ -180,19 +176,20 @@ private void check(PositionUpdate update) {
180176
player.clientVelocity.multiply(0.98); // This is vanilla, do not touch
181177
}
182178

179+
final PacketEntity riding = player.compensatedEntities.getSelf().getRiding();
183180
if (player.vehicleData.wasVehicleSwitch || player.vehicleData.lastDummy) {
184181
update.setTeleport(true);
185182

186183
player.vehicleData.lastDummy = false;
187184
player.vehicleData.wasVehicleSwitch = false;
188185

189-
if (player.compensatedEntities.getSelf().getRiding() != null) {
186+
if (riding != null) {
190187
Vector pos = new Vector(player.x, player.y, player.z);
191-
SimpleCollisionBox interTruePositions = player.compensatedEntities.getSelf().getRiding().getPossibleCollisionBoxes();
188+
SimpleCollisionBox interTruePositions = riding.getPossibleCollisionBoxes();
192189

193190
// We shrink the expanded bounding box to what the packet positions can be, for a smaller box
194-
float width = BoundingBoxSize.getWidth(player, player.compensatedEntities.getSelf().getRiding());
195-
float height = BoundingBoxSize.getHeight(player, player.compensatedEntities.getSelf().getRiding());
191+
float width = BoundingBoxSize.getWidth(player, riding) * riding.scale;
192+
float height = BoundingBoxSize.getHeight(player, riding) * riding.scale;
196193
interTruePositions.expand(-width, 0, -width);
197194
interTruePositions.expandMax(0, -height, 0);
198195

@@ -258,25 +255,25 @@ private void check(PositionUpdate update) {
258255
player.checkManager.getExplosionHandler().forceExempt();
259256

260257
// When in control of the entity, the player sets the entity position to their current position
261-
player.compensatedEntities.getSelf().getRiding().setPositionRaw(GetBoundingBox.getPacketEntityBoundingBox(player, player.x, player.y, player.z, player.compensatedEntities.getSelf().getRiding()));
258+
riding.setPositionRaw(GetBoundingBox.getPacketEntityBoundingBox(player, player.x, player.y, player.z, riding));
262259

263-
if (player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityTrackXRot) {
264-
PacketEntityTrackXRot boat = (PacketEntityTrackXRot) player.compensatedEntities.getSelf().getRiding();
260+
if (riding instanceof PacketEntityTrackXRot) {
261+
PacketEntityTrackXRot boat = (PacketEntityTrackXRot) riding;
265262
boat.packetYaw = player.xRot;
266263
boat.interpYaw = player.xRot;
267264
boat.steps = 0;
268265
}
269266

270-
if (player.hasGravity != player.compensatedEntities.getSelf().getRiding().hasGravity) {
267+
if (player.hasGravity != riding.hasGravity) {
271268
player.pointThreeEstimator.updatePlayerGravity();
272269
}
273-
player.hasGravity = player.compensatedEntities.getSelf().getRiding().hasGravity;
270+
player.hasGravity = riding.hasGravity;
274271

275272
// For whatever reason the vehicle move packet occurs AFTER the player changes slots...
276-
if (player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityRideable) {
273+
if (riding instanceof PacketEntityRideable) {
277274
EntityControl control = player.checkManager.getPostPredictionCheck(EntityControl.class);
278275

279-
ItemType requiredItem = player.compensatedEntities.getSelf().getRiding().getType() == EntityTypes.PIG ? ItemTypes.CARROT_ON_A_STICK : ItemTypes.WARPED_FUNGUS_ON_A_STICK;
276+
ItemType requiredItem = riding.getType() == EntityTypes.PIG ? ItemTypes.CARROT_ON_A_STICK : ItemTypes.WARPED_FUNGUS_ON_A_STICK;
280277
ItemStack mainHand = player.getInventory().getHeldItem();
281278
ItemStack offHand = player.getInventory().getOffHand();
282279

@@ -323,7 +320,7 @@ private void check(PositionUpdate update) {
323320
player.isSprinting = false;
324321
player.isSneaking = false;
325322

326-
if (player.compensatedEntities.getSelf().getRiding().getType() != EntityTypes.PIG && player.compensatedEntities.getSelf().getRiding().getType() != EntityTypes.STRIDER) {
323+
if (riding.getType() != EntityTypes.PIG && riding.getType() != EntityTypes.STRIDER) {
327324
player.isClimbing = false;
328325
}
329326
}
@@ -427,7 +424,7 @@ private void check(PositionUpdate update) {
427424
boolean wasChecked = false;
428425

429426
// Exempt if the player is dead or is riding a dead entity
430-
if (player.compensatedEntities.getSelf().isDead || (player.compensatedEntities.getSelf().getRiding() != null && player.compensatedEntities.getSelf().getRiding().isDead)) {
427+
if (player.compensatedEntities.getSelf().isDead || (riding != null && riding.isDead)) {
431428
// Dead players can't cheat, if you find a way how they could, open an issue
432429
player.predictedVelocity = new VectorData(new Vector(), VectorData.VectorType.Dead);
433430
player.clientVelocity = new Vector();
@@ -441,7 +438,7 @@ private void check(PositionUpdate update) {
441438
player.gravity = 0;
442439
player.friction = 0.91f;
443440
PredictionEngineNormal.staticVectorEndOfTick(player, player.clientVelocity);
444-
} else if (player.compensatedEntities.getSelf().getRiding() == null) {
441+
} else if (riding == null) {
445442
wasChecked = true;
446443

447444
// Depth strider was added in 1.8
@@ -495,17 +492,17 @@ private void check(PositionUpdate update) {
495492
// The player and server are both on a version with client controlled entities
496493
// If either or both of the client server version has server controlled entities
497494
// The player can't use entities (or the server just checks the entities)
498-
if (EntityTypes.isTypeInstanceOf(player.compensatedEntities.getSelf().getRiding().getType(), EntityTypes.BOAT)) {
495+
if (EntityTypes.isTypeInstanceOf(riding.getType(), EntityTypes.BOAT)) {
499496
new PlayerBaseTick(player).doBaseTick();
500497
// Speed doesn't affect anything with boat movement
501498
new BoatPredictionEngine(player).guessBestMovement(0.1f, player);
502-
} else if (player.compensatedEntities.getSelf().getRiding() instanceof PacketEntityHorse) {
499+
} else if (riding instanceof PacketEntityHorse) {
503500
new PlayerBaseTick(player).doBaseTick();
504501
new MovementTickerHorse(player).livingEntityAIStep();
505-
} else if (player.compensatedEntities.getSelf().getRiding().getType() == EntityTypes.PIG) {
502+
} else if (riding.getType() == EntityTypes.PIG) {
506503
new PlayerBaseTick(player).doBaseTick();
507504
new MovementTickerPig(player).livingEntityAIStep();
508-
} else if (player.compensatedEntities.getSelf().getRiding().getType() == EntityTypes.STRIDER) {
505+
} else if (riding.getType() == EntityTypes.STRIDER) {
509506
new PlayerBaseTick(player).doBaseTick();
510507
new MovementTickerStrider(player).livingEntityAIStep();
511508
MovementTickerStrider.floatStrider(player);

src/main/java/ac/grim/grimac/predictionengine/UncertaintyHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ public void tickFireworksBox() {
138138
if (entity == null) continue;
139139

140140
SimpleCollisionBox entityBox = entity.getPossibleCollisionBoxes();
141-
float width = BoundingBoxSize.getWidth(player, entity);
142-
float height = BoundingBoxSize.getHeight(player, entity);
141+
float width = BoundingBoxSize.getWidth(player, entity) * entity.scale;
142+
float height = BoundingBoxSize.getHeight(player, entity) * entity.scale;
143143

144144
// Convert back to coordinates instead of hitbox
145145
entityBox.maxY -= height;

src/main/java/ac/grim/grimac/utils/anticheat/update/BlockPlace.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -574,16 +574,16 @@ public void set(Vector3i position, WrappedBlockState state) {
574574
for (PacketEntity entity : player.compensatedEntities.entityMap.values()) {
575575
SimpleCollisionBox interpBox = entity.getPossibleCollisionBoxes();
576576

577-
double width = BoundingBoxSize.getWidth(player, entity);
578-
double height = BoundingBoxSize.getHeight(player, entity);
577+
double width = BoundingBoxSize.getWidth(player, entity) * entity.scale;
578+
double height = BoundingBoxSize.getHeight(player, entity) * entity.scale;
579579
double interpWidth = Math.max(interpBox.maxX - interpBox.minX, interpBox.maxZ - interpBox.minZ);
580580
double interpHeight = interpBox.maxY - interpBox.minY;
581581

582582
// If not accurate, fall back to desync pos
583583
// This happens due to the lack of an idle packet on 1.9+ clients
584584
// On 1.8 clients this should practically never happen
585585
if (interpWidth - width > 0.05 || interpHeight - height > 0.05) {
586-
Vector3d entityPos = entity.desyncClientPos;
586+
Vector3d entityPos = entity.trackedServerPosition.getPos();
587587
interpBox = GetBoundingBox.getPacketEntityBoundingBox(player, entityPos.getX(), entityPos.getY(), entityPos.getZ(), entity);
588588
}
589589

src/main/java/ac/grim/grimac/utils/collisions/blocks/connecting/DynamicWall.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import com.github.retrooper.packetevents.protocol.world.states.enums.South;
1515
import com.github.retrooper.packetevents.protocol.world.states.enums.West;
1616
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
17-
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
1817

1918
public class DynamicWall extends DynamicConnecting implements CollisionFactory {
2019
public static final CollisionBox[] BOXES = makeShapes(4.0F, 3.0F, 16.0F, 0.0F, 16.0F, false);

0 commit comments

Comments
 (0)