Update from Git Manager GUI
This commit is contained in:
@@ -1,42 +0,0 @@
|
||||
package net.viper.status;
|
||||
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class FileDownloader {
|
||||
private final Plugin plugin;
|
||||
|
||||
public FileDownloader(Plugin plugin) { this.plugin = plugin; }
|
||||
|
||||
public void downloadFile(String urlString, File destination, Runnable onSuccess) {
|
||||
plugin.getProxy().getScheduler().runAsync(plugin, () -> {
|
||||
BufferedInputStream bufferedInputStream = null;
|
||||
FileOutputStream fileOutputStream = null;
|
||||
try {
|
||||
URL url = new URL(urlString);
|
||||
bufferedInputStream = new BufferedInputStream(url.openStream());
|
||||
fileOutputStream = new FileOutputStream(destination);
|
||||
byte[] buffer = new byte[1024];
|
||||
int count;
|
||||
while ((count = bufferedInputStream.read(buffer, 0, 1024)) != -1) {
|
||||
fileOutputStream.write(buffer, 0, count);
|
||||
}
|
||||
fileOutputStream.close();
|
||||
bufferedInputStream.close();
|
||||
plugin.getProxy().getScheduler().schedule(plugin, onSuccess, 1, java.util.concurrent.TimeUnit.MILLISECONDS);
|
||||
} catch (Throwable e) {
|
||||
plugin.getLogger().warning("Download fehlgeschlagen: " + e.getMessage());
|
||||
if (destination.exists()) destination.delete();
|
||||
} finally {
|
||||
if (fileOutputStream != null) try { fileOutputStream.close(); } catch (IOException ignored) {}
|
||||
if (bufferedInputStream != null) try { bufferedInputStream.close(); } catch (IOException ignored) {}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PostLoginEvent event) {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
|
||||
if (backupFile.exists()) {
|
||||
ProxyServer.getInstance().getScheduler().schedule(this, () -> {
|
||||
if (backupFile.exists()) backupFile.delete();
|
||||
},1, TimeUnit.MINUTES);
|
||||
// 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() {
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
package net.viper.status.modules.AutoMessage;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.viper.status.module.Module;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class AutoMessageModule implements Module {
|
||||
|
||||
private int taskId = -1;
|
||||
|
||||
// Diese Methode fehlte bisher und ist zwingend für das Interface
|
||||
@Override
|
||||
public String getName() {
|
||||
return "AutoMessage";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable(Plugin plugin) {
|
||||
// Hier casten wir das Plugin-Objekt zu StatusAPI, um an spezifische Methoden zu kommen
|
||||
StatusAPI api = (StatusAPI) plugin;
|
||||
|
||||
// Konfiguration aus der zentralen verify.properties laden
|
||||
Properties props = api.getVerifyProperties();
|
||||
|
||||
boolean enabled = Boolean.parseBoolean(props.getProperty("automessage.enabled", "false"));
|
||||
|
||||
if (!enabled) {
|
||||
api.getLogger().info("AutoMessage-Modul ist deaktiviert.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Interval in Sekunden einlesen
|
||||
int intervalSeconds;
|
||||
try {
|
||||
intervalSeconds = Integer.parseInt(props.getProperty("automessage.interval", "300"));
|
||||
} catch (NumberFormatException e) {
|
||||
api.getLogger().warning("Ungültiges Intervall für AutoMessage! Nutze Standard (300s).");
|
||||
intervalSeconds = 300;
|
||||
}
|
||||
|
||||
// Dateiname einlesen (Standard: messages.txt)
|
||||
String fileName = props.getProperty("automessage.file", "messages.txt");
|
||||
File messageFile = new File(api.getDataFolder(), fileName);
|
||||
|
||||
if (!messageFile.exists()) {
|
||||
api.getLogger().warning("Die Datei '" + fileName + "' wurde nicht gefunden (" + messageFile.getAbsolutePath() + ")!");
|
||||
api.getLogger().info("Erstelle eine leere Datei '" + fileName + "' als Vorlage...");
|
||||
try {
|
||||
messageFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
api.getLogger().severe("Konnte Datei nicht erstellen: " + e.getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Nachrichten aus der Datei lesen
|
||||
List<String> messages;
|
||||
try {
|
||||
messages = Files.readAllLines(messageFile.toPath(), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
api.getLogger().severe("Fehler beim Lesen von '" + fileName + "': " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
// Leere Zeilen und Kommentare herausfiltern
|
||||
messages.removeIf(line -> line.trim().isEmpty() || line.trim().startsWith("#"));
|
||||
|
||||
if (messages.isEmpty()) {
|
||||
api.getLogger().warning("Die Datei '" + fileName + "' enthält keine gültigen Nachrichten!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Optional: Prefix aus Config lesen
|
||||
String prefixRaw = props.getProperty("automessage.prefix", "");
|
||||
String prefix = ChatColor.translateAlternateColorCodes('&', prefixRaw);
|
||||
|
||||
api.getLogger().info("Starte AutoMessage-Task (" + messages.size() + " Nachrichten aus " + fileName + ")");
|
||||
|
||||
// Finaler Index für den Lambda-Ausdruck
|
||||
final int[] currentIndex = {0};
|
||||
|
||||
// Task planen
|
||||
taskId = ProxyServer.getInstance().getScheduler().schedule(plugin, () -> {
|
||||
String msg = messages.get(currentIndex[0]);
|
||||
|
||||
String finalMessage = (prefix.isEmpty() ? "" : prefix + " ") + msg;
|
||||
|
||||
// Nachricht an alle auf dem Proxy senden
|
||||
ProxyServer.getInstance().broadcast(TextComponent.fromLegacy(finalMessage));
|
||||
|
||||
// Index erhöhen und Loop starten
|
||||
currentIndex[0] = (currentIndex[0] + 1) % messages.size();
|
||||
}, intervalSeconds, intervalSeconds, TimeUnit.SECONDS).getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable(Plugin plugin) {
|
||||
if (taskId != -1) {
|
||||
ProxyServer.getInstance().getScheduler().cancel(taskId);
|
||||
taskId = -1;
|
||||
plugin.getLogger().info("AutoMessage-Task gestoppt.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
package net.viper.status.modules.customcommands;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.CopyOption;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ChatEvent;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.api.plugin.Plugin; // Import für das Interface Argument
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
import net.md_5.bungee.config.ConfigurationProvider;
|
||||
import net.md_5.bungee.config.YamlConfiguration;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.viper.status.StatusAPI;
|
||||
import net.viper.status.module.Module;
|
||||
|
||||
public class CustomCommandModule implements Module, Listener {
|
||||
|
||||
private StatusAPI plugin;
|
||||
private Configuration config;
|
||||
private Command chatCommand;
|
||||
|
||||
public CustomCommandModule() {
|
||||
// Leerer Konstruktor
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CustomCommandModule";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable(Plugin plugin) {
|
||||
// Hier casten wir 'Plugin' zu 'StatusAPI', da wir wissen, dass es das ist
|
||||
this.plugin = (StatusAPI) plugin;
|
||||
|
||||
this.plugin.getLogger().info("Lade CustomCommandModule...");
|
||||
reloadConfig();
|
||||
|
||||
// /bcmds Reload Befehl registrieren
|
||||
this.plugin.getProxy().getPluginManager().registerCommand(this.plugin, new Command("bcmds") {
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if (!sender.hasPermission("statusapi.bcmds")) {
|
||||
sender.sendMessage(new TextComponent(ChatColor.RED + "You don't have permission."));
|
||||
} else {
|
||||
reloadConfig();
|
||||
sender.sendMessage(new TextComponent(ChatColor.GREEN + "Config reloaded."));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// /chat Befehl registrieren (falls aktiviert)
|
||||
if (config.getBoolean("chat-command", true)) {
|
||||
chatCommand = new Command("chat") {
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
if (sender instanceof ProxiedPlayer) {
|
||||
ProxiedPlayer player = (ProxiedPlayer) sender;
|
||||
String msg = String.join(" ", args);
|
||||
ChatEvent e = new ChatEvent(player, player.getServer(), msg);
|
||||
ProxyServer.getInstance().getPluginManager().callEvent(e);
|
||||
if (!e.isCancelled()) {
|
||||
if (!e.isCommand() || !ProxyServer.getInstance().getPluginManager().dispatchCommand(sender, msg.substring(1))) {
|
||||
player.chat(msg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String msg = String.join(" ", args);
|
||||
if(msg.startsWith("/")) {
|
||||
ProxyServer.getInstance().getPluginManager().dispatchCommand(sender, msg.substring(1));
|
||||
} else {
|
||||
sender.sendMessage(new TextComponent("Console cannot send chat messages via /chat usually."));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
this.plugin.getProxy().getPluginManager().registerCommand(this.plugin, chatCommand);
|
||||
}
|
||||
|
||||
this.plugin.getProxy().getPluginManager().registerListener(this.plugin, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable(Plugin plugin) {
|
||||
// Optional: Cleanup logic, falls nötig.
|
||||
// Wir nutzen hier das übergebene 'plugin' Argument (oder this.plugin, ist egal)
|
||||
// Listener und Commands werden automatisch entfernt, wenn das Plugin stoppt.
|
||||
}
|
||||
|
||||
public void reloadConfig() {
|
||||
try {
|
||||
if (!this.plugin.getDataFolder().exists()) {
|
||||
this.plugin.getDataFolder().mkdirs();
|
||||
}
|
||||
File file = new File(this.plugin.getDataFolder(), "customcommands.yml");
|
||||
if (!file.exists()) {
|
||||
// Kopieren aus Resources
|
||||
Files.copy(this.plugin.getResourceAsStream("customcommands.yml"), file.toPath(), new CopyOption[0]);
|
||||
}
|
||||
this.config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(file);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
this.plugin.getLogger().severe("Konnte customcommands.yml nicht laden!");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = 64)
|
||||
public void onCommand(ChatEvent e) {
|
||||
if (!e.isCommand()) return;
|
||||
if (!(e.getSender() instanceof ProxiedPlayer)) return;
|
||||
|
||||
final ProxiedPlayer player = (ProxiedPlayer) e.getSender();
|
||||
String[] split = e.getMessage().split(" ");
|
||||
String label = split[0].substring(1);
|
||||
|
||||
final List<String> args = new ArrayList<>(Arrays.asList(split));
|
||||
args.remove(0);
|
||||
|
||||
Configuration cmds = config.getSection("commands");
|
||||
if (cmds == null) return;
|
||||
|
||||
Configuration section = null;
|
||||
String foundKey = null;
|
||||
|
||||
for (String key : cmds.getKeys()) {
|
||||
Configuration cmdSection = cmds.getSection(key);
|
||||
if (key.equalsIgnoreCase(label)) {
|
||||
section = cmdSection;
|
||||
foundKey = key;
|
||||
break;
|
||||
}
|
||||
for (String alias : cmdSection.getStringList("aliases")) {
|
||||
if (alias.equalsIgnoreCase(label)) {
|
||||
section = cmdSection;
|
||||
foundKey = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (section != null) break;
|
||||
}
|
||||
|
||||
if (section == null) return;
|
||||
|
||||
String type = section.getString("type", "line");
|
||||
String sendertype = section.getString("sender", "default");
|
||||
String permission = section.getString("permission", "");
|
||||
final List<String> commands = section.getStringList("commands");
|
||||
|
||||
if (!permission.isEmpty() && !player.hasPermission(permission)) {
|
||||
player.sendMessage(new TextComponent(ChatColor.RED + "You don't have permission."));
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
e.setCancelled(true);
|
||||
|
||||
final CommandSender target;
|
||||
if (sendertype.equals("default")) {
|
||||
target = player;
|
||||
} else if (sendertype.equals("admin")) {
|
||||
target = new ForwardSender(player, true);
|
||||
} else if (sendertype.equals("console")) {
|
||||
target = ProxyServer.getInstance().getConsole();
|
||||
} else {
|
||||
ProxiedPlayer targetPlayer = ProxyServer.getInstance().getPlayer(sendertype);
|
||||
if (targetPlayer == null || !targetPlayer.isConnected()) {
|
||||
player.sendMessage(new TextComponent(ChatColor.RED + "Player " + sendertype + " is not online."));
|
||||
return;
|
||||
}
|
||||
target = targetPlayer;
|
||||
}
|
||||
|
||||
String argsString = args.size() >= 1 ? String.join(" ", args) : "";
|
||||
final String finalArgs = argsString;
|
||||
final String senderName = player.getName();
|
||||
|
||||
if (type.equals("random")) {
|
||||
int randomIndex = new Random().nextInt(commands.size());
|
||||
String rawCommand = commands.get(randomIndex);
|
||||
executeCommand(target, rawCommand, finalArgs, senderName);
|
||||
} else if (type.equals("line")) {
|
||||
ProxyServer.getInstance().getScheduler().runAsync(this.plugin, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (String rawCommand : commands) {
|
||||
executeCommand(target, rawCommand, finalArgs, senderName);
|
||||
try {
|
||||
Thread.sleep(100L);
|
||||
} catch (InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.plugin.getLogger().warning("Unknown type '" + type + "' for command " + foundKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeCommand(CommandSender sender, String rawCommand, String args, String playerName) {
|
||||
String parsed = rawCommand
|
||||
.replaceAll("%args%", args)
|
||||
.replaceAll("%sender%", playerName);
|
||||
|
||||
String commandToDispatch = parsed.startsWith("/") ? parsed.substring(1) : parsed;
|
||||
ProxyServer.getInstance().getPluginManager().dispatchCommand(sender, commandToDispatch);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package net.viper.status.modules.customcommands;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collection;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.connection.Connection;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.connection.Connection.Unsafe;
|
||||
|
||||
public class ForwardSender implements CommandSender, Connection {
|
||||
private ProxiedPlayer target;
|
||||
private Boolean admin;
|
||||
|
||||
public ForwardSender(ProxiedPlayer sender, Boolean admin) {
|
||||
this.target = sender;
|
||||
this.admin = admin;
|
||||
}
|
||||
|
||||
public ProxiedPlayer target() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.target.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String message) {
|
||||
this.target.sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessages(String... messages) {
|
||||
this.target.sendMessages(messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(BaseComponent... message) {
|
||||
this.target.sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(BaseComponent message) {
|
||||
this.target.sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getGroups() {
|
||||
return this.target.getGroups();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addGroups(String... groups) {
|
||||
this.target.addGroups(groups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroups(String... groups) {
|
||||
this.target.removeGroups(groups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
return this.admin ? true : this.target.hasPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(String permission, boolean value) {
|
||||
this.target.setPermission(permission, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getPermissions() {
|
||||
Collection<String> perms = this.target.getPermissions();
|
||||
if (this.admin) {
|
||||
perms.add("*");
|
||||
}
|
||||
return perms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getAddress() {
|
||||
return this.target.getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getSocketAddress() {
|
||||
return this.target.getSocketAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(String reason) {
|
||||
this.target.disconnect(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(BaseComponent... reason) {
|
||||
this.target.disconnect(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(BaseComponent reason) {
|
||||
this.target.disconnect(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return this.target.isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Unsafe unsafe() {
|
||||
return this.target.unsafe();
|
||||
}
|
||||
}
|
||||
41
src/main/resources/customcommands.yml
Normal file
41
src/main/resources/customcommands.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
# If you want to enable /chat
|
||||
chat-command: true
|
||||
# The commands
|
||||
commands:
|
||||
test:
|
||||
aliases:
|
||||
- test2
|
||||
permission: ""
|
||||
type: random
|
||||
sender: default
|
||||
commands:
|
||||
- "alert Das ist ein Random Test Befehl!"
|
||||
- "glist"
|
||||
anothercommand:
|
||||
aliases:
|
||||
- thisisacommand
|
||||
permission: "myplugin.mypermission"
|
||||
type: line
|
||||
sender: default
|
||||
commands:
|
||||
- "alert Hello World!"
|
||||
- "alert How're you?"
|
||||
- "alert I'd like to tell you that %args%"
|
||||
# - "test" # Vorsicht: Rekursion, falls 'test' in dieser Liste steht und 'test' selbst definiert ist
|
||||
sudo:
|
||||
aliases:
|
||||
- runasadmin
|
||||
permission: "commands.sudo"
|
||||
type: line
|
||||
sender: admin
|
||||
commands:
|
||||
- "alert Running as Admin: %args%"
|
||||
- "%args%"
|
||||
something:
|
||||
aliases:
|
||||
- anything
|
||||
permission: "some.permission"
|
||||
type: line
|
||||
sender: console
|
||||
commands:
|
||||
- "alert %sender% would like to say that %args%"
|
||||
18
src/main/resources/messages.txt
Normal file
18
src/main/resources/messages.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
§8[§2Viper-Netzwerk§8] §7Der Server läuft 24/7 – also keine Hektik beim Spielen :)
|
||||
§8[§2Viper-Netzwerk§8] §7Dies ist ein privater Server – hier zählt der Zusammenhalt.
|
||||
§8[§dTipp§8] §7Wenn du denkst, du bist sicher… schau nochmal nach. Creeper machen keine Geräusche beim Tippen.
|
||||
§8[§2Viper-Netzwerk§8] §7Wähle einen Server, leg los – der Rest ergibt sich. Oder explodiert.
|
||||
§8[§2Viper-Netzwerk§8] §7Mehr Server. Mehr Blöcke. Mehr Unfälle. Willkommen!
|
||||
§8[§dTipp§8] §7Halte eine Spitzhacke mit Glück bereit. Man weiß nie, wann das nächste Erz kommt.
|
||||
§8[§dTipp§8] §7Mit §e/home§7 kannst du dich jederzeit nach Hause teleportieren.
|
||||
§8[§2Viper-Netzwerk§8] §7Das wichtigste Plugin? Du selbst. Spiel fair, sei kreativ!
|
||||
§8[§2Viper-Netzwerk§8] §7Redstone ist keine Magie – aber fast.
|
||||
§8[§dTipp§8] §7Schilde sind cool. Besonders wenn Skelette zielen.
|
||||
§8[§2Viper-Netzwerk§8] §7Wenn du in Lava fällst, bist du nicht der Erste. Nur der Nächste.
|
||||
§8[§dTipp§8] §7Villager sind nicht dumm – nur sehr… eigen.
|
||||
§8[§2Viper-Netzwerk§8] §7Bau groß, bau sicher – oder bau eine Treppe zur Nachbarschaftsklage.
|
||||
§8[§2Viper-Netzwerk§8] §7Gras wächst. Spieler auch. Gib jedem eine Chance!
|
||||
§8[§2Viper-Netzwerk§8] §7Ein Creeper ist keine Begrüßung. Es sei denn, du willst es spannend machen.
|
||||
§8[§dTipp§8] §7Ein voller Magen ist halbe Miete. Farmen lohnt sich!
|
||||
§8[§2Viper-Netzwerk§8] §7Wir haben keine Probleme – nur Redstone-Schaltungen mit Charakter.
|
||||
§8[§dTipp§8] §7Markiere dein Grundstück mit §e/p claim§7, bevor es jemand anderes tut!
|
||||
@@ -1,6 +1,6 @@
|
||||
name: StatusAPI
|
||||
main: net.viper.status.StatusAPI
|
||||
version: 4.0.6
|
||||
version: 4.0.8
|
||||
author: M_Viper
|
||||
description: StatusAPI für BungeeCord inkl. Update-Checker und Modul-System
|
||||
|
||||
|
||||
@@ -64,8 +64,6 @@ server.skyblock.secret=GeheimesWortFuerSkyBlock789
|
||||
|
||||
# Beispiel: Deinen UUID hier einfügen
|
||||
override.uuid-hier-einfügen = Owner
|
||||
override.uuid-hier-einfügen = Admin
|
||||
override.uuid-hier-einfügen = Developer
|
||||
|
||||
# ===========================
|
||||
# Chat-Formate für Gruppen
|
||||
@@ -82,8 +80,31 @@ groupformat.developer=&b[Dev] || &3 || &a
|
||||
groupformat.premium=&6[Premium] || &e || &7
|
||||
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
|
||||
|
||||
# ===========================
|
||||
# CUSTOM COMMANDS
|
||||
# ===========================
|
||||
# Aktiviert das Modul für benutzerdefinierte Befehle und Aliases.
|
||||
# Wenn aktiviert, wird die Datei 'customcommands.yml' geladen.
|
||||
customcommands.enabled=true
|
||||
@@ -63,7 +63,7 @@ server.skyblock.secret=GeheimesWortFuerSkyBlock789
|
||||
# WICHTIG: Die Gruppe (z.B. Owner) muss unten bei groupformat definiert sein!
|
||||
|
||||
# Beispiel: Deinen UUID hier einfügen
|
||||
# override.uuid-hier-einfügen = Owner
|
||||
override.uuid-hier-einfügen = Owner
|
||||
|
||||
|
||||
# ===========================
|
||||
|
||||
Reference in New Issue
Block a user