- 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
232 lines
8.7 KiB
Java
232 lines
8.7 KiB
Java
package com.xeroth.xeroanticheat.manager;
|
|
|
|
import com.xeroth.xeroanticheat.XeroAntiCheat;
|
|
import com.xeroth.xeroanticheat.check.Check;
|
|
import com.xeroth.xeroanticheat.data.PlayerData;
|
|
import net.kyori.adventure.text.Component;
|
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.command.CommandSender;
|
|
import org.bukkit.entity.Player;
|
|
|
|
import java.io.File;
|
|
import java.io.FileWriter;
|
|
import java.io.IOException;
|
|
import java.io.PrintWriter;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.Date;
|
|
import java.util.Set;
|
|
import java.util.UUID;
|
|
import java.util.logging.Level;
|
|
|
|
/**
|
|
* Handles punishment execution and logging.
|
|
*/
|
|
public class PunishmentManager {
|
|
|
|
private final XeroAntiCheat plugin;
|
|
private final ViolationManager violationManager;
|
|
|
|
private final MiniMessage miniMessage = MiniMessage.miniMessage();
|
|
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
|
private File logsFolder;
|
|
private File punishmentsLog;
|
|
|
|
public PunishmentManager(XeroAntiCheat plugin, ViolationManager violationManager) {
|
|
this.plugin = plugin;
|
|
this.violationManager = violationManager;
|
|
initializeLogs();
|
|
}
|
|
|
|
private void initializeLogs() {
|
|
logsFolder = new File(plugin.getDataFolder(), "logs");
|
|
if (!logsFolder.exists()) {
|
|
logsFolder.mkdirs();
|
|
}
|
|
|
|
punishmentsLog = new File(logsFolder, "punishments.log");
|
|
if (!punishmentsLog.exists()) {
|
|
try {
|
|
punishmentsLog.createNewFile();
|
|
} catch (IOException e) {
|
|
plugin.getLogger().log(Level.SEVERE, "Could not create punishments log", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Evaluate violations and apply appropriate punishment
|
|
*/
|
|
public void evaluate(Player player, String checkName) {
|
|
if (!plugin.getConfigManager().isEnabled()) return;
|
|
|
|
PlayerData data = violationManager.getPlayerData(player);
|
|
if (data == null) return;
|
|
|
|
double vl = data.getViolationLevel(checkName);
|
|
|
|
String checkPath = "checks." + checkName.toLowerCase() + ".";
|
|
|
|
int warnVl = plugin.getConfigManager().getInt(checkPath + "warn_vl", 10);
|
|
int kickVl = plugin.getConfigManager().getInt(checkPath + "kick_vl", 25);
|
|
int tempbanVl = plugin.getConfigManager().getInt(checkPath + "tempban_vl", 50);
|
|
int permbanVl = plugin.getConfigManager().getInt(checkPath + "permban_vl", 100);
|
|
|
|
Check check = plugin.getCheckManager().getCheck(checkName);
|
|
String category = check != null ? check.getCategory() : "misc";
|
|
|
|
long cooldownMs = plugin.getConfigManager().getInt("alerts.cooldown_ms", 5000);
|
|
long now = System.currentTimeMillis();
|
|
long lastWarn = data.getLastWarnTime(checkName);
|
|
boolean cooledDown = (now - lastWarn) >= cooldownMs;
|
|
|
|
boolean isPunishment = vl >= kickVl;
|
|
|
|
if (cooledDown || isPunishment) {
|
|
sendAlert(player, checkName, vl, category);
|
|
data.setLastWarnTime(checkName, now);
|
|
}
|
|
|
|
if (vl >= permbanVl) {
|
|
punish(player, checkName, "PERMBAN", permbanVl);
|
|
} else if (vl >= tempbanVl) {
|
|
punish(player, checkName, "TEMPBAN", tempbanVl);
|
|
} else if (vl >= kickVl) {
|
|
punish(player, checkName, "KICK", kickVl);
|
|
} else if (vl >= warnVl && cooledDown) {
|
|
warn(player, checkName);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send warning to player
|
|
*/
|
|
private void warn(Player player, String checkName) {
|
|
Component message = miniMessage.deserialize(
|
|
"<red>Warning: <white>Suspicious behavior detected (" + checkName + ")"
|
|
);
|
|
player.sendMessage(message);
|
|
}
|
|
|
|
/**
|
|
* Apply punishment based on type
|
|
*/
|
|
private void punish(Player player, String checkName, String type, double vl) {
|
|
String reason = plugin.getConfigManager().getString("punishments.default_reason", "Suspicious activity");
|
|
String playerName = player.getName();
|
|
|
|
switch (type) {
|
|
case "KICK" -> {
|
|
String kickCmd = plugin.getConfigManager().getString("punishments.kick_command",
|
|
"kick %player% &c[XAC] Illegal activity detected");
|
|
kickCmd = kickCmd.replace("%player%", playerName).replace("%reason%", reason);
|
|
executeCommand(kickCmd);
|
|
logPunishment(type, player, checkName, vl);
|
|
plugin.getMetricsManager().recordPunishment();
|
|
}
|
|
case "TEMPBAN" -> {
|
|
String tempbanCmd = plugin.getConfigManager().getString("punishments.tempban_command",
|
|
"tempban %player% 30d %reason%");
|
|
tempbanCmd = tempbanCmd.replace("%player%", playerName).replace("%reason%", reason);
|
|
executeCommand(tempbanCmd);
|
|
logPunishment(type, player, checkName, vl);
|
|
plugin.getMetricsManager().recordPunishment();
|
|
}
|
|
case "PERMBAN" -> {
|
|
String permbanCmd = plugin.getConfigManager().getString("punishments.permban_command",
|
|
"ban %player% %reason%");
|
|
permbanCmd = permbanCmd.replace("%player%", playerName).replace("%reason%", reason);
|
|
executeCommand(permbanCmd);
|
|
logPunishment(type, player, checkName, vl);
|
|
plugin.getMetricsManager().recordPunishment();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute a console command
|
|
*/
|
|
private void executeCommand(String command) {
|
|
final String cmd = command.startsWith("/") ? command.substring(1) : command;
|
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
|
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Send alert to staff members
|
|
*/
|
|
public void sendAlert(Player player, String checkName, double vl, String category) {
|
|
if (!plugin.getConfigManager().isAlertsEnabled()) return;
|
|
|
|
String format = plugin.getConfigManager().getAlertsFormat();
|
|
format = format.replace("%player%", player.getName())
|
|
.replace("%check%", checkName)
|
|
.replace("%vl%", String.valueOf((int) vl))
|
|
.replace("%category%", category);
|
|
|
|
Component message = miniMessage.deserialize(format);
|
|
|
|
String categoryPerm = "xac.alerts." + category;
|
|
|
|
for (Player staff : Bukkit.getOnlinePlayers()) {
|
|
boolean hasPermission = staff.hasPermission("xac.alerts")
|
|
|| staff.hasPermission("xac.admin")
|
|
|| staff.hasPermission(categoryPerm);
|
|
if (!hasPermission) continue;
|
|
if (!plugin.isAlertsEnabled(staff.getUniqueId())) continue;
|
|
staff.sendMessage(message);
|
|
}
|
|
|
|
plugin.getLogger().info(
|
|
player.getName() + " failed " + checkName
|
|
+ " [" + category + "] (VL: " + (int) vl + ")"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Log punishment to file and database
|
|
*/
|
|
private void logPunishment(String type, Player player, String checkName, double vl) {
|
|
final String timestamp = dateFormat.format(new Date());
|
|
final String playerName = player.getName();
|
|
final String playerUuid = player.getUniqueId().toString();
|
|
|
|
final String logLine = String.format("[%s] %s | %s | %s | %s | %.1f",
|
|
timestamp,
|
|
type,
|
|
playerName,
|
|
playerUuid,
|
|
checkName,
|
|
vl);
|
|
|
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
|
try (FileWriter fw = new FileWriter(punishmentsLog, true);
|
|
PrintWriter pw = new PrintWriter(fw)) {
|
|
pw.println(logLine);
|
|
} catch (IOException e) {
|
|
plugin.getLogger().log(Level.WARNING, "Could not write to punishments log", e);
|
|
}
|
|
|
|
DatabaseManager db = plugin.getDatabaseManager();
|
|
boolean dbEnabled = plugin.getConfigManager().getBoolean("database.enabled", true);
|
|
if (db != null && db.isAvailable() && dbEnabled) {
|
|
db.insertPunishment(timestamp, type, playerUuid, playerName, checkName, vl);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Manually punish a player for a check
|
|
*/
|
|
public void manualPunish(Player player, String checkName) {
|
|
PlayerData data = violationManager.getPlayerData(player);
|
|
if (data == null) return;
|
|
|
|
// Set VL to kick threshold and evaluate
|
|
data.setViolationLevel(checkName, plugin.getConfigManager().getInt("checks." + checkName.toLowerCase() + ".kick_vl", 25));
|
|
evaluate(player, checkName);
|
|
}
|
|
}
|