diff --git a/src/main/java/de/fussball/plugin/commands/FussballCommand.java b/src/main/java/de/fussball/plugin/commands/FussballCommand.java index eafe58f..55f7981 100644 --- a/src/main/java/de/fussball/plugin/commands/FussballCommand.java +++ b/src/main/java/de/fussball/plugin/commands/FussballCommand.java @@ -11,6 +11,7 @@ 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.*; @@ -81,6 +82,36 @@ public class FussballCommand implements CommandExecutor, TabCompleter { } 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; } @@ -294,6 +325,9 @@ public class FussballCommand implements CommandExecutor, TabCompleter { 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"); @@ -364,6 +398,98 @@ public class FussballCommand implements CommandExecutor, TabCompleter { 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)")); @@ -378,7 +504,7 @@ public class FussballCommand implements CommandExecutor, TabCompleter { } } } - default -> player.sendMessage(MessageUtil.error("Gültig: set goals|wins|match | remove | delete goals|wins|match | reload | list")); + default -> player.sendMessage(MessageUtil.error("Gültig: set | remove | delete | text | textpreview | textreset | reload | list")); } } @@ -517,7 +643,8 @@ public class FussballCommand implements CommandExecutor, TabCompleter { 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: §chologram set goals|wins|match / remove / reload"); + s.sendMessage("§c§lAdmin: §cstats reset "); + s.sendMessage("§c§lAdmin: §chologram set|delete|text|textpreview|textreset "); } } @@ -536,6 +663,24 @@ public class FussballCommand implements CommandExecutor, TabCompleter { 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"; @@ -565,16 +710,21 @@ public class FussballCommand implements CommandExecutor, TabCompleter { 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", "reload", "list")); - } else if (args.length == 3 && args[0].equalsIgnoreCase("hologram") && args[1].equalsIgnoreCase("set")) { + 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") && args[1].equalsIgnoreCase("set")) { - list.addAll(List.of("goals", "wins", "match")); - } else if (args.length == 3 && args[0].equalsIgnoreCase("hologram") && args[1].equalsIgnoreCase("delete")) { - list.addAll(plugin.getArenaManager().getArenaNames()); - } else if (args.length == 4 && args[0].equalsIgnoreCase("hologram") && args[1].equalsIgnoreCase("delete")) { + } 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]); diff --git a/src/main/java/de/fussball/plugin/hologram/FussballHologram.java b/src/main/java/de/fussball/plugin/hologram/FussballHologram.java index ed3a623..876e191 100644 --- a/src/main/java/de/fussball/plugin/hologram/FussballHologram.java +++ b/src/main/java/de/fussball/plugin/hologram/FussballHologram.java @@ -4,6 +4,7 @@ import de.fussball.plugin.Fussball; import de.fussball.plugin.game.Game; import de.fussball.plugin.game.GameState; import de.fussball.plugin.stats.StatsManager; +import org.bukkit.ChatColor; import org.bukkit.Bukkit; import org.bukkit.Color; import org.bukkit.Location; @@ -15,6 +16,10 @@ import org.bukkit.util.Transformation; import org.joml.AxisAngle4f; import org.joml.Vector3f; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -44,14 +49,22 @@ public class FussballHologram { private final Map playerInteractions = new ConcurrentHashMap<>(); /** Aktuell angezeigte Seite (0 = GOALS, 1 = WINS) pro Spieler */ private final Map currentPage = new ConcurrentHashMap<>(); + private final Map> customTextTemplates = new EnumMap<>(HoloType.class); private final Fussball plugin; public FussballHologram(String id, Location location, HoloType type, Fussball plugin) { + this(id, location, type, plugin, Collections.emptyMap()); + } + + public FussballHologram(String id, Location location, HoloType type, Fussball plugin, Map> customTextTemplates) { this.id = id; this.location = location.clone(); this.type = type; this.plugin = plugin; + for (Map.Entry> entry : customTextTemplates.entrySet()) { + setCustomText(entry.getKey(), entry.getValue()); + } } // ── Seiten-Wechsel ─────────────────────────────────────────────────────── @@ -183,70 +196,228 @@ public class FussballHologram { .anyMatch(i -> i.getUniqueId().equals(entityId)); } + public void setCustomText(HoloType targetType, List lines) { + if (lines == null || lines.isEmpty()) { + customTextTemplates.remove(targetType); + return; + } + List sanitized = new ArrayList<>(); + for (String line : lines) { + sanitized.add(ChatColor.translateAlternateColorCodes('&', line)); + } + customTextTemplates.put(targetType, List.copyOf(sanitized)); + } + + public void clearCustomText(HoloType targetType) { + customTextTemplates.remove(targetType); + } + + public List getCustomText(HoloType targetType) { + return customTextTemplates.getOrDefault(targetType, Collections.emptyList()); + } + /** Baut den anzuzeigenden Text aus den aktuellen Top-10-Statistiken */ private String buildText(HoloType showType) { if (showType == HoloType.MATCH) { return buildMatchText(); } - StringBuilder sb = new StringBuilder(); + String customText = buildCustomStatsText(showType); + if (customText != null) { + return customText; + } + + return buildDefaultStatsText(showType); + } + + private String buildDefaultStatsText(HoloType showType) { + String nameColor = holoColor("name-color", "&0"); + String labelColor = holoColor("label-color", "&8"); + String sep = holoColor("separator-color", "&8&m") + "══════════════════════" + ChatColor.RESET; + StringBuilder sb = new StringBuilder(); if (showType == HoloType.GOALS) { - sb.append("§6§l⚽ TOP 10 TORSCHÜTZEN ⚽\n"); - sb.append("§8§m══════════════════════§r\n"); + String title = holoColor("goals-title-color", "&6&l") + "⚽ TOP 10 TORSCHÜTZEN ⚽"; + String valColor = holoColor("goals-value-color", "&4"); + String toggle = holoColor("toggle-color", "&8&o") + "[Rechtsklick → Siege anzeigen]"; + sb.append(title).append("\n"); + sb.append(sep).append("\n"); var list = plugin.getStatsManager().getTopScorers(10); if (list.isEmpty()) { - sb.append("§8Noch keine Statistiken vorhanden."); + sb.append(labelColor).append("Noch keine Statistiken vorhanden."); } else { for (int i = 0; i < list.size(); i++) { StatsManager.PlayerStats s = list.get(i).getValue(); sb.append(medal(i + 1)) - .append(" §0").append(s.name) - .append(" §4").append(s.goals).append(" §8Tore"); + .append(" ").append(nameColor).append(s.name) + .append(" ").append(valColor).append(s.goals).append(" ").append(labelColor).append("Tore"); if (i < list.size() - 1) sb.append("\n"); } } - sb.append("\n§8§m══════════════════════§r"); - sb.append("\n§8§o[Rechtsklick → Siege anzeigen]"); + sb.append("\n").append(sep); + sb.append("\n").append(toggle); } else { - sb.append("§2§l🏆 TOP 10 GEWINNER 🏆\n"); - sb.append("§8§m══════════════════════§r\n"); + String title = holoColor("wins-title-color", "&2&l") + "🏆 TOP 10 GEWINNER 🏆"; + String valColor = holoColor("wins-value-color", "&2"); + String toggle = holoColor("toggle-color", "&8&o") + "[Rechtsklick → Tore anzeigen]"; + sb.append(title).append("\n"); + sb.append(sep).append("\n"); var list = plugin.getStatsManager().getTopWins(10); if (list.isEmpty()) { - sb.append("§8Noch keine Statistiken vorhanden."); + sb.append(labelColor).append("Noch keine Statistiken vorhanden."); } else { for (int i = 0; i < list.size(); i++) { StatsManager.PlayerStats s = list.get(i).getValue(); sb.append(medal(i + 1)) - .append(" §0").append(s.name) - .append(" §2").append(s.wins).append(" §8Siege") - .append(" §8(").append(String.format("%.0f", s.getWinRate())).append("%)"); + .append(" ").append(nameColor).append(s.name) + .append(" ").append(valColor).append(s.wins).append(" ").append(labelColor).append("Siege") + .append(" ").append(labelColor).append("(").append(String.format("%.0f", s.getWinRate())).append("%)"); if (i < list.size() - 1) sb.append("\n"); } } - sb.append("\n§8§m══════════════════════§r"); - sb.append("\n§8§o[Rechtsklick → Tore anzeigen]"); + sb.append("\n").append(sep); + sb.append("\n").append(toggle); } return sb.toString(); } - private String buildMatchText() { - Game game = findRelevantGame(); - if (game == null) { - return "§e§lLive Match\n§8§m────────────────\n§7Kein Spiel aktiv\n§8- : -\n§8--:--"; + private String buildCustomStatsText(HoloType showType) { + List template = customTextTemplates.get(showType); + if (template == null || template.isEmpty()) { + return null; } - String header = "§e§lLive Match"; - String separator = "§8§m────────────────"; - String phase = buildPhaseLabel(game); - String score = "§c§l" + game.getRedScore() + " §r§7: §9§l" + game.getBlueScore(); - String timeLabel = game.isInInjuryTime() - ? "§c+" + formatInjury(game.getInjuryTimeBuffer()) + " §7(Nachspielzeit)" - : "§e" + formatMainTime(game.getTimeLeft()); + String sep = holoColor("separator-color", "&8&m") + "══════════════════════" + ChatColor.RESET; + String title, toggle; + if (showType == HoloType.GOALS) { + title = holoColor("goals-title-color", "&6&l") + "⚽ TOP 10 TORSCHÜTZEN ⚽"; + toggle = holoColor("toggle-color", "&8&o") + "[Rechtsklick → Siege anzeigen]"; + } else { + title = holoColor("wins-title-color", "&2&l") + "🏆 TOP 10 GEWINNER 🏆"; + toggle = holoColor("toggle-color", "&8&o") + "[Rechtsklick → Tore anzeigen]"; + } + String entries = buildStatsEntries(showType); - return header + "\n" + separator + "\n" + phase + "\n" + score + "\n" + timeLabel; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < template.size(); i++) { + String line = template.get(i) + .replace("{title}", title) + .replace("{separator}", sep) + .replace("{entries}", entries) + .replace("{toggle}", toggle); + sb.append(line); + if (i < template.size() - 1) { + sb.append("\n"); + } + } + return sb.toString(); + } + + private String buildStatsEntries(HoloType showType) { + String nameColor = holoColor("name-color", "&0"); + String labelColor = holoColor("label-color", "&8"); + StringBuilder entries = new StringBuilder(); + if (showType == HoloType.GOALS) { + String valColor = holoColor("goals-value-color", "&4"); + var list = plugin.getStatsManager().getTopScorers(10); + if (list.isEmpty()) { + return labelColor + "Noch keine Statistiken vorhanden."; + } + for (int i = 0; i < list.size(); i++) { + StatsManager.PlayerStats s = list.get(i).getValue(); + entries.append(medal(i + 1)) + .append(" ").append(nameColor).append(s.name) + .append(" ").append(valColor).append(s.goals).append(" ").append(labelColor).append("Tore"); + if (i < list.size() - 1) { + entries.append("\n"); + } + } + return entries.toString(); + } + + String valColor = holoColor("wins-value-color", "&2"); + var list = plugin.getStatsManager().getTopWins(10); + if (list.isEmpty()) { + return labelColor + "Noch keine Statistiken vorhanden."; + } + for (int i = 0; i < list.size(); i++) { + StatsManager.PlayerStats s = list.get(i).getValue(); + entries.append(medal(i + 1)) + .append(" ").append(nameColor).append(s.name) + .append(" ").append(valColor).append(s.wins).append(" ").append(labelColor).append("Siege") + .append(" ").append(labelColor).append("(").append(String.format("%.0f", s.getWinRate())).append("%)"); + if (i < list.size() - 1) { + entries.append("\n"); + } + } + return entries.toString(); + } + + private String buildMatchText() { + String customText = buildCustomMatchText(); + if (customText != null) { + return customText; + } + + Game game = findRelevantGame(); + String header = holoColor("match-header-color", "&e&l") + "Live Match"; + String sep = holoColor("separator-color", "&8&m") + "────────────────"; + if (game == null) { + String lc = holoColor("label-color", "&8"); + return header + "\n" + sep + "\n§7Kein Spiel aktiv\n" + lc + "- : -\n" + lc + "--:--"; + } + + String phase = buildPhaseLabel(game); + String score = holoColor("match-score-red", "&c&l") + game.getRedScore() + + " §r§7: " + + holoColor("match-score-blue", "&9&l") + game.getBlueScore(); + String timeLabel = game.isInInjuryTime() + ? holoColor("match-injury-color", "&c") + "+" + formatInjury(game.getInjuryTimeBuffer()) + " §7(Nachspielzeit)" + : holoColor("match-time-color", "&e") + formatMainTime(game.getTimeLeft()); + + return header + "\n" + sep + "\n" + phase + "\n" + score + "\n" + timeLabel; + } + + private String buildCustomMatchText() { + List template = customTextTemplates.get(HoloType.MATCH); + if (template == null || template.isEmpty()) { + return null; + } + + Game game = findRelevantGame(); + String header = holoColor("match-header-color", "&e&l") + "Live Match"; + String separator = holoColor("separator-color", "&8&m") + "────────────────"; + String phase = game == null ? "§7Kein Spiel aktiv" : buildPhaseLabel(game); + String score, time; + if (game == null) { + String lc = holoColor("label-color", "&8"); + score = lc + "- : -"; + time = lc + "--:--"; + } else { + score = holoColor("match-score-red", "&c&l") + game.getRedScore() + + " §r§7: " + + holoColor("match-score-blue", "&9&l") + game.getBlueScore(); + time = game.isInInjuryTime() + ? holoColor("match-injury-color", "&c") + "+" + formatInjury(game.getInjuryTimeBuffer()) + " §7(Nachspielzeit)" + : holoColor("match-time-color", "&e") + formatMainTime(game.getTimeLeft()); + } + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < template.size(); i++) { + String line = template.get(i) + .replace("{header}", header) + .replace("{separator}", separator) + .replace("{phase}", phase) + .replace("{score}", score) + .replace("{time}", time); + sb.append(line); + if (i < template.size() - 1) { + sb.append("\n"); + } + } + return sb.toString(); } private String buildPhaseLabel(Game game) { @@ -317,6 +488,11 @@ public class FussballHologram { return "+" + safe + "s"; } + private String holoColor(String key, String def) { + String val = plugin.getConfig().getString("holograms." + key, def); + return ChatColor.translateAlternateColorCodes('&', val != null ? val : def); + } + private String medal(int rank) { return switch (rank) { case 1 -> "§6§l#1"; // Gold bleibt – hebt sich gut ab diff --git a/src/main/java/de/fussball/plugin/hologram/HologramManager.java b/src/main/java/de/fussball/plugin/hologram/HologramManager.java index 8d029b2..8dfe467 100644 --- a/src/main/java/de/fussball/plugin/hologram/HologramManager.java +++ b/src/main/java/de/fussball/plugin/hologram/HologramManager.java @@ -21,6 +21,10 @@ import org.bukkit.scheduler.BukkitTask; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -115,7 +119,7 @@ public class HologramManager implements Listener { type = FussballHologram.HoloType.GOALS; } - holograms.put(id, new FussballHologram(id, loc, type, plugin)); + holograms.put(id, new FussballHologram(id, loc, type, plugin, loadCustomTextTemplates(path))); } plugin.getLogger().info("[Hologram] " + holograms.size() + " Hologramme geladen."); @@ -189,6 +193,7 @@ public class HologramManager implements Listener { /** Alle Hologramme neu laden (z.B. nach /fb hologram reload) */ public void reload() { + plugin.reloadConfig(); loadConfig(); loadHolograms(); // Für alle Online-Spieler sofort rendern @@ -197,6 +202,51 @@ public class HologramManager implements Listener { } } + public FussballHologram getHologram(String id) { + return holograms.get(id); + } + + public boolean setCustomText(String id, FussballHologram.HoloType type, List lines) { + FussballHologram holo = holograms.get(id); + if (holo == null) { + return false; + } + + List sanitized = new ArrayList<>(lines); + holo.setCustomText(type, sanitized); + holoConfig.set(getTextPath(id, type), sanitized); + saveConfig(); + rerenderHologram(holo); + return true; + } + + public boolean resetCustomText(String id, FussballHologram.HoloType type) { + FussballHologram holo = holograms.get(id); + if (holo == null) { + return false; + } + + holo.clearCustomText(type); + holoConfig.set(getTextPath(id, type), null); + saveConfig(); + rerenderHologram(holo); + return true; + } + + public List getCustomText(String id, FussballHologram.HoloType type) { + FussballHologram holo = holograms.get(id); + if (holo == null) { + return Collections.emptyList(); + } + return holo.getCustomText(type); + } + + public void refreshAll() { + for (Player player : Bukkit.getOnlinePlayers()) { + holograms.values().forEach(h -> h.renderForPlayer(player)); + } + } + // ── Render-Task ────────────────────────────────────────────────────────── /** @@ -296,4 +346,25 @@ public class HologramManager implements Listener { /** @return Set aller Hologramm-IDs (für Tab-Completion) */ public Set getHologramIds() { return holograms.keySet(); } + + private Map> loadCustomTextTemplates(String path) { + Map> templates = new EnumMap<>(FussballHologram.HoloType.class); + for (FussballHologram.HoloType holoType : FussballHologram.HoloType.values()) { + List lines = holoConfig.getStringList(path + ".text." + holoType.name().toLowerCase()); + if (!lines.isEmpty()) { + templates.put(holoType, lines); + } + } + return templates; + } + + private String getTextPath(String id, FussballHologram.HoloType type) { + return "holograms." + id + ".text." + type.name().toLowerCase(); + } + + private void rerenderHologram(FussballHologram holo) { + for (Player player : Bukkit.getOnlinePlayers()) { + holo.renderForPlayer(player); + } + } } \ No newline at end of file diff --git a/src/main/java/de/fussball/plugin/stats/StatsManager.java b/src/main/java/de/fussball/plugin/stats/StatsManager.java index e55f8df..29b0007 100644 --- a/src/main/java/de/fussball/plugin/stats/StatsManager.java +++ b/src/main/java/de/fussball/plugin/stats/StatsManager.java @@ -124,6 +124,34 @@ public class StatsManager { save(); } + public boolean resetStats(UUID uuid) { + boolean removed = cache.remove(uuid) != null; + if (!removed) { + return false; + } + save(); + return true; + } + + public int resetAllStats() { + int count = cache.size(); + if (count == 0) { + return 0; + } + cache.clear(); + save(); + return count; + } + + public UUID findPlayerUuidByName(String playerName) { + for (Map.Entry entry : cache.entrySet()) { + if (entry.getValue().name != null && entry.getValue().name.equalsIgnoreCase(playerName)) { + return entry.getKey(); + } + } + return null; + } + /** Gibt die Top-N-Torschützen zurück, sortiert nach Toren */ public List> getTopScorers(int limit) { List> list = new ArrayList<>(cache.entrySet()); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 3a92440..7d86a7a 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -61,6 +61,24 @@ atmosphere: enabled: true goal-fireworks: 5 # Anzahl Feuerwerke bei einem Tor (0 = deaktiviert) +# ── Hologramm-Farben ──────────────────────────────────────────────────────── +# Verwende &-Codes (z.B. &6 = Gold, &c = Rot, &9 = Blau, &l = Fett, &o = Kursiv) +# Änderungen werden nach /fb hologram reload wirksam. +holograms: + goals-title-color: "&6&l" # Titel Tore-Hologramm (Standard: Gold + Fett) + goals-value-color: "&4" # Tor-Anzahl in der Liste (Standard: Dunkelrot) + wins-title-color: "&2&l" # Titel Siege-Hologramm (Standard: Dunkelgrün + Fett) + wins-value-color: "&2" # Siege-Anzahl in der Liste (Standard: Dunkelgrün) + name-color: "&0" # Spielername in der Liste (Standard: Schwarz) + label-color: "&8" # Beschriftungen (Tore/Siege) (Standard: Dunkelgrau) + separator-color: "&8&m" # Trennlinie (Standard: Durchgestrichen) + toggle-color: "&8&o" # Umschalte-Hinweis (Standard: Kursiv Dunkelgrau) + match-header-color: "&e&l" # Match-Header (Standard: Gelb + Fett) + match-score-red: "&c&l" # Rot-Team Spielstand (Standard: Rot + Fett) + match-score-blue: "&9&l" # Blau-Team Spielstand (Standard: Blau + Fett) + match-time-color: "&e" # Spielzeit (Standard: Gelb) + match-injury-color: "&c" # Nachspielzeit (Standard: Rot) + # ── Nachrichten (alle editierbar) ───────────────────────────────────────────── # Verfügbare Platzhalter je nach Kontext: # {player} = Spielername diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 8c49736..cd0afc2 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: Fussball -version: 1.0.2 +version: 1.0.3 main: de.fussball.plugin.Fussball api-version: 1.21 author: M_Viper @@ -19,5 +19,5 @@ permissions: commands: fussball: description: Hauptbefehl des Fußball-Plugins - usage: /fussball + usage: "/fussball | Admin: stats reset, hologram text/textpreview/textreset" aliases: [fb, soccer] \ No newline at end of file