Update from Git Manager GUI

This commit is contained in:
2026-01-21 00:32:53 +01:00
parent bce695829e
commit 5303cbcb95
10 changed files with 696 additions and 130 deletions

View File

@@ -1,8 +1,14 @@
package net.viper.status;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.config.ListenerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin;
import net.viper.status.module.ModuleManager;
import net.viper.status.stats.PlayerStats;
@@ -12,15 +18,15 @@ import net.viper.status.modules.globalchat.GlobalChatModule;
import net.viper.status.modules.navigation.NavigationModule;
import net.viper.status.modules.commandblocker.CommandBlockerModule;
import net.viper.status.modules.broadcast.BroadcastModule;
import net.viper.status.modules.AutoMessage.AutoMessageModule;
import net.viper.status.modules.customcommands.CustomCommandModule;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.net.ServerSocket;
@@ -29,24 +35,31 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.TimeUnit;
import net.md_5.bungee.event.EventHandler;
/**
* StatusAPI - zentraler Bungee HTTP-Status- und Broadcast-Endpunkt
*/
public class StatusAPI extends Plugin implements Runnable {
public class StatusAPI extends Plugin implements Runnable, Listener {
private Thread thread;
private int port = 9191;
private ModuleManager moduleManager;
private UpdateChecker updateChecker;
private FileDownloader fileDownloader;
private Properties verifyProperties;
// Speicher für Updates beim Join
private boolean updatePending = false;
private String latestVersionString = "";
private final Set<UUID> informedAdmins = new HashSet<>();
@Override
public void onEnable() {
getLogger().info("StatusAPI Core wird initialisiert...");
// Event Listener registrieren
getProxy().getPluginManager().registerListener(this, this);
if (!getDataFolder().exists()) {
getDataFolder().mkdirs();
}
@@ -63,6 +76,16 @@ public class StatusAPI extends Plugin implements Runnable {
moduleManager.registerModule(new NavigationModule());
moduleManager.registerModule(new BroadcastModule());
moduleManager.registerModule(new CommandBlockerModule());
moduleManager.registerModule(new AutoMessageModule());
// CustomCommandModule nur laden, wenn aktiviert
boolean customCommandsEnabled = Boolean.parseBoolean(getVerifyProperties().getProperty("customcommands.enabled", "false"));
if (customCommandsEnabled) {
moduleManager.registerModule(new CustomCommandModule()); // Korrigiert: Kein Argument im Konstruktor
getLogger().info("CustomCommandModule aktiviert.");
} else {
getLogger().info("CustomCommandModule deaktiviert (siehe verify.properties).");
}
moduleManager.enableAll(this);
@@ -71,22 +94,114 @@ public class StatusAPI extends Plugin implements Runnable {
thread = new Thread(this, "StatusAPI-HTTP-Server");
thread.start();
// Update System
String currentVersion = getDescription() != null ? getDescription().getVersion() : "0.0.0";
updateChecker = new UpdateChecker(this, currentVersion, 6);
fileDownloader = new FileDownloader(this);
// Einfacher Update-Check (Nur Benachrichtigung für Admins beim Start oder beim Join)
checkForUpdatesAndNotify();
}
File pluginFile = getFile();
File backupFile = new File(pluginFile.getParentFile(), "StatusAPI.jar.bak");
if (backupFile.exists()) {
ProxyServer.getInstance().getScheduler().schedule(this, () -> {
if (backupFile.exists()) backupFile.delete();
},1, TimeUnit.MINUTES);
@EventHandler
public void onPlayerJoin(PostLoginEvent event) {
ProxiedPlayer player = event.getPlayer();
// Wir prüfen hier nur, ob ein Update aussteht. Der Rest wird im Scheduler verzögert geprüft.
if (updatePending && isAdmin(player)) {
// Verzögerung um 2 Sekunden
getProxy().getScheduler().schedule(this, () -> {
// Prüfen, ob Spieler noch online ist und noch nicht informiert wurde
if (player.isConnected() && !informedAdmins.contains(player.getUniqueId()) && isAdmin(player)) {
sendStyledUpdateMessage(player);
informedAdmins.add(player.getUniqueId());
getLogger().info("Admin " + player.getName() + " wurde über das neue Update informiert.");
}
}, 2, TimeUnit.SECONDS);
}
}
checkAndMaybeUpdate();
ProxyServer.getInstance().getScheduler().schedule(this, this::checkAndMaybeUpdate, 6, 6, TimeUnit.HOURS);
/**
* Sendet eine formatierte Nachricht mit klickbarem Link.
*/
private void sendStyledUpdateMessage(ProxiedPlayer player) {
String currentVersion = getDescription() != null ? getDescription().getVersion() : "Unbekannt";
String downloadUrl = "https://git.viper.ipv64.net/M_Viper/StatusAPI/releases";
ComponentBuilder builder = new ComponentBuilder("");
// Zeile 1: Update Info
// Wir konvertieren Legacy-Strings zu BaseComponents und fügen sie an den Builder an
builder.append(TextComponent.fromLegacyText("§a[StatusAPI] "))
.append(TextComponent.fromLegacyText("§eEine neue Version ist verfügbar: "))
.append(TextComponent.fromLegacyText("§c" + latestVersionString))
.append(TextComponent.fromLegacyText(" §7(Deine Version: "))
.append(TextComponent.fromLegacyText("§c" + currentVersion))
.append(TextComponent.fromLegacyText("§7)\n"));
// Zeile 2: Download
builder.append(TextComponent.fromLegacyText("§7Download: "));
// Der Klickbare Teil
TextComponent link = new TextComponent("§e§nLink");
link.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, downloadUrl));
link.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.fromLegacyText("§aKlicke hier um die Release-Seite zu öffnen")));
builder.append(link);
// Korrektur: Nur die Components senden, nicht den Spieler als Argument
player.sendMessage(builder.create());
}
/**
* Überprüft auf Updates und benachrichtigt Spieler mit Admin-Rechten (OP/Owner).
*/
private void checkForUpdatesAndNotify() {
String currentVersion = getDescription() != null ? getDescription().getVersion() : "0.0.0";
// Der UpdateChecker wird nur lokal instanziiert für den Check
UpdateChecker checker = new UpdateChecker(this, currentVersion, 6);
try {
checker.checkNow();
if (checker.isUpdateAvailable(currentVersion)) {
String newVersion = checker.getLatestVersion();
String url = checker.getLatestUrl();
getLogger().warning("------------------------------------------------");
getLogger().warning("Neue Version verfügbar: " + newVersion);
getLogger().warning("Aktuelle Version: " + currentVersion);
getLogger().warning("Download: " + url);
getLogger().warning("------------------------------------------------");
// Info speichern (nur Version, URL ist statisch für den Chat-Link)
this.updatePending = true;
this.latestVersionString = newVersion;
// Benachrichtigung an online Admins / OPs (mit Verzögerung, um konsistent mit Join zu sein)
boolean notifiedSomeone = false;
for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) {
if (isAdmin(p)) {
final ProxiedPlayer player = p;
getProxy().getScheduler().schedule(this, () -> {
if (player.isConnected() && !informedAdmins.contains(player.getUniqueId())) {
sendStyledUpdateMessage(player);
informedAdmins.add(player.getUniqueId());
}
}, 2, TimeUnit.SECONDS);
notifiedSomeone = true;
}
}
if (!notifiedSomeone) {
getLogger().info("Keine Admins waren online, um benachrichtigt zu werden. Sie werden beim Join informiert.");
}
} else {
getLogger().info("Keine Updates verfügbar.");
}
} catch (Exception e) {
getLogger().severe("Fehler beim Update-Check: " + e.getMessage());
}
}
// Hilfsmethode zum Prüfen von Admin-Rechten
private boolean isAdmin(ProxiedPlayer player) {
return player.hasPermission("statusapi.admin") || player.hasPermission("bungeecord.command.server");
}
@Override
@@ -190,8 +305,6 @@ public class StatusAPI extends Plugin implements Runnable {
"",
"# Beispiel: Deinen UUID hier einfügen",
"override.uuid-hier-einfügen = Owner",
"override.uuid-hier-einfügen-2 = Admin",
"override.uuid-hier-einfügen-3 = Developer",
"",
"# ===========================",
"# Chat-Formate für Gruppen",
@@ -209,10 +322,33 @@ public class StatusAPI extends Plugin implements Runnable {
"groupformat.spieler=&f[Spieler] || &7 || &8",
"",
"# ===========================",
"# AUTOMESSAGE",
"# ===========================",
"# Aktiviert den automatischen Nachrichten-Rundruf",
"automessage.enabled=false",
"",
"# Zeitintervall in Sekunden (Standard: 300 = 5 Minuten)",
"automessage.interval=300",
"",
"# Optional: Ein Prefix, das VOR jede Nachricht aus der Datei gesetzt wird.",
"# Wenn du das Prefix bereits IN der messages.txt hast, lass dieses Feld einfach leer.",
"automessage.prefix=",
"",
"# Der Name der Datei, in der die Nachrichten stehen (liegt im Plugin-Ordner)",
"automessage.file=messages.txt",
"",
"# ===========================",
"# COMMAND BLOCKER",
"# ===========================",
"commandblocker.enabled=true",
"commandblocker.bypass.permission=commandblocker.bypass"
"commandblocker.bypass.permission=commandblocker.bypass",
"",
"# ===========================",
"# CUSTOM COMMANDS",
"# ===========================",
"# Aktiviert das Modul für benutzerdefinierte Befehle und Aliases.",
"# Wenn aktiviert, wird die Datei 'customcommands.yml' geladen.",
"customcommands.enabled=true"
);
// 2. Existierende Werte einlesen
@@ -321,69 +457,6 @@ public class StatusAPI extends Plugin implements Runnable {
}
}
// --- Update Logik ---
private void checkAndMaybeUpdate() {
try {
updateChecker.checkNow();
String currentVersion = getDescription() != null ? getDescription().getVersion() : "0.0.0";
if (updateChecker.isUpdateAvailable(currentVersion)) {
String newVersion = updateChecker.getLatestVersion();
String url = updateChecker.getLatestUrl();
getLogger().warning("----------------------------------------");
getLogger().warning("Neue Version verfügbar: " + newVersion);
getLogger().warning("Starte automatisches Update...");
getLogger().warning("----------------------------------------");
File pluginFile = getFile();
File newFile = new File(pluginFile.getParentFile(), "StatusAPI.jar.new");
fileDownloader.downloadFile(url, newFile, () -> triggerUpdateScript(pluginFile, newFile));
}
} catch (Exception e) {
getLogger().severe("Fehler beim Update-Check: " + e.getMessage());
}
}
private void triggerUpdateScript(File currentFile, File newFile) {
try {
File pluginsFolder = currentFile.getParentFile();
File rootFolder = pluginsFolder.getParentFile();
File batFile = new File(rootFolder, "StatusAPI_Update_" + System.currentTimeMillis() + ".bat");
String batContent = "@echo off\n" +
"echo Bitte warten, der Server fährt herunter...\n" +
"timeout /t 5 /nobreak >nul\n" +
"cd /d \"" + pluginsFolder.getAbsolutePath().replace("\\", "/") + "\"\n" +
"echo Fuehre Datei-Tausch durch...\n" +
"if exist StatusAPI.jar.bak del StatusAPI.jar.bak\n" +
"if exist StatusAPI.jar (\n" +
" ren StatusAPI.jar StatusAPI.jar.bak\n" +
")\n" +
"if exist StatusAPI.new.jar (\n" +
" ren StatusAPI.new.jar StatusAPI.jar\n" +
" echo Update erfolgreich!\n" +
") else (\n" +
" echo FEHLER: StatusAPI.new.jar nicht gefunden!\n" +
" pause\n" +
")\n" +
"del \"%~f0\"";
try (PrintWriter out = new PrintWriter(batFile)) { out.println(batContent); }
for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) {
p.disconnect("§cServer fährt für ein Update neu herunter. Bitte etwas warten.");
}
getLogger().info("Starte Update-Skript...");
Runtime.getRuntime().exec("cmd /c start \"Update_Proc\" \"" + batFile.getAbsolutePath() + "\"");
ProxyServer.getInstance().stop();
} catch (Exception e) {
getLogger().severe("Fehler beim Vorbereiten des Updates: " + e.getMessage());
}
}
// --- WebServer & JSON ---
@Override
public void run() {