Files
XeroAntiCheat/src/main/java/com/xeroth/xeroanticheat/XeroAntiCheat.java

293 lines
10 KiB
Java

package com.xeroth.xeroanticheat;
import com.xeroth.xeroanticheat.checks.combat.*;
import com.xeroth.xeroanticheat.checks.misc.*;
import com.xeroth.xeroanticheat.checks.movement.*;
import com.xeroth.xeroanticheat.check.Check;
import com.xeroth.xeroanticheat.command.XACCommand;
import com.xeroth.xeroanticheat.listener.CombatListener;
import com.xeroth.xeroanticheat.listener.MiscListener;
import com.xeroth.xeroanticheat.listener.MovementListener;
import com.xeroth.xeroanticheat.manager.CheckManager;
import com.xeroth.xeroanticheat.manager.ConfigManager;
import com.xeroth.xeroanticheat.manager.DatabaseManager;
import com.xeroth.xeroanticheat.manager.PunishmentManager;
import com.xeroth.xeroanticheat.manager.ViolationManager;
import com.xeroth.xeroanticheat.protocol.PacketListener;
import com.xeroth.xeroanticheat.data.PlayerData;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* XeroAntiCheat - Lightweight, accurate anti-cheat for Paper 1.21.x
*
* This plugin provides comprehensive cheat detection including movement,
* combat, and miscellaneous checks with minimal false positives.
*/
public final class XeroAntiCheat extends JavaPlugin {
private static XeroAntiCheat instance;
private ConfigManager configManager;
private ViolationManager violationManager;
private PunishmentManager punishmentManager;
private CheckManager checkManager;
private PacketListener packetListener;
private DatabaseManager databaseManager;
private boolean protocolLibLoaded = false;
private org.bukkit.scheduler.BukkitTask decayTask;
// Staff alert toggles
private final Map<UUID, Boolean> alertToggles = new ConcurrentHashMap<>();
// Verbose targets (per-player debug output)
private final Set<UUID> verboseTargets = ConcurrentHashMap.newKeySet();
@Override
public void onEnable() {
instance = this;
// Check for ProtocolLib
checkProtocolLib();
// Initialize managers
initializeManagers();
// Register listeners
registerListeners();
// Register commands
registerCommands();
// Register checks
registerChecks();
// Start decay task
startDecayTask();
// Start potion effect refresh task
startPotionRefreshTask();
// Start TimerCheck blink detection task
startTimerBlinkTask();
getLogger().info("XeroAntiCheat v" + getDescription().getVersion() + " enabled!");
if (protocolLibLoaded) {
getLogger().info("ProtocolLib detected - packet-level checks enabled");
} else {
getLogger().info("ProtocolLib not found - using event-based detection");
}
}
@Override
public void onDisable() {
// Cancel all tasks
Bukkit.getScheduler().cancelTasks(this);
// Save any pending data
if (violationManager != null) {
violationManager.saveAll();
}
// Close database
if (databaseManager != null) {
databaseManager.close();
}
getLogger().info("XeroAntiCheat disabled!");
}
private void checkProtocolLib() {
try {
Class.forName("com.comphenix.protocol.ProtocolLibrary");
protocolLibLoaded = true;
} catch (ClassNotFoundException e) {
protocolLibLoaded = false;
}
}
private void initializeManagers() {
configManager = new ConfigManager(this);
configManager.loadConfig();
violationManager = new ViolationManager(this);
punishmentManager = new PunishmentManager(this, violationManager);
checkManager = new CheckManager(this);
databaseManager = new DatabaseManager(this);
databaseManager.initialize();
}
private void registerListeners() {
getServer().getPluginManager().registerEvents(new MovementListener(this), this);
getServer().getPluginManager().registerEvents(new CombatListener(this), this);
getServer().getPluginManager().registerEvents(new MiscListener(this), this);
if (protocolLibLoaded) {
packetListener = new PacketListener(this);
packetListener.register();
}
}
private void registerCommands() {
getCommand("xac").setExecutor(new XACCommand(this));
}
private void registerChecks() {
// Movement checks
checkManager.registerCheck(new SpeedCheck(this));
checkManager.registerCheck(new FlyCheck(this));
checkManager.registerCheck(new JesusCheck(this));
checkManager.registerCheck(new NoFallCheck(this));
checkManager.registerCheck(new TimerCheck(this));
checkManager.registerCheck(new SpiderCheck(this));
checkManager.registerCheck(new GlideCheck(this));
checkManager.registerCheck(new PhaseCheck(this));
// Combat checks
checkManager.registerCheck(new KillAuraCheck(this));
checkManager.registerCheck(new ReachCheck(this));
checkManager.registerCheck(new CriticalCheck(this));
checkManager.registerCheck(new AutoClickerCheck(this));
// VelocityCheck requires ProtocolLib
if (protocolLibLoaded) {
checkManager.registerCheck(new VelocityCheck(this));
}
// Misc checks
checkManager.registerCheck(new FastPlaceCheck(this));
checkManager.registerCheck(new ScaffoldCheck(this));
checkManager.registerCheck(new FastEatCheck(this));
checkManager.registerCheck(new InventoryMoveCheck(this));
getLogger().info("Registered " + checkManager.getRegisteredChecks().size() + " checks");
}
private void startDecayTask() {
int interval = configManager.getInt("violation.decay_interval", 30) * 20;
decayTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> {
violationManager.decayAll();
}, interval, interval);
}
private void startPotionRefreshTask() {
Bukkit.getScheduler().runTaskTimer(this, () -> {
for (Player player : Bukkit.getOnlinePlayers()) {
PlayerData data = violationManager.getPlayerData(player);
if (data == null) continue;
data.setHasSpeedEffect(player.hasPotionEffect(PotionEffectType.SPEED));
data.setHasSlownessEffect(player.hasPotionEffect(PotionEffectType.SLOWNESS));
data.setHasLevitation(player.hasPotionEffect(PotionEffectType.LEVITATION));
data.setHasDolphinsGrace(player.hasPotionEffect(PotionEffectType.DOLPHINS_GRACE));
data.setHasJumpBoost(player.hasPotionEffect(PotionEffectType.JUMP_BOOST));
data.setHasSlowFalling(player.hasPotionEffect(PotionEffectType.SLOW_FALLING));
var speed = player.getPotionEffect(PotionEffectType.SPEED);
data.setSpeedLevel(speed != null ? speed.getAmplifier() + 1 : 0);
var slowness = player.getPotionEffect(PotionEffectType.SLOWNESS);
data.setSlownessLevel(slowness != null ? slowness.getAmplifier() + 1 : 0);
var jump = player.getPotionEffect(PotionEffectType.JUMP_BOOST);
data.setJumpBoostLevel(jump != null ? jump.getAmplifier() + 1 : 0);
}
}, 10L, 10L);
}
private void startTimerBlinkTask() {
Bukkit.getScheduler().runTaskTimer(this, () -> {
long now = System.currentTimeMillis();
long threshold = configManager.getInt("checks.timer.blink_threshold_ms", 500);
Check timerCheck = checkManager.getCheck("Timer");
for (Player player : Bukkit.getOnlinePlayers()) {
if (timerCheck != null && timerCheck.isBypassed(player)) continue;
PlayerData data = violationManager.getPlayerData(player);
if (data == null || data.getLastMovePacketTime() == 0) continue;
long gap = now - data.getLastMovePacketTime();
if (gap > threshold) {
violationManager.addViolation(player, "Timer", 2.0);
punishmentManager.evaluate(player, "Timer");
data.setLastMovePacketTime(now);
}
}
}, 5L, 5L);
}
/**
* Reload the plugin configuration and re-register checks
*/
public void reload() {
configManager.loadConfig();
violationManager.clearAll();
violationManager.setDecayRate(
configManager.getDouble("violation.decay_rate", 0.5));
if (decayTask != null) {
decayTask.cancel();
}
startDecayTask();
getLogger().info("Configuration reloaded!");
}
// Getters
public static XeroAntiCheat getInstance() {
return instance;
}
public ConfigManager getConfigManager() {
return configManager;
}
public ViolationManager getViolationManager() {
return violationManager;
}
public PunishmentManager getPunishmentManager() {
return punishmentManager;
}
public CheckManager getCheckManager() {
return checkManager;
}
public DatabaseManager getDatabaseManager() {
return databaseManager;
}
public boolean isProtocolLibLoaded() {
return protocolLibLoaded;
}
public boolean isAlertsEnabled(java.util.UUID uuid) {
return alertToggles.getOrDefault(uuid, true);
}
public void setAlertsEnabled(java.util.UUID uuid, boolean enabled) {
alertToggles.put(uuid, enabled);
}
public boolean isVerboseTarget(UUID uuid) {
return verboseTargets.contains(uuid);
}
public void toggleVerboseTarget(UUID uuid) {
if (!verboseTargets.remove(uuid)) {
verboseTargets.add(uuid);
}
}
}