From 8b43fe4264abb5586013fb6c677ecb9a9984e22c Mon Sep 17 00:00:00 2001 From: Git Manager GUI Date: Fri, 24 Apr 2026 12:42:38 +0200 Subject: [PATCH] Upload folder via GUI - src --- src/main/java/net/viper/status/StatusAPI.java | 29 ++++++- .../modules/broadcast/BroadcastModule.java | 75 +++++++++++++++++-- 2 files changed, 96 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/viper/status/StatusAPI.java b/src/main/java/net/viper/status/StatusAPI.java index 8aaadd7..b221b95 100644 --- a/src/main/java/net/viper/status/StatusAPI.java +++ b/src/main/java/net/viper/status/StatusAPI.java @@ -774,8 +774,31 @@ public class StatusAPI extends Plugin implements Runnable { boolean escape = false; while (i < json.length()) { char ch = json.charAt(i++); - if (escape) { sb.append(ch); escape = false; } - else { + if (escape) { + switch (ch) { + case 'n': sb.append('\n'); break; + case 'r': sb.append('\r'); break; + case 't': sb.append('\t'); break; + case '"': sb.append('"'); break; + case '\\': sb.append('\\'); break; + case '/': sb.append('/'); break; + case 'b': sb.append('\b'); break; + case 'f': sb.append('\f'); break; + case 'u': + if (i + 4 <= json.length()) { + try { + int cp = Integer.parseInt(json.substring(i, i + 4), 16); + sb.append((char) cp); + i += 4; + } catch (NumberFormatException ignored) { + sb.append("\\u"); + } + } + break; + default: sb.append(ch); break; + } + escape = false; + } else { if (ch == '\\') escape = true; else if (ch == '"') break; else sb.append(ch); @@ -947,4 +970,4 @@ public class StatusAPI extends Plugin implements Runnable { String e = event.trim().toLowerCase(Locale.ROOT); return e.contains("ip_rate") || e.contains("vpn") || e.contains("learning_threshold_block") || e.contains("block"); } -} +} \ No newline at end of file diff --git a/src/main/java/net/viper/status/modules/broadcast/BroadcastModule.java b/src/main/java/net/viper/status/modules/broadcast/BroadcastModule.java index 1defc1d..14c16be 100644 --- a/src/main/java/net/viper/status/modules/broadcast/BroadcastModule.java +++ b/src/main/java/net/viper/status/modules/broadcast/BroadcastModule.java @@ -3,6 +3,9 @@ package net.viper.status.modules.broadcast; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.plugin.Listener; import net.viper.status.module.Module; @@ -20,6 +23,9 @@ import java.util.concurrent.TimeUnit; * Fixes: * - loadSchedules(): ID-Split nutzt jetzt indexOf/lastIndexOf statt split("\\.") mit length==2-Check. * Damit werden auch clientScheduleIds die Punkte enthalten korrekt geladen. (Bug #2) + * - handleBroadcast(): &-Farbcodes werden jetzt auch in der Nachricht selbst übersetzt. (Bug #3) + * - handleBroadcast(): Literal \n in der Nachricht wird als echter Zeilenumbruch gerendert. (Bug #4) + * - handleBroadcast(): URLs (http/https) werden als anklickbare TextComponents eingebettet. (Bug #5) */ public class BroadcastModule implements Module, Listener { @@ -115,24 +121,83 @@ public class BroadcastModule implements Module, Listener { finalPrefix = prefixColorCode + usedPrefix + ChatColor.RESET; } - String coloredMessage = (messageColorCode.isEmpty() ? "" : messageColorCode) + message; + // FIX #1: &-Farbcodes auch in der Nachricht selbst übersetzen + String translatedMessage = ChatColor.translateAlternateColorCodes('&', message); + String coloredMessage = (messageColorCode.isEmpty() ? "" : messageColorCode) + translatedMessage; + String out = format .replace("%name%", sourceName) .replace("%prefix%", finalPrefix) .replace("%prefixColored%", finalPrefix) - .replace("%message%", message) + .replace("%message%", translatedMessage) .replace("%messageColored%",coloredMessage) .replace("%type%", type); - TextComponent tc = new TextComponent(out); + // FIX #2: \r entfernen (Windows CRLF -> nur LF), Literal \\n als Fallback + out = out.replace("\r\n", "\n").replace("\r", "").replace("\\n", "\n"); + + // FIX #3: Nachricht mit anklickbaren URLs aufbauen + BaseComponent[] components = buildClickableComponents(out); int sent = 0; for (ProxiedPlayer p : plugin.getProxy().getPlayers()) { - try { p.sendMessage(tc); sent++; } catch (Throwable ignored) {} + try { p.sendMessage(components); sent++; } catch (Throwable ignored) {} } plugin.getLogger().info("[BroadcastModule] Broadcast gesendet (Empfänger=" + sent + "): " + message); return true; } + /** + * Baut ein BaseComponent-Array aus einem formatierten String. + * URLs (http/https) werden als anklickbare TextComponents eingebettet. + * Unterstützt auch echte Newlines (\n) als Zeilenumbruch. + */ + private BaseComponent[] buildClickableComponents(String text) { + // Regex für URLs + java.util.regex.Pattern urlPattern = java.util.regex.Pattern.compile( + "(https?://[^\\s\\n]+)", java.util.regex.Pattern.CASE_INSENSITIVE); + + ComponentBuilder builder = new ComponentBuilder(""); + + // Zeilenweise aufteilen (echte \n) + String[] lines = text.split("\n", -1); + for (int li = 0; li < lines.length; li++) { + if (li > 0) { + // Zeilenumbruch als eigene Komponente + builder.append(TextComponent.fromLegacyText("\n")); + } + + String line = lines[li]; + java.util.regex.Matcher matcher = urlPattern.matcher(line); + int lastEnd = 0; + + while (matcher.find()) { + // Text vor der URL (mit Minecraft-Farbcodes) + if (matcher.start() > lastEnd) { + String before = line.substring(lastEnd, matcher.start()); + builder.append(TextComponent.fromLegacyText(before)); + } + + // URL selbst: anklickbar + unterstrichen + String url = matcher.group(1); + TextComponent urlComponent = new TextComponent(url); + urlComponent.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)); + // Farbe der URL auf Cyan setzen damit sie sich abhebt + urlComponent.setColor(ChatColor.AQUA); + urlComponent.setUnderlined(true); + builder.append(urlComponent, ComponentBuilder.FormatRetention.NONE); + + lastEnd = matcher.end(); + } + + // Restlicher Text nach der letzten URL + if (lastEnd < line.length()) { + builder.append(TextComponent.fromLegacyText(line.substring(lastEnd))); + } + } + + return builder.create(); + } + private String normalizeColorCode(String code) { if (code == null) return ""; code = code.trim(); @@ -310,4 +375,4 @@ public class BroadcastModule implements Module, Listener { this.recur = recur == null ? "none" : recur; } } -} +} \ No newline at end of file