Dateien nach "src/main/java" hochladen

This commit is contained in:
2025-07-26 19:59:08 +00:00
parent 5ad50052e9
commit 79fc135853

View File

@@ -0,0 +1,737 @@
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.block.Sign;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
public class PlayerStatusSign extends JavaPlugin implements Listener {
private File signsFile;
private FileConfiguration signsConfig;
private File playersFile;
private FileConfiguration playersConfig;
private File configFile;
private FileConfiguration config;
private Map<Location, String> signLocations; // Schildposition -> Spielername
private Map<UUID, Long> lastPlayerMovement; // Spieler UUID -> Zeitpunkt
private Map<UUID, Boolean> afkPlayers; // Spieler UUID -> AFK-Status
private Map<UUID, Boolean> fakeOfflinePlayers; // Spieler UUID -> Fake-Offline-Status
private Map<UUID, GameMode> originalGameModes; // Spieler UUID -> Ursprünglicher Gamemode
private String prefix;
private String onlineColor;
private String afkColor;
private String offlineColor;
private String playerColor;
private String dateFormat;
private long afkTimeout;
private boolean afkChangeGamemode;
private static final String CONFIG_VERSION = "1.0.6";
private static final String PLUGIN_AUTHOR = "M_Viper";
// ------------------------------------------------------------
// Lifecycle
// ------------------------------------------------------------
@Override
public void onEnable() {
try {
getServer().getPluginManager().registerEvents(this, this);
signLocations = new HashMap<>();
lastPlayerMovement = new HashMap<>();
afkPlayers = new HashMap<>();
fakeOfflinePlayers = new HashMap<>();
originalGameModes = new HashMap<>();
loadConfig();
loadSigns();
loadPlayers();
startSignUpdater();
// Konsolenmeldung beim Plugin-Start
getLogger().info("[>] ========================================== [<]");
getLogger().info(" PlayerStatusSign - " + getDescription().getVersion() + " (cfg " + CONFIG_VERSION + ")");
getLogger().info(" Ersteller: " + PLUGIN_AUTHOR);
getLogger().info("[>] ========================================== [<]");
} catch (Exception e) {
getLogger().severe("Fehler beim Laden des Plugins: " + e.getMessage());
e.printStackTrace();
getServer().getPluginManager().disablePlugin(this);
}
}
@Override
public void onDisable() {
// Setze alle AFK- und Fake-Offline-Spieler zurück
for (UUID uuid : new HashSet<>(afkPlayers.keySet())) {
Player player = getServer().getPlayer(uuid);
if (player != null && afkPlayers.getOrDefault(uuid, false)) {
setPlayerAfk(player, false);
}
}
for (UUID uuid : new HashSet<>(fakeOfflinePlayers.keySet())) {
Player player = getServer().getPlayer(uuid);
if (player != null && fakeOfflinePlayers.getOrDefault(uuid, false)) {
setPlayerFakeOffline(player, false);
}
}
saveSigns();
savePlayers();
}
// ------------------------------------------------------------
// Config / Storage
// ------------------------------------------------------------
private void loadConfig() {
configFile = new File(getDataFolder(), "config.yml");
try {
if (!getDataFolder().exists() && !getDataFolder().mkdirs()) {
getLogger().severe("Konnte Plugin-Verzeichnis nicht erstellen!");
return;
}
if (!configFile.exists()) {
saveResource("config.yml", false);
getLogger().info("config.yml wurde erstellt.");
}
config = YamlConfiguration.loadConfiguration(configFile);
// Defaults
prefix = config.getString("prefix", "Status");
onlineColor = config.getString("colors.online", "&a");
afkColor = config.getString("colors.afk", "&e");
offlineColor = config.getString("colors.offline", "&c");
playerColor = config.getString("colors.player", "&9");
dateFormat = config.getString("date-format", "dd.MM.yyyy HH:mm");
afkTimeout = config.getLong("afk-timeout-seconds", 300) * 1000L;
afkChangeGamemode = config.getBoolean("afk-change-gamemode", true);
} catch (Exception e) {
getLogger().severe("Fehler beim Laden von config.yml: " + e.getMessage());
e.printStackTrace();
config = new YamlConfiguration(); // Fallback
}
}
private void ensureSignsFile() throws IOException {
if (signsFile == null) {
signsFile = new File(getDataFolder(), "playerstatussign_signs.yml");
}
if (!signsFile.exists()) {
signsFile.createNewFile();
getLogger().info("playerstatussign_signs.yml erstellt.");
}
if (signsConfig == null) {
signsConfig = YamlConfiguration.loadConfiguration(signsFile);
}
}
private void loadSigns() {
try {
ensureSignsFile();
signLocations.clear();
if (!signsConfig.contains("signs")) {
getLogger().info("Keine Schilder gefunden.");
return;
}
for (String key : signsConfig.getConfigurationSection("signs").getKeys(false)) {
String world = signsConfig.getString("signs." + key + ".world");
int x = signsConfig.getInt("signs." + key + ".x");
int y = signsConfig.getInt("signs." + key + ".y");
int z = signsConfig.getInt("signs." + key + ".z");
String playerName = signsConfig.getString("signs." + key + ".player");
if (world != null && playerName != null) {
Location loc = new Location(getServer().getWorld(world), x, y, z);
if (loc.getWorld() != null) {
signLocations.put(loc, playerName);
}
}
}
getLogger().info("playerstatussign_signs.yml geladen. (" + signLocations.size() + " Schilder)");
} catch (IOException e) {
getLogger().severe("Fehler beim Laden von playerstatussign_signs.yml: " + e.getMessage());
e.printStackTrace();
}
}
private void saveSigns() {
try {
ensureSignsFile();
signsConfig.set("signs", null); // Reset
for (Map.Entry<Location, String> entry : signLocations.entrySet()) {
Location loc = entry.getKey();
String key = locationKey(loc);
signsConfig.set("signs." + key + ".world", loc.getWorld().getName());
signsConfig.set("signs." + key + ".x", loc.getBlockX());
signsConfig.set("signs." + key + ".y", loc.getBlockY());
signsConfig.set("signs." + key + ".z", loc.getBlockZ());
signsConfig.set("signs." + key + ".player", entry.getValue());
}
signsConfig.save(signsFile);
getLogger().info("playerstatussign_signs.yml erfolgreich gespeichert.");
} catch (IOException e) {
getLogger().severe("Fehler beim Speichern von playerstatussign_signs.yml: " + e.getMessage());
e.printStackTrace();
}
}
private void loadPlayers() {
playersFile = new File(getDataFolder(), "playerstatussign_players.yml");
try {
if (!playersFile.exists()) {
playersFile.createNewFile();
getLogger().info("playerstatussign_players.yml erstellt.");
}
playersConfig = YamlConfiguration.loadConfiguration(playersFile);
getLogger().info("playerstatussign_players.yml geladen.");
} catch (IOException e) {
getLogger().severe("Fehler beim Erstellen oder Laden von playerstatussign_players.yml: " + e.getMessage());
e.printStackTrace();
}
}
private void savePlayers() {
if (playersConfig == null || playersFile == null) {
getLogger().severe("Fehler: playersConfig oder playersFile ist null!");
return;
}
try {
playersConfig.save(playersFile);
getLogger().info("playerstatussign_players.yml erfolgreich gespeichert.");
} catch (IOException e) {
getLogger().severe("Fehler beim Speichern von playerstatussign_players.yml: " + e.getMessage());
e.printStackTrace();
}
}
// ------------------------------------------------------------
// Utils
// ------------------------------------------------------------
private String getMessage(String key) {
if (config == null) {
getLogger().warning("Konfigurationsdatei nicht geladen! Schlüssel: " + key);
return ChatColor.RED + "Fehler: Nachricht nicht gefunden (" + key + ")";
}
String message = config.getString("messages." + key, "Message not found: " + key);
return ChatColor.translateAlternateColorCodes('&', message);
}
private String locationKey(Location loc) {
return loc.getWorld().getName() + "_" + loc.getBlockX() + "_" + loc.getBlockY() + "_" + loc.getBlockZ();
}
// ------------------------------------------------------------
// Scheduler
// ------------------------------------------------------------
private void startSignUpdater() {
new BukkitRunnable() {
@Override
public void run() {
// Prüfe Inaktivität für alle Spieler
for (Player player : getServer().getOnlinePlayers()) {
UUID uuid = player.getUniqueId();
if (!afkPlayers.getOrDefault(uuid, false) && !fakeOfflinePlayers.getOrDefault(uuid, false)) {
Long lastMove = lastPlayerMovement.get(uuid);
if (lastMove != null && System.currentTimeMillis() - lastMove > afkTimeout) {
setPlayerAfk(player, true);
}
}
}
// Aktualisiere Schilder
List<Location> toRemove = new ArrayList<>();
for (Map.Entry<Location, String> entry : signLocations.entrySet()) {
Location loc = entry.getKey();
String playerName = entry.getValue();
try {
if (loc.getBlock().getState() instanceof Sign) {
Sign sign = (Sign) loc.getBlock().getState();
updateSign(sign, playerName);
} else {
toRemove.add(loc);
}
} catch (Exception e) {
getLogger().warning("Fehler beim Aktualisieren des Schildes bei " + loc + ": " + e.getMessage());
}
}
if (!toRemove.isEmpty()) {
for (Location loc : toRemove) {
signLocations.remove(loc);
String key = locationKey(loc);
signsConfig.set("signs." + key, null);
}
saveSigns();
}
}
}.runTaskTimer(this, 0L, 100L); // alle 5 Sekunden
}
// ------------------------------------------------------------
// Core
// ------------------------------------------------------------
private void updateSign(Sign sign, String playerName) {
Player player = getServer().getPlayerExact(playerName);
String line1, line2, line3, line4;
line2 = ChatColor.translateAlternateColorCodes('&', playerColor + playerName); // Spielername
if (player != null && player.isOnline() && !fakeOfflinePlayers.getOrDefault(player.getUniqueId(), false)) {
if (isAfk(player)) {
// AFK
line1 = ChatColor.translateAlternateColorCodes('&', "x-" + afkColor + "^&r-x");
line3 = ChatColor.translateAlternateColorCodes('&', afkColor + "AFK");
line4 = ChatColor.translateAlternateColorCodes('&', "x-" + afkColor + "v&r-x");
} else {
// Online
line1 = ChatColor.translateAlternateColorCodes('&', "x-" + onlineColor + "^&r-x");
line3 = ChatColor.translateAlternateColorCodes('&', onlineColor + "Online");
line4 = ChatColor.translateAlternateColorCodes('&', "x-" + onlineColor + "v&r-x");
}
} else {
// Offline (oder Fake-Offline)
line1 = ChatColor.translateAlternateColorCodes('&', "x-" + offlineColor + "^&r-x");
long lastLogin = playersConfig.getLong("players." + playerName + ".last-login", -1);
String dateStr = lastLogin != -1 ? new SimpleDateFormat(dateFormat).format(new Date(lastLogin)) : "Unbekannt";
line3 = ChatColor.translateAlternateColorCodes('&', offlineColor + dateStr);
line4 = ChatColor.translateAlternateColorCodes('&', "x-" + offlineColor + "v&r-x");
}
try {
sign.setLine(0, line1);
sign.setLine(1, line2);
sign.setLine(2, line3);
sign.setLine(3, line4);
sign.update();
} catch (Exception e) {
getLogger().warning("Fehler beim Aktualisieren des Schildes für " + playerName + ": " + e.getMessage());
}
}
private boolean isAfk(Player player) {
return afkPlayers.getOrDefault(player.getUniqueId(), false);
}
private void setPlayerAfk(Player player, boolean afk) {
UUID uuid = player.getUniqueId();
try {
if (afk && !afkPlayers.getOrDefault(uuid, false)) {
afkPlayers.put(uuid, true);
if (afkChangeGamemode) {
originalGameModes.put(uuid, player.getGameMode());
player.setGameMode(GameMode.ADVENTURE);
}
player.sendMessage(getMessage("afk-enabled"));
updateSignsForPlayer(player.getName());
} else if (!afk && afkPlayers.getOrDefault(uuid, false)) {
afkPlayers.put(uuid, false);
if (afkChangeGamemode) {
GameMode originalMode = originalGameModes.getOrDefault(uuid, GameMode.SURVIVAL);
player.setGameMode(originalMode);
originalGameModes.remove(uuid);
}
player.sendMessage(getMessage("afk-disabled"));
updateSignsForPlayer(player.getName());
}
} catch (Exception e) {
getLogger().warning("Fehler beim Setzen des AFK-Status für " + player.getName() + ": " + e.getMessage());
}
}
private void setPlayerFakeOffline(Player player, boolean fakeOffline) {
UUID uuid = player.getUniqueId();
String playerName = player.getName();
try {
if (fakeOffline && !fakeOfflinePlayers.getOrDefault(uuid, false)) {
// Spieler wird Fake-Offline
fakeOfflinePlayers.put(uuid, true);
// Timestamp direkt speichern
long now = System.currentTimeMillis();
playersConfig.set("players." + playerName + ".last-login", now);
savePlayers();
player.sendMessage(getMessage("status-offline-enabled"));
updateSignsForPlayer(playerName);
} else if (!fakeOffline && fakeOfflinePlayers.getOrDefault(uuid, false)) {
// Spieler wieder sichtbar
fakeOfflinePlayers.put(uuid, false);
player.sendMessage(getMessage("status-offline-disabled"));
updateSignsForPlayer(playerName);
}
} catch (Exception e) {
getLogger().warning("Fehler beim Setzen des Fake-Offline-Status für " + playerName + ": " + e.getMessage());
}
}
private void updateSignsForPlayer(String playerName) {
for (Map.Entry<Location, String> entry : signLocations.entrySet()) {
if (entry.getValue().equalsIgnoreCase(playerName)) {
Location loc = entry.getKey();
try {
if (loc.getBlock().getState() instanceof Sign) {
Sign sign = (Sign) loc.getBlock().getState();
updateSign(sign, playerName);
}
} catch (Exception e) {
getLogger().warning("Fehler beim Aktualisieren des Schildes für " + playerName + " bei " + loc + ": " + e.getMessage());
}
}
}
}
// ------------------------------------------------------------
// GUI
// ------------------------------------------------------------
private void openStatsGUI(Player viewer, String targetPlayerName) {
try {
Player target = getServer().getPlayerExact(targetPlayerName);
Inventory gui = getServer().createInventory(null, 9, ChatColor.translateAlternateColorCodes('&', "&6Statistiken von " + targetPlayerName));
long playTimeTicks = 0;
int deaths = 0;
int playerKills = 0;
int blocksMined = 0;
double distanceWalkedCm = 0;
if (target != null && target.isOnline()) {
playTimeTicks = target.getStatistic(Statistic.PLAY_ONE_MINUTE);
deaths = target.getStatistic(Statistic.DEATHS);
playerKills = target.getStatistic(Statistic.PLAYER_KILLS);
for (Material material : Material.values()) {
if (material.isBlock()) {
try {
blocksMined += target.getStatistic(Statistic.MINE_BLOCK, material);
} catch (IllegalArgumentException ignored) { }
}
}
distanceWalkedCm = target.getStatistic(Statistic.WALK_ONE_CM);
} else {
playTimeTicks = playersConfig.getLong ("players." + targetPlayerName + ".stats.play-time", 0);
deaths = playersConfig.getInt ("players." + targetPlayerName + ".stats.deaths", 0);
playerKills = playersConfig.getInt ("players." + targetPlayerName + ".stats.player-kills", 0);
blocksMined = playersConfig.getInt ("players." + targetPlayerName + ".stats.blocks-mined", 0);
distanceWalkedCm = playersConfig.getDouble("players." + targetPlayerName + ".stats.distance-walked", 0);
}
double playTimeHours = playTimeTicks / 72000.0; // 20 Ticks * 3600 Sekunden
double distanceWalkedKm = distanceWalkedCm / 100000.0;
ItemStack playTimeItem = new ItemStack(Material.CLOCK);
ItemMeta playTimeMeta = playTimeItem.getItemMeta();
if (playTimeMeta != null) {
playTimeMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&eSpielzeit"));
playTimeMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', "&7" + String.format("%.2f", playTimeHours) + " Stunden")));
playTimeItem.setItemMeta(playTimeMeta);
}
gui.setItem(0, playTimeItem);
ItemStack deathsItem = new ItemStack(Material.SKELETON_SKULL);
ItemMeta deathsMeta = deathsItem.getItemMeta();
if (deathsMeta != null) {
deathsMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&cTode"));
deathsMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', "&7" + deaths + " Tode")));
deathsItem.setItemMeta(deathsMeta);
}
gui.setItem(1, deathsItem);
ItemStack killsItem = new ItemStack(Material.DIAMOND_SWORD);
ItemMeta killsMeta = killsItem.getItemMeta();
if (killsMeta != null) {
killsMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&aSpieler-Kills"));
killsMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', "&7" + playerKills + " Kills")));
killsItem.setItemMeta(killsMeta);
}
gui.setItem(2, killsItem);
ItemStack blocksMinedItem = new ItemStack(Material.IRON_PICKAXE);
ItemMeta blocksMinedMeta = blocksMinedItem.getItemMeta();
if (blocksMinedMeta != null) {
blocksMinedMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&bAbgebaute Blöcke"));
blocksMinedMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', "&7" + blocksMined + " Blöcke")));
blocksMinedItem.setItemMeta(blocksMinedMeta);
}
gui.setItem(3, blocksMinedItem);
ItemStack distanceItem = new ItemStack(Material.COMPASS);
ItemMeta distanceMeta = distanceItem.getItemMeta();
if (distanceMeta != null) {
distanceMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&9Gelaufene Distanz"));
distanceMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', "&7" + String.format("%.2f", distanceWalkedKm) + " km")));
distanceItem.setItemMeta(distanceMeta);
}
gui.setItem(4, distanceItem);
viewer.openInventory(gui);
} catch (Exception e) {
getLogger().warning("Fehler beim Öffnen der Statistik-GUI für " + targetPlayerName + ": " + e.getMessage());
viewer.sendMessage(getMessage("gui-error"));
}
}
// ------------------------------------------------------------
// Commands
// ------------------------------------------------------------
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage(getMessage("player-only"));
return true;
}
Player player = (Player) sender;
if (config == null) {
player.sendMessage(ChatColor.RED + "Fehler: Plugin-Konfiguration nicht geladen!");
getLogger().severe("Konfigurationsdatei nicht verfügbar bei Befehlsausführung!");
return true;
}
switch (command.getName().toLowerCase()) {
case "statussign":
if (args.length == 0) {
player.sendMessage(getMessage("help-title"));
player.sendMessage(getMessage("help-reload"));
player.sendMessage(getMessage("help-help"));
return true;
}
if (args[0].equalsIgnoreCase("reload")) {
if (!player.hasPermission("statussign.admin")) {
player.sendMessage(getMessage("no-permission-admin"));
return true;
}
loadConfig();
loadSigns();
loadPlayers();
player.sendMessage(getMessage("reload-success"));
return true;
}
if (args[0].equalsIgnoreCase("help")) {
player.sendMessage(getMessage("help-title"));
player.sendMessage(getMessage("help-reload"));
player.sendMessage(getMessage("help-help"));
return true;
}
player.sendMessage(getMessage("unknown-subcommand"));
return true;
case "statusafk":
if (!player.hasPermission("statussign.admin")) {
player.sendMessage(getMessage("no-permission-admin"));
return true;
}
if (fakeOfflinePlayers.getOrDefault(player.getUniqueId(), false)) {
player.sendMessage(getMessage("cannot-afk-while-offline"));
return true;
}
setPlayerAfk(player, !isAfk(player));
return true;
case "statusoffline":
if (!player.hasPermission("statussign.admin")) {
player.sendMessage(getMessage("no-permission-admin"));
return true;
}
if (isAfk(player)) {
setPlayerAfk(player, false);
}
setPlayerFakeOffline(player, true);
return true;
case "statusonline":
if (!player.hasPermission("statussign.admin")) {
player.sendMessage(getMessage("no-permission-admin"));
return true;
}
setPlayerFakeOffline(player, false);
return true;
default:
return false;
}
}
// ------------------------------------------------------------
// Events
// ------------------------------------------------------------
@EventHandler(priority = EventPriority.LOW)
public void onSignChange(SignChangeEvent event) {
if (event.isCancelled()) return;
Player player = event.getPlayer();
if (!player.hasPermission("statussign.admin")) {
player.sendMessage(getMessage("no-permission-admin"));
event.setCancelled(true);
return;
}
if (event.getLine(0).equalsIgnoreCase("[" + prefix + "]")) {
String playerName = event.getLine(1);
if (playerName == null || playerName.trim().isEmpty()) {
player.sendMessage(getMessage("invalid-player"));
event.setCancelled(true);
return;
}
try {
Location loc = event.getBlock().getLocation();
String key = locationKey(loc);
signLocations.put(loc, playerName);
ensureSignsFile();
signsConfig.set("signs." + key + ".world", loc.getWorld().getName());
signsConfig.set("signs." + key + ".x", loc.getBlockX());
signsConfig.set("signs." + key + ".y", loc.getBlockY());
signsConfig.set("signs." + key + ".z", loc.getBlockZ());
signsConfig.set("signs." + key + ".player", playerName);
signsConfig.save(signsFile);
// Sofortige Status-Anzeige
Sign sign = (Sign) event.getBlock().getState();
updateSign(sign, playerName);
player.sendMessage(getMessage("sign-created").replace("%player%", playerName));
} catch (Exception e) {
getLogger().warning("Fehler beim Erstellen des Schildes für " + playerName + ": " + e.getMessage());
player.sendMessage(getMessage("sign-error"));
event.setCancelled(true);
}
}
}
@EventHandler(priority = EventPriority.LOW)
public void onPlayerInteract(PlayerInteractEvent event) {
if (event.isCancelled()) return;
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
if (event.getClickedBlock() == null || !(event.getClickedBlock().getState() instanceof Sign)) return;
Sign sign = (Sign) event.getClickedBlock().getState();
Location loc = sign.getLocation();
if (!signLocations.containsKey(loc)) return;
Player player = event.getPlayer();
if (!player.hasPermission("statussign.use")) {
player.sendMessage(getMessage("no-permission-use"));
event.setCancelled(true);
return;
}
String targetPlayer = signLocations.get(loc);
openStatsGUI(player, targetPlayer);
event.setCancelled(true);
}
@EventHandler(priority = EventPriority.LOW)
public void onBlockBreak(BlockBreakEvent event) {
if (event.isCancelled()) return;
if (!(event.getBlock().getState() instanceof Sign)) return;
Location loc = event.getBlock().getLocation();
if (!signLocations.containsKey(loc)) return;
Player player = event.getPlayer();
if (!player.hasPermission("statussign.admin")) {
event.setCancelled(true);
player.sendMessage(getMessage("no-permission-break-sign"));
return;
}
if (!player.isSneaking()) {
event.setCancelled(true);
player.sendMessage(getMessage("break-sign-sneak"));
return;
}
try {
String playerName = signLocations.get(loc);
signLocations.remove(loc);
String key = locationKey(loc);
ensureSignsFile();
signsConfig.set("signs." + key, null);
signsConfig.save(signsFile);
player.sendMessage(getMessage("sign-removed").replace("%player%", playerName));
} catch (Exception e) {
getLogger().warning("Fehler beim Entfernen des Schildes bei " + loc + ": " + e.getMessage());
player.sendMessage(getMessage("sign-error"));
event.setCancelled(true);
}
}
@EventHandler(priority = EventPriority.LOW)
public void onPlayerMove(PlayerMoveEvent event) {
if (event.isCancelled()) return;
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
lastPlayerMovement.put(uuid, System.currentTimeMillis());
if (isAfk(player) && !fakeOfflinePlayers.getOrDefault(uuid, false)) {
setPlayerAfk(player, false);
}
}
@EventHandler(priority = EventPriority.LOW)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
String playerName = player.getName();
UUID uuid = player.getUniqueId();
try {
// Speichere Statistiken
playersConfig.set("players." + playerName + ".last-login", System.currentTimeMillis());
playersConfig.set("players." + playerName + ".stats.play-time", player.getStatistic(Statistic.PLAY_ONE_MINUTE));
playersConfig.set("players." + playerName + ".stats.deaths", player.getStatistic(Statistic.DEATHS));
playersConfig.set("players." + playerName + ".stats.player-kills", player.getStatistic(Statistic.PLAYER_KILLS));
int blocksMined = 0;
for (Material material : Material.values()) {
if (material.isBlock()) {
try {
blocksMined += player.getStatistic(Statistic.MINE_BLOCK, material);
} catch (IllegalArgumentException ignored) { }
}
}
playersConfig.set("players." + playerName + ".stats.blocks-mined", blocksMined);
playersConfig.set("players." + playerName + ".stats.distance-walked", player.getStatistic(Statistic.WALK_ONE_CM));
savePlayers();
afkPlayers.remove(uuid);
fakeOfflinePlayers.remove(uuid);
originalGameModes.remove(uuid);
lastPlayerMovement.remove(uuid);
} catch (Exception e) {
getLogger().warning("Fehler beim Speichern der Daten für " + playerName + ": " + e.getMessage());
}
}
}