Files
Fussball/src/main/java/de/fussball/plugin/commands/FussballCommand.java
2026-03-17 16:15:01 +01:00

753 lines
52 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 <arena>")); 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 <arena>")); 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<Arena> 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 <spieler|all>")); 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 <name>")); 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 <arena>")); 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 <arena>")); 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 <arena> <spieler>
if (args.length < 3) { sender.sendMessage(MessageUtil.error("Benutze: /fb setgk <arena> <spieler>")); 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 <arena>")); 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 <arena> 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<Map<?, ?>> 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 <arena>")); 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 <arena> goals|wins|match Hologramm erstellen/verschieben
// /fb hologram remove Nächstes Hologramm (< 5 Blöcke) entfernen
// /fb hologram delete <arena> 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 <arena> 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 <arena> goals|wins|match §7 Gezielt löschen");
player.sendMessage("§e/fb hologram text <arena> goals|wins|match <zeile> <text> §7 Textzeile anpassen");
player.sendMessage("§e/fb hologram textpreview <arena> goals|wins|match §7 Aktuelles Textlayout ansehen");
player.sendMessage("§e/fb hologram textreset <arena> 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 <arena> 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 <arena> 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 <arena> goals|wins|match <zeile> <text>"));
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<String> 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 <arena> 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<String> 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 <arena> 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 <arena> §7- Spiel beitreten");
s.sendMessage("§e/fb leave §7- Spiel / Zuschauer verlassen");
s.sendMessage("§e/fb spectate <arena> §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 <spieler|all>");
s.sendMessage("§c§lAdmin: §chologram set|delete|text|textpreview|textreset <arena> <typ>");
}
}
private void sendSetupHelp(Player p) {
p.sendMessage(MessageUtil.header("Setup-Optionen"));
p.sendMessage("§e/fb setup <arena> lobby|redspawn|bluespawn|ballspawn|center");
p.sendMessage("§e/fb setup <arena> redgoalmin|redgoalmax|bluegoalmin|bluegoalmax");
p.sendMessage("§e/fb setup <arena> fieldmin|fieldmax §8(optional Aus-Erkennung)");
p.sendMessage("§e/fb setup <arena> redpenaltymin|redpenaltymax|bluepenaltymin|bluepenaltymax §8(optional auto-berechnet wenn leer)");
p.sendMessage("§e/fb setup <arena> minplayers <n>|maxplayers <n>|duration <s>|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<String> getEditableHologramTemplate(HologramManager hologramManager, String id, FussballHologram.HoloType type) {
List<String> custom = hologramManager.getCustomText(id, type);
return custom.isEmpty() ? getDefaultHologramTemplate(type) : custom;
}
private List<String> 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<String> onTabComplete(CommandSender sender, Command cmd, String alias, String[] args) {
List<String> 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;
}
}