From 1179398aed45b6309efedad83a302706aff58fce Mon Sep 17 00:00:00 2001 From: Git Manager GUI Date: Tue, 7 Apr 2026 19:55:07 +0200 Subject: [PATCH] Upload folder via GUI - src --- .../statusapibridge/StatusAPIBridge.java | 142 +++++++++++ src/main/resources/config.yml | 8 + src/main/resources/plugin.yml | 235 +----------------- 3 files changed, 157 insertions(+), 228 deletions(-) create mode 100644 src/main/java/net/viper/statusapibridge/StatusAPIBridge.java create mode 100644 src/main/resources/config.yml diff --git a/src/main/java/net/viper/statusapibridge/StatusAPIBridge.java b/src/main/java/net/viper/statusapibridge/StatusAPIBridge.java new file mode 100644 index 0000000..636c655 --- /dev/null +++ b/src/main/java/net/viper/statusapibridge/StatusAPIBridge.java @@ -0,0 +1,142 @@ +package net.viper.statusapibridge; + +import net.milkbowl.vault.economy.Economy; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class StatusAPIBridge extends JavaPlugin implements Listener { + + private Economy economy; + private String statusApiUrl; + private int pushDelayTicks; + private int liveSyncIntervalTicks; + private final Map lastPushedBalance = new ConcurrentHashMap<>(); + private final ExecutorService httpExecutor = Executors.newSingleThreadExecutor(r -> { + Thread t = new Thread(r, "StatusAPIBridge-HTTP"); + t.setDaemon(true); + return t; + }); + + @Override + public void onEnable() { + saveDefaultConfig(); + statusApiUrl = getConfig().getString("statusapi-url", "http://127.0.0.1:9191").trim(); + pushDelayTicks = getConfig().getInt("push-delay-ticks", 40); + liveSyncIntervalTicks = Math.max(20, getConfig().getInt("live-sync-interval-ticks", 20)); + + if (!setupEconomy()) { + getLogger().warning("Vault/Economy nicht gefunden – Economy-Push deaktiviert."); + } else { + getLogger().info("Vault Economy gefunden: " + economy.getName()); + } + + Bukkit.getPluginManager().registerEvents(this, this); + + // Live-Sync: Alle X Ticks online Spieler prüfen und bei Balance-Änderung pushen. + Bukkit.getScheduler().runTaskTimer(this, this::pushChangedBalancesForOnlinePlayers, liveSyncIntervalTicks, liveSyncIntervalTicks); + getLogger().info("StatusAPIBridge gestartet. Ziel: " + statusApiUrl); + } + + @Override + public void onDisable() { + httpExecutor.shutdownNow(); + } + + private boolean setupEconomy() { + if (getServer().getPluginManager().getPlugin("Vault") == null) return false; + RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(Economy.class); + if (rsp == null) return false; + economy = rsp.getProvider(); + return economy != null; + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onJoin(PlayerJoinEvent e) { + if (economy == null) return; + Player player = e.getPlayer(); + // Verzögert pushen, damit das Economy-Plugin den Account vollständig geladen hat + Bukkit.getScheduler().runTaskLater(this, () -> { + if (player.isOnline()) pushEconomy(player); + }, pushDelayTicks); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onQuit(PlayerQuitEvent e) { + if (economy == null) return; + Player player = e.getPlayer(); + // Synchron lesen, dann async senden + double balance = economy.getBalance(player); + pushEconomyAsync(player.getUniqueId(), player.getName(), balance); + lastPushedBalance.remove(player.getUniqueId()); + } + + public void pushEconomy(Player player) { + double balance = economy.getBalance(player); + pushEconomyAsync(player.getUniqueId(), player.getName(), balance); + } + + private void pushEconomyAsync(UUID uuid, String name, double balance) { + httpExecutor.execute(() -> { + try { + String json = "{\"uuid\":\"" + uuid + "\",\"name\":\"" + escapeName(name) + "\",\"balance\":" + balance + "}"; + sendPost(statusApiUrl + "/economy/update", json); + lastPushedBalance.put(uuid, balance); + } catch (Exception e) { + getLogger().warning("Economy-Push fehlgeschlagen fuer " + name + ": " + e.getMessage()); + } + }); + } + + private void pushChangedBalancesForOnlinePlayers() { + if (economy == null) return; + for (Player player : Bukkit.getOnlinePlayers()) { + double current = economy.getBalance(player); + Double last = lastPushedBalance.get(player.getUniqueId()); + if (last == null || Math.abs(current - last) > 0.000001d) { + pushEconomyAsync(player.getUniqueId(), player.getName(), current); + } + } + } + + private void sendPost(String urlStr, String json) throws Exception { + URL url = new URL(urlStr); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + conn.setDoOutput(true); + conn.setConnectTimeout(3000); + conn.setReadTimeout(3000); + conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); + byte[] body = json.getBytes(StandardCharsets.UTF_8); + conn.setRequestProperty("Content-Length", String.valueOf(body.length)); + try (OutputStream os = conn.getOutputStream()) { + os.write(body); + } + int code = conn.getResponseCode(); + if (code != 200) { + getLogger().warning("StatusAPI antwortete mit Code " + code + " fuer " + urlStr); + } + conn.disconnect(); + } + + private String escapeName(String name) { + if (name == null) return ""; + return name.replace("\\", "\\\\").replace("\"", "\\\""); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..be2cd64 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,8 @@ +# URL der BungeeCord StatusAPI (kein Slash am Ende) +statusapi-url: "http://127.0.0.1:9191" + +# Wie viele Ticks nach dem Join wird die Balance gepusht? (20 Ticks = 1 Sekunde) +push-delay-ticks: 40 + +# Live-Sync Intervall fuer Economy-Updates waehrend der Spieler online ist (mind. 20 Ticks = 1 Sekunde) +live-sync-interval-ticks: 20 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 6ed888f..b091468 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,228 +1,7 @@ -name: StatusAPI -main: net.viper.status.StatusAPI -version: 4.1.0 -author: M_Viper -description: StatusAPI für BungeeCord inkl. Update-Checker, Modul-System und ChatModule -# Mindestanforderung: Minecraft 1.20 / BungeeCord mit PlayerChatEvent-Unterstützung - -softdepend: - - LuckPerms - - Geyser-BungeeCord - -commands: - # ── Verify Modul ────────────────────────────────────────── - verify: - description: Verifiziere dich mit einem Token - usage: /verify - - # ── ForumBridge Modul ───────────────────────────────────── - forumlink: - description: Verknüpfe deinen Minecraft-Account mit dem Forum - usage: /forumlink - - # ── NetworkInfo Modul ───────────────────────────────────── - netinfo: - description: Zeigt erweiterte Proxy- und Systeminfos an - usage: /netinfo - - antibot: - description: Zeigt AntiBot-Status und Verwaltung - usage: /antibot - - # ── ChatModule – Kanal ──────────────────────────────────── - channel: - description: Kanal wechseln oder Kanalliste anzeigen - usage: /channel [kanalname] - aliases: [ch, kanal] - - # ── ChatModule – HelpOp ─────────────────────────────────── - helpop: - description: Sende eine Hilfeanfrage an das Team - usage: /helpop - - # ── ChatModule – Privat-Nachrichten ─────────────────────── - msg: - description: Sende eine private Nachricht - usage: /msg - aliases: [tell, w, whisper] - - r: - description: Antworte auf die letzte private Nachricht - usage: /r - aliases: [reply, antwort] - - # ── ChatModule – Blockieren ─────────────────────────────── - ignore: - description: Spieler ignorieren - usage: /ignore - aliases: [block] - - unignore: - description: Spieler nicht mehr ignorieren - usage: /unignore - aliases: [unblock] - - # ── ChatModule – Mute (Admin) ───────────────────────────── - chatmute: - description: Spieler im Chat stumm schalten - usage: /chatmute [Minuten] - aliases: [gmute] - - chatunmute: - description: Chat-Stummschaltung aufheben - usage: /chatunmute - aliases: [gunmute] - - # ── ChatModule – Selbst-Mute ────────────────────────────── - chataus: - description: Eigenen Chat-Empfang ein-/ausschalten - usage: /chataus - aliases: [togglechat, chaton, chatoff] - - # ── ChatModule – Broadcast ──────────────────────────────── - broadcast: - description: Nachricht an alle Spieler senden - usage: /broadcast - aliases: [bc, alert] - - # ── ChatModule – Emoji ──────────────────────────────────── - emoji: - description: Liste aller verfügbaren Emojis - usage: /emoji - aliases: [emojis] - - # ── ChatModule – Social Spy ─────────────────────────────── - socialspy: - description: Private Nachrichten mitlesen (Admin) - usage: /socialspy - aliases: [spy] - - # ── ChatModule – Reload ─────────────────────────────────── - chatreload: - description: Chat-Konfiguration neu laden - usage: /chatreload - - # ── ChatModule – Admin-Info ─────────────────────────────── - chatinfo: - description: Chat-Informationen ueber einen Spieler anzeigen (Admin) - usage: /chatinfo - - # ── ChatModule – Chat-History ───────────────────────────── - chathist: - description: Chat-History aus dem Logfile anzeigen (Admin) - usage: /chathist [Spieler] [Anzahl] - - # ── ChatModule – Mentions ───────────────────────────────── - mentions: - description: Mention-Benachrichtigungen ein-/ausschalten - usage: /mentions - aliases: [mention] - - # ── ChatModule – Plugin-Bypass ──────────────────────────── - chatbypass: - description: ChatModule fuer naechste Eingabe ueberspringen (fuer Plugin-Dialoge wie CMI) - usage: /chatbypass - aliases: [cbp] - - # ── ChatModule – Account-Verknuepfung ───────────────────── - linkdiscord: - description: Minecraft-Account mit Discord verknuepfen - usage: /linkdiscord - aliases: [discordlink] - - linktelegram: - description: Minecraft-Account mit Telegram verknuepfen - usage: /linktelegram - aliases: [telegramlink] - - unlink: - description: Account-Verknuepfung aufheben - usage: /unlink - - # ── ChatModule – Report ─────────────────────────────────── - report: - description: Spieler melden - usage: /report - - reports: - description: Offene Reports anzeigen (Admin) - usage: /reports [all] - - reportclose: - description: Report schliessen (Admin) - usage: /reportclose - -permissions: - # ── StatusAPI Core ──────────────────────────────────────── - statusapi.update.notify: - description: Erlaubt Update-Benachrichtigungen - default: op - - statusapi.netinfo: - description: Zugriff auf /netinfo - default: op - - statusapi.antibot: - description: Zugriff auf /antibot - default: op - - # ── ChatModule – Kanaele ────────────────────────────────── - chat.channel.local: - description: Zugang zum Local-Kanal - default: true - - chat.channel.trade: - description: Zugang zum Trade-Kanal - default: true - - chat.channel.staff: - description: Zugang zum Staff-Kanal - default: false - - # ── ChatModule – HelpOp ─────────────────────────────────── - chat.helpop.receive: - description: HelpOp-Nachrichten empfangen - default: false - - # ── ChatModule – Mute ───────────────────────────────────── - chat.mute: - description: Spieler muten / unmuten - default: false - - # ── ChatModule – Broadcast ──────────────────────────────── - chat.broadcast: - description: Broadcast-Nachrichten senden - default: false - - # ── ChatModule – Social Spy ─────────────────────────────── - chat.socialspy: - description: Private Nachrichten mitlesen - default: false - - # ── ChatModule – Admin ──────────────────────────────────── - chat.admin.bypass: - description: Admin-Bypass - Kann nicht geblockt/gemutet werden - default: op - - chat.admin.notify: - description: Benachrichtigungen ueber Mutes und Blocks erhalten - default: false - - # ── ChatModule – Report ─────────────────────────────────── - chat.report: - description: Spieler reporten (/report) - default: true - - # ── ChatModule – Farben ─────────────────────────────────── - chat.color: - description: Farbcodes (&a, &b, ...) im Chat nutzen - default: false - - chat.color.format: - description: Formatierungen (&l, &o, &n, ...) im Chat nutzen - default: false - - # ── ChatModule – Filter ─────────────────────────────────── - chat.filter.bypass: - description: Chat-Filter (Anti-Spam, Caps, Blacklist) umgehen - default: false \ No newline at end of file +name: StatusAPIBridge +version: 1.0.0 +main: net.viper.statusapibridge.StatusAPIBridge +api-version: 1.21 +description: Sendet Vault-Economy-Daten an die BungeeCord StatusAPI +authors: [Viper] +softdepend: [Vault]