XeroAntiCheat v1.1.0 bug fixes
This commit is contained in:
@@ -1,2 +1,10 @@
|
|||||||
# XeroAntiCheat
|
# 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.
|
||||||
|
|||||||
2
pom.xml
2
pom.xml
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>com.xeroth</groupId>
|
<groupId>com.xeroth</groupId>
|
||||||
<artifactId>xeroanticheat</artifactId>
|
<artifactId>xeroanticheat</artifactId>
|
||||||
<version>1.0.9</version>
|
<version>1.1.0</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>XeroAntiCheat</name>
|
<name>XeroAntiCheat</name>
|
||||||
|
|||||||
@@ -5,9 +5,6 @@ import com.xeroth.xeroanticheat.check.Check;
|
|||||||
import com.xeroth.xeroanticheat.data.PlayerData;
|
import com.xeroth.xeroanticheat.data.PlayerData;
|
||||||
import org.bukkit.entity.Player;
|
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.
|
* 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
|
* Check click pattern for suspiciously low variance
|
||||||
*/
|
*/
|
||||||
private void checkPattern(PlayerData data, Player player, double minVariance) {
|
private void checkPattern(PlayerData data, Player player, double minVariance) {
|
||||||
List<Long> clicks = new ArrayList<>(data.getClickTimestamps());
|
if (data.getClickTimestamps().size() < 5) return;
|
||||||
|
|
||||||
if (clicks.size() < 5) return;
|
|
||||||
|
|
||||||
// Calculate intervals between clicks
|
|
||||||
List<Long> 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
|
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
for (Long interval : intervals) {
|
int intervalCount = 0;
|
||||||
sum += interval;
|
Long prev = null;
|
||||||
|
for (Long ts : data.getClickTimestamps()) {
|
||||||
|
if (prev != null) {
|
||||||
|
sum += (prev - ts);
|
||||||
|
intervalCount++;
|
||||||
|
}
|
||||||
|
prev = ts;
|
||||||
}
|
}
|
||||||
double mean = sum / intervals.size();
|
if (intervalCount == 0) return;
|
||||||
|
double mean = sum / intervalCount;
|
||||||
|
|
||||||
// Calculate variance
|
|
||||||
double varianceSum = 0;
|
double varianceSum = 0;
|
||||||
for (Long interval : intervals) {
|
prev = null;
|
||||||
double diff = interval - mean;
|
for (Long ts : data.getClickTimestamps()) {
|
||||||
varianceSum += diff * diff;
|
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) {
|
if (stdDev < minVariance && data.getCPS() > 10) {
|
||||||
flag(data, player, 1.0);
|
flag(data, player, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.xeroth.xeroanticheat.checks.combat;
|
|||||||
import com.xeroth.xeroanticheat.XeroAntiCheat;
|
import com.xeroth.xeroanticheat.XeroAntiCheat;
|
||||||
import com.xeroth.xeroanticheat.check.Check;
|
import com.xeroth.xeroanticheat.check.Check;
|
||||||
import com.xeroth.xeroanticheat.data.PlayerData;
|
import com.xeroth.xeroanticheat.data.PlayerData;
|
||||||
import org.bukkit.EntityEffect;
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|||||||
@@ -60,12 +60,20 @@ public class ReachCheck extends Check {
|
|||||||
// Get player eye location
|
// Get player eye location
|
||||||
Location eyeLoc = player.getEyeLocation();
|
Location eyeLoc = player.getEyeLocation();
|
||||||
|
|
||||||
// Get target location (center of entity hitbox)
|
// Use center of entity bounding box, not feet position.
|
||||||
Location targetLoc = target.getLocation();
|
// 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
|
// Calculate 3D distance from player eye to entity center (no Location object needed)
|
||||||
double distance = eyeLoc.distance(targetLoc);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ public class TimerCheck extends Check {
|
|||||||
|
|
||||||
// Get thresholds
|
// Get thresholds
|
||||||
int maxPacketsPerSecond = getConfigInt("max_packets_per_second", 22);
|
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 ProtocolLib is active, packet counting is handled by PacketListener
|
||||||
if (plugin.isProtocolLibLoaded()) {
|
if (plugin.isProtocolLibLoaded()) {
|
||||||
@@ -57,28 +56,6 @@ public class TimerCheck extends Check {
|
|||||||
flag(data, player, (data.getPacketsThisSecond() - maxPacketsPerSecond) * 0.5);
|
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);
|
data.setLastMovePacketTime(now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: XeroAntiCheat
|
name: XeroAntiCheat
|
||||||
version: 1.0.9
|
version: 1.1.0
|
||||||
main: com.xeroth.xeroanticheat.XeroAntiCheat
|
main: com.xeroth.xeroanticheat.XeroAntiCheat
|
||||||
author: Xeroth
|
author: Xeroth
|
||||||
description: Lightweight, accurate anti-cheat for Paper 1.21.x
|
description: Lightweight, accurate anti-cheat for Paper 1.21.x
|
||||||
|
|||||||
Reference in New Issue
Block a user