diff --git a/src/main/java/ac/grim/grimac/checks/impl/combat/MultiInteractA.java b/src/main/java/ac/grim/grimac/checks/impl/combat/MultiInteractA.java new file mode 100644 index 0000000000..b599e0f350 --- /dev/null +++ b/src/main/java/ac/grim/grimac/checks/impl/combat/MultiInteractA.java @@ -0,0 +1,66 @@ +package ac.grim.grimac.checks.impl.combat; + +import ac.grim.grimac.checks.Check; +import ac.grim.grimac.checks.CheckData; +import ac.grim.grimac.checks.type.PostPredictionCheck; +import ac.grim.grimac.player.GrimPlayer; +import ac.grim.grimac.utils.anticheat.update.PredictionComplete; +import com.github.retrooper.packetevents.event.PacketReceiveEvent; +import com.github.retrooper.packetevents.protocol.packettype.PacketType; +import com.github.retrooper.packetevents.protocol.player.ClientVersion; +import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity; +import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying; + +import java.util.ArrayList; + +@CheckData(name = "MultiInteractA", experimental = true) +public class MultiInteractA extends Check implements PostPredictionCheck { + public MultiInteractA(final GrimPlayer player) { + super(player); + } + + private final ArrayList flags = new ArrayList<>(); + private int lastEntity; + private boolean hasInteracted = false; + + @Override + public void onPacketReceive(PacketReceiveEvent event) { + if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) { + int entity = new WrapperPlayClientInteractEntity(event).getEntityId(); + + if (hasInteracted && entity != lastEntity) { + String verbose = "lastEntity=" + lastEntity + ", entity=" + entity; + if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) { + if (flagAndAlert(verbose) && shouldModifyPackets()) { + event.setCancelled(true); + player.onPacketCancel(); + } + } else { + flags.add(verbose); + } + } + + lastEntity = entity; + hasInteracted = true; + } + + if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) && !player.packetStateData.lastPacketWasTeleport) { + hasInteracted = false; + } + } + + @Override + public void onPredictionComplete(PredictionComplete predictionComplete) { + // we don't need to check pre-1.9 players here (no tick skipping) + if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return; + + if (!player.skippedTickInActualMovement) { + for (String verbose : flags) { + flagAndAlert(verbose); + } + } + + flags.clear(); + hasInteracted = false; + } +} diff --git a/src/main/java/ac/grim/grimac/checks/impl/combat/MultiInteractB.java b/src/main/java/ac/grim/grimac/checks/impl/combat/MultiInteractB.java new file mode 100644 index 0000000000..ca68bd5d5a --- /dev/null +++ b/src/main/java/ac/grim/grimac/checks/impl/combat/MultiInteractB.java @@ -0,0 +1,72 @@ +package ac.grim.grimac.checks.impl.combat; + +import ac.grim.grimac.checks.Check; +import ac.grim.grimac.checks.CheckData; +import ac.grim.grimac.checks.type.PostPredictionCheck; +import ac.grim.grimac.player.GrimPlayer; +import ac.grim.grimac.utils.anticheat.MessageUtil; +import ac.grim.grimac.utils.anticheat.update.PredictionComplete; +import com.github.retrooper.packetevents.event.PacketReceiveEvent; +import com.github.retrooper.packetevents.protocol.packettype.PacketType; +import com.github.retrooper.packetevents.protocol.player.ClientVersion; +import com.github.retrooper.packetevents.util.Vector3f; +import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity; +import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying; + +import java.util.ArrayList; + +@CheckData(name = "MultiInteractB", experimental = true) +public class MultiInteractB extends Check implements PostPredictionCheck { + public MultiInteractB(final GrimPlayer player) { + super(player); + } + + private final ArrayList flags = new ArrayList<>(); + private Vector3f lastPos; + private boolean hasInteracted = false; + + @Override + public void onPacketReceive(PacketReceiveEvent event) { + if (event.getPacketType() == PacketType.Play.Client.INTERACT_ENTITY) { + Vector3f pos = new WrapperPlayClientInteractEntity(event).getTarget().orElse(null); + + if (pos == null) { + return; + } + + if (hasInteracted && !pos.equals(lastPos)) { + String verbose = "pos=" + MessageUtil.toUnlabledString(pos) + ", lastPos=" + MessageUtil.toUnlabledString(lastPos); + if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) { + if (flagAndAlert(verbose) && shouldModifyPackets()) { + event.setCancelled(true); + player.onPacketCancel(); + } + } else { + flags.add(verbose); + } + } + + lastPos = pos; + hasInteracted = true; + } + + if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType()) && player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8) && !player.packetStateData.lastPacketWasTeleport) { + hasInteracted = false; + } + } + + @Override + public void onPredictionComplete(PredictionComplete predictionComplete) { + // we don't need to check pre-1.9 players here (no tick skipping) + if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_8)) return; + + if (!player.skippedTickInActualMovement) { + for (String verbose : flags) { + flagAndAlert(verbose); + } + } + + flags.clear(); + hasInteracted = false; + } +} diff --git a/src/main/java/ac/grim/grimac/manager/CheckManager.java b/src/main/java/ac/grim/grimac/manager/CheckManager.java index c396ca0455..9c83338e6c 100644 --- a/src/main/java/ac/grim/grimac/manager/CheckManager.java +++ b/src/main/java/ac/grim/grimac/manager/CheckManager.java @@ -6,6 +6,8 @@ import ac.grim.grimac.checks.impl.aim.AimModulo360; import ac.grim.grimac.checks.impl.aim.processor.AimProcessor; import ac.grim.grimac.checks.impl.badpackets.*; +import ac.grim.grimac.checks.impl.combat.MultiInteractA; +import ac.grim.grimac.checks.impl.combat.MultiInteractB; import ac.grim.grimac.checks.impl.combat.Reach; import ac.grim.grimac.checks.impl.crash.*; import ac.grim.grimac.checks.impl.exploit.ExploitA; @@ -129,6 +131,8 @@ public CheckManager(GrimPlayer player) { .put(NoSlowC.class, new NoSlowC(player)) .put(NoSlowD.class, new NoSlowD(player)) .put(NoSlowE.class, new NoSlowE(player)) + .put(MultiInteractA.class, new MultiInteractA(player)) + .put(MultiInteractB.class, new MultiInteractB(player)) .put(SetbackTeleportUtil.class, new SetbackTeleportUtil(player)) // Avoid teleporting to new position, update safe pos last .put(CompensatedFireworks.class, player.compensatedFireworks) .put(SneakingEstimator.class, new SneakingEstimator(player)) diff --git a/src/main/resources/punishments/de.yml b/src/main/resources/punishments/de.yml index ffb36b28d9..d8b7460a5a 100644 --- a/src/main/resources/punishments/de.yml +++ b/src/main/resources/punishments/de.yml @@ -81,6 +81,7 @@ Punishments: Combat: remove-violations-after: 300 checks: + - "Interact" - "Killaura" - "Aim" commands: diff --git a/src/main/resources/punishments/en.yml b/src/main/resources/punishments/en.yml index 00f6e842c5..eaf4af6e57 100644 --- a/src/main/resources/punishments/en.yml +++ b/src/main/resources/punishments/en.yml @@ -81,6 +81,7 @@ Punishments: Combat: remove-violations-after: 300 checks: + - "Interact" - "Killaura" - "Aim" commands: diff --git a/src/main/resources/punishments/es.yml b/src/main/resources/punishments/es.yml index d8542bf0b1..8965d5fd4d 100644 --- a/src/main/resources/punishments/es.yml +++ b/src/main/resources/punishments/es.yml @@ -81,6 +81,7 @@ Punishments: Combat: remove-violations-after: 300 checks: + - "Interact" - "Killaura" - "Aim" commands: diff --git a/src/main/resources/punishments/fr.yml b/src/main/resources/punishments/fr.yml index f1113cc77a..09f85f4dc4 100644 --- a/src/main/resources/punishments/fr.yml +++ b/src/main/resources/punishments/fr.yml @@ -81,6 +81,7 @@ Punishments: Combat: remove-violations-after: 300 checks: + - "Interact" - "Killaura" - "Aim" commands: diff --git a/src/main/resources/punishments/it.yml b/src/main/resources/punishments/it.yml index 4521e1622e..71bda391eb 100644 --- a/src/main/resources/punishments/it.yml +++ b/src/main/resources/punishments/it.yml @@ -68,6 +68,7 @@ Punishments: Combat: remove-violations-after: 300 checks: + - "Interact" - "Killaura" - "Aim" commands: diff --git a/src/main/resources/punishments/nl.yml b/src/main/resources/punishments/nl.yml index 1f0c8075cc..a67948eee1 100644 --- a/src/main/resources/punishments/nl.yml +++ b/src/main/resources/punishments/nl.yml @@ -81,6 +81,7 @@ Punishments: Combat: remove-violations-after: 300 checks: + - "Interact" - "Killaura" - "Aim" commands: diff --git a/src/main/resources/punishments/pt.yml b/src/main/resources/punishments/pt.yml index d6e811564e..3dc8bbccee 100644 --- a/src/main/resources/punishments/pt.yml +++ b/src/main/resources/punishments/pt.yml @@ -81,6 +81,7 @@ Punishments: Combat: remove-violations-after: 300 checks: + - "Interact" - "Killaura" - "Aim" commands: diff --git a/src/main/resources/punishments/ru.yml b/src/main/resources/punishments/ru.yml index 1486066fe0..17a5433f1e 100644 --- a/src/main/resources/punishments/ru.yml +++ b/src/main/resources/punishments/ru.yml @@ -81,6 +81,7 @@ Punishments: Combat: remove-violations-after: 300 checks: + - "Interact" - "Killaura" - "Aim" commands: diff --git a/src/main/resources/punishments/tr.yml b/src/main/resources/punishments/tr.yml index b376eed155..acf80586b6 100644 --- a/src/main/resources/punishments/tr.yml +++ b/src/main/resources/punishments/tr.yml @@ -79,6 +79,7 @@ Punishments: Combat: remove-violations-after: 300 checks: + - "Interact" - "Killaura" - "Aim" commands: diff --git a/src/main/resources/punishments/zh.yml b/src/main/resources/punishments/zh.yml index 76b60092be..6093911f8e 100644 --- a/src/main/resources/punishments/zh.yml +++ b/src/main/resources/punishments/zh.yml @@ -81,6 +81,7 @@ Punishments: Combat: remove-violations-after: 300 checks: + - "Interact" - "Killaura" - "Aim" commands: