f55d71c35d43783254d64c2d1c221a054e0d791b
XeroAntiCheat - Minecraft Anti-Cheat Plugin
A lightweight, production-ready anti-cheat plugin for Paper 1.21.x (compatible with 1.20-1.22).
Overview
XeroAntiCheat is designed to detect common Minecraft cheats while minimizing false positives. It features:
- 17 comprehensive checks across movement, combat, and miscellaneous categories
- Thread-safe architecture with async/sync operation separation
- Configurable thresholds via config.yml
- Violation level (VL) system with temporal decay
- Punishment pipeline (warn → kick → tempban → permban)
- MiniMessage support for modern chat formatting
- ProtocolLib integration (optional) for packet-level detection
- Automatic potion effect tracking for accurate speed/fall detection
- Staff alert toggle - staff can opt out of receiving alerts
Latest Updates (v1.0.5)
Bug Fixes
- DatabaseManager race condition - Fixed
close()method to be synchronized and null the connection after closing. PreventsSQLException: database is closederrors when async inserts race with plugin disable. - PhaseCheck teleport false positives - Added
max_distanceconfig (default 5.0 blocks). Movement deltas exceeding this value are now ignored (treated as teleports). Also replaced hardcoded Y-offset0.1withplayer.getEyeHeight()for state-aware ray-casting. - Position history reset on teleport - Added
PlayerTeleportEventhandler in MovementListener that clears position/velocity history, resets air ticks, and clears server velocity. Prevents false positives across all inter-position checks after teleportation. - VelocityCheck grace period - Added
PlayerRespawnEventhandler in MiscListener that clears server velocity and position history. Prevents false positives after respawn. - ScaffoldCheck Signal 4 false positive - Changed
lastPlacementYawinitial value from0toFloat.NaNas a sentinel. Signal 4 now skips on first block placement of the session to prevent false positives when yaw happens to be near 0.
Quality Improvements
- Listener bypass comments - Added explanatory comments at
hasPermission("xac.bypass")early-return sites in all listeners to clarify that category/per-check bypass is enforced deeper in the call stack.
Latest Updates (v1.0.7)
Bug Fixes
- KillAura multi-target time window -
checkMultiTarget()was ignoring the configured time window entirely. Was counting all-time target transitions (up to 5 attacks) instead of distinct entities attacked within the window. Fixed by using parallel iterators overattackTimestampsandattackedEntitiesto correctly count unique targets within the lastwindowmilliseconds. - PlayerData deque capacity mismatch -
attackedEntitiesdeque was capped at 5 whileattackTimestampswas capped at 10. After 5 attacks, deques would desync and parallel iteration would produce incorrect results. Fixed by aligning both to capacity 10. - NoFall Feather Falling negative damage - Custom enchant levels above 8 would produce negative expected damage (e.g., level 9 → multiplier -0.08), permanently disabling the check. Fixed by clamping multiplier to minimum 0.0.
- ScaffoldCheck allocation in hot path -
computePlacementIntervalStdDev()was callingtoArray()on every block placement, allocating arrays in a performance-critical path. Fixed with zero-allocation two-pass iterator approach.
Latest Updates (v1.0.6)
Bug Fixes
- SpiderCheck and GlideCheck cross-player pollution - Tick counters (
spiderAirTicks,glideAirTicks) were stored as instance fields on the check class, shared across ALL players. Fixed by moving counters to PlayerData for per-player state. - KillAuraCheck angle NaN false negative -
Math.acos()was receiving unconstrained dot product values, which can produce NaN when floating-point rounding pushes values outside [-1, 1]. This silently disabled angle detection. Fixed by clamping dot product to [-1, 1] before acos. - SpeedCheck rolling average implementation -
bufferTicksconfig was read but never used. Implemented actual consecutive-tick counter that flags only after speed exceeds max for N consecutive ticks. - SpeedCheck latency compensation ignored actual ping - Was using fixed config value regardless of player ping. Now scales with actual ping using formula
min(ping / 100.0 * 0.01 * pingFactor, 0.15), consistent with ReachCheck. - PlayerData.getSecondLastPosition() allocation - Method was calling
toArray()on every call, allocating a temporary array in a hot path. Replaced with iterator-based access.
Config Changes
- Renamed
checks.speed.latency_compensationtochecks.speed.ping_factorfor clarity
Latest Updates (v1.0.4)
Bug Fixes
- FastEat bypass permissions - Fixed missing
isBypassed()guard in MiscListener for FastEat check. Permissionsxac.bypass.fasteatandxac.bypass.miscnow work correctly. - Bypass consistency - Replaced
hasPermission("xac.bypass")withisBypassed(player)in all 15 check classes for consistent three-tier permission checking.
ProtocolLib Integration
- Real packet listeners - PacketListener.java completely rewritten to use actual ProtocolLib API (no more reflection-based stubs)
- Three packet adapters:
- Movement packets (POSITION, POSITION_LOOK, LOOK) → feeds TimerCheck counters and KillAura rotation history
- ARM_ANIMATION → feeds AutoClickerCheck click tracking
- ENTITY_VELOCITY → feeds VelocityCheck knockback verification
- Event guard - TimerCheck now skips event-based counter increment when ProtocolLib is active (prevents double-counting)
- Click guard - CombatListener no longer adds clicks via event when ProtocolLib handles ARM_ANIMATION
New Checks
- PhaseCheck - Detects players clipping through solid blocks using server-side ray-casting between positions. Requires 0.5+ block movement to trigger.
- VelocityCheck - Detects players ignoring server-sent knockback (no-knockback hacks). Requires ProtocolLib. Compares actual horizontal displacement against expected velocity over 4 ticks.
Scaffold Improvements
- Two new detection signals:
- Signal 4: Rotation lock - detects fixed yaw while side-bridging (yaw change <2° with horizontal speed >0.15)
- Signal 5: Placement interval variance - detects suspiciously perfect timing (stdDev <30ms at 5+ BPS)
- Now has 5 signals total, still requires 2 to flag
SQLite Database
- DatabaseManager - New manager for SQLite-based punishment logging
- Punishments now logged to both flat-file (
logs/punishments.log) and SQLite (data.db) - Configurable via
database.enabledin config.yml (default: true)
Latest Updates (v1.0.3)
Bug Fixes
- Granular bypass permissions now working - Added
isBypassed(Player)method to Check.java and guarded all directaddViolation()calls in CombatListener and MiscListener. The permissionsxac.bypass.reach,xac.bypass.killaura,xac.bypass.critical,xac.bypass.scaffold,xac.bypass.nofall, and category bypasses now function correctly for all checks. - TimerCheck blink detection - Fixed bypass check to use three-tier permission hierarchy instead of only checking global
xac.bypass. - SpeedCheck Slowness calculation - Fixed incorrect field reference: was using
getSpeedLevel()instead ofgetSlownessLevel()for Slowness potion penalty, causing false positives for players under Slowness effect. - Async file I/O -
logPunishment()now writes to disk on a background thread to prevent tick lag.
Quality Improvements
- Main thread Bukkit API - Changed
startPotionRefreshTask()from async to sync (Bukkit API should only be called from main thread). - Thread-safe collections - Changed
alertTogglesfromHashMaptoConcurrentHashMapfor future-proofing.
Permission System Overhaul (v1.0.2)
- Granular permission tree - One permission per action with wildcard inheritance
- Per-category alerts - Staff can receive only movement, combat, or misc alerts
- Per-check bypass - Bypass specific checks (e.g.,
xac.bypass.speed) - Category bypass - Bypass entire categories (e.g.,
xac.bypass.movement) - New commands:
/xac clearviolations <player>,/xac verbose <player> - Verbose mode - Per-flag debug output (disabled by default, enable with
/xac verbose <player>) - Category-filtered alerts respect permissions:
xac.alerts.movement,xac.alerts.combat,xac.alerts.misc
Bug Fixes (v1.0.2)
- NoFallCheck: Rewrote damage detection logic - now properly calculates expected fall damage and compares against actual damage via EntityDamageEvent
- CriticalCheck: Fixed physics-based crit detection - now uses velocity/fall distance instead of damage modulo (was causing 100% false positives)
- airTicks: Fixed multiple checks incrementing airTicks in same tick - now only MovementListener manages airTicks, checks have their own counters
- Potion Effects: Added automatic potion effect refresh task (runs every 10 ticks async) - Speed, Slowness, Levitation, Dolphins Grace, Jump Boost, Slow Falling now properly tracked
- Knockback: Added knockback tracking - SpeedCheck now accounts for knockback (500ms grace after taking damage)
- FastEatCheck: Fixed to track eat start time (PlayerInteractEvent) instead of consume-to-consume interval
- JesusCheck: Added isSwimming() check to avoid false positives for underwater movement
- ReachCheck: Ping compensation now scales dynamically with actual player ping (0.03 blocks per 100ms, capped at 0.3)
- TimerCheck: Added scheduled task for blink detection (checks every 5 ticks for gaps >500ms)
- Alert Toggle: Staff can now toggle alerts on/off with
/xac alerts on/off - ConfigManager: Fixed validation to use getDouble() for max_speed
- Food Detection: MiscListener now uses Paper API isEdible() instead of hardcoded switch
Architecture Improvements
- Async potion effect refresh task keeps all check data up-to-date
- Independent tick counters per check prevent false positives from shared state
- EntityDamageEvent listener for accurate damage comparison in NoFallCheck
- Dynamic ping compensation in ReachCheck scales with actual network conditions
Project Structure
/home/axel/Músicas/Java
├── pom.xml # Maven build configuration
├── src/main/
│ ├── java/com/xeroth/xeroanticheat/
│ │ ├── XeroAntiCheat.java # Main plugin class
│ │ ├── check/
│ │ │ └── Check.java # Abstract base class for all checks
│ │ ├── checks/
│ │ │ ├── movement/ # Movement-related checks
│ │ │ │ ├── SpeedCheck.java
│ │ │ │ ├── FlyCheck.java
│ │ │ │ ├── JesusCheck.java
│ │ │ │ ├── NoFallCheck.java
│ │ │ │ ├── TimerCheck.java
│ │ │ │ ├── SpiderCheck.java
│ │ │ │ └── GlideCheck.java
│ │ │ ├── combat/ # Combat-related checks
│ │ │ │ ├── KillAuraCheck.java
│ │ │ │ ├── ReachCheck.java
│ │ │ │ ├── CriticalCheck.java
│ │ │ │ └── AutoClickerCheck.java
│ │ │ └── misc/ # Miscellaneous checks
│ │ │ ├── FastPlaceCheck.java
│ │ │ ├── ScaffoldCheck.java
│ │ │ ├── FastEatCheck.java
│ │ │ └── InventoryMoveCheck.java
│ │ ├── manager/ # Core managers
│ │ │ ├── CheckManager.java
│ │ │ ├── ConfigManager.java
│ │ │ ├── PunishmentManager.java
│ │ │ └── ViolationManager.java
│ │ ├── data/
│ │ │ └── PlayerData.java # Per-player state storage
│ │ ├── command/
│ │ │ └── XACCommand.java # Command handler
│ │ ├── listener/ # Event listeners
│ │ │ ├── MovementListener.java
│ │ │ ├── CombatListener.java
│ │ │ └── MiscListener.java
│ │ └── protocol/
│ │ └── PacketListener.java # ProtocolLib integration
│ └── resources/
│ ├── plugin.yml # Plugin metadata
│ └── config.yml # Configuration file
└── target/
└── XeroAntiCheat.jar # Built plugin
Architecture
Module Interaction
┌─────────────────────────────────────────────────────────────┐
│ XeroAntiCheat (Main) │
│ - onEnable(): Initialize all managers, register listeners │
│ - onDisable(): Cleanup, save data, cancel tasks │
└─────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ ConfigManager │ │ CheckManager │ │ PlayerData Cache│
│ - loadConfig() │ │ - registerCheck│ │ - ConcurrentHM │
│ - getTyped() │ │ - runCheck() │ │ - onJoin/Quit │
│ - validate() │ │ - getCheck() │ │ - thread-safe │
└──────────────────┘ └──────────────────┘ └──────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ Event Listeners (Sync) │
│ - MovementListener → PlayerMoveEvent │
│ - CombatListener → EntityDamageByEntityEvent │
│ - MiscListener → BlockPlaceEvent, PlayerItemConsumeEvent│
└─────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ ViolationManager │ │ PunishmentManager │ │ ProtocolLib │
│ - addViolation │ │ - evaluate() │ │ PacketListener │
│ - decayVL() │ │ - punish() │ │ - MONITOR │
│ - getVL() │ │ - warn/kick/ban │ │ - hasProtocolLib│
└──────────────────┘ └──────────────────┘ └──────────────────┘
Key Design Decisions
- Thread Safety: PlayerData uses
ConcurrentHashMapandArrayDequefor thread-safe operations - Performance: Movement checks only run when
hasChangedPosition()is true - Async Operations: VL decay, potion refresh, config validation run async
- Fallback System: Features work without ProtocolLib (reduced accuracy)
Check Descriptions
Movement Checks
| Check | Detection Method |
|---|---|
| SpeedCheck | Horizontal movement exceeding max speed for player state (sprinting, sneaking, swimming, potions, ice, etc.). Uses rolling average over 5 ticks with TPS/ping compensation. |
| FlyCheck | Sustained flight without elytra/creative/spectator. Tracks air ticks and ground desync between client/server. |
| JesusCheck | Walking on water without Frost Walker enchantment or boat. Checks block type at feet. |
| NoFallCheck | No fall damage after falling >3 blocks. Compares expected damage vs actual, accounting for Feather Falling, Slow Falling, water, honey blocks. |
| TimerCheck | Packet timing anomalies: >22 packets/sec or blink (no packets >500ms then teleport). |
| SpiderCheck | Climbing non-climbable blocks (non-ladder/vine/scaffolding) with upward velocity. |
| GlideCheck | Elytra-like fall curve (slow Y decrease) without elytra equipped. |
| PhaseCheck | Server-side ray-cast between positions. Flags if solid block intersects movement path. Requires 0.5+ block travel. |
Combat Checks
| Check | Detection Method |
|---|---|
| KillAuraCheck | Three sub-checks: (1) Attack angle >100° from look direction, (2) Snap rotation >45° between attacks, (3) Multi-targeting >2 entities within 100ms. |
| ReachCheck | 3D distance from player eye to entity hitbox. Default threshold 3.2 blocks (survival), 5.0 (creative), with ping compensation. |
| CriticalCheck | Critical hits without airborne state. Detects crits while on ground or while sprinting (cancels sprint). Allows legitimate jump-crits. |
| AutoClickerCheck | CPS tracking over 1-second window. Flags >20 CPS. Also analyzes inter-click variance - flags suspiciously perfect patterns (stdDev < 2.0). |
| VelocityCheck | Compares actual horizontal displacement against server-sent ENTITY_VELOCITY. Flags if player moves <20% of expected knockback. Requires ProtocolLib. |
Miscellaneous Checks
| Check | Detection Method |
|---|---|
| FastPlaceCheck | Block placement >20 blocks/sec. Uses timestamp deque for tracking. |
| ScaffoldCheck | Multi-signal detection (5 signals): (1) Pitch >75° while running, (2) Placing below player, (3) No valid support face, (4) Rotation lock (yaw change <2° while moving), (5) Placement interval variance (too-perfect timing). Requires 2+ signals. |
| FastEatCheck | Food consumption faster than 32 ticks (1.6 seconds). |
| InventoryMoveCheck | Position change >0.1 while inventory is open. |
Violation System
VL Accumulation
- Each check maintains its own violation level per player
addViolation(player, checkName, weight)increments VL- Default weight is 1.0, scaled by detection severity
Decay
- Runs every 30 seconds (configurable)
- Reduces each check's VL by decay_rate (default: 0.5)
- Minimum VL is 0.0
Thresholds
Configurable per check in config.yml:
checks.<check>:
warn_vl: 10 # Send warning
kick_vl: 25 # Kick player
tempban_vl: 50 # Temporary ban (30 days)
permban_vl: 100 # Permanent ban
Punishment Pipeline
- Warning (VL ≥ warn_vl): MiniMessage alert to player
- Kick (VL ≥ kick_vl):
player.kick() - TempBan (VL ≥ tempban_vl): Execute config command
- PermBan (VL ≥ permban_vl): Execute config command
Commands are configurable in config.yml:
punishments:
kick_command: "kick %player% &c[XAC] Illegal activity detected"
tempban_command: "tempban %player% 30d %reason%"
permban_command: "ban %player% %reason%"
All punishments logged to plugins/XeroAntiCheat/logs/punishments.log.
Configuration
All settings in config.yml:
General
enabled: Enable/disable plugindebug: Additional loggingasync_task_threads: Background thread count
Violation
decay_interval: Seconds between decay (default: 30)decay_rate: Amount to reduce VL per decay (default: 0.5)
Checks
Each check has enabled and threshold settings. See config.yml for defaults.
Commands
reload_permission: xac.adminbypass_permission: xac.bypassalerts_permission: xac.alerts
Commands
| Command | Permission | Description |
|---|---|---|
/xac reload |
xac.command.reload | Reload configuration |
/xac status <player> |
xac.command.status | Show player's VL levels and ping |
/xac punish <player> <check> |
xac.command.punish | Manually trigger punishment |
/xac clearviolations <player> |
xac.command.clearviolations | Clear all VL for a player |
/xac verbose <player> |
xac.command.verbose | Toggle per-flag debug output |
/xac alerts [on|off] |
xac.command.alerts | Toggle alert receiving |
/xac version |
xac.command.version | Show plugin version |
Permissions
Wildcards
xac.*- All permissions (admin + bypass)xac.admin- All commands and alerts (does NOT grant bypass)xac.bypass- Bypass all checksxac.alerts- Receive all alerts
Command Permissions
xac.command.reload- /xac reloadxac.command.status- /xac statusxac.command.punish- /xac punishxac.command.clearviolations- /xac clearviolationsxac.command.verbose- /xac verbosexac.command.alerts- /xac alertsxac.command.version- /xac version
Category Alerts
xac.alerts.movement- Movement check alerts onlyxac.alerts.combat- Combat check alerts onlyxac.alerts.misc- Misc check alerts only
Bypass Permissions
Movement:
xac.bypass.movement- All movement checksxac.bypass.speed,xac.bypass.fly,xac.bypass.jesus,xac.bypass.nofall,xac.bypass.timer,xac.bypass.spider,xac.bypass.glide
Combat:
xac.bypass.combat- All combat checksxac.bypass.killaura,xac.bypass.reach,xac.bypass.critical,xac.bypass.autoclicker
Misc:
xac.bypass.misc- All misc checksxac.bypass.fastplace,xac.bypass.scaffold,xac.bypass.fasteat,xac.bypass.inventorymove
LuckPerms Example Roles
# Helper - read-only, sees all alerts
/lp group helper permission set xac.command.status true
/lp group helper permission set xac.command.alerts true
/lp group helper permission set xac.alerts true
# Junior Mod - combat alerts only
/lp group junior-mod permission set xac.alerts.combat true
# Moderator - full alerts + punish
/lp group moderator permission set xac.alerts true
/lp group moderator permission set xac.command.punish true
# Streamer - bypass movement + combat
/lp group streamer permission set xac.bypass.movement true
/lp group streamer permission set xac.bypass.combat true
# Build team - bypass speed/fly only
/lp group build permission set xac.bypass.speed true
/lp group build permission set xac.bypass.fly true
Build Instructions
# Build the plugin
mvn package
# The JAR will be in target/XeroAntiCheat.jar
Dependencies
- Paper API 1.21.1-R0.1-SNAPSHOT (provided)
- ProtocolLib (optional, for packet-level detection)
Performance Optimizations
- Event Filtering: Movement checks only run when position actually changes
- Fixed-Size Data Structures: ArrayDeque for position/click history (max 20 entries)
- Primitive Math: Avoid creating new Location/Vector objects in hot paths
- TPS Compensation: Velocity thresholds scale with server TPS
- Async Operations: VL decay, config validation, logging run on background threads
Edge Case Handling
| Scenario | Handling |
|---|---|
| Creative mode | Most checks ignored |
| Bypass permission | Silently ignored |
| Lag spikes | TPS compensation applied |
| Pearl teleportation | Reset air timers, position buffers |
| Jump-crits | Allow if wasAirborne previous 3 ticks |
| Frost Walker | Allow water walking |
| Slow Falling potion | Ignore fall damage |
| Water/honey landing | No damage expected |
Future Enhancements
Potential areas for expansion:
- Entity prediction check
- More scaffold signals
- Velocity verification
- Phase detection
- Packet order validation
- SQL-based violation logging
- Web dashboard integration
Description
Languages
Java
100%