package de.fussball.plugin.commands; import de.fussball.plugin.Fussball; import de.fussball.plugin.arena.Arena; import de.fussball.plugin.game.Ball; import de.fussball.plugin.game.Game; import de.fussball.plugin.game.GameState; import de.fussball.plugin.game.Team; import de.fussball.plugin.hologram.FussballHologram; import de.fussball.plugin.hologram.HologramManager; import de.fussball.plugin.stats.MatchHistory; import de.fussball.plugin.stats.StatsManager; import de.fussball.plugin.utils.MessageUtil; import org.bukkit.ChatColor; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.command.*; import org.bukkit.entity.Player; import java.util.*; public class FussballCommand implements CommandExecutor, TabCompleter { private final Fussball plugin; public FussballCommand(Fussball plugin) { this.plugin = plugin; } @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (args.length == 0) { sendHelp(sender); return true; } switch (args[0].toLowerCase()) { // ── Spieler-Befehle ────────────────────────────────────────────── case "join" -> { if (!(sender instanceof Player player)) { sender.sendMessage("Nur für Spieler!"); return true; } if (args.length < 2) { player.sendMessage(MessageUtil.error("Benutze: /fb join ")); return true; } Arena arena = plugin.getArenaManager().getArena(args[1]); if (arena == null) { player.sendMessage(MessageUtil.error("Arena §e" + args[1] + " §cnicht gefunden!")); return true; } if (!arena.isSetupComplete()) { player.sendMessage(MessageUtil.error("Arena nicht vollständig eingerichtet!")); return true; } if (plugin.getGameManager().isInAnyGame(player)) { player.sendMessage(MessageUtil.error("Du bist bereits in einem Spiel! Tippe §e/fb leave§c.")); return true; } plugin.getGameManager().createGame(arena).addPlayer(player); } case "leave" -> { if (!(sender instanceof Player player)) { sender.sendMessage("Nur für Spieler!"); return true; } // Aus Spiel Game game = plugin.getGameManager().getPlayerGame(player); if (game != null) { game.removePlayer(player); player.sendMessage(MessageUtil.success("Du hast das Spiel verlassen!")); return true; } // Aus Zuschauer Game specGame = plugin.getGameManager().getSpectatorGame(player); if (specGame != null) { specGame.removeSpectator(player); player.sendMessage(MessageUtil.success("Du hast das Zuschauen beendet!")); return true; } // Aus Warteschlange plugin.getGameManager().removeFromAllQueues(player); player.sendMessage(MessageUtil.warn("Du bist in keinem Spiel und in keiner Warteschlange.")); } case "spectate", "spec" -> { if (!(sender instanceof Player player)) { sender.sendMessage("Nur für Spieler!"); return true; } if (args.length < 2) { player.sendMessage(MessageUtil.error("Benutze: /fb spectate ")); return true; } Arena arena = plugin.getArenaManager().getArena(args[1]); if (arena == null) { player.sendMessage(MessageUtil.error("Arena nicht gefunden!")); return true; } if (plugin.getGameManager().isInAnyGame(player)) { player.sendMessage(MessageUtil.error("Verlasse zuerst dein aktuelles Spiel!")); return true; } Game game = plugin.getGameManager().getGame(arena.getName()); if (game == null) { player.sendMessage(MessageUtil.error("Kein laufendes Spiel in dieser Arena!")); return true; } game.addSpectator(player); } case "list" -> { sender.sendMessage(MessageUtil.header("⚽ Verfügbare Arenen")); Collection arenas = plugin.getArenaManager().getAllArenas(); if (arenas.isEmpty()) { sender.sendMessage(MessageUtil.warn("Keine Arenen vorhanden.")); return true; } for (Arena a : arenas) { Game g = plugin.getGameManager().getGame(a.getName()); int queueSize = plugin.getGameManager().getQueueSize(a.getName()); String status = g != null ? statusDot(g.getState()) : "§a●"; String players = g != null ? g.getAllPlayers().size() + "/" + a.getMaxPlayers() : "0/" + a.getMaxPlayers(); String setup = a.isSetupComplete() ? "§a✔" : "§c✗"; String queue = queueSize > 0 ? " §8(§e" + queueSize + " §8warten)" : ""; sender.sendMessage("§7 " + status + " §e" + a.getName() + " §7[" + players + "] " + setup + queue); } } case "stats" -> { if (args.length >= 2 && args[1].equalsIgnoreCase("reset")) { if (!sender.hasPermission("fussball.admin")) { sender.sendMessage(MessageUtil.error("Keine Berechtigung!")); return true; } if (args.length < 3) { sender.sendMessage(MessageUtil.error("Benutze: /fb stats reset ")); return true; } if (args[2].equalsIgnoreCase("all") || args[2].equalsIgnoreCase("*")) { int removed = plugin.getStatsManager().resetAllStats(); plugin.getHologramManager().refreshAll(); sender.sendMessage(MessageUtil.success("Alle Statistiken zurückgesetzt! §7(" + removed + " Einträge)")); return true; } Player onlineTarget = Bukkit.getPlayerExact(args[2]); UUID targetUuid = onlineTarget != null ? onlineTarget.getUniqueId() : plugin.getStatsManager().findPlayerUuidByName(args[2]); if (targetUuid == null) { sender.sendMessage(MessageUtil.error("Keine gespeicherten Statistiken für §e" + args[2] + " §cgefunden!")); return true; } if (!plugin.getStatsManager().resetStats(targetUuid)) { sender.sendMessage(MessageUtil.error("Statistiken von §e" + args[2] + " §ckonnten nicht zurückgesetzt werden.")); return true; } plugin.getHologramManager().refreshAll(); sender.sendMessage(MessageUtil.success("Statistiken von §e" + args[2] + " §azurückgesetzt!")); return true; } if (!(sender instanceof Player player)) { sender.sendMessage("Nur für Spieler!"); return true; } Player target = args.length >= 2 ? Bukkit.getPlayer(args[1]) : player; if (target == null) { player.sendMessage(MessageUtil.error("Spieler §e" + args[1] + " §cnicht gefunden!")); return true; } StatsManager.PlayerStats s = plugin.getStatsManager().getStats(target.getUniqueId()); player.sendMessage(MessageUtil.header("Statistiken: " + target.getName())); player.sendMessage("§7 ⚽ Tore: §e" + s.goals); player.sendMessage("§7 🅾 Eigentore: §c" + s.ownGoals); player.sendMessage("§7 🎯 Vorlagen: §a" + s.assists); player.sendMessage("§7 👟 Schüsse: §e" + s.kicks); player.sendMessage("§7 🏆 Siege: §a" + s.wins); player.sendMessage("§7 ❌ Niederlagen: §c" + s.losses); player.sendMessage("§7 ➖ Unentschieden: §7" + s.draws); player.sendMessage("§7 📊 Gespielte Spiele: §e" + s.games); player.sendMessage("§7 📈 Siegquote: §e" + String.format("%.1f", s.getWinRate()) + "§7%"); // In-Game-Statistik anhängen wenn aktiv Game inGame = plugin.getGameManager().getPlayerGame(target); if (inGame != null) { player.sendMessage("§8--- Aktuelles Spiel ---"); player.sendMessage("§7 Tore heute: §e" + inGame.getGoals().getOrDefault(target.getUniqueId(), 0)); player.sendMessage("§7 Schüsse heute: §e" + inGame.getKicks().getOrDefault(target.getUniqueId(), 0)); } } // ── Admin-Befehle ──────────────────────────────────────────────── case "create" -> { if (!sender.hasPermission("fussball.admin")) { sender.sendMessage(MessageUtil.error("Keine Berechtigung!")); return true; } if (args.length < 2) { sender.sendMessage(MessageUtil.error("Benutze: /fb create ")); return true; } if (plugin.getArenaManager().arenaExists(args[1])) { sender.sendMessage(MessageUtil.error("Arena §e" + args[1] + " §cexistiert bereits!")); return true; } plugin.getArenaManager().createArena(args[1]); sender.sendMessage(MessageUtil.success("Arena §e" + args[1] + " §aerstellt! Richte sie mit §e/fb setup §aein.")); } case "delete" -> { if (!sender.hasPermission("fussball.admin")) { sender.sendMessage(MessageUtil.error("Keine Berechtigung!")); return true; } if (args.length < 2) { sender.sendMessage(MessageUtil.error("Benutze: /fb delete ")); return true; } sender.sendMessage(plugin.getArenaManager().deleteArena(args[1]) ? MessageUtil.success("Arena §e" + args[1] + " §agelöscht!") : MessageUtil.error("Arena nicht gefunden!")); } case "setup" -> { if (!sender.hasPermission("fussball.admin")) { sender.sendMessage(MessageUtil.error("Keine Berechtigung!")); return true; } if (!(sender instanceof Player player)) { sender.sendMessage("Nur für Spieler!"); return true; } if (args.length < 3) { sendSetupHelp(player); return true; } handleSetup(player, args); } case "stop" -> { if (!sender.hasPermission("fussball.admin")) { sender.sendMessage(MessageUtil.error("Keine Berechtigung!")); return true; } if (args.length < 2) { sender.sendMessage(MessageUtil.error("Benutze: /fb stop ")); return true; } Game game = plugin.getGameManager().getGame(args[1]); if (game == null) { sender.sendMessage(MessageUtil.error("Kein aktives Spiel in §e" + args[1] + "§c!")); return true; } game.endGame(null); sender.sendMessage(MessageUtil.success("Spiel in §e" + args[1] + " §aberendet.")); } // ── Torwart manuell zuweisen ───────────────────────────────────────── case "setgk" -> { if (!sender.hasPermission("fussball.admin")) { sender.sendMessage(MessageUtil.error("Keine Berechtigung!")); return true; } // Nutzung: /fb setgk if (args.length < 3) { sender.sendMessage(MessageUtil.error("Benutze: /fb setgk ")); return true; } Game gkGame = plugin.getGameManager().getGame(args[1]); if (gkGame == null) { sender.sendMessage(MessageUtil.error("Kein aktives Spiel in §e" + args[1] + "§c!")); return true; } Player target = Bukkit.getPlayerExact(args[2]); if (target == null) { sender.sendMessage(MessageUtil.error("Spieler §e" + args[2] + " §cnicht online!")); return true; } if (!gkGame.isInGame(target)) { sender.sendMessage(MessageUtil.error("§e" + args[2] + " §cist nicht in diesem Spiel!")); return true; } if (!gkGame.setGoalkeeper(target)) { sender.sendMessage(MessageUtil.error("Konnte Torwart nicht zuweisen – Spieler hat kein Team?")); } else { sender.sendMessage(MessageUtil.success("§e" + target.getName() + " §aist jetzt Torwart!")); } } case "top" -> { if (args.length < 2) { sender.sendMessage(MessageUtil.error("Benutze: /fussball top goals|wins|kicks")); return true; } switch (args[1].toLowerCase()) { case "goals" -> { sender.sendMessage(MessageUtil.header("🏆 Top Torschützen")); var list = plugin.getStatsManager().getTopScorers(10); if (list.isEmpty()) { sender.sendMessage(MessageUtil.warn("Noch keine Daten.")); break; } for (int i = 0; i < list.size(); i++) { var e = list.get(i); sender.sendMessage("§e#" + (i+1) + " §f" + e.getValue().name + " §7— §e" + e.getValue().goals + " §7Tore" + " §8(§7" + e.getValue().games + " Spiele§8)"); } } case "wins" -> { sender.sendMessage(MessageUtil.header("🏆 Top Gewinner")); var list = plugin.getStatsManager().getTopWins(10); if (list.isEmpty()) { sender.sendMessage(MessageUtil.warn("Noch keine Daten.")); break; } for (int i = 0; i < list.size(); i++) { var e = list.get(i); sender.sendMessage("§e#" + (i+1) + " §f" + e.getValue().name + " §7— §a" + e.getValue().wins + " §7Siege" + " §8(§7" + String.format("%.0f", e.getValue().getWinRate()) + "% WR§8)"); } } case "kicks" -> { sender.sendMessage(MessageUtil.header("🏆 Top Schützen (Schüsse)")); var kickList = new java.util.ArrayList<>(plugin.getStatsManager().getTopScorers(100)); kickList.sort((a, b) -> b.getValue().kicks - a.getValue().kicks); for (int i = 0; i < Math.min(10, kickList.size()); i++) { var e = kickList.get(i); sender.sendMessage("§e#" + (i+1) + " §f" + e.getValue().name + " §7— §e" + e.getValue().kicks + " §7Schüsse"); } } default -> sender.sendMessage(MessageUtil.error("Gültig: goals | wins | kicks")); } } case "debug" -> { if (!sender.hasPermission("fussball.admin")) { sender.sendMessage(MessageUtil.error("Keine Berechtigung!")); return true; } if (!(sender instanceof Player player)) { sender.sendMessage("Nur für Spieler!"); return true; } if (args.length < 2) { sender.sendMessage(MessageUtil.error("Benutze: /fb debug ")); return true; } Arena arena = plugin.getArenaManager().getArena(args[1]); if (arena == null) { sender.sendMessage(MessageUtil.error("Arena nicht gefunden!")); return true; } handleDebug(player, arena); } // ── Teamwahl ───────────────────────────────────────────────────── case "team" -> { if (!(sender instanceof Player player)) { sender.sendMessage("Nur für Spieler!"); return true; } if (args.length < 2) { player.sendMessage(MessageUtil.error("Benutze: /fb team rot|blau")); return true; } Game game = plugin.getGameManager().getPlayerGame(player); if (game == null) { // Noch nicht im Spiel – Wunsch für nächstes Beitreten speichern // (Spiel muss noch gesucht werden – Wunsch für alle Spiele gilt nicht; // Spieler muss zuerst beitreten) player.sendMessage(MessageUtil.warn("Du bist in keinem Spiel. Tritt zuerst mit /fb join bei.")); return true; } if (game.getState() != GameState.WAITING && game.getState() != GameState.STARTING) { player.sendMessage(MessageUtil.error("Teamwahl ist nur vor Spielstart möglich!")); return true; } Team desired = switch (args[1].toLowerCase()) { case "rot", "red", "r" -> Team.RED; case "blau", "blue", "b" -> Team.BLUE; default -> null; }; if (desired == null) { player.sendMessage(MessageUtil.error("Ungültiges Team! Benutze: rot oder blau")); return true; } game.requestTeam(player, desired); } // ── Match-History ──────────────────────────────────────────────── case "history" -> { int count = 5; if (args.length >= 2) { try { count = Integer.parseInt(args[1]); } catch (NumberFormatException ignored) {} } count = Math.max(1, Math.min(count, 20)); List> matches = plugin.getMatchHistory().getMatches(count); sender.sendMessage(MessageUtil.header("📋 Match-History (" + matches.size() + " Einträge)")); if (matches.isEmpty()) { sender.sendMessage(MessageUtil.warn("Noch keine Spiele gespeichert.")); return true; } for (int i = 0; i < matches.size(); i++) { Map raw = matches.get(i); // Sicher auslesen über Object → String/Number-Cast String date = raw.get("date") instanceof String s ? s : "?"; String arena = raw.get("arena") instanceof String s ? s : "?"; String winner = raw.get("winner") instanceof String s ? s : "Unentschieden"; int rs = raw.get("redScore") instanceof Number n ? n.intValue() : 0; int bs = raw.get("blueScore") instanceof Number n ? n.intValue() : 0; int rp = raw.get("redPoss") instanceof Number n ? n.intValue() : 50; int bp = raw.get("bluePoss") instanceof Number n ? n.intValue() : 50; int pr = raw.get("penaltyRed") instanceof Number n ? n.intValue() : 0; int pb = raw.get("penaltyBlue") instanceof Number n ? n.intValue() : 0; String penStr = (pr + pb > 0) ? " §8(Elfm. §c" + pr + "§8:§9" + pb + "§8)" : ""; String winColor = winner.equals("Rot") ? "§c" : winner.equals("Blau") ? "§9" : "§7"; sender.sendMessage("§e#" + (i+1) + " §8[" + date + "] §7" + arena + " §c" + rs + "§7:§9" + bs + penStr + " §8│ " + winColor + winner + " §8│ §7Besitz §c" + rp + "% §7/ §9" + bp + "%"); } } // ── Drop Ball (Admin) ───────────────────────────────────────────── case "dropball" -> { if (!sender.hasPermission("fussball.admin")) { sender.sendMessage(MessageUtil.error("Keine Berechtigung!")); return true; } if (args.length < 2) { sender.sendMessage(MessageUtil.error("Benutze: /fb dropball ")); return true; } Game dropGame = plugin.getGameManager().getGame(args[1]); if (dropGame == null) { sender.sendMessage(MessageUtil.error("Kein aktives Spiel in §e" + args[1] + "§c!")); return true; } Location dropLoc = null; if (sender instanceof Player p) dropLoc = p.getLocation(); dropGame.dropBall(dropLoc); sender.sendMessage(MessageUtil.success("Schiedsrichterball ausgeführt!")); } // ── Hologramm-Verwaltung ───────────────────────────────────────── // /fb hologram set goals|wins|match – Hologramm erstellen/verschieben // /fb hologram remove – Nächstes Hologramm (< 5 Blöcke) entfernen // /fb hologram delete goals|wins|match – Hologramm gezielt löschen // /fb hologram reload – Alle Hologramme neu spawnen // /fb hologram list – Alle Hologramme anzeigen case "hologram", "holo" -> { if (!sender.hasPermission("fussball.admin")) { sender.sendMessage(MessageUtil.error("Keine Berechtigung!")); return true; } if (!(sender instanceof Player player)) { sender.sendMessage("Nur für Spieler!"); return true; } if (args.length < 2) { player.sendMessage(MessageUtil.header("Hologramm-Befehle")); player.sendMessage("§e/fb hologram set goals|wins|match §7– Hologramm setzen"); player.sendMessage("§e/fb hologram remove §7– Nächstes entfernen (< 5 Blöcke)"); player.sendMessage("§e/fb hologram delete goals|wins|match §7– Gezielt löschen"); player.sendMessage("§e/fb hologram text goals|wins|match §7– Textzeile anpassen"); player.sendMessage("§e/fb hologram textpreview goals|wins|match §7– Aktuelles Textlayout ansehen"); player.sendMessage("§e/fb hologram textreset goals|wins|match §7– Standardtext wiederherstellen"); player.sendMessage("§e/fb hologram reload §7– Alle neu laden"); player.sendMessage("§e/fb hologram list §7– Alle anzeigen"); player.sendMessage("§7Gesamt: §e" + plugin.getHologramManager().getCount() + " §7Hologramme"); player.sendMessage("§7§oRechtsklick auf Hologramm → Tore ↔ Siege wechseln"); return true; } switch (args[1].toLowerCase()) { case "set" -> { if (args.length < 4) { player.sendMessage(MessageUtil.error("Benutze: /fb hologram set goals|wins|match")); return true; } Arena arena = plugin.getArenaManager().getArena(args[2]); if (arena == null) { player.sendMessage(MessageUtil.error("Arena §e" + args[2] + " §cnicht gefunden!")); return true; } FussballHologram.HoloType type = switch (args[3].toLowerCase()) { case "wins", "siege" -> FussballHologram.HoloType.WINS; case "match", "live", "game" -> FussballHologram.HoloType.MATCH; default -> FussballHologram.HoloType.GOALS; }; String id = buildHologramId(arena.getName(), type); plugin.getHologramManager().removeHologram(id); if (!plugin.getHologramManager().createHologram(id, player.getLocation(), type)) { player.sendMessage(MessageUtil.error("Konnte das Hologramm für Arena §e" + arena.getName() + " §cund Typ §e" + hologramTypeName(type) + " §cnicht setzen.")); return true; } player.sendMessage(MessageUtil.success("Hologramm §e" + hologramTypeName(type) + " §afür Arena §e" + arena.getName() + " §agesetzt!")); if (type == FussballHologram.HoloType.MATCH) { player.sendMessage("§7§oLive-Match-Hologramm aktualisiert sich automatisch bei Toren und Nachspielzeit."); } else { player.sendMessage("§7§oRechtsklick auf das Hologramm wechselt zwischen Tore und Siege."); } } case "remove" -> { String removed = plugin.getHologramManager().removeNearest(player.getLocation()); if (removed != null) { player.sendMessage(MessageUtil.success("Hologramm §e" + removed + " §aentfernt!")); } else { player.sendMessage(MessageUtil.error("Kein Hologramm innerhalb von 5 Blöcken gefunden!")); } } case "delete" -> { if (args.length >= 4) { Arena arena = plugin.getArenaManager().getArena(args[2]); if (arena == null) { player.sendMessage(MessageUtil.error("Arena §e" + args[2] + " §cnicht gefunden!")); return true; } FussballHologram.HoloType type = switch (args[3].toLowerCase()) { case "wins", "siege" -> FussballHologram.HoloType.WINS; case "match", "live", "game" -> FussballHologram.HoloType.MATCH; default -> FussballHologram.HoloType.GOALS; }; String id = buildHologramId(arena.getName(), type); if (plugin.getHologramManager().removeHologram(id)) { player.sendMessage(MessageUtil.success("Hologramm §e" + hologramTypeName(type) + " §ader Arena §e" + arena.getName() + " §agelöscht!")); } else { player.sendMessage(MessageUtil.error("Kein Hologramm vom Typ §e" + hologramTypeName(type) + " §cfür Arena §e" + arena.getName() + " §cgefunden!")); } return true; } if (args.length < 3) { player.sendMessage(MessageUtil.error("Benutze: /fb hologram delete goals|wins|match")); return true; } if (plugin.getHologramManager().removeHologram(args[2])) { player.sendMessage(MessageUtil.success("Legacy-Hologramm §e" + args[2] + " §agelöscht!")); } else { player.sendMessage(MessageUtil.error("Kein Hologramm mit ID §e" + args[2] + "§c gefunden!")); } } case "text" -> { if (args.length < 6) { player.sendMessage(MessageUtil.error("Benutze: /fb hologram text goals|wins|match ")); return true; } Arena arena = plugin.getArenaManager().getArena(args[2]); if (arena == null) { player.sendMessage(MessageUtil.error("Arena §e" + args[2] + " §cnicht gefunden!")); return true; } FussballHologram.HoloType type = parseHologramType(args[3]); int line; try { line = Integer.parseInt(args[4]); } catch (NumberFormatException ex) { player.sendMessage(MessageUtil.error("§e" + args[4] + " §cist keine gültige Zeilennummer!")); return true; } if (line < 1) { player.sendMessage(MessageUtil.error("Zeilennummer muss mindestens §e1 §csein!")); return true; } String id = buildHologramId(arena.getName(), type); HologramManager hologramManager = plugin.getHologramManager(); if (hologramManager.getHologram(id) == null) { player.sendMessage(MessageUtil.error("Hologramm §e" + hologramTypeName(type) + " §cfür Arena §e" + arena.getName() + " §cexistiert nicht!")); return true; } List lines = new ArrayList<>(getEditableHologramTemplate(hologramManager, id, type)); while (lines.size() < line) { lines.add(" "); } lines.set(line - 1, ChatColor.translateAlternateColorCodes('&', joinArgs(args, 5))); if (!hologramManager.setCustomText(id, type, lines)) { player.sendMessage(MessageUtil.error("Konnte den Hologramm-Text nicht speichern!")); return true; } player.sendMessage(MessageUtil.success("Hologramm-Text für §e" + arena.getName() + " §a(" + hologramTypeName(type) + ") aktualisiert.")); player.sendMessage("§7Zeile §e" + line + "§7: " + lines.get(line - 1)); } case "textpreview" -> { if (args.length < 4) { player.sendMessage(MessageUtil.error("Benutze: /fb hologram textpreview goals|wins|match")); return true; } Arena arena = plugin.getArenaManager().getArena(args[2]); if (arena == null) { player.sendMessage(MessageUtil.error("Arena §e" + args[2] + " §cnicht gefunden!")); return true; } FussballHologram.HoloType type = parseHologramType(args[3]); String id = buildHologramId(arena.getName(), type); HologramManager hologramManager = plugin.getHologramManager(); if (hologramManager.getHologram(id) == null) { player.sendMessage(MessageUtil.error("Hologramm §e" + hologramTypeName(type) + " §cfür Arena §e" + arena.getName() + " §cexistiert nicht!")); return true; } List lines = getEditableHologramTemplate(hologramManager, id, type); player.sendMessage(MessageUtil.header("Holo-Text: " + arena.getName() + " / " + hologramTypeName(type))); for (int i = 0; i < lines.size(); i++) { player.sendMessage("§e" + (i + 1) + "§7: " + lines.get(i)); } if (type == FussballHologram.HoloType.MATCH) { player.sendMessage("§8Platzhalter: §7{header} {separator} {phase} {score} {time}"); } else { player.sendMessage("§8Platzhalter: §7{title} {separator} {entries} {toggle}"); } } case "textreset" -> { if (args.length < 4) { player.sendMessage(MessageUtil.error("Benutze: /fb hologram textreset goals|wins|match")); return true; } Arena arena = plugin.getArenaManager().getArena(args[2]); if (arena == null) { player.sendMessage(MessageUtil.error("Arena §e" + args[2] + " §cnicht gefunden!")); return true; } FussballHologram.HoloType type = parseHologramType(args[3]); String id = buildHologramId(arena.getName(), type); HologramManager hologramManager = plugin.getHologramManager(); if (hologramManager.getHologram(id) == null) { player.sendMessage(MessageUtil.error("Hologramm §e" + hologramTypeName(type) + " §cfür Arena §e" + arena.getName() + " §cexistiert nicht!")); return true; } hologramManager.resetCustomText(id, type); player.sendMessage(MessageUtil.success("Standardtext für §e" + arena.getName() + " §a(" + hologramTypeName(type) + ") wiederhergestellt.")); } case "reload" -> { plugin.getHologramManager().reload(); player.sendMessage(MessageUtil.success("Hologramme neu geladen! §7(" + plugin.getHologramManager().getCount() + " gesamt)")); } case "list" -> { player.sendMessage(MessageUtil.header("Hologramme (" + plugin.getHologramManager().getCount() + ")")); if (plugin.getHologramManager().getCount() == 0) { player.sendMessage(MessageUtil.warn("Keine Hologramme vorhanden.")); } else { for (String id : plugin.getHologramManager().getHologramIds()) { player.sendMessage("§7 • §e" + formatHologramDisplay(id)); } } } default -> player.sendMessage(MessageUtil.error("Gültig: set | remove | delete | text | textpreview | textreset | reload | list")); } } default -> sendHelp(sender); } return true; } // ── Setup-Handler ──────────────────────────────────────────────────────── private void handleSetup(Player player, String[] args) { Arena arena = plugin.getArenaManager().getArena(args[1]); if (arena == null) { player.sendMessage(MessageUtil.error("Arena §e" + args[1] + " §cnicht gefunden!")); return; } switch (args[2].toLowerCase()) { case "lobby" -> { arena.setLobby(player.getLocation()); player.sendMessage(MessageUtil.success("Lobby gesetzt: " + locStr(player.getLocation()))); } case "redspawn" -> { arena.setRedSpawn(player.getLocation()); player.sendMessage(MessageUtil.success("Roter Spawn gesetzt: " + locStr(player.getLocation()))); } case "bluespawn" -> { arena.setBlueSpawn(player.getLocation()); player.sendMessage(MessageUtil.success("Blauer Spawn gesetzt: " + locStr(player.getLocation()))); } case "ballspawn" -> { arena.setBallSpawn(player.getLocation()); player.sendMessage(MessageUtil.success("Ball-Spawn gesetzt: " + locStr(player.getLocation()))); } case "center" -> { arena.setCenter(player.getLocation()); player.sendMessage(MessageUtil.success("Mittelpunkt gesetzt: " + locStr(player.getLocation()))); } case "redgoalmin" -> { arena.setRedGoalMin(player.getLocation()); player.sendMessage(MessageUtil.success("Rotes Tor Min gesetzt: " + locStr(player.getLocation()))); } case "redgoalmax" -> { arena.setRedGoalMax(player.getLocation()); player.sendMessage(MessageUtil.success("Rotes Tor Max gesetzt: " + locStr(player.getLocation()))); } case "bluegoalmin" -> { arena.setBlueGoalMin(player.getLocation()); player.sendMessage(MessageUtil.success("Blaues Tor Min gesetzt: " + locStr(player.getLocation()))); } case "bluegoalmax" -> { arena.setBlueGoalMax(player.getLocation()); player.sendMessage(MessageUtil.success("Blaues Tor Max gesetzt: " + locStr(player.getLocation()))); } case "fieldmin" -> { arena.setFieldMin(player.getLocation()); player.sendMessage(MessageUtil.success("Spielfeld Min gesetzt: " + locStr(player.getLocation()))); } case "fieldmax" -> { arena.setFieldMax(player.getLocation()); player.sendMessage(MessageUtil.success("Spielfeld Max gesetzt: " + locStr(player.getLocation()))); } case "redpenaltymin" -> { arena.setRedPenaltyMin(player.getLocation()); player.sendMessage(MessageUtil.success("Roter Strafraum Min gesetzt: " + locStr(player.getLocation()))); } case "redpenaltymax" -> { arena.setRedPenaltyMax(player.getLocation()); player.sendMessage(MessageUtil.success("Roter Strafraum Max gesetzt: " + locStr(player.getLocation()))); } case "bluepenaltymin" -> { arena.setBluePenaltyMin(player.getLocation()); player.sendMessage(MessageUtil.success("Blauer Strafraum Min gesetzt: "+ locStr(player.getLocation()))); } case "bluepenaltymax" -> { arena.setBluePenaltyMax(player.getLocation()); player.sendMessage(MessageUtil.success("Blauer Strafraum Max gesetzt: "+ locStr(player.getLocation()))); } case "redpenaltyspot" -> { arena.setRedPenaltySpot(player.getLocation()); player.sendMessage(MessageUtil.success("Roter Elfmeter-Punkt gesetzt: " + locStr(player.getLocation()))); } case "bluepenaltyspot" -> { arena.setBluePenaltySpot(player.getLocation()); player.sendMessage(MessageUtil.success("Blauer Elfmeter-Punkt gesetzt: " + locStr(player.getLocation()))); } case "spectatorspawn" -> { arena.setSpectatorSpawn(player.getLocation()); player.sendMessage(MessageUtil.success("Zuschauer-Spawn gesetzt: " + locStr(player.getLocation()))); } case "minplayers" -> { if (args.length < 4) return; try { arena.setMinPlayers(Integer.parseInt(args[3])); player.sendMessage(MessageUtil.success("Min-Spieler: §e" + args[3])); } catch (NumberFormatException ex) { player.sendMessage(MessageUtil.error("§e" + args[3] + " §cist keine gültige Zahl!")); } } case "maxplayers" -> { if (args.length < 4) return; try { arena.setMaxPlayers(Integer.parseInt(args[3])); player.sendMessage(MessageUtil.success("Max-Spieler: §e" + args[3])); } catch (NumberFormatException ex) { player.sendMessage(MessageUtil.error("§e" + args[3] + " §cist keine gültige Zahl!")); } } case "duration" -> { if (args.length < 4) return; try { arena.setGameDuration(Integer.parseInt(args[3])); player.sendMessage(MessageUtil.success("Spieldauer: §e" + args[3] + "s")); } catch (NumberFormatException ex) { player.sendMessage(MessageUtil.error("§e" + args[3] + " §cist keine gültige Zahl!")); } } case "info" -> { player.sendMessage(MessageUtil.header("Arena: " + arena.getName())); player.sendMessage("§7 Lobby: " + check(arena.getLobby())); player.sendMessage("§7 Roter Spawn: " + check(arena.getRedSpawn())); player.sendMessage("§7 Blauer Spawn: " + check(arena.getBlueSpawn())); player.sendMessage("§7 Ball-Spawn: " + check(arena.getBallSpawn())); player.sendMessage("§7 Mittelpunkt: " + check(arena.getCenter())); player.sendMessage("§7 Rotes Tor: " + check(arena.getRedGoalMin(), arena.getRedGoalMax())); player.sendMessage("§7 Blaues Tor: " + check(arena.getBlueGoalMin(), arena.getBlueGoalMax())); player.sendMessage("§7 Spielfeld: " + check(arena.getFieldMin(), arena.getFieldMax()) + " §8(optional)"); player.sendMessage("§7 Roter Strafraum: " + check(arena.getRedPenaltyMin(), arena.getRedPenaltyMax()) + " §8(optional – sonst auto-berechnet)"); player.sendMessage("§7 Blauer Strafraum: " + check(arena.getBluePenaltyMin(), arena.getBluePenaltyMax()) + " §8(optional – sonst auto-berechnet)"); player.sendMessage("§7 Zuschauer-Spawn: " + check(arena.getSpectatorSpawn()) + " §8(optional – sonst Spielfeldrand)"); player.sendMessage("§7 Blauer Elfmeter-Punkt: " + check(arena.getBluePenaltySpot()) + " §8(optional – sonst ball-spawn)"); player.sendMessage("§7 Min. Spieler: §e" + arena.getMinPlayers()); player.sendMessage("§7 Max. Spieler: §e" + arena.getMaxPlayers()); player.sendMessage("§7 Spieldauer: §e" + arena.getGameDuration() + "s"); player.sendMessage("§7 Setup komplett: " + (arena.isSetupComplete() ? "§a✔ JA" : "§c✗ NEIN")); return; } default -> { sendSetupHelp(player); return; } } plugin.getArenaManager().saveArena(arena); } // ── Debug-Handler ──────────────────────────────────────────────────────── private void handleDebug(Player player, Arena arena) { player.sendMessage(MessageUtil.header("DEBUG: " + arena.getName())); printRegion(player, "§cROTES TOR", arena.getRedGoalMin(), arena.getRedGoalMax()); printRegion(player, "§9BLAUES TOR", arena.getBlueGoalMin(), arena.getBlueGoalMax()); printRegion(player, "§aSPIELFELD", arena.getFieldMin(), arena.getFieldMax()); Game game = plugin.getGameManager().getGame(arena.getName()); if (game != null && game.getBall() != null && game.getBall().isActive()) { Ball ball = game.getBall(); Location bl = ball.getEntity().getLocation(); Location bh = bl.clone().add(0, 1.4, 0); player.sendMessage("§e--- BALL ---"); player.sendMessage("§7Fuß: §f" + locStr(bl)); player.sendMessage("§7Kopf: §f" + locStr(bh)); player.sendMessage("§7RotesTor: Fuß=" + yn(arena.isInRedGoal(bl)) + " Kopf=" + yn(arena.isInRedGoal(bh))); player.sendMessage("§7BlauesTor: Fuß=" + yn(arena.isInBlueGoal(bl)) + " Kopf=" + yn(arena.isInBlueGoal(bh))); player.sendMessage("§7Im Feld: " + yn(arena.isInField(bl))); player.sendMessage("§7Aus-Seite: §f" + (arena.getOutSide(bl) != null ? arena.getOutSide(bl) : "keine")); } else { player.sendMessage("§7(Kein aktiver Ball)"); } player.sendMessage("§e--- DEINE POSITION ---"); player.sendMessage("§f" + locStr(player.getLocation())); player.sendMessage("§7RotesTor: " + yn(arena.isInRedGoal(player.getLocation()))); player.sendMessage("§7BlauesTor: " + yn(arena.isInBlueGoal(player.getLocation()))); player.sendMessage("§7Im Feld: " + yn(arena.isInField(player.getLocation()))); } // ── Hilfsmethoden ──────────────────────────────────────────────────────── private String statusDot(GameState s) { return switch (s) { case WAITING -> "§a●"; case STARTING -> "§e●"; case RUNNING, GOAL, HALFTIME, OVERTIME -> "§c●"; case PENALTY -> "§d●"; case ENDING -> "§7●"; }; } private void printRegion(Player p, String label, Location min, Location max) { p.sendMessage("§e--- " + label + " §e---"); if (min == null || max == null) { p.sendMessage("§cNICHT GESETZT"); return; } p.sendMessage("§7Min: §f" + locStr(min) + " §7Max: §f" + locStr(max)); p.sendMessage("§7X: §f" + fmt(Math.min(min.getX(), max.getX())) + "§7─§f" + fmt(Math.max(min.getX(), max.getX()))); p.sendMessage("§7Y: §f" + fmt(Math.min(min.getY(), max.getY())) + "§7─§f" + fmt(Math.max(min.getY(), max.getY()))); p.sendMessage("§7Z: §f" + fmt(Math.min(min.getZ(), max.getZ())) + "§7─§f" + fmt(Math.max(min.getZ(), max.getZ()))); } private void sendHelp(CommandSender s) { s.sendMessage(MessageUtil.header("⚽ Fußball Plugin")); s.sendMessage("§e/fb join §7- Spiel beitreten"); s.sendMessage("§e/fb leave §7- Spiel / Zuschauer verlassen"); s.sendMessage("§e/fb spectate §7- Spiel zuschauen"); s.sendMessage("§e/fb team rot|blau §7- Teamwahl (vor Spielstart)"); s.sendMessage("§e/fb list §7- Arenen anzeigen"); s.sendMessage("§e/fb stats [spieler] §7- Statistiken anzeigen"); s.sendMessage("§e/fb top [goals|wins] §7- Bestenliste"); s.sendMessage("§e/fb history [n] §7- Letzte Spiele anzeigen"); if (s.hasPermission("fussball.admin")) { s.sendMessage("§c§lAdmin: §ccreate / delete / setup / stop / debug / dropball"); s.sendMessage("§c§lAdmin: §cstats reset "); s.sendMessage("§c§lAdmin: §chologram set|delete|text|textpreview|textreset "); } } private void sendSetupHelp(Player p) { p.sendMessage(MessageUtil.header("Setup-Optionen")); p.sendMessage("§e/fb setup lobby|redspawn|bluespawn|ballspawn|center"); p.sendMessage("§e/fb setup redgoalmin|redgoalmax|bluegoalmin|bluegoalmax"); p.sendMessage("§e/fb setup fieldmin|fieldmax §8(optional – Aus-Erkennung)"); p.sendMessage("§e/fb setup redpenaltymin|redpenaltymax|bluepenaltymin|bluepenaltymax §8(optional – auto-berechnet wenn leer)"); p.sendMessage("§e/fb setup minplayers |maxplayers |duration |info"); } private String check(Location l) { return l != null ? "§a✔ " + locStr(l) : "§c✗ nicht gesetzt"; } private String check(Location a, Location b) { return (a != null && b != null) ? "§a✔ gesetzt" : "§c✗ nicht gesetzt"; } private String yn(boolean b) { return b ? "§aJA" : "§cNEIN"; } private String locStr(Location l) { return fmt(l.getX()) + " / " + fmt(l.getY()) + " / " + fmt(l.getZ()); } private String fmt(double d) { return String.format("%.1f", d); } private String buildHologramId(String arenaName, FussballHologram.HoloType type) { return arenaName.toLowerCase() + "_" + hologramTypeName(type); } private String joinArgs(String[] args, int start) { return String.join(" ", Arrays.copyOfRange(args, start, args.length)); } private List getEditableHologramTemplate(HologramManager hologramManager, String id, FussballHologram.HoloType type) { List custom = hologramManager.getCustomText(id, type); return custom.isEmpty() ? getDefaultHologramTemplate(type) : custom; } private List getDefaultHologramTemplate(FussballHologram.HoloType type) { if (type == FussballHologram.HoloType.MATCH) { return List.of("{header}", "{separator}", "{phase}", "{score}", "{time}"); } return List.of("{title}", "{separator}", "{entries}", "{separator}", "{toggle}"); } private FussballHologram.HoloType parseHologramType(String rawType) { return switch (rawType.toLowerCase()) { case "wins", "siege" -> FussballHologram.HoloType.WINS; case "match", "live", "game" -> FussballHologram.HoloType.MATCH; default -> FussballHologram.HoloType.GOALS; }; } private String hologramTypeName(FussballHologram.HoloType type) { return switch (type) { case WINS -> "wins"; case MATCH -> "match"; default -> "goals"; }; } private String formatHologramDisplay(String id) { int split = id.lastIndexOf('_'); if (split > 0 && split < id.length() - 1) { String arena = id.substring(0, split); String type = id.substring(split + 1); if (type.equals("goals") || type.equals("wins") || type.equals("match")) { return arena + " §7→ §e" + type; } } return id; } // ── Tab-Completion ─────────────────────────────────────────────────────── @Override public List onTabComplete(CommandSender sender, Command cmd, String alias, String[] args) { List list = new ArrayList<>(); if (args.length == 1) { list.addAll(List.of("join", "leave", "list", "stats", "top", "spectate", "team", "history")); if (sender.hasPermission("fussball.admin")) list.addAll(List.of("create", "delete", "setup", "stop", "setgk", "debug", "hologram", "dropball")); } else if (args.length == 2 && List.of("join","delete","setup","stop","setgk","debug","spectate","dropball").contains(args[0].toLowerCase())) { list.addAll(plugin.getArenaManager().getArenaNames()); } else if (args.length == 2 && args[0].equalsIgnoreCase("stats") && sender.hasPermission("fussball.admin")) { list.addAll(List.of("reset")); } else if (args.length == 3 && args[0].equalsIgnoreCase("stats") && args[1].equalsIgnoreCase("reset") && sender.hasPermission("fussball.admin")) { list.add("all"); for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { list.add(onlinePlayer.getName()); } } else if (args.length == 2 && args[0].equalsIgnoreCase("hologram")) { list.addAll(List.of("set", "remove", "delete", "text", "textpreview", "textreset", "reload", "list")); } else if (args.length == 3 && args[0].equalsIgnoreCase("hologram") && List.of("set", "delete", "text", "textpreview", "textreset").contains(args[1].toLowerCase())) { list.addAll(plugin.getArenaManager().getArenaNames()); } else if (args.length == 4 && args[0].equalsIgnoreCase("hologram") && List.of("set", "delete", "text", "textpreview", "textreset").contains(args[1].toLowerCase())) { list.addAll(List.of("goals", "wins", "match")); } else if (args.length == 5 && args[0].equalsIgnoreCase("hologram") && args[1].equalsIgnoreCase("text")) { list.addAll(List.of("1", "2", "3", "4", "5")); } else if (args.length == 3 && args[0].equalsIgnoreCase("setgk")) { // Spielernamen aus dem aktiven Spiel vorschlagen Game gkGame = plugin.getGameManager().getGame(args[1]); if (gkGame != null) { for (UUID uuid : gkGame.getAllPlayers()) { Player p = Bukkit.getPlayer(uuid); if (p != null) list.add(p.getName()); } } } else if (args.length == 3 && args[0].equalsIgnoreCase("setup")) { list.addAll(List.of("lobby","redspawn","bluespawn","ballspawn","center", "redgoalmin","redgoalmax","bluegoalmin","bluegoalmax", "fieldmin","fieldmax", "redpenaltymin","redpenaltymax","bluepenaltymin","bluepenaltymax", "redpenaltyspot","bluepenaltyspot","spectatorspawn", "minplayers","maxplayers","duration","info")); } else if (args.length == 2 && args[0].equalsIgnoreCase("top")) { list.addAll(List.of("goals", "wins")); } else if (args.length == 2 && args[0].equalsIgnoreCase("team")) { list.addAll(List.of("rot", "blau")); } String input = args[args.length - 1].toLowerCase(); list.removeIf(s -> !s.toLowerCase().startsWith(input)); return list; } }