diff --git a/README.md b/README.md
index 0ba9625..d6f7ac4 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,10 @@
# XeroAntiCheat
+Lightweight, accurate anti-cheat for Paper 1.21.x
+
+## Latest Updates (v1.1.0)
+
+- **ReachCheck**: Now measures distance to entity bounding box center instead of feet. Eliminates false negatives when attacking tall entities (horses, iron golems, withers). Also switched from `distance()` to `distanceSquared()` comparison, removing a `Math.sqrt()` from the hot path.
+- **AutoClickerCheck**: `checkPattern()` rewritten with zero-allocation two-pass iterator approach. Previously allocated two `ArrayList` objects on every combat click.
+- **TimerCheck**: Removed redundant blink detection from `check()` method. Blink detection is fully handled by the 5-tick scheduled task. `setLastMovePacketTime()` retained to feed the task.
+- **KillAuraCheck**: Removed unused `EntityEffect` import.
diff --git a/pom.xml b/pom.xml
index feae0eb..7d44431 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.xeroth
xeroanticheat
- 1.0.9
+ 1.1.0
jar
XeroAntiCheat
diff --git a/src/main/java/com/xeroth/xeroanticheat/checks/combat/AutoClickerCheck.java b/src/main/java/com/xeroth/xeroanticheat/checks/combat/AutoClickerCheck.java
index 15e9a6f..66689a6 100644
--- a/src/main/java/com/xeroth/xeroanticheat/checks/combat/AutoClickerCheck.java
+++ b/src/main/java/com/xeroth/xeroanticheat/checks/combat/AutoClickerCheck.java
@@ -5,9 +5,6 @@ import com.xeroth.xeroanticheat.check.Check;
import com.xeroth.xeroanticheat.data.PlayerData;
import org.bukkit.entity.Player;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* AutoClickerCheck - Tracks CPS (clicks per second) over a 1-second sliding window.
*
@@ -54,35 +51,33 @@ public class AutoClickerCheck extends Check {
* Check click pattern for suspiciously low variance
*/
private void checkPattern(PlayerData data, Player player, double minVariance) {
- List clicks = new ArrayList<>(data.getClickTimestamps());
-
- if (clicks.size() < 5) return;
-
- // Calculate intervals between clicks
- List intervals = new ArrayList<>();
- for (int i = 0; i < clicks.size() - 1; i++) {
- intervals.add(clicks.get(i) - clicks.get(i + 1));
- }
-
- if (intervals.isEmpty()) return;
-
- // Calculate mean
+ if (data.getClickTimestamps().size() < 5) return;
+
double sum = 0;
- for (Long interval : intervals) {
- sum += interval;
+ int intervalCount = 0;
+ Long prev = null;
+ for (Long ts : data.getClickTimestamps()) {
+ if (prev != null) {
+ sum += (prev - ts);
+ intervalCount++;
+ }
+ prev = ts;
}
- double mean = sum / intervals.size();
-
- // Calculate variance
+ if (intervalCount == 0) return;
+ double mean = sum / intervalCount;
+
double varianceSum = 0;
- for (Long interval : intervals) {
- double diff = interval - mean;
- varianceSum += diff * diff;
+ prev = null;
+ for (Long ts : data.getClickTimestamps()) {
+ if (prev != null) {
+ double diff = (prev - ts) - mean;
+ varianceSum += diff * diff;
+ }
+ prev = ts;
}
- double variance = varianceSum / intervals.size();
- double stdDev = Math.sqrt(variance);
-
- // If variance is too low, flag (too perfect)
+
+ double stdDev = Math.sqrt(varianceSum / intervalCount);
+
if (stdDev < minVariance && data.getCPS() > 10) {
flag(data, player, 1.0);
}
diff --git a/src/main/java/com/xeroth/xeroanticheat/checks/combat/KillAuraCheck.java b/src/main/java/com/xeroth/xeroanticheat/checks/combat/KillAuraCheck.java
index 6be9975..402ce2e 100644
--- a/src/main/java/com/xeroth/xeroanticheat/checks/combat/KillAuraCheck.java
+++ b/src/main/java/com/xeroth/xeroanticheat/checks/combat/KillAuraCheck.java
@@ -3,7 +3,6 @@ package com.xeroth.xeroanticheat.checks.combat;
import com.xeroth.xeroanticheat.XeroAntiCheat;
import com.xeroth.xeroanticheat.check.Check;
import com.xeroth.xeroanticheat.data.PlayerData;
-import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
diff --git a/src/main/java/com/xeroth/xeroanticheat/checks/combat/ReachCheck.java b/src/main/java/com/xeroth/xeroanticheat/checks/combat/ReachCheck.java
index 869cbab..f4f25c9 100644
--- a/src/main/java/com/xeroth/xeroanticheat/checks/combat/ReachCheck.java
+++ b/src/main/java/com/xeroth/xeroanticheat/checks/combat/ReachCheck.java
@@ -60,12 +60,20 @@ public class ReachCheck extends Check {
// Get player eye location
Location eyeLoc = player.getEyeLocation();
- // Get target location (center of entity hitbox)
- Location targetLoc = target.getLocation();
+ // Use center of entity bounding box, not feet position.
+ // getLocation() returns feet; bounding box center is more accurate for tall entities.
+ org.bukkit.util.BoundingBox bb = target.getBoundingBox();
+ double targetX = (bb.getMinX() + bb.getMaxX()) / 2.0;
+ double targetY = (bb.getMinY() + bb.getMaxY()) / 2.0;
+ double targetZ = (bb.getMinZ() + bb.getMaxZ()) / 2.0;
- // Calculate 3D distance
- double distance = eyeLoc.distance(targetLoc);
+ // Calculate 3D distance from player eye to entity center (no Location object needed)
+ double dx = eyeLoc.getX() - targetX;
+ double dy = eyeLoc.getY() - targetY;
+ double dz = eyeLoc.getZ() - targetZ;
+ double distanceSquared = dx * dx + dy * dy + dz * dz;
- return distance > maxReach;
+ double maxReachSquared = maxReach * maxReach;
+ return distanceSquared > maxReachSquared;
}
}
diff --git a/src/main/java/com/xeroth/xeroanticheat/checks/movement/TimerCheck.java b/src/main/java/com/xeroth/xeroanticheat/checks/movement/TimerCheck.java
index 80c9853..11b876b 100644
--- a/src/main/java/com/xeroth/xeroanticheat/checks/movement/TimerCheck.java
+++ b/src/main/java/com/xeroth/xeroanticheat/checks/movement/TimerCheck.java
@@ -32,7 +32,6 @@ public class TimerCheck extends Check {
// Get thresholds
int maxPacketsPerSecond = getConfigInt("max_packets_per_second", 22);
- long blinkThresholdMs = getConfigInt("blink_threshold_ms", 500);
// If ProtocolLib is active, packet counting is handled by PacketListener
if (plugin.isProtocolLibLoaded()) {
@@ -57,28 +56,6 @@ public class TimerCheck extends Check {
flag(data, player, (data.getPacketsThisSecond() - maxPacketsPerSecond) * 0.5);
}
- // Check for blink (packet suppression)
- long lastMoveTime = data.getLastMovePacketTime();
- if (lastMoveTime > 0) {
- long gap = now - lastMoveTime;
- if (gap > blinkThresholdMs) {
- // Check if player teleported during the gap
- PlayerData.PositionSnapshot current = data.getLastPosition();
- PlayerData.PositionSnapshot last = data.getSecondLastPosition();
- if (current != null && last != null) {
- double dx = current.x() - last.x();
- double dy = current.y() - last.y();
- double dz = current.z() - last.z();
- double distance = Math.sqrt(dx*dx + dy*dy + dz*dz);
-
- // If teleported more than 10 blocks, likely blink
- if (distance > 10) {
- flag(data, player, 2.0);
- }
- }
- }
- }
-
data.setLastMovePacketTime(now);
}
}
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index c7507c2..f3797b7 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -1,5 +1,5 @@
name: XeroAntiCheat
-version: 1.0.9
+version: 1.1.0
main: com.xeroth.xeroanticheat.XeroAntiCheat
author: Xeroth
description: Lightweight, accurate anti-cheat for Paper 1.21.x