src/main/java/PlayerStatusSign.java aktualisiert

This commit is contained in:
2025-08-12 18:27:23 +00:00
parent 525aeb0537
commit 48fa0aec64

View File

@@ -1,4 +1,5 @@
import org.bstats.bukkit.Metrics; // bStats import import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
@@ -16,7 +17,10 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.Action; import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
@@ -27,8 +31,12 @@ import org.bukkit.scheduler.BukkitRunnable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import java.util.Scanner;
import java.util.function.Consumer;
public class PlayerStatusSign extends JavaPlugin implements Listener { public class PlayerStatusSign extends JavaPlugin implements Listener {
@@ -39,11 +47,11 @@ public class PlayerStatusSign extends JavaPlugin implements Listener {
private File configFile; private File configFile;
private FileConfiguration config; private FileConfiguration config;
private Map<Location, String> signLocations; // Schildposition -> Spielername private Map<Location, String> signLocations; // Schildposition -> Spielername
private Map<UUID, Long> lastPlayerMovement; // Spieler UUID -> Zeitpunkt private Map<UUID, Long> lastPlayerMovement; // Spieler UUID -> Zeitpunkt
private Map<UUID, Boolean> afkPlayers; // Spieler UUID -> AFK-Status private Map<UUID, Boolean> afkPlayers; // Spieler UUID -> AFK-Status
private Map<UUID, Boolean> fakeOfflinePlayers; // Spieler UUID -> Fake-Offline-Status private Map<UUID, Boolean> fakeOfflinePlayers; // Spieler UUID -> Fake-Offline-Status
private Map<UUID, GameMode> originalGameModes; // Spieler UUID -> Ursprünglicher Gamemode private Map<UUID, GameMode> originalGameModes; // Spieler UUID -> Ursprünglicher Gamemode
private String prefix; private String prefix;
private String onlineColor; private String onlineColor;
@@ -61,6 +69,10 @@ public class PlayerStatusSign extends JavaPlugin implements Listener {
private static final int BSTATS_PLUGIN_ID = 26877; // <-- bStats Service-ID hier eintragen! private static final int BSTATS_PLUGIN_ID = 26877; // <-- bStats Service-ID hier eintragen!
private Metrics metrics; private Metrics metrics;
// Neue Variablen zum Speichern des Update-Status
private boolean updateAvailable = false;
private String latestVersion = null;
// ------------------------------------------------------------ // ------------------------------------------------------------
// Lifecycle // Lifecycle
// ------------------------------------------------------------ // ------------------------------------------------------------
@@ -84,10 +96,34 @@ public class PlayerStatusSign extends JavaPlugin implements Listener {
metrics = new Metrics(this, BSTATS_PLUGIN_ID); metrics = new Metrics(this, BSTATS_PLUGIN_ID);
getLogger().info("bStats wurde gestartet (Plugin-ID: " + BSTATS_PLUGIN_ID + ")"); getLogger().info("bStats wurde gestartet (Plugin-ID: " + BSTATS_PLUGIN_ID + ")");
// ---- Spigot Update Checker ----
int resourceId = 127335; // Ersetze dies mit der ID deiner Plugin-Ressource auf SpigotMC
new UpdateChecker(this, resourceId).getVersion(version -> {
if (this.getDescription().getVersion().equals(version)) {
getLogger().info("Das Plugin ist auf dem neuesten Stand.");
updateAvailable = false;
latestVersion = null;
} else {
getLogger().info("Eine neue Plugin-Version ist verfügbar: " + version);
updateAvailable = true;
latestVersion = version;
// Sofort Nachricht an alle Operatoren oder “statussign.admin”-Permission
Bukkit.getScheduler().runTask(this, () -> {
for (Player player : Bukkit.getOnlinePlayers()) {
if (player.isOp() || player.hasPermission("statussign.admin")) {
player.sendMessage(ChatColor.GREEN + "Es ist eine neue Version von PlayerStatusSign verfügbar: " + ChatColor.GOLD + version);
player.sendMessage(ChatColor.GREEN + "Lade sie auf SpigotMC herunter!");
}
}
});
}
});
// Konsolenmeldung beim Plugin-Start // Konsolenmeldung beim Plugin-Start
getLogger().info("[>] ========================================== [<]"); getLogger().info("[>] ========================================== [<]");
getLogger().info(" PlayerStatusSign - " + getDescription().getVersion() + " (cfg " + CONFIG_VERSION + ")"); getLogger().info(" PlayerStatusSign - " + getDescription().getVersion() + " (cfg " + CONFIG_VERSION + ")");
getLogger().info(" Ersteller: " + PLUGIN_AUTHOR); getLogger().info(" Ersteller: " + PLUGIN_AUTHOR);
getLogger().info("[>] ========================================== [<]"); getLogger().info("[>] ========================================== [<]");
} catch (Exception e) { } catch (Exception e) {
getLogger().severe("Fehler beim Laden des Plugins: " + e.getMessage()); getLogger().severe("Fehler beim Laden des Plugins: " + e.getMessage());
@@ -116,6 +152,47 @@ public class PlayerStatusSign extends JavaPlugin implements Listener {
savePlayers(); savePlayers();
} }
// Spieler-Join Event für Ingame Update-Nachricht
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
if (updateAvailable && (player.isOp() || player.hasPermission("statussign.admin"))) {
player.sendMessage(ChatColor.GREEN + "Es ist eine neue Version von PlayerStatusSign verfügbar: " + ChatColor.GOLD + latestVersion);
player.sendMessage(ChatColor.GREEN + "Lade sie auf SpigotMC herunter!");
}
}
// ... (restliche Methoden wie loadConfig, EventHandler etc. hier weiterhin einfügen) ...
// ------------------------------------------------------------
// UpdateChecker Klasse (innerhalb derselben Datei oder als separate Datei)
// ------------------------------------------------------------
public static class UpdateChecker {
private final JavaPlugin plugin;
private final int resourceId;
public UpdateChecker(JavaPlugin plugin, int resourceId) {
this.plugin = plugin;
this.resourceId = resourceId;
}
public void getVersion(final Consumer<String> consumer) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try (InputStream is = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + resourceId).openStream();
Scanner scanner = new Scanner(is)) {
if (scanner.hasNext()) {
consumer.accept(scanner.next());
}
} catch (IOException e) {
plugin.getLogger().warning("Unable to check for updates: " + e.getMessage());
}
});
}
}
// ------------------------------------------------------------ // ------------------------------------------------------------
// Config / Storage // Config / Storage
// ------------------------------------------------------------ // ------------------------------------------------------------
@@ -420,93 +497,180 @@ public class PlayerStatusSign extends JavaPlugin implements Listener {
} }
// ------------------------------------------------------------ // ------------------------------------------------------------
// GUI // GUI
// ------------------------------------------------------------ // ------------------------------------------------------------
private void openStatsGUI(Player viewer, String targetPlayerName) { private void openStatsGUI(Player viewer, String targetPlayerName) {
try { try {
Player target = getServer().getPlayerExact(targetPlayerName); Player target = getServer().getPlayerExact(targetPlayerName);
Inventory gui = getServer().createInventory(null, 9, ChatColor.translateAlternateColorCodes('&', "&6Statistiken von " + targetPlayerName)); Inventory gui = getServer().createInventory(null, 9, ChatColor.translateAlternateColorCodes('&', "&3Statistiken von " + targetPlayerName));
long playTimeTicks = 0; long playTimeTicks = 0;
int deaths = 0; int deaths = 0;
int playerKills = 0; int playerKills = 0;
int blocksMined = 0; int blocksMined = 0;
double distanceWalkedCm = 0; double distanceWalkedCm = 0;
if (target != null && target.isOnline()) { if (target != null && target.isOnline()) {
playTimeTicks = target.getStatistic(Statistic.PLAY_ONE_MINUTE); playTimeTicks = target.getStatistic(Statistic.PLAY_ONE_MINUTE);
deaths = target.getStatistic(Statistic.DEATHS); deaths = target.getStatistic(Statistic.DEATHS);
playerKills = target.getStatistic(Statistic.PLAYER_KILLS); playerKills = target.getStatistic(Statistic.PLAYER_KILLS);
for (Material material : Material.values()) { for (Material material : Material.values()) {
if (material.isBlock()) { if (material.isBlock()) {
try { try {
blocksMined += target.getStatistic(Statistic.MINE_BLOCK, material); blocksMined += target.getStatistic(Statistic.MINE_BLOCK, material);
} catch (IllegalArgumentException ignored) { } } 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);
} }
distanceWalkedCm = target.getStatistic(Statistic.WALK_ONE_CM);
double playTimeHours = playTimeTicks / 72000.0; // 20 Ticks * 3600 Sekunden } else {
double distanceWalkedKm = distanceWalkedCm / 100000.0; playTimeTicks = playersConfig.getLong ("players." + targetPlayerName + ".stats.play-time", 0);
deaths = playersConfig.getInt ("players." + targetPlayerName + ".stats.deaths", 0);
ItemStack playTimeItem = new ItemStack(Material.CLOCK); playerKills = playersConfig.getInt ("players." + targetPlayerName + ".stats.player-kills", 0);
ItemMeta playTimeMeta = playTimeItem.getItemMeta(); blocksMined = playersConfig.getInt ("players." + targetPlayerName + ".stats.blocks-mined", 0);
if (playTimeMeta != null) { distanceWalkedCm = playersConfig.getDouble("players." + targetPlayerName + ".stats.distance-walked", 0);
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"));
} }
double playTimeHours = playTimeTicks / 72000.0;
double distanceWalkedKm = distanceWalkedCm / 100000.0;
// Spielzeit
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);
// Tode
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);
// Kills
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);
// Abgebaute Blöcke
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);
// Gelaufene Distanz
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);
// NEU 5: Geflogene Distanz
double flewDistanceCm = (target != null && target.isOnline()) ?
target.getStatistic(Statistic.FLY_ONE_CM) :
playersConfig.getDouble("players." + targetPlayerName + ".stats.flew-distance", 0);
double flewDistanceKm = flewDistanceCm / 100000.0;
ItemStack flewDistanceItem = new ItemStack(Material.ELYTRA);
ItemMeta flewMeta = flewDistanceItem.getItemMeta();
if (flewMeta != null) {
flewMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&9Geflogene Distanz"));
flewMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', String.format("&7%.2f km", flewDistanceKm))));
flewDistanceItem.setItemMeta(flewMeta);
}
gui.setItem(5, flewDistanceItem);
// NEU 6: Crafting
int craftedCount = 0;
if (target != null && target.isOnline()) {
for (Material m : Material.values()) {
if (m.isItem()) {
try { craftedCount += target.getStatistic(Statistic.CRAFT_ITEM, m); } catch (Exception ignored) {}
}
}
} else {
craftedCount = playersConfig.getInt("players." + targetPlayerName + ".stats.crafted-items", 0);
}
ItemStack craftedItem = new ItemStack(Material.CRAFTING_TABLE);
ItemMeta craftedMeta = craftedItem.getItemMeta();
if (craftedMeta != null) {
craftedMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&eItems hergestellt"));
craftedMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', "&7" + craftedCount)));
craftedItem.setItemMeta(craftedMeta);
}
gui.setItem(6, craftedItem);
// NEU 7: Blöcke gesetzt
int blocksPlaced = 0;
if (target != null && target.isOnline()) {
for (Material m : Material.values()) {
if (m.isBlock()) {
try { blocksPlaced += target.getStatistic(Statistic.USE_ITEM, m); } catch (Exception ignored) {}
}
}
} else {
blocksPlaced = playersConfig.getInt("players." + targetPlayerName + ".stats.blocks-placed", 0);
}
ItemStack placedItem = new ItemStack(Material.OAK_PLANKS);
ItemMeta placedMeta = placedItem.getItemMeta();
if (placedMeta != null) {
placedMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&aGesetzte Blöcke"));
placedMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&', "&7" + blocksPlaced)));
placedItem.setItemMeta(placedMeta);
}
gui.setItem(7, placedItem);
// NEU 8: Zeit seit letztem Tod
long lastDeathMs;
if (target != null && target.isOnline()) {
lastDeathMs = System.currentTimeMillis() - (target.getStatistic(Statistic.TIME_SINCE_DEATH) * 50L);
} else {
long recordedTime = playersConfig.getLong("players." + targetPlayerName + ".stats.last-death-time", System.currentTimeMillis());
lastDeathMs = System.currentTimeMillis() - recordedTime;
}
// Zeit seit letztem Tod in Stunden
if (target != null && target.isOnline()) {
lastDeathMs = System.currentTimeMillis() - (target.getStatistic(Statistic.TIME_SINCE_DEATH) * 50L);
} else {
long recordedTime = playersConfig.getLong("players." + targetPlayerName + ".stats.last-death-time", System.currentTimeMillis());
lastDeathMs = System.currentTimeMillis() - recordedTime;
}
double hoursSinceDeath = lastDeathMs / 3600000.0; // Millisekunden → Stunden
ItemStack deathItem = new ItemStack(Material.CLOCK);
ItemMeta deathMeta = deathItem.getItemMeta();
if (deathMeta != null) {
deathMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', "&6Zeit seit letztem Tod"));
deathMeta.setLore(Collections.singletonList(ChatColor.translateAlternateColorCodes('&',
String.format("&7%.2f Stunden", hoursSinceDeath))));
deathItem.setItemMeta(deathMeta);
}
gui.setItem(8, deathItem);
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 // Commands
@@ -662,6 +826,22 @@ public class PlayerStatusSign extends JavaPlugin implements Listener {
event.setCancelled(true); event.setCancelled(true);
} }
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
String title = ChatColor.stripColor(event.getView().getTitle());
if (title != null && title.startsWith("Statistiken von ")) {
event.setCancelled(true); // Verhindert Herausnehmen/Verschieben von Items im Stats-GUI
}
}
@EventHandler
public void onInventoryDrag(InventoryDragEvent event) {
String title = ChatColor.stripColor(event.getView().getTitle());
if (title != null && title.startsWith("Statistiken von ")) {
event.setCancelled(true); // Verhindert Drag & Drop im Stats-GUI
}
}
@EventHandler(priority = EventPriority.LOW) @EventHandler(priority = EventPriority.LOW)
public void onBlockBreak(BlockBreakEvent event) { public void onBlockBreak(BlockBreakEvent event) {
if (event.isCancelled()) return; if (event.isCancelled()) return;