Upload folder via GUI - src
This commit is contained in:
@@ -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)) {
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user