- Setback System: Teleports flagged players to lastSafeLocation (opt-in per check) - TPS Lag Compensation: isServerLagging() helper, guards in Fly/Spider/Glide checks - Universal Buffer System: Buffer fields for Jesus/Reach/KillAura/Timer/FastPlace/Scaffold/FastEat - /xac debug command: Shows check-specific debug info for players - Public API: XACApi with isFlagged(), getViolationLevel(), getTotalViolations(), isBypassed() - Performance Metrics: /xac stats command with checks/flags/punishments tracking
145 lines
4.3 KiB
Java
145 lines
4.3 KiB
Java
package com.xeroth.xeroanticheat.check;
|
|
|
|
import com.xeroth.xeroanticheat.XeroAntiCheat;
|
|
import com.xeroth.xeroanticheat.data.PlayerData;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.entity.Player;
|
|
|
|
/**
|
|
* Abstract base class for all anti-cheat checks.
|
|
* All checks must extend this class and implement the check logic.
|
|
*/
|
|
public abstract class Check {
|
|
|
|
protected final XeroAntiCheat plugin;
|
|
protected final String name;
|
|
protected final String configPath;
|
|
|
|
private boolean enabled;
|
|
|
|
public Check(XeroAntiCheat plugin, String name) {
|
|
this.plugin = plugin;
|
|
this.name = name;
|
|
this.configPath = "checks." + name.toLowerCase() + ".";
|
|
this.enabled = true;
|
|
}
|
|
|
|
/**
|
|
* Execute the check logic.
|
|
*
|
|
* @param data Player data for the player being checked
|
|
* @param player The player being checked
|
|
*/
|
|
public abstract void check(PlayerData data, Player player);
|
|
|
|
/**
|
|
* Called when the check detects a violation.
|
|
*
|
|
* @param data Player data
|
|
* @param player The player
|
|
* @param weight Violation weight to add
|
|
*/
|
|
protected void flag(PlayerData data, Player player, double weight) {
|
|
if (!isEnabled()) return;
|
|
|
|
if (player.hasPermission("xac.bypass")) return;
|
|
if (player.hasPermission("xac.bypass." + getCategory())) return;
|
|
if (player.hasPermission("xac.bypass." + name.toLowerCase())) return;
|
|
|
|
plugin.getViolationManager().addViolation(player, name, weight);
|
|
plugin.getPunishmentManager().evaluate(player, name);
|
|
}
|
|
|
|
/**
|
|
* Simplified flag with default weight
|
|
*/
|
|
protected void flag(PlayerData data, Player player) {
|
|
flag(data, player, 1.0);
|
|
}
|
|
|
|
/**
|
|
* Get the check name
|
|
*/
|
|
public String getName() {
|
|
return name;
|
|
}
|
|
|
|
/**
|
|
* Check if this check is enabled
|
|
*/
|
|
public boolean isEnabled() {
|
|
return enabled && plugin.getConfigManager().getBoolean(configPath + "enabled", true);
|
|
}
|
|
|
|
/**
|
|
* Set enabled state
|
|
*/
|
|
public void setEnabled(boolean enabled) {
|
|
this.enabled = enabled;
|
|
}
|
|
|
|
/**
|
|
* Get a configuration value
|
|
*/
|
|
protected boolean getConfigBoolean(String key, boolean defaultValue) {
|
|
return plugin.getConfigManager().getBoolean(configPath + key, defaultValue);
|
|
}
|
|
|
|
/**
|
|
* Get a configuration value
|
|
*/
|
|
protected int getConfigInt(String key, int defaultValue) {
|
|
return plugin.getConfigManager().getInt(configPath + key, defaultValue);
|
|
}
|
|
|
|
/**
|
|
* Get a configuration value
|
|
*/
|
|
protected double getConfigDouble(String key, double defaultValue) {
|
|
return plugin.getConfigManager().getDouble(configPath + key, defaultValue);
|
|
}
|
|
|
|
/**
|
|
* Get a configuration value
|
|
*/
|
|
protected String getConfigString(String key, String defaultValue) {
|
|
return plugin.getConfigManager().getString(configPath + key, defaultValue);
|
|
}
|
|
|
|
public String getCategory() {
|
|
String pkg = getClass().getPackageName();
|
|
if (pkg.endsWith("movement")) return "movement";
|
|
if (pkg.endsWith("combat")) return "combat";
|
|
return "misc";
|
|
}
|
|
|
|
/**
|
|
* Returns true if the given player should be exempt from this check,
|
|
* based on the three-tier bypass permission hierarchy:
|
|
* xac.bypass → xac.bypass.<category> → xac.bypass.<checkname>
|
|
*
|
|
* @param player The player to test
|
|
* @return true if the player has any applicable bypass permission
|
|
*/
|
|
public boolean isBypassed(Player player) {
|
|
return player.hasPermission("xac.bypass")
|
|
|| player.hasPermission("xac.bypass." + getCategory())
|
|
|| player.hasPermission("xac.bypass." + name.toLowerCase());
|
|
}
|
|
|
|
protected void setback(Player player, PlayerData data) {
|
|
if (!getConfigBoolean("setback", false)) return;
|
|
org.bukkit.Location safe = data.getLastSafeLocation();
|
|
if (safe == null) return;
|
|
data.clearPositionHistory();
|
|
player.teleport(safe);
|
|
}
|
|
|
|
protected boolean isServerLagging() {
|
|
if (!plugin.getConfigManager().getBoolean("tps.enabled", true)) return false;
|
|
double tps = Bukkit.getTPS()[0];
|
|
double minTps = plugin.getConfigManager().getDouble("tps.min_tps_threshold", 18.0);
|
|
return tps < minTps;
|
|
}
|
|
}
|