Upload folder via GUI - src

This commit is contained in:
Git Manager GUI
2026-04-03 05:19:16 +02:00
parent 7b96b7453a
commit eedcd95385
3 changed files with 291 additions and 1 deletions

View File

@@ -1,17 +1,24 @@
package de.viper.autoworldreset; package de.viper.autoworldreset;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.WorldCreator; import org.bukkit.WorldCreator;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.UUID;
public class ResetManager { public class ResetManager {
@@ -22,6 +29,11 @@ public class ResetManager {
} }
public void resetWorld() { public void resetWorld() {
if (!Bukkit.isPrimaryThread()) {
Bukkit.getScheduler().runTask(plugin, this::resetWorld);
return;
}
String worldName = plugin.getConfig().getString("world-name"); String worldName = plugin.getConfig().getString("world-name");
if (worldName == null || worldName.isEmpty()) { if (worldName == null || worldName.isEmpty()) {
@@ -29,6 +41,8 @@ public class ResetManager {
return; return;
} }
executeConfiguredCommands("pre-reset-commands", "Pre-Reset", worldName);
// BUG FIX #6: Die Backup-Prüfung wurde aus resetWorld() entfernt und korrekt // BUG FIX #6: Die Backup-Prüfung wurde aus resetWorld() entfernt und korrekt
// platziert. Zuvor wurde backup.enabled geprüft, um einen RESTORE abzubrechen // platziert. Zuvor wurde backup.enabled geprüft, um einen RESTORE abzubrechen
// das ist logisch falsch. Das Flag sollte nur das automatische Erstellen eines // das ist logisch falsch. Das Flag sollte nur das automatische Erstellen eines
@@ -37,7 +51,10 @@ public class ResetManager {
boolean success = restoreBackup(worldName); boolean success = restoreBackup(worldName);
if (!success) { if (!success) {
plugin.getLogger().warning("Reset fehlgeschlagen: Backup konnte nicht wiederhergestellt werden."); plugin.getLogger().warning("Reset fehlgeschlagen: Backup konnte nicht wiederhergestellt werden.");
return;
} }
executeConfiguredCommands("post-reset-commands", "Post-Reset", worldName);
} }
public boolean createBackup() { public boolean createBackup() {
@@ -156,6 +173,242 @@ public class ResetManager {
} }
} }
private void executeConfiguredCommands(String pathPrefix, String label, String worldName) {
if (!plugin.getConfig().getBoolean(pathPrefix + ".enabled", false)) return;
List<String> commands = plugin.getConfig().getStringList(pathPrefix + ".commands");
if (commands.isEmpty()) return;
String configuredHomeName = plugin.getConfig().getString("home-name", worldName);
String homeName = (configuredHomeName == null || configuredHomeName.isBlank())
? worldName
: configuredHomeName;
for (String command : commands) {
if (command.startsWith("@cmi-deletehomes-world")) {
String resolved = command
.replace("{world}", worldName)
.replace("{home}", homeName);
String[] parts = resolved.split("\\s+");
String targetWorld = parts.length >= 2 ? parts[1] : worldName;
plugin.getLogger().info("Führe " + label + "-Spezialbefehl aus: CMI Homes in Welt '" + targetWorld + "' löschen");
boolean success = deleteCmiHomesInWorldViaApi(targetWorld);
if (!success) {
plugin.getLogger().warning("CMI API-Löschung fehlgeschlagen. Prüfe, ob CMI geladen ist und Homes vorhanden sind.");
}
continue;
}
if (command.contains("{player}")) {
int executed = 0;
for (OfflinePlayer offlinePlayer : Bukkit.getOfflinePlayers()) {
if (!offlinePlayer.isOnline() && !offlinePlayer.hasPlayedBefore()) continue;
String playerName = offlinePlayer.getName();
if (playerName == null || playerName.isBlank()) continue;
String resolved = command
.replace("{world}", worldName)
.replace("{home}", homeName)
.replace("{player}", playerName);
plugin.getLogger().info("Führe " + label + "-Befehl aus: " + resolved);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), resolved);
executed++;
}
plugin.getLogger().info(label + "-Befehl mit {player} für " + executed + " Spieler ausgeführt.");
continue;
}
String resolved = command
.replace("{world}", worldName)
.replace("{home}", homeName);
plugin.getLogger().info("Führe " + label + "-Befehl aus: " + resolved);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), resolved);
}
}
private boolean deleteCmiHomesInWorldViaApi(String worldName) {
Plugin cmiPlugin = Bukkit.getPluginManager().getPlugin("CMI");
if (cmiPlugin == null || !cmiPlugin.isEnabled()) {
plugin.getLogger().warning("CMI ist nicht geladen oder nicht aktiv.");
return false;
}
try {
Class<?> cmiClass = Class.forName("com.Zrips.CMI.CMI");
Method getInstance = cmiClass.getMethod("getInstance");
Object cmiInstance = getInstance.invoke(null);
if (cmiInstance == null) return false;
Object playerManager = invokeNoArg(cmiInstance, "getPlayerManager");
if (playerManager == null) {
plugin.getLogger().warning("CMI PlayerManager konnte nicht gefunden werden.");
return false;
}
int removed = 0;
int checked = 0;
int usersCount = 0;
Map<String, Object> users = collectCmiUsers(playerManager);
for (Map.Entry<String, Object> entry : users.entrySet()) {
String playerName = entry.getKey();
Object user = entry.getValue();
if (playerName == null || playerName.isBlank() || user == null) continue;
usersCount++;
List<String> homesInWorld = getHomeNamesForWorld(user, worldName);
checked += homesInWorld.size();
for (String home : homesInWorld) {
String cmd = "cmi removehome " + home + " " + playerName;
boolean ok = Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd);
if (ok) removed++;
}
}
plugin.getLogger().info("CMI API: User geprüft=" + usersCount + ", Homes in Welt '" + worldName + "' gefunden=" + checked + ", entfernt=" + removed + ".");
return true;
} catch (Throwable t) {
plugin.getLogger().warning("CMI API-Integration fehlgeschlagen: " + t.getMessage());
return false;
}
}
private Map<String, Object> collectCmiUsers(Object playerManager) {
Map<String, Object> result = new LinkedHashMap<>();
// Primär: direkt aus CMI PlayerManager lesen (umfasst mehr als Bukkit Offline-Cache)
Object usersObj = invokeNoArg(playerManager, "getAllUsers");
if (usersObj == null) usersObj = invokeNoArg(playerManager, "getUsers");
if (usersObj == null) usersObj = invokeNoArg(playerManager, "getUsersMap");
if (usersObj instanceof Map<?, ?> map) {
for (Object value : map.values()) {
String name = extractCmiUserName(value);
if (name != null && !name.isBlank()) {
result.putIfAbsent(name, value);
}
}
} else if (usersObj instanceof Collection<?> collection) {
for (Object value : collection) {
String name = extractCmiUserName(value);
if (name != null && !name.isBlank()) {
result.putIfAbsent(name, value);
}
}
}
// Fallback: Bukkit OfflinePlayer durchprobieren
for (OfflinePlayer offlinePlayer : Bukkit.getOfflinePlayers()) {
if (!offlinePlayer.isOnline() && !offlinePlayer.hasPlayedBefore()) continue;
String playerName = offlinePlayer.getName();
if (playerName == null || playerName.isBlank() || result.containsKey(playerName)) continue;
Object user = getCmiUser(playerManager, offlinePlayer, playerName);
if (user != null) {
result.put(playerName, user);
}
}
return result;
}
private String extractCmiUserName(Object cmiUser) {
if (cmiUser == null) return null;
Object name = invokeNoArg(cmiUser, "getName");
if (name instanceof String s && !s.isBlank()) return s;
Object playerName = invokeNoArg(cmiUser, "getPlayerName");
if (playerName instanceof String s && !s.isBlank()) return s;
Object offline = invokeNoArg(cmiUser, "getOfflinePlayer");
if (offline instanceof OfflinePlayer op && op.getName() != null && !op.getName().isBlank()) {
return op.getName();
}
return null;
}
private Object getCmiUser(Object playerManager, OfflinePlayer offlinePlayer, String playerName) {
Object user = invokeOneArg(playerManager, "getUser", UUID.class, offlinePlayer.getUniqueId());
if (user != null) return user;
user = invokeOneArg(playerManager, "getUser", String.class, playerName);
if (user != null) return user;
return invokeOneArg(playerManager, "getUser", OfflinePlayer.class, offlinePlayer);
}
private List<String> getHomeNamesForWorld(Object cmiUser, String worldName) {
List<String> result = new ArrayList<>();
Object homesObj = invokeNoArg(cmiUser, "getHomes");
if (!(homesObj instanceof Map<?, ?> homesMap)) return result;
for (Map.Entry<?, ?> entry : homesMap.entrySet()) {
String homeName = String.valueOf(entry.getKey());
Object homeObj = entry.getValue();
if (homeName == null || homeName.isBlank() || homeObj == null) continue;
if (isHomeInWorld(homeObj, worldName)) {
result.add(homeName);
}
}
return result;
}
private boolean isHomeInWorld(Object homeObj, String worldName) {
String lowerWorld = worldName.toLowerCase();
Object worldNameObj = invokeNoArg(homeObj, "getWorldName");
if (worldNameObj instanceof String s && s.equalsIgnoreCase(worldName)) return true;
Object worldObj = invokeNoArg(homeObj, "getWorld");
if (worldObj instanceof World w && w.getName().equalsIgnoreCase(worldName)) return true;
if (worldObj instanceof String s && s.equalsIgnoreCase(worldName)) return true;
Object locationObj = invokeNoArg(homeObj, "getLoc");
if (locationObj == null) locationObj = invokeNoArg(homeObj, "getLocation");
if (locationObj != null) {
Object locWorld = invokeNoArg(locationObj, "getWorld");
if (locWorld instanceof World w && w.getName().equalsIgnoreCase(worldName)) return true;
Object locWorldName = invokeNoArg(locationObj, "getWorldName");
if (locWorldName instanceof String s && s.equalsIgnoreCase(worldName)) return true;
}
// Fallback: Einige CMI Home-Objekte enthalten den Weltnamen in toString().
return homeObj.toString().toLowerCase().contains(lowerWorld);
}
private Object invokeNoArg(Object target, String methodName) {
if (target == null) return null;
try {
Method method = target.getClass().getMethod(methodName);
method.setAccessible(true);
return method.invoke(target);
} catch (Throwable ignored) {
return null;
}
}
private Object invokeOneArg(Object target, String methodName, Class<?> argType, Object arg) {
if (target == null) return null;
try {
Method method = target.getClass().getMethod(methodName, argType);
method.setAccessible(true);
return method.invoke(target, arg);
} catch (Throwable ignored) {
return null;
}
}
private void deleteFolder(Path path) throws IOException { private void deleteFolder(Path path) throws IOException {
if (Files.notExists(path)) return; if (Files.notExists(path)) return;
if (Files.isDirectory(path)) { if (Files.isDirectory(path)) {

View File

@@ -1,6 +1,10 @@
# Weltname, die zurückgesetzt werden soll # Weltname, die zurückgesetzt werden soll
world-name: "world" world-name: "world"
# Home-Name für Home-Plugins (falls Home-Name nicht dem Weltnamen entspricht)
# Beispiel: Test-01 -> /cmi removehome Test-01 <spieler>
home-name: "world"
# Ob beim Serverstart automatisch ein Reset durchgeführt werden soll # Ob beim Serverstart automatisch ein Reset durchgeführt werden soll
auto-reset-on-startup: false auto-reset-on-startup: false
@@ -36,6 +40,38 @@ scheduler:
# "0 0 */6 * * ?" → Alle 6 Stunden # "0 0 */6 * * ?" → Alle 6 Stunden
cron: "0 0 4 * * ?" cron: "0 0 4 * * ?"
# Befehle, die VOR dem Reset als Konsole ausgeführt werden.
# Nützlich um z.B. Homes in der zurückgesetzten Welt zu löschen.
# Platzhalter: {world} = Name der Welt, die zurückgesetzt wird
# {home} = Home-Name aus 'home-name' (Fallback: {world})
# {player} = Spielername (Befehl wird für alle bekannten Spieler ausgeführt)
#
# Bekannte Befehle für verbreitete Home-Plugins:
# HuskHomes: "huskhomes delete homes {world}"
# Optional: "huskhomes delete homes {world} <server_name> confirm"
# UltimateHomes: "delhome {world}"
# Für alle bekannten Spieler: "delhome {player} {world}"
# CMI: "@cmi-deletehomes-world {world}"
# (interner Spezialbefehl von AutoWorldReset, löscht alle CMI-Homes in dieser Welt)
#
# Eigenen Befehl einfach eintragen wird als Konsole ausgeführt.
pre-reset-commands:
enabled: false
commands:
# - "huskhomes delete homes {world} confirm" # HuskHomes
# - "huskhomes delete homes {world} s1 confirm" # HuskHomes (mit Servername + confirm)
# - "uh deleteallhomesinworld {world}" # UltimateHomes Wichtig! der Befehl muss in der config von Ultimatehomes auf true gestellt werden, damit er funktioniert: enableDeleteAllHomesInWorldAdminCommand true
# - "cmi removehome {home} {player}" # CMI (besser in post-reset)
# Befehle, die NACH dem erfolgreichen Reset ausgeführt werden.
# Nützlich für Plugin-Reloads oder Cache-Refresh (z.B. Home-GUIs).
post-reset-commands:
enabled: false
commands:
# - "@cmi-deletehomes-world {world}" # CMI API: alle Homes dieser Welt löschen
# - "cmi saveall" # CMI Daten direkt persistent speichern
# - "cmi reload" # CMI Cache/GUI neu laden
# Nachrichten können vollständig in lang.yml angepasst werden. # Nachrichten können vollständig in lang.yml angepasst werden.
# lang.yml hat Vorrang vor den Werten hier. # lang.yml hat Vorrang vor den Werten hier.
messages: messages:

View File

@@ -1,9 +1,10 @@
name: AutoWorldReset name: AutoWorldReset
version: 1.2 version: 1.3
main: de.viper.autoworldreset.AutoWorldReset main: de.viper.autoworldreset.AutoWorldReset
api-version: 1.21 api-version: 1.21
description: Automatisches Welt-Reset Plugin mit Backup-System & Quartz Cron-Scheduler description: Automatisches Welt-Reset Plugin mit Backup-System & Quartz Cron-Scheduler
author: M_Viper author: M_Viper
softdepend: [CMI]
commands: commands:
autoworldreset: autoworldreset: