Update from Git Manager GUI

This commit is contained in:
2026-03-17 16:15:01 +01:00
parent 22c5837455
commit a6d17f4d64
6 changed files with 483 additions and 40 deletions

View File

@@ -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 <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; }
@@ -294,6 +325,9 @@ public class FussballCommand implements CommandExecutor, TabCompleter {
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");
@@ -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 <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)"));
@@ -378,7 +504,7 @@ public class FussballCommand implements CommandExecutor, TabCompleter {
}
}
}
default -> player.sendMessage(MessageUtil.error("Gültig: set <arena> goals|wins|match | remove | delete <arena> 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 <arena> goals|wins|match / remove / reload");
s.sendMessage("§c§lAdmin: §cstats reset <spieler|all>");
s.sendMessage("§c§lAdmin: §chologram set|delete|text|textpreview|textreset <arena> <typ>");
}
}
@@ -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<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";
@@ -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]);

View File

@@ -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<UUID, Interaction> playerInteractions = new ConcurrentHashMap<>();
/** Aktuell angezeigte Seite (0 = GOALS, 1 = WINS) pro Spieler */
private final Map<UUID, Integer> currentPage = new ConcurrentHashMap<>();
private final Map<HoloType, List<String>> 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<HoloType, List<String>> customTextTemplates) {
this.id = id;
this.location = location.clone();
this.type = type;
this.plugin = plugin;
for (Map.Entry<HoloType, List<String>> 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<String> lines) {
if (lines == null || lines.isEmpty()) {
customTextTemplates.remove(targetType);
return;
}
List<String> 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<String> 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<String> 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<String> 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

View File

@@ -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<String> lines) {
FussballHologram holo = holograms.get(id);
if (holo == null) {
return false;
}
List<String> 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<String> 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<String> getHologramIds() { return holograms.keySet(); }
private Map<FussballHologram.HoloType, List<String>> loadCustomTextTemplates(String path) {
Map<FussballHologram.HoloType, List<String>> templates = new EnumMap<>(FussballHologram.HoloType.class);
for (FussballHologram.HoloType holoType : FussballHologram.HoloType.values()) {
List<String> 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);
}
}
}

View File

@@ -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<UUID, PlayerStats> 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<Map.Entry<UUID, PlayerStats>> getTopScorers(int limit) {
List<Map.Entry<UUID, PlayerStats>> list = new ArrayList<>(cache.entrySet());

View File

@@ -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

View File

@@ -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 <join|leave|spectate|team|list|stats|top|history|create|delete|setup|stop|setgk|dropball|debug|hologram>
usage: "/fussball <join|leave|spectate|team|list|stats|top|history|create|delete|setup|stop|setgk|dropball|debug|hologram> | Admin: stats reset, hologram text/textpreview/textreset"
aliases: [fb, soccer]