From 87274ffc9c8d133b675546fcb237ad0d100af8e2 Mon Sep 17 00:00:00 2001 From: Git Manager GUI Date: Sun, 10 May 2026 23:12:09 +0200 Subject: [PATCH] Upload folder via GUI - src --- .../main/java/net/viper/status/StatusAPI.java | 26 ++ .../modules/scoreboard/ScoreboardModule.java | 235 ++++++++++++------ .../src/main/resources/scoreboard.properties | 37 ++- 3 files changed, 223 insertions(+), 75 deletions(-) diff --git a/StatusAPI/src/main/java/net/viper/status/StatusAPI.java b/StatusAPI/src/main/java/net/viper/status/StatusAPI.java index 880f44e..5ddf209 100644 --- a/StatusAPI/src/main/java/net/viper/status/StatusAPI.java +++ b/StatusAPI/src/main/java/net/viper/status/StatusAPI.java @@ -801,6 +801,32 @@ public class StatusAPI extends Plugin implements Runnable { return; } + // POST /ticket/update – TicketSystem Daten (von StatusAPIBridge) + if ("POST".equalsIgnoreCase(method) && "/ticket/update".equalsIgnoreCase(pathOnly)) { + String body = readBody(in, headers); + String uuidStr = extractJsonString(body, "uuid"); + if (uuidStr != null && !uuidStr.isEmpty()) { + try { + UUID uid = UUID.fromString(uuidStr.trim()); + String myOpen = extractJsonString(body, "my_open"); + if (myOpen != null) + net.viper.status.modules.scoreboard.ScoreboardModule.ticketMyOpen.put(uid, Integer.parseInt(myOpen)); + } catch (Exception ignored) {} + } + try { + String totOpen = extractJsonString(body, "total_open"); + String totClaimed = extractJsonString(body, "total_claimed"); + String ratGood = extractJsonString(body, "rating_good"); + String ratBad = extractJsonString(body, "rating_bad"); + if (totOpen != null) net.viper.status.modules.scoreboard.ScoreboardModule.ticketTotalOpen.set(Integer.parseInt(totOpen)); + if (totClaimed != null) net.viper.status.modules.scoreboard.ScoreboardModule.ticketTotalClaimed.set(Integer.parseInt(totClaimed)); + if (ratGood != null) net.viper.status.modules.scoreboard.ScoreboardModule.ticketRatingGood.set(Integer.parseInt(ratGood)); + if (ratBad != null) net.viper.status.modules.scoreboard.ScoreboardModule.ticketRatingBad.set(Integer.parseInt(ratBad)); + } catch (Exception ignored) {} + sendHttpResponse(out, "{\"success\":true}", 200); + return; + } + // POST /player/data – Koordinaten, Gamemode, Exp, Food, Speed if ("POST".equalsIgnoreCase(method) && "/player/data".equalsIgnoreCase(pathOnly)) { String body = readBody(in, headers); diff --git a/StatusAPI/src/main/java/net/viper/status/modules/scoreboard/ScoreboardModule.java b/StatusAPI/src/main/java/net/viper/status/modules/scoreboard/ScoreboardModule.java index 246c446..37140d5 100644 --- a/StatusAPI/src/main/java/net/viper/status/modules/scoreboard/ScoreboardModule.java +++ b/StatusAPI/src/main/java/net/viper/status/modules/scoreboard/ScoreboardModule.java @@ -39,6 +39,7 @@ public class ScoreboardModule implements Module, Listener { private static final String CONFIG_FILE = "scoreboard.properties"; private static final String OBJ_NAME = "vpsb"; private static final String OBJ_NAME_ADMIN = "vpsbadmin"; + private static final String OBJ_NAME_SUPP = "vpsbsupp"; public static final ConcurrentHashMap playerHealth = new ConcurrentHashMap<>(); public static final ConcurrentHashMap playerCompass = new ConcurrentHashMap<>(); @@ -53,6 +54,18 @@ public class ScoreboardModule implements Module, Listener { public static final ConcurrentHashMap playerFood = new ConcurrentHashMap<>(); public static final ConcurrentHashMap playerSpeed = new ConcurrentHashMap<>(); + // ── TicketSystem Placeholder ────────────────────────────────────────────── + /** Eigene aktive Tickets des Spielers (OPEN + CLAIMED + FORWARDED) */ + public static final ConcurrentHashMap ticketMyOpen = new ConcurrentHashMap<>(); + /** Alle offenen Tickets gesamt (Status: OPEN) – für Supporter & Admin */ + public static final java.util.concurrent.atomic.AtomicInteger ticketTotalOpen = new java.util.concurrent.atomic.AtomicInteger(0); + /** Alle Tickets in Bearbeitung gesamt (Status: CLAIMED) – für Admin */ + public static final java.util.concurrent.atomic.AtomicInteger ticketTotalClaimed = new java.util.concurrent.atomic.AtomicInteger(0); + /** Positive Bewertungen gesamt – für Admin */ + public static final java.util.concurrent.atomic.AtomicInteger ticketRatingGood = new java.util.concurrent.atomic.AtomicInteger(0); + /** Negative Bewertungen gesamt – für Admin */ + public static final java.util.concurrent.atomic.AtomicInteger ticketRatingBad = new java.util.concurrent.atomic.AtomicInteger(0); + private final ConcurrentHashMap joinTimes = new ConcurrentHashMap<>(); // Spieler, die das Scoreboard ausgeblendet haben /** FIX: Referenz auf NetworkInfoModule für TPS-Fallback */ @@ -65,9 +78,11 @@ public class ScoreboardModule implements Module, Listener { private final Set hiddenPlayers = ConcurrentHashMap.newKeySet(); // Spieler, die manuell auf Player-Board gezwungen wurden (Override) - private final Set forcePlayerView = ConcurrentHashMap.newKeySet(); + private final Set forcePlayerView = ConcurrentHashMap.newKeySet(); + // Spieler, die manuell auf Supporter-Board gezwungen wurden + private final Set forceSupporterView = ConcurrentHashMap.newKeySet(); // Spieler, die manuell auf Admin-Board gezwungen wurden (ohne Perm) - private final Set forceAdminView = ConcurrentHashMap.newKeySet(); + private final Set forceAdminView = ConcurrentHashMap.newKeySet(); private boolean enabled = true; private int updateInterval = 500; // Millisekunden @@ -79,7 +94,9 @@ public class ScoreboardModule implements Module, Listener { private float waveSpeed = 0.05f; // Bewegung pro Tick private String title = "&6&lViper Network"; private String adminTitle = "&c&l[Admin] &4&lPanel"; - private String adminPermission = "statusapi.scoreboard.admin"; + private String supporterTitle = "&e&l[Support] &6&lPanel"; + private String adminPermission = "statusapi.scoreboard.admin"; + private String supporterPermission = "statusapi.scoreboard.supporter"; private String timeFormat = "HH:mm"; private String dateFormat = "dd.MM.yyyy"; private String timeZone = "Europe/Berlin"; @@ -90,8 +107,9 @@ public class ScoreboardModule implements Module, Listener { private int tickerWidth = 24; // Key = Zeilennummer (1-based), Value = Liste der Inhalte pro Page // Zeilen mit nur 1 Eintrag rotieren nicht, Zeilen mit 2+ Eintraegen wechseln - private Map> playerLineMap = new LinkedHashMap<>(); - private Map> adminLineMap = new LinkedHashMap<>(); + private Map> playerLineMap = new LinkedHashMap<>(); + private Map> adminLineMap = new LinkedHashMap<>(); + private Map> supporterLineMap = new LinkedHashMap<>(); private int rotationInterval = 4; // Sekunden pro Page // News-Ticker private String newsText = ""; @@ -120,8 +138,9 @@ public class ScoreboardModule implements Module, Listener { private final ConcurrentHashMap tickerPos = new ConcurrentHashMap<>(); private final ConcurrentHashMap rainbowIdx = new ConcurrentHashMap<>(); - private final Set created = ConcurrentHashMap.newKeySet(); - private final Set createdAdmin = ConcurrentHashMap.newKeySet(); + private final Set created = ConcurrentHashMap.newKeySet(); + private final Set createdAdmin = ConcurrentHashMap.newKeySet(); + private final Set createdSupporter = ConcurrentHashMap.newKeySet(); private static final ChatColor[] RAINBOW = { ChatColor.RED, ChatColor.GOLD, ChatColor.YELLOW, @@ -177,11 +196,12 @@ public class ScoreboardModule implements Module, Listener { if (titleTask != null) { titleTask.cancel(); titleTask = null; } if (newsTask != null) { newsTask.cancel(); newsTask = null; } for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) { - if (created.contains(p.getUniqueId())) removeObjectiveAndTeams(p, OBJ_NAME, "vt"); - if (createdAdmin.contains(p.getUniqueId())) removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); + if (created.contains(p.getUniqueId())) removeObjectiveAndTeams(p, OBJ_NAME, "vt"); + if (createdAdmin.contains(p.getUniqueId())) removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); + if (createdSupporter.contains(p.getUniqueId())) removeObjectiveAndTeams(p, OBJ_NAME_SUPP, "vts"); } - created.clear(); createdAdmin.clear(); tickerPos.clear(); rainbowIdx.clear(); - hiddenPlayers.clear(); forceAdminView.clear(); forcePlayerView.clear(); newsPos.clear(); + created.clear(); createdAdmin.clear(); createdSupporter.clear(); tickerPos.clear(); rainbowIdx.clear(); + hiddenPlayers.clear(); forceAdminView.clear(); forcePlayerView.clear(); forceSupporterView.clear(); newsPos.clear(); } @EventHandler @@ -195,6 +215,7 @@ public class ScoreboardModule implements Module, Listener { // Nur State initialisieren – onSwitch baut das Scoreboard auf created.remove(id); createdAdmin.remove(id); + createdSupporter.remove(id); } @EventHandler @@ -203,15 +224,17 @@ public class ScoreboardModule implements Module, Listener { ProxiedPlayer p = e.getPlayer(); UUID id = p.getUniqueId(); // Altes Objective sauber entfernen – tickAll übernimmt den Neuaufbau - if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } - if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } + if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (createdSupporter.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_SUPP, "vts"); createdSupporter.remove(id); } // Kein verzögerter sendAll-Call mehr – tickAll baut nach max. 500ms neu auf } @EventHandler public void onQuit(PlayerDisconnectEvent e) { UUID id = e.getPlayer().getUniqueId(); - tickerPos.remove(id); rainbowIdx.remove(id); created.remove(id); createdAdmin.remove(id); + tickerPos.remove(id); rainbowIdx.remove(id); created.remove(id); createdAdmin.remove(id); createdSupporter.remove(id); + forcePlayerView.remove(id); forceSupporterView.remove(id); forceAdminView.remove(id); playerHealth.remove(id); playerCompass.remove(id); playerTps.remove(id); playerX.remove(id); playerY.remove(id); playerZ.remove(id); playerWorld.remove(id); playerGamemode.remove(id); @@ -230,9 +253,10 @@ public class ScoreboardModule implements Module, Listener { if (!p.isConnected()) continue; UUID id = p.getUniqueId(); if (hiddenPlayers.contains(id)) continue; - boolean isAdmin = !forcePlayerView.contains(id) + boolean isAdmin = !forceSupporterView.contains(id) && !forcePlayerView.contains(id) && (p.hasPermission(adminPermission) || forceAdminView.contains(id)); - Set activeCreated = isAdmin ? createdAdmin : created; + boolean isSupporter = !isAdmin && (forceSupporterView.contains(id) || (!forcePlayerView.contains(id) && p.hasPermission(supporterPermission))); + Set activeCreated = isAdmin ? createdAdmin : isSupporter ? createdSupporter : created; if (!activeCreated.contains(id)) continue; // Position vorrücken @@ -267,7 +291,7 @@ public class ScoreboardModule implements Module, Listener { // Team-Packet nur für diese Zeile senden net.md_5.bungee.protocol.packet.Team team = new net.md_5.bungee.protocol.packet.Team(); - team.setName((isAdmin ? "vta" : "vt") + lineIdx); + team.setName((isAdmin ? "vta" : isSupporter ? "vts" : "vt") + lineIdx); team.setMode((byte) 2); // UPDATE net.md_5.bungee.api.chat.TextComponent tc = new net.md_5.bungee.api.chat.TextComponent(""); @@ -293,15 +317,15 @@ public class ScoreboardModule implements Module, Listener { if (!p.isConnected()) continue; UUID id = p.getUniqueId(); if (hiddenPlayers.contains(id)) continue; - boolean isAdmin = !forcePlayerView.contains(id) + boolean isAdmin = !forceSupporterView.contains(id) && !forcePlayerView.contains(id) && (p.hasPermission(adminPermission) || forceAdminView.contains(id)); - Set activeCreated = isAdmin ? createdAdmin : created; - if (!activeCreated.contains(id)) continue; // noch nicht aufgebaut + boolean isSupporter = !isAdmin && (forceSupporterView.contains(id) || (!forcePlayerView.contains(id) && p.hasPermission(supporterPermission))); + Set activeCreated = isAdmin ? createdAdmin : isSupporter ? createdSupporter : created; try { int rIdx = (rainbowIdx.getOrDefault(id, 0) + 1) % 10000; rainbowIdx.put(id, rIdx); - String activeObjName = isAdmin ? OBJ_NAME_ADMIN : OBJ_NAME; - String rawTitle = isAdmin ? adminTitle : title; + String activeObjName = isAdmin ? OBJ_NAME_ADMIN : isSupporter ? OBJ_NAME_SUPP : OBJ_NAME; + String rawTitle = isAdmin ? adminTitle : isSupporter ? supporterTitle : title; String titleStr = rainbow(c(rawTitle), rIdx); ScoreboardObjective obj = new ScoreboardObjective(); obj.setName(activeObjName); @@ -348,9 +372,10 @@ public class ScoreboardModule implements Module, Listener { } // forcePlayerView hat Vorrang vor Perm und forceAdminView - boolean isAdmin = !forcePlayerView.contains(id) + boolean isAdmin = !forceSupporterView.contains(id) && !forcePlayerView.contains(id) && (p.hasPermission(adminPermission) || forceAdminView.contains(id)); - + boolean isSupporter = !isAdmin && (forceSupporterView.contains(id) + || (!forcePlayerView.contains(id) && p.hasPermission(supporterPermission))); String rawTicker = stripColors(tickerText); int tLen = Math.max(1, rawTicker.length()); int tOff = (tickerPos.getOrDefault(id, 0) + tickerSpeed) % tLen; @@ -403,8 +428,22 @@ public class ScoreboardModule implements Module, Listener { String servers = String.valueOf(ProxyServer.getInstance().getServers().size()); String proxymem = getRam(); + // ── TicketSystem ────────────────────────────────────────────────────── + String ticketMyOpenStr = String.valueOf(ticketMyOpen.getOrDefault(id, 0)); + String ticketTotalOpenStr = String.valueOf(ticketTotalOpen.get()); + String ticketTotalClaimedStr = String.valueOf(ticketTotalClaimed.get()); + String ticketRatingGoodStr = String.valueOf(ticketRatingGood.get()); + String ticketRatingBadStr = String.valueOf(ticketRatingBad.get()); + int _tGood = ticketRatingGood.get(); + int _tBad = ticketRatingBad.get(); + String ticketRatingPctStr = (_tGood + _tBad == 0) ? "-" + : String.valueOf(Math.round(_tGood * 100.0 / (_tGood + _tBad))); + // Per-Zeile Rotation: Zeilen mit mehreren Inhalten wechseln automatisch - Map> lineMap = (isAdmin && !adminLineMap.isEmpty()) ? adminLineMap : playerLineMap; + Map> lineMap = isAdmin ? adminLineMap + : isSupporter ? supporterLineMap + : playerLineMap; + if (lineMap.isEmpty()) lineMap = playerLineMap; // Aktueller Page-Index basierend auf Zeit int pageIdx = (rotationInterval > 0) ? (int)((System.currentTimeMillis() / 1000) / rotationInterval) @@ -424,36 +463,41 @@ public class ScoreboardModule implements Module, Listener { } } List lines = new ArrayList<>(); - boolean hasTicker = !tickerText.isEmpty() && !isAdmin; + boolean hasTicker = !tickerText.isEmpty() && !isAdmin && !isSupporter; if (hasTicker) lines.add(ticker(rawTicker, tOff, rIdx)); // Maximale Inhaltszeilen: MAX_LINES insgesamt (Ticker zählt als eine) for (String tpl : srcLines) { if (lines.size() >= MAX_LINES) break; lines.add(c(ph(tpl, pn, rank, money, srv, comp, hp, hpNum, ping, online, maxpl, tps, ram, time, playtime, - xCoord, yCoord, zCoord, world, gamemode, exp, food, foodSym, speed, uptime, servers, proxymem, date, news))); + xCoord, yCoord, zCoord, world, gamemode, exp, food, foodSym, speed, uptime, servers, proxymem, date, news, + ticketMyOpenStr, ticketTotalOpenStr, ticketTotalClaimedStr, + ticketRatingGoodStr, ticketRatingBadStr, ticketRatingPctStr))); } // Immer genau MAX_LINES Zeilen (Rest mit Leerzeilen auffüllen) if (lines.size() > MAX_LINES) lines = new ArrayList<>(lines.subList(0, MAX_LINES)); while (lines.size() < MAX_LINES) lines.add(" "); - // Admin-Scoreboard hat eigenen Objective-Namen und Titel - String activeObjName = isAdmin ? OBJ_NAME_ADMIN : OBJ_NAME; - String titleStr = isAdmin - ? rainbow(c(adminTitle), rIdx) - : rainbow(c(title), rIdx); + // Objective-Name und Titel je nach Rolle + String activeObjName = isAdmin ? OBJ_NAME_ADMIN + : isSupporter ? OBJ_NAME_SUPP + : OBJ_NAME; + String titleStr = isAdmin ? rainbow(c(adminTitle), rIdx) + : isSupporter ? rainbow(c(supporterTitle), rIdx) + : rainbow(c(title), rIdx); - // Wenn Admin-Status wechselt: altes Objective entfernen - // Wechsel zwischen Player- und Admin-Board: - // Altes Objective + alle zugehörigen Teams sauber entfernen - if (isAdmin && created.contains(id)) { - removeObjectiveAndTeams(p, OBJ_NAME, "vt"); - created.remove(id); - } else if (!isAdmin && createdAdmin.contains(id)) { - removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); - createdAdmin.remove(id); + // Wenn Rolle wechselt: altes Objective sauber entfernen + if (isAdmin) { + if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } + if (createdSupporter.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_SUPP, "vts"); createdSupporter.remove(id); } + } else if (isSupporter) { + if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } + if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + } else { + if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (createdSupporter.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_SUPP, "vts"); createdSupporter.remove(id); } } - Set activeCreated = isAdmin ? createdAdmin : created; + Set activeCreated = isAdmin ? createdAdmin : isSupporter ? createdSupporter : created; // Objective CREATE (einmalig) oder UPDATE_TITLE boolean justCreated = !activeCreated.contains(id); @@ -505,7 +549,7 @@ public class ScoreboardModule implements Module, Listener { sendPkt.invoke(p, score); Team team = new Team(); - team.setName((isAdmin ? "vta" : "vt") + i); + team.setName((isAdmin ? "vta" : isSupporter ? "vts" : "vt") + i); // CREATE wenn das Objective gerade frisch angelegt wurde, sonst UPDATE team.setMode(justCreated ? (byte) 0 : (byte) 2); // Hex-Farben: BaseComponent[] als Container-TextComponent verpacken @@ -787,7 +831,9 @@ public class ScoreboardModule implements Module, Listener { String tps, String ram, String time, String playtime, String x, String y, String z, String world, String gamemode, String exp, String food, String foodSymbol, String speed, - String uptime, String servers, String proxymem, String date, String news) { + String uptime, String servers, String proxymem, String date, String news, + String ticketMyOpen, String ticketTotalOpen, String ticketTotalClaimed, + String ticketRatingGood, String ticketRatingBad, String ticketRatingPct) { if (tpl == null) return " "; String s = tpl .replace("%player%", player) .replace("%rank%", rank) @@ -805,7 +851,14 @@ public class ScoreboardModule implements Module, Listener { .replace("%uptime%", uptime) .replace("%servers%", servers) .replace("%proxymem%", proxymem) .replace("%date%", date) - .replace("%news%", news); + .replace("%news%", news) + // ── TicketSystem ────────────────────────────────────────────────── + .replace("%ticket_my_open%", ticketMyOpen) + .replace("%ticket_open%", ticketTotalOpen) + .replace("%ticket_claimed%", ticketTotalClaimed) + .replace("%ticket_rating_good%", ticketRatingGood) + .replace("%ticket_rating_bad%", ticketRatingBad) + .replace("%ticket_rating_pct%", ticketRatingPct); s = applyGradients(s); s = s.replace("%line%", c(separator)); return s.isEmpty() ? " " : s; @@ -1179,7 +1232,8 @@ public class ScoreboardModule implements Module, Listener { "scoreboard.enabled=true\n" + "scoreboard.update_interval=500\n" + "scoreboard.title=&lViper Network\n" + - "scoreboard.admin_title=&l[Admin] Panel\n\n" + + "scoreboard.admin_title=&l[Admin] Panel\n" + + "scoreboard.supporter_title=&l[Support] Panel\n\n" + "scoreboard.ticker.text=\n" + "scoreboard.ticker.width=26\n" + "scoreboard.ticker.speed=1\n\n" + @@ -1190,7 +1244,8 @@ public class ScoreboardModule implements Module, Listener { "scoreboard.rainbow.speed=10\n" + "# Leer = voller HSB-Regenbogen\n" + "scoreboard.rainbow.colors=#FF0000,#FF6600,#FFFF00,#00FF00,#00FFFF,#0000FF,#FF00FF\n\n" + - "scoreboard.admin_permission=statusapi.scoreboard.admin\n\n" + + "scoreboard.admin_permission=statusapi.scoreboard.admin\n" + + "scoreboard.supporter_permission=statusapi.scoreboard.supporter\n\n" + "scoreboard.time_format=HH:mm\n" + "scoreboard.date_format=dd.MM.yyyy\n" + "scoreboard.timezone=Europe/Berlin\n" + @@ -1252,7 +1307,25 @@ public class ScoreboardModule implements Module, Listener { "scoreboard.admin_lines.13=%news%\n" + "scoreboard.admin_lines.14=%line%\n" + "scoreboard.admin_lines.15=&7%compass%\n" + - "scoreboard.admin_lines.15.2=&7Pos: X:&f%x% &7Y:&f%y% &7Z:&f%z%\n"; + "scoreboard.admin_lines.15.2=&7Pos: X:&f%x% &7Y:&f%y% &7Z:&f%z%\n" + + "# ===================================================\n" + + "# SUPPORTER-ZEILEN\n" + + "# ===================================================\n" + + "scoreboard.supporter_lines.1=%line%\n" + + "scoreboard.supporter_lines.2=%gradient:&6:&f:&6:&l> Support Panel:%\n" + + "scoreboard.supporter_lines.3=&7%rank% &f%player%\n" + + "scoreboard.supporter_lines.4=&7Ping: &f%ping%ms &8| &7%server%\n" + + "scoreboard.supporter_lines.5=\n" + + "scoreboard.supporter_lines.6=%gradient:&6:&f:&6:&l> Tickets:%\n" + + "scoreboard.supporter_lines.7=&7Offen: &c%ticket_open%\n" + + "scoreboard.supporter_lines.8=&7Meine Tickets: &e%ticket_my_open%\n" + + "scoreboard.supporter_lines.9=\n" + + "scoreboard.supporter_lines.10=%gradient:&6:&f:&6:&l> Server Info:%\n" + + "scoreboard.supporter_lines.11=&7Online: &f%online% &8/ &7%maxplayers%\n" + + "scoreboard.supporter_lines.12=&7Zeit: &f%time%\n" + + "scoreboard.supporter_lines.13=\n" + + "scoreboard.supporter_lines.14=%line%\n" + + "scoreboard.supporter_lines.15=&7%compass%\n"; try (OutputStream out = new FileOutputStream(f)) { out.write(content.getBytes(StandardCharsets.UTF_8)); } catch (Exception e) { @@ -1283,6 +1356,7 @@ public class ScoreboardModule implements Module, Listener { updateInterval = Math.max(250, pi(g.apply("scoreboard.update_interval", "500"), 500)); title = g.apply("scoreboard.title", "&6&lViper Network"); adminTitle = g.apply("scoreboard.admin_title", "&c&l[Admin] &4&lPanel"); + supporterTitle = g.apply("scoreboard.supporter_title", "&e&l[Support] &6&lPanel"); tickerText = g.apply("scoreboard.ticker.text", " Viper Network "); tickerWidth = pi(g.apply("scoreboard.ticker.width", "26"), 26); tickerSpeed = pi(g.apply("scoreboard.ticker.speed", "1"), 1); @@ -1319,7 +1393,8 @@ public class ScoreboardModule implements Module, Listener { } else { waveColors = null; // HSB-Fallback } - adminPermission = g.apply("scoreboard.admin_permission", "statusapi.scoreboard.admin"); + adminPermission = g.apply("scoreboard.admin_permission", "statusapi.scoreboard.admin"); + supporterPermission = g.apply("scoreboard.supporter_permission", "statusapi.scoreboard.supporter"); timeFormat = g.apply("scoreboard.time_format", "HH:mm"); dateFormat = g.apply("scoreboard.date_format", "dd.MM.yyyy"); timeZone = g.apply("scoreboard.timezone", "Europe/Berlin"); @@ -1355,10 +1430,13 @@ public class ScoreboardModule implements Module, Listener { loadLineMap(map, "scoreboard.lines.", playerLineMap); adminLineMap.clear(); loadLineMap(map, "scoreboard.admin_lines.", adminLineMap); + supporterLineMap.clear(); + loadLineMap(map, "scoreboard.supporter_lines.", supporterLineMap); plugin.getLogger().info("[ScoreboardModule] " + playerLineMap.size() + " Player-Zeilen, " - + adminLineMap.size() + " Admin-Zeilen. RotInterval=" + rotationInterval + "s"); + + adminLineMap.size() + " Admin-Zeilen, " + + supporterLineMap.size() + " Supporter-Zeilen. RotInterval=" + rotationInterval + "s"); } /** @@ -1466,56 +1544,73 @@ public class ScoreboardModule implements Module, Listener { switch (sub) { case "hide": - // Erst sauber entfernen, dann verstecken - if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } - if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } + if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (createdSupporter.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_SUPP, "vts"); createdSupporter.remove(id); } hiddenPlayers.add(id); p.sendMessage(msg("&7Scoreboard &causgeblendet&7. (/sb zum Einblenden)")); break; case "show": - // Sauber entfernen → nächster tickAll baut neu auf - if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } - if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } + if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (createdSupporter.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_SUPP, "vts"); createdSupporter.remove(id); } hiddenPlayers.remove(id); p.sendMessage(msg("&7Scoreboard &aeingeblendet&7.")); break; case "player": - // Aktuell angezeigtes Board sauber entfernen, dann auf Player umschalten - if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } - if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } - forcePlayerView.add(id); // überschreibt Admin-Perm + if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } + if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (createdSupporter.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_SUPP, "vts"); createdSupporter.remove(id); } + forcePlayerView.add(id); forceAdminView.remove(id); + forceSupporterView.remove(id); hiddenPlayers.remove(id); p.sendMessage(msg("&7Zeige &eSpieler&7-Scoreboard.")); break; + case "supporter": + if (!p.hasPermission(supporterPermission) && !p.hasPermission(adminPermission)) { + p.sendMessage(msg("&cKeine Berechtigung.")); + return; + } + if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } + if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (createdSupporter.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_SUPP, "vts"); createdSupporter.remove(id); } + forceSupporterView.add(id); + forceAdminView.remove(id); + forcePlayerView.remove(id); + hiddenPlayers.remove(id); + p.sendMessage(msg("&7Zeige &6Supporter&7-Scoreboard.")); + break; + case "admin": if (!p.hasPermission(adminPermission)) { p.sendMessage(msg("&cKeine Berechtigung.")); return; } - // Aktuell angezeigtes Board sauber entfernen, dann auf Admin umschalten - if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } - if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } + if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (createdSupporter.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_SUPP, "vts"); createdSupporter.remove(id); } forceAdminView.add(id); - forcePlayerView.remove(id); // Admin-Perm wieder aktiv + forcePlayerView.remove(id); + forceSupporterView.remove(id); hiddenPlayers.remove(id); p.sendMessage(msg("&7Zeige &cAdmin&7-Scoreboard.")); break; default: // "toggle" if (hiddenPlayers.contains(id)) { - // Einblenden: sauber entfernen → neu aufbauen - if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } - if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } + if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (createdSupporter.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_SUPP, "vts"); createdSupporter.remove(id); } hiddenPlayers.remove(id); p.sendMessage(msg("&7Scoreboard &aeingeblendet&7.")); } else { - // Ausblenden - if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } - if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (created.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME, "vt"); created.remove(id); } + if (createdAdmin.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_ADMIN, "vta"); createdAdmin.remove(id); } + if (createdSupporter.contains(id)) { removeObjectiveAndTeams(p, OBJ_NAME_SUPP, "vts"); createdSupporter.remove(id); } hiddenPlayers.add(id); p.sendMessage(msg("&7Scoreboard &causgeblendet&7. (/sb zum Einblenden)")); } diff --git a/StatusAPI/src/main/resources/scoreboard.properties b/StatusAPI/src/main/resources/scoreboard.properties index 31027cb..898abba 100644 --- a/StatusAPI/src/main/resources/scoreboard.properties +++ b/StatusAPI/src/main/resources/scoreboard.properties @@ -3,6 +3,9 @@ # %ping% %online% %maxplayers% %time% %playtime% %news% # %x% %y% %z% %world% %gamemode% %exp% %food% %foodsym% %speed% # Platzhalter Admin: %tps% %ram% %proxymem% %uptime% %servers% +# Ticket (Spieler): %ticket_my_open% +# Ticket (Supporter): %ticket_open% +# Ticket (Admin): %ticket_open% %ticket_claimed% %ticket_rating_good% %ticket_rating_bad% %ticket_rating_pct% # Gradient: %gradient:FARBE1:FARBE2:TEXT% (beliebig viele Farb-Stopps) # Sonstiges: %line% # Farben: &-Codes und Hex &#FF6600 @@ -12,6 +15,7 @@ scoreboard.enabled=true scoreboard.update_interval=500 scoreboard.title=&lViper Network scoreboard.admin_title=&l[Admin] Panel +scoreboard.supporter_title=&l[Support] Panel # Laufschrift – leer lassen zum Deaktivieren scoreboard.ticker.text= @@ -28,6 +32,7 @@ scoreboard.rainbow.speed=10 scoreboard.rainbow.colors=#FF0000,#FF6600,#FFFF00,#00FF00,#00FFFF,#0000FF,#FF00FF scoreboard.admin_permission=statusapi.scoreboard.admin +scoreboard.supporter_permission=statusapi.scoreboard.supporter scoreboard.time_format=HH:mm scoreboard.date_format=dd.MM.yyyy @@ -92,6 +97,9 @@ scoreboard.lines.13=%news% scoreboard.lines.14=%line% scoreboard.lines.15=&7%compass% +# TicketSystem-Zeilen (auskommentiert – nach Bedarf einbinden): +# scoreboard.lines.X=&7Tickets: &e%ticket_my_open% + # =================================================== # ADMIN-ZEILEN # =================================================== @@ -108,8 +116,27 @@ scoreboard.admin_lines.8.2=&7Proxy: &f%uptime% scoreboard.admin_lines.9= scoreboard.admin_lines.10=&7TPS: &a%tps% scoreboard.admin_lines.11= -scoreboard.admin_lines.12=&7Spieler: &f%online% &8| &7%maxplayers% -scoreboard.admin_lines.13=%news% -scoreboard.admin_lines.14=%line% -scoreboard.admin_lines.15=&7%compass% -scoreboard.admin_lines.15.2=&7Pos: X:&f%x% &7Y:&f%y% &7Z:&f%z% +scoreboard.admin_lines.12=%gradient:&b:&f:&b:&l> Tickets:% +scoreboard.admin_lines.13=&7Offen: &c%ticket_open% &8| &7Aktiv: &e%ticket_claimed% +scoreboard.admin_lines.14=&7Bewertung: &a%ticket_rating_good%&8/&c%ticket_rating_bad% &7(&f%ticket_rating_pct%&7%&7) +scoreboard.admin_lines.15=%line% +scoreboard.admin_lines.15.2=&7%compass% + +# =================================================== +# SUPPORTER-ZEILEN +# =================================================== +scoreboard.supporter_lines.1=%line% +scoreboard.supporter_lines.2=%gradient:&6:&f:&6:&l> Support Panel:% +scoreboard.supporter_lines.3=&7%rank% &f%player% +scoreboard.supporter_lines.4=&7Ping: &f%ping%ms &8| &7%server% +scoreboard.supporter_lines.5= +scoreboard.supporter_lines.6=%gradient:&6:&f:&6:&l> Tickets:% +scoreboard.supporter_lines.7=&7Offen: &c%ticket_open% +scoreboard.supporter_lines.8=&7Meine Tickets: &e%ticket_my_open% +scoreboard.supporter_lines.9= +scoreboard.supporter_lines.10=%gradient:&6:&f:&6:&l> Server Info:% +scoreboard.supporter_lines.11=&7Online: &f%online% &8/ &7%maxplayers% +scoreboard.supporter_lines.12=&7Zeit: &f%time% +scoreboard.supporter_lines.13= +scoreboard.supporter_lines.14=%line% +scoreboard.supporter_lines.15=&7%compass%