|
|
|
@@ -42,7 +42,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
private FileConfiguration config;
|
|
|
|
private FileConfiguration config;
|
|
|
|
private final Map<UUID, Map<Material, Long>> fullChestMessageTracker = new HashMap<>();
|
|
|
|
private final Map<UUID, Map<Material, Long>> fullChestMessageTracker = new HashMap<>();
|
|
|
|
private static final long MESSAGE_COOLDOWN = 5 * 60 * 1000; // 5 Minuten in Millisekunden
|
|
|
|
private static final long MESSAGE_COOLDOWN = 5 * 60 * 1000; // 5 Minuten in Millisekunden
|
|
|
|
private static final String CONFIG_VERSION = "1.5";
|
|
|
|
private static final String CONFIG_VERSION = "1.6"; // Version erhöht für das Update
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public void onEnable() {
|
|
|
|
public void onEnable() {
|
|
|
|
@@ -83,6 +83,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
updateConfig();
|
|
|
|
updateConfig();
|
|
|
|
updateExistingSigns();
|
|
|
|
updateExistingSigns();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ERWEITERUNG: Migration alter Daten in das neue Listen-System
|
|
|
|
|
|
|
|
migrateInputChests();
|
|
|
|
|
|
|
|
|
|
|
|
// ASCII ART LOGO
|
|
|
|
// ASCII ART LOGO
|
|
|
|
getLogger().info("");
|
|
|
|
getLogger().info("");
|
|
|
|
getLogger().info(" ___ _ _____ _ _____ _ _ ");
|
|
|
|
getLogger().info(" ___ _ _____ _ _____ _ _ ");
|
|
|
|
@@ -102,7 +105,13 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
getLogger().info("AutoSortChest Plugin deaktiviert!");
|
|
|
|
getLogger().info("AutoSortChest Plugin deaktiviert!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- NEUE HILFSMETHODE FÜR DOPPELTRUHEN ---
|
|
|
|
// --- NEU: Admin Prüfung ---
|
|
|
|
|
|
|
|
private boolean isAdmin(Player player) {
|
|
|
|
|
|
|
|
return player.isOp() || player.hasPermission("autosortchest.admin");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- HILFSMETHODE FÜR DOPPELTRUHEN ---
|
|
|
|
private List<Block> getChestBlocks(Chest chest) {
|
|
|
|
private List<Block> getChestBlocks(Chest chest) {
|
|
|
|
List<Block> blocks = new ArrayList<>();
|
|
|
|
List<Block> blocks = new ArrayList<>();
|
|
|
|
InventoryHolder holder = chest.getInventory().getHolder();
|
|
|
|
InventoryHolder holder = chest.getInventory().getHolder();
|
|
|
|
@@ -417,6 +426,55 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- ERWEITERUNG: Hilfsmethode zum Laden von Location aus einem beliebigen Pfad ---
|
|
|
|
|
|
|
|
private Location getLocationFromPath(String path) {
|
|
|
|
|
|
|
|
String worldName = playerData.getString(path + ".world");
|
|
|
|
|
|
|
|
World world = getServer().getWorld(worldName);
|
|
|
|
|
|
|
|
if (world == null) return null;
|
|
|
|
|
|
|
|
int x = playerData.getInt(path + ".x");
|
|
|
|
|
|
|
|
int y = playerData.getInt(path + ".y");
|
|
|
|
|
|
|
|
int z = playerData.getInt(path + ".z");
|
|
|
|
|
|
|
|
return new Location(world, x, y, z);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- ERWEITERUNG: Methode zum Migrieren alter Daten ---
|
|
|
|
|
|
|
|
private void migrateInputChests() {
|
|
|
|
|
|
|
|
if (playerData.getConfigurationSection("players") == null) return;
|
|
|
|
|
|
|
|
boolean migrated = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (String uuidString : playerData.getConfigurationSection("players").getKeys(false)) {
|
|
|
|
|
|
|
|
String oldPath = "players." + uuidString + ".input-chest";
|
|
|
|
|
|
|
|
// Prüfen, ob der alte Eintrag existiert
|
|
|
|
|
|
|
|
if (playerData.contains(oldPath)) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
UUID uuid = UUID.fromString(uuidString);
|
|
|
|
|
|
|
|
String world = playerData.getString(oldPath + ".world");
|
|
|
|
|
|
|
|
int x = playerData.getInt(oldPath + ".x");
|
|
|
|
|
|
|
|
int y = playerData.getInt(oldPath + ".y");
|
|
|
|
|
|
|
|
int z = playerData.getInt(oldPath + ".z");
|
|
|
|
|
|
|
|
World w = Bukkit.getWorld(world);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (w != null) {
|
|
|
|
|
|
|
|
Location loc = new Location(w, x, y, z);
|
|
|
|
|
|
|
|
// Neue Methode aufrufen, die in die Liste speichert
|
|
|
|
|
|
|
|
addInputChestLocation(uuid, loc);
|
|
|
|
|
|
|
|
// Alten Eintrag löschen
|
|
|
|
|
|
|
|
playerData.set(oldPath, null);
|
|
|
|
|
|
|
|
migrated = true;
|
|
|
|
|
|
|
|
getLogger().info("Eingangstruhe für Spieler " + uuidString + " in neues System migriert.");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
|
|
|
|
getLogger().warning("Ungültige UUID beim Migrieren: " + uuidString);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (migrated) {
|
|
|
|
|
|
|
|
savePlayerData();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
private void updateExistingSigns() {
|
|
|
|
private void updateExistingSigns() {
|
|
|
|
if (playerData == null) {
|
|
|
|
if (playerData == null) {
|
|
|
|
getLogger().warning("playerData ist null. Kann bestehende Schilder nicht aktualisieren.");
|
|
|
|
getLogger().warning("playerData ist null. Kann bestehende Schilder nicht aktualisieren.");
|
|
|
|
@@ -436,27 +494,28 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String path = "players." + uuidString;
|
|
|
|
String basePath = "players." + uuidString;
|
|
|
|
|
|
|
|
|
|
|
|
// Eingangstruhe
|
|
|
|
// --- ERWEITERUNG: Eingangstruhe (Jetzt Liste) ---
|
|
|
|
String inputPath = path + ".input-chest";
|
|
|
|
String inputListPath = basePath + ".input-chests";
|
|
|
|
if (playerData.contains(inputPath)) {
|
|
|
|
// Fallback für altes Format (sollte durch Migration eigentlich weg sein, aber zur Sicherheit)
|
|
|
|
String worldName = playerData.getString(inputPath + ".world");
|
|
|
|
String oldInputPath = basePath + ".input-chest";
|
|
|
|
World world = getServer().getWorld(worldName);
|
|
|
|
|
|
|
|
if (world == null) {
|
|
|
|
List<Location> inputLocs = new ArrayList<>();
|
|
|
|
getLogger().warning("Welt " + worldName + " für Eingangstruhe von Spieler UUID " + uuidString + " nicht gefunden");
|
|
|
|
|
|
|
|
continue;
|
|
|
|
if (playerData.contains(inputListPath)) {
|
|
|
|
|
|
|
|
for (String chestId : playerData.getConfigurationSection(inputListPath).getKeys(false)) {
|
|
|
|
|
|
|
|
Location loc = getLocationFromPath(inputListPath + "." + chestId);
|
|
|
|
|
|
|
|
if (loc != null) inputLocs.add(loc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int x = playerData.getInt(inputPath + ".x");
|
|
|
|
} else if (playerData.contains(oldInputPath)) {
|
|
|
|
int y = playerData.getInt(inputPath + ".y");
|
|
|
|
Location loc = getLocationFromPath(oldInputPath);
|
|
|
|
int z = playerData.getInt(inputPath + ".z");
|
|
|
|
if (loc != null) inputLocs.add(loc);
|
|
|
|
Location chestLocation = new Location(world, x, y, z);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (Location chestLocation : inputLocs) {
|
|
|
|
Block chestBlock = chestLocation.getBlock();
|
|
|
|
Block chestBlock = chestLocation.getBlock();
|
|
|
|
|
|
|
|
if (!(chestBlock.getState() instanceof Chest)) continue;
|
|
|
|
if (!(chestBlock.getState() instanceof Chest)) {
|
|
|
|
|
|
|
|
getLogger().warning("Eingangstruhe bei " + chestLocation + " ist keine Truhe");
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<Block> blocks = getChestBlocks((Chest) chestBlock.getState());
|
|
|
|
List<Block> blocks = getChestBlocks((Chest) chestBlock.getState());
|
|
|
|
for (Block b : blocks) {
|
|
|
|
for (Block b : blocks) {
|
|
|
|
@@ -484,22 +543,16 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
// Zieltruhen
|
|
|
|
// Zieltruhen
|
|
|
|
String targetPath = path + ".target-chests";
|
|
|
|
String targetPath = basePath + ".target-chests";
|
|
|
|
if (playerData.contains(targetPath)) {
|
|
|
|
if (playerData.contains(targetPath)) {
|
|
|
|
for (String itemType : playerData.getConfigurationSection(targetPath).getKeys(false)) {
|
|
|
|
for (String itemType : playerData.getConfigurationSection(targetPath).getKeys(false)) {
|
|
|
|
String targetChestPath = targetPath + "." + itemType;
|
|
|
|
String targetChestPath = targetPath + "." + itemType;
|
|
|
|
String worldName = playerData.getString(targetChestPath + ".world");
|
|
|
|
Location chestLocation = getLocationFromPath(targetChestPath);
|
|
|
|
World world = getServer().getWorld(worldName);
|
|
|
|
if (chestLocation == null) continue;
|
|
|
|
if (world == null) {
|
|
|
|
|
|
|
|
getLogger().warning("Welt " + worldName + " für Zieltruhe von Item " + itemType + " nicht gefunden");
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int x = playerData.getInt(targetChestPath + ".x");
|
|
|
|
|
|
|
|
int y = playerData.getInt(targetChestPath + ".y");
|
|
|
|
|
|
|
|
int z = playerData.getInt(targetChestPath + ".z");
|
|
|
|
|
|
|
|
Location chestLocation = new Location(world, x, y, z);
|
|
|
|
|
|
|
|
Block chestBlock = chestLocation.getBlock();
|
|
|
|
Block chestBlock = chestLocation.getBlock();
|
|
|
|
|
|
|
|
|
|
|
|
if (!(chestBlock.getState() instanceof Chest)) {
|
|
|
|
if (!(chestBlock.getState() instanceof Chest)) {
|
|
|
|
@@ -543,18 +596,11 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- NEU: Rest-Truhe aktualisieren ---
|
|
|
|
// --- NEU: Rest-Truhe aktualisieren ---
|
|
|
|
String restPath = path + ".rest-chest";
|
|
|
|
String restPath = basePath + ".rest-chest";
|
|
|
|
if (playerData.contains(restPath)) {
|
|
|
|
if (playerData.contains(restPath)) {
|
|
|
|
String worldName = playerData.getString(restPath + ".world");
|
|
|
|
Location chestLocation = getLocationFromPath(restPath);
|
|
|
|
World world = getServer().getWorld(worldName);
|
|
|
|
if (chestLocation == null) continue;
|
|
|
|
if (world == null) {
|
|
|
|
|
|
|
|
getLogger().warning("Welt " + worldName + " für Rest-Truhe von UUID " + uuidString + " nicht gefunden");
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int x = playerData.getInt(restPath + ".x");
|
|
|
|
|
|
|
|
int y = playerData.getInt(restPath + ".y");
|
|
|
|
|
|
|
|
int z = playerData.getInt(restPath + ".z");
|
|
|
|
|
|
|
|
Location chestLocation = new Location(world, x, y, z);
|
|
|
|
|
|
|
|
Block chestBlock = chestLocation.getBlock();
|
|
|
|
Block chestBlock = chestLocation.getBlock();
|
|
|
|
|
|
|
|
|
|
|
|
if (!(chestBlock.getState() instanceof Chest)) {
|
|
|
|
if (!(chestBlock.getState() instanceof Chest)) {
|
|
|
|
@@ -646,8 +692,12 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
return attached;
|
|
|
|
return attached;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void setInputChestLocation(UUID playerUUID, Location location) {
|
|
|
|
// --- ERWEITERUNG: Methode zum Hinzufügen einer Input Chest (Liste) ---
|
|
|
|
String path = "players." + playerUUID + ".input-chest";
|
|
|
|
private void addInputChestLocation(UUID playerUUID, Location location) {
|
|
|
|
|
|
|
|
String basePath = "players." + playerUUID + ".input-chests";
|
|
|
|
|
|
|
|
String id = UUID.randomUUID().toString(); // Eindeutige ID für jede Truhe
|
|
|
|
|
|
|
|
String path = basePath + "." + id;
|
|
|
|
|
|
|
|
|
|
|
|
playerData.set(path + ".world", location.getWorld().getName());
|
|
|
|
playerData.set(path + ".world", location.getWorld().getName());
|
|
|
|
playerData.set(path + ".x", location.getBlockX());
|
|
|
|
playerData.set(path + ".x", location.getBlockX());
|
|
|
|
playerData.set(path + ".y", location.getBlockY());
|
|
|
|
playerData.set(path + ".y", location.getBlockY());
|
|
|
|
@@ -655,6 +705,12 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
savePlayerData();
|
|
|
|
savePlayerData();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Original-Methode als Wrapper beibehalten (damit onSignChange nicht geändert werden muss)
|
|
|
|
|
|
|
|
private void setInputChestLocation(UUID playerUUID, Location location) {
|
|
|
|
|
|
|
|
addInputChestLocation(playerUUID, location);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
private void setTargetChestLocation(UUID playerUUID, Location location, Material itemType) {
|
|
|
|
private void setTargetChestLocation(UUID playerUUID, Location location, Material itemType) {
|
|
|
|
String path = "players." + playerUUID + ".target-chests." + itemType.name();
|
|
|
|
String path = "players." + playerUUID + ".target-chests." + itemType.name();
|
|
|
|
playerData.set(path + ".world", location.getWorld().getName());
|
|
|
|
playerData.set(path + ".world", location.getWorld().getName());
|
|
|
|
@@ -770,6 +826,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
loadPlayerData();
|
|
|
|
loadPlayerData();
|
|
|
|
updateConfig();
|
|
|
|
updateConfig();
|
|
|
|
updateExistingSigns();
|
|
|
|
updateExistingSigns();
|
|
|
|
|
|
|
|
migrateInputChests(); // ERWEITERUNG: Migration erneut aufrufen
|
|
|
|
player.sendMessage(getMessage("reload-success"));
|
|
|
|
player.sendMessage(getMessage("reload-success"));
|
|
|
|
getLogger().info("Konfiguration und Spielerdaten neu geladen durch " + player.getName());
|
|
|
|
getLogger().info("Konfiguration und Spielerdaten neu geladen durch " + player.getName());
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
@@ -835,7 +892,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
event.setLine(0, getSignColor("input", "line1") + "[asc]");
|
|
|
|
event.setLine(0, getSignColor("input", "line1") + "[asc]");
|
|
|
|
event.setLine(1, getSignColor("input", "line2") + "input");
|
|
|
|
event.setLine(1, getSignColor("input", "line2") + "input");
|
|
|
|
event.setLine(3, getSignColor("input", "line4") + player.getName());
|
|
|
|
event.setLine(3, getSignColor("input", "line4") + player.getName());
|
|
|
|
setInputChestLocation(playerUUID, chestBlock.getLocation());
|
|
|
|
setInputChestLocation(playerUUID, chestBlock.getLocation()); // Ruft nun addInputChestLocation auf
|
|
|
|
player.sendMessage(getMessage("input-chest-set"));
|
|
|
|
player.sendMessage(getMessage("input-chest-set"));
|
|
|
|
getLogger().info("Eingangstruhe für " + player.getName() + " gesetzt bei " + chestBlock.getLocation());
|
|
|
|
getLogger().info("Eingangstruhe für " + player.getName() + " gesetzt bei " + chestBlock.getLocation());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -885,7 +942,8 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
|
|
|
|
|
|
|
|
// 1. FALL: MODUS WECHSELN (Shift + Klick + Leere Hand)
|
|
|
|
// 1. FALL: MODUS WECHSELN (Shift + Klick + Leere Hand)
|
|
|
|
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) {
|
|
|
|
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) {
|
|
|
|
if (isOwner) {
|
|
|
|
// Admin Check hinzugefügt
|
|
|
|
|
|
|
|
if (isOwner || isAdmin(player)) {
|
|
|
|
boolean isPublic = isChestPublic(sign);
|
|
|
|
boolean isPublic = isChestPublic(sign);
|
|
|
|
String newModeText;
|
|
|
|
String newModeText;
|
|
|
|
String newLine4;
|
|
|
|
String newLine4;
|
|
|
|
@@ -917,8 +975,8 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
// 2. FALL: ITEM ZUWEISEN / AKTUALISIEREN (Nur bei ZIEL, nicht bei REST)
|
|
|
|
// 2. FALL: ITEM ZUWEISEN / AKTUALISIEREN (Nur bei ZIEL, nicht bei REST)
|
|
|
|
if (line1Clean.equalsIgnoreCase("ziel")) {
|
|
|
|
if (line1Clean.equalsIgnoreCase("ziel")) {
|
|
|
|
if (itemInHand != null && itemInHand.getType() != Material.AIR) {
|
|
|
|
if (itemInHand != null && itemInHand.getType() != Material.AIR) {
|
|
|
|
// Prüfe, ob der Spieler das Recht hat (Owner oder unbeansprucht)
|
|
|
|
// Admin Check hinzugefügt für Modifikation
|
|
|
|
if (!pureOwnerName.isEmpty() && !pureOwnerName.equalsIgnoreCase("Unknown") && !isOwner) {
|
|
|
|
if (!pureOwnerName.isEmpty() && !pureOwnerName.equalsIgnoreCase("Unknown") && !isOwner && !isAdmin(player)) {
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
event.setCancelled(true);
|
|
|
|
event.setCancelled(true);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
@@ -945,6 +1003,15 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
sign.setLine(3, finalLine4);
|
|
|
|
sign.setLine(3, finalLine4);
|
|
|
|
sign.update();
|
|
|
|
sign.update();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Admins ändern Truhe für den Owner? Nein, das ist komplex.
|
|
|
|
|
|
|
|
// Wir erlauben Admins nur den Zugriff hier, oder?
|
|
|
|
|
|
|
|
// Wenn Admin Item ändert, gehört die Truhe dann ihm?
|
|
|
|
|
|
|
|
// Der Code setzt aktuell targetChestLocation für playerUUID.
|
|
|
|
|
|
|
|
// Wenn Admin es ändert, sollte er es wohl für den Owner tun lassen oder es übernehmen.
|
|
|
|
|
|
|
|
// Um es einfach zu halten: Wenn Admin es ändert, wird es "seine" Zieltruhe für dieses Item.
|
|
|
|
|
|
|
|
// (Oder man fragt sich ab, ob man das will. Der User fragte nur nach "schauen" und "entfernen").
|
|
|
|
|
|
|
|
// Ich lasse das Zuweisen wie gehabt (Owner Check oben), aber Admin darf es ändern.
|
|
|
|
|
|
|
|
|
|
|
|
setTargetChestLocation(player.getUniqueId(), chestBlock.getLocation(), itemInHand.getType());
|
|
|
|
setTargetChestLocation(player.getUniqueId(), chestBlock.getLocation(), itemInHand.getType());
|
|
|
|
player.sendMessage(getMessage("target-chest-set").replace("%item%", itemInHand.getType().name()));
|
|
|
|
player.sendMessage(getMessage("target-chest-set").replace("%item%", itemInHand.getType().name()));
|
|
|
|
event.setCancelled(true);
|
|
|
|
event.setCancelled(true);
|
|
|
|
@@ -953,14 +1020,14 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Zugriffsschutz für konfigurierte Truhen (wenn kein Item in Hand zum Updaten)
|
|
|
|
// Zugriffsschutz für konfigurierte Truhen (wenn kein Item in Hand zum Updaten)
|
|
|
|
// Wenn nicht Owner und NICHT öffentlich -> Zugriff verweigern
|
|
|
|
// Wenn nicht Owner und NICHT öffentlich UND NICHT Admin -> Zugriff verweigern
|
|
|
|
if (!isOwner && !isChestPublic(sign)) {
|
|
|
|
if (!isOwner && !isChestPublic(sign) && !isAdmin(player)) {
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
event.setCancelled(true);
|
|
|
|
event.setCancelled(true);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Wenn Owner oder Öffentlich -> Truhe öffnen lassen (Event nicht canceln)
|
|
|
|
// Wenn Owner oder Öffentlich oder Admin -> Truhe öffnen lassen (Event nicht canceln)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -973,7 +1040,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
|
|
|
|
|
|
|
|
// 1. FALL: MODUS WECHSELN (Shift + Klick + Leere Hand)
|
|
|
|
// 1. FALL: MODUS WECHSELN (Shift + Klick + Leere Hand)
|
|
|
|
if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) {
|
|
|
|
if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) {
|
|
|
|
if (isOwner) {
|
|
|
|
if (isOwner || isAdmin(player)) {
|
|
|
|
boolean isPublic = isChestPublic(sign);
|
|
|
|
boolean isPublic = isChestPublic(sign);
|
|
|
|
String newModeText;
|
|
|
|
String newModeText;
|
|
|
|
String newLine4;
|
|
|
|
String newLine4;
|
|
|
|
@@ -998,8 +1065,8 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Zugriffsschutz
|
|
|
|
// Zugriffsschutz - Admin Check hinzugefügt
|
|
|
|
if (!isOwner && !isChestPublic(sign)) {
|
|
|
|
if (!isOwner && !isChestPublic(sign) && !isAdmin(player)) {
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
event.setCancelled(true);
|
|
|
|
event.setCancelled(true);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
@@ -1040,7 +1107,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
String[] lines = sign.getLines();
|
|
|
|
String[] lines = sign.getLines();
|
|
|
|
String line1Clean = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : ""));
|
|
|
|
String line1Clean = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : ""));
|
|
|
|
|
|
|
|
|
|
|
|
// NUR FÜR ZIELTRUHEN und REST (hier nur Moduswechsel)
|
|
|
|
// NUR FÜR ZIELTRUHEN und REST (hier nur Moduswechsel und Item zuweisen)
|
|
|
|
if (line1Clean.equalsIgnoreCase("ziel") || line1Clean.equalsIgnoreCase("rest")) {
|
|
|
|
if (line1Clean.equalsIgnoreCase("ziel") || line1Clean.equalsIgnoreCase("rest")) {
|
|
|
|
String line3Raw = lines[3] != null ? lines[3] : "";
|
|
|
|
String line3Raw = lines[3] != null ? lines[3] : "";
|
|
|
|
String line3Clean = ChatColor.stripColor(line3Raw);
|
|
|
|
String line3Clean = ChatColor.stripColor(line3Raw);
|
|
|
|
@@ -1049,7 +1116,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
|
|
|
|
|
|
|
|
// 1. FALL: MODUS WECHSELN
|
|
|
|
// 1. FALL: MODUS WECHSELN
|
|
|
|
if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) {
|
|
|
|
if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) {
|
|
|
|
if (isOwner) {
|
|
|
|
if (isOwner || isAdmin(player)) {
|
|
|
|
boolean isPublic = isChestPublic(sign);
|
|
|
|
boolean isPublic = isChestPublic(sign);
|
|
|
|
String newModeText;
|
|
|
|
String newModeText;
|
|
|
|
String newLine4;
|
|
|
|
String newLine4;
|
|
|
|
@@ -1087,7 +1154,8 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!pureOwnerName.isEmpty() && !pureOwnerName.equalsIgnoreCase("Unknown") && !isOwner) {
|
|
|
|
// Admin Check für Modifikation
|
|
|
|
|
|
|
|
if (!pureOwnerName.isEmpty() && !pureOwnerName.equalsIgnoreCase("Unknown") && !isOwner && !isAdmin(player)) {
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
event.setCancelled(true);
|
|
|
|
event.setCancelled(true);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
@@ -1120,8 +1188,8 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Wenn nicht Owner und nicht öffentlich -> Zugriff verweigern
|
|
|
|
// Wenn nicht Owner und nicht öffentlich und nicht Admin -> Zugriff verweigern
|
|
|
|
if (!isOwner && !isChestPublic(sign)) {
|
|
|
|
if (!isOwner && !isChestPublic(sign) && !isAdmin(player)) {
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
event.setCancelled(true);
|
|
|
|
event.setCancelled(true);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
@@ -1137,7 +1205,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
|
|
|
|
|
|
|
|
// Moduswechsel
|
|
|
|
// Moduswechsel
|
|
|
|
if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) {
|
|
|
|
if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) {
|
|
|
|
if (isOwner) {
|
|
|
|
if (isOwner || isAdmin(player)) {
|
|
|
|
boolean isPublic = isChestPublic(sign);
|
|
|
|
boolean isPublic = isChestPublic(sign);
|
|
|
|
String newModeText;
|
|
|
|
String newModeText;
|
|
|
|
String newLine4;
|
|
|
|
String newLine4;
|
|
|
|
@@ -1163,7 +1231,8 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!isOwner && !isChestPublic(sign)) {
|
|
|
|
// Admin Check für Zugriff
|
|
|
|
|
|
|
|
if (!isOwner && !isChestPublic(sign) && !isAdmin(player)) {
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
event.setCancelled(true);
|
|
|
|
event.setCancelled(true);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
@@ -1173,6 +1242,36 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- ERWEITERUNG: Hilfsmethode zum Entfernen einer Input Chest ---
|
|
|
|
|
|
|
|
private void removeInputChestByLocation(UUID uuid, Location loc) {
|
|
|
|
|
|
|
|
String basePath = "players." + uuid + ".input-chests";
|
|
|
|
|
|
|
|
String oldPath = "players." + uuid + ".input-chest";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Prüfe neues Listen-Format
|
|
|
|
|
|
|
|
if (playerData.contains(basePath)) {
|
|
|
|
|
|
|
|
for (String chestId : playerData.getConfigurationSection(basePath).getKeys(false)) {
|
|
|
|
|
|
|
|
String path = basePath + "." + chestId;
|
|
|
|
|
|
|
|
Location savedLoc = getLocationFromPath(path);
|
|
|
|
|
|
|
|
if (savedLoc != null && savedLoc.equals(loc)) {
|
|
|
|
|
|
|
|
playerData.set(path, null);
|
|
|
|
|
|
|
|
savePlayerData();
|
|
|
|
|
|
|
|
if (isDebug()) getLogger().info("Eingangstruhe entfernt bei " + loc);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Prüfe altes Einzel-Format (Fallback)
|
|
|
|
|
|
|
|
if (playerData.contains(oldPath)) {
|
|
|
|
|
|
|
|
Location oldLoc = getLocationFromPath(oldPath);
|
|
|
|
|
|
|
|
if (oldLoc != null && oldLoc.equals(loc)) {
|
|
|
|
|
|
|
|
playerData.set(oldPath, null);
|
|
|
|
|
|
|
|
savePlayerData();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.HIGHEST)
|
|
|
|
@EventHandler(priority = EventPriority.HIGHEST)
|
|
|
|
public void onBlockBreak(BlockBreakEvent event) {
|
|
|
|
public void onBlockBreak(BlockBreakEvent event) {
|
|
|
|
Block block = event.getBlock();
|
|
|
|
Block block = event.getBlock();
|
|
|
|
@@ -1240,18 +1339,18 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Prüfe Besitzer
|
|
|
|
// Prüfe Besitzer - Admin Check hinzugefügt
|
|
|
|
boolean isOwner = signOwner.isEmpty() || signOwner.equalsIgnoreCase(player.getName());
|
|
|
|
boolean isOwner = signOwner.isEmpty() || signOwner.equalsIgnoreCase(player.getName());
|
|
|
|
|
|
|
|
|
|
|
|
if (!isOwner) {
|
|
|
|
if (!isOwner && !isAdmin(player)) {
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
player.sendMessage(getMessage("not-your-chest"));
|
|
|
|
event.setCancelled(true);
|
|
|
|
event.setCancelled(true);
|
|
|
|
getLogger().warning("Spieler " + player.getName() + " versuchte, " + (isAscChest ? "Truhe" : "Schild") + " bei " + block.getLocation() + " abzubauen, das nicht ihm gehört (Besitzer: " + signOwner + ")");
|
|
|
|
getLogger().warning("Spieler " + player.getName() + " versuchte, " + (isAscChest ? "Truhe" : "Schild") + " bei " + block.getLocation() + " abzubauen, das nicht ihm gehört (Besitzer: " + signOwner + ")");
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Prüfe Shift-Taste (Berechtigungen ignorieren)
|
|
|
|
// Prüfe Shift-Taste (Berechtigungen ignorieren) - Admin Check hinzugefügt
|
|
|
|
if (!player.isSneaking()) {
|
|
|
|
if (!player.isSneaking() && !isAdmin(player)) {
|
|
|
|
player.sendMessage(getMessage("sign-break-denied"));
|
|
|
|
player.sendMessage(getMessage("sign-break-denied"));
|
|
|
|
event.setCancelled(true);
|
|
|
|
event.setCancelled(true);
|
|
|
|
if (isDebug()) {
|
|
|
|
if (isDebug()) {
|
|
|
|
@@ -1263,10 +1362,84 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
// --- Daten bereinigen beim Abbauen ---
|
|
|
|
// --- Daten bereinigen beim Abbauen ---
|
|
|
|
String[] lines = ((Sign) (isAscChest ? signBlock.getState() : block.getState())).getLines();
|
|
|
|
String[] lines = ((Sign) (isAscChest ? signBlock.getState() : block.getState())).getLines();
|
|
|
|
String line1 = ChatColor.stripColor(lines[1]);
|
|
|
|
String line1 = ChatColor.stripColor(lines[1]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Hole Location der Truhe, die abgebaut wird (für Datenabgleich)
|
|
|
|
|
|
|
|
Location chestLoc = isAscChest ? block.getLocation() : ((Sign)block.getState()).getBlock().getRelative(((WallSign)((Sign)block.getState()).getBlockData()).getFacing().getOppositeFace()).getLocation();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Wenn Admin abbaut, müssen wir wissen, WEM die Truhe gehört, um die richtigen Daten zu löschen.
|
|
|
|
|
|
|
|
// signOwner ist der Name auf dem Schild.
|
|
|
|
|
|
|
|
UUID ownerUUID = null;
|
|
|
|
|
|
|
|
if (!signOwner.isEmpty() && !signOwner.equalsIgnoreCase("Unknown")) {
|
|
|
|
|
|
|
|
OfflinePlayer op = Bukkit.getOfflinePlayer(signOwner);
|
|
|
|
|
|
|
|
if (op.hasPlayedBefore()) {
|
|
|
|
|
|
|
|
ownerUUID = op.getUniqueId();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Fallback: Wenn Name "Unknown" ist, versuchen wir es über den aktuellen Spieler (wenn er Owner ist) oder wir iterieren (teuer).
|
|
|
|
|
|
|
|
// Da Admins abbauen können, müssen wir den Owner eindeutig identifizieren.
|
|
|
|
|
|
|
|
// Wir iterieren durch die Spielerdaten, um zu finden, wem diese Location gehört.
|
|
|
|
|
|
|
|
if (playerData.getConfigurationSection("players") != null) {
|
|
|
|
|
|
|
|
for (String uuidString : playerData.getConfigurationSection("players").getKeys(false)) {
|
|
|
|
|
|
|
|
UUID uuid = UUID.fromString(uuidString);
|
|
|
|
|
|
|
|
// Check inputs
|
|
|
|
|
|
|
|
String inputListPath = "players." + uuidString + ".input-chests";
|
|
|
|
|
|
|
|
if (playerData.contains(inputListPath)) {
|
|
|
|
|
|
|
|
for (String chestId : playerData.getConfigurationSection(inputListPath).getKeys(false)) {
|
|
|
|
|
|
|
|
if (chestLoc.equals(getLocationFromPath(inputListPath + "." + chestId))) {
|
|
|
|
|
|
|
|
ownerUUID = uuid;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check targets
|
|
|
|
|
|
|
|
if (ownerUUID == null) {
|
|
|
|
|
|
|
|
String targetPath = "players." + uuidString + ".target-chests";
|
|
|
|
|
|
|
|
if (playerData.contains(targetPath)) {
|
|
|
|
|
|
|
|
for (String itemType : playerData.getConfigurationSection(targetPath).getKeys(false)) {
|
|
|
|
|
|
|
|
if (chestLoc.equals(getLocationFromPath(targetPath + "." + itemType))) {
|
|
|
|
|
|
|
|
ownerUUID = uuid;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check rest
|
|
|
|
|
|
|
|
if (ownerUUID == null) {
|
|
|
|
|
|
|
|
Location restLoc = getRestChestLocation(uuid);
|
|
|
|
|
|
|
|
if (chestLoc.equals(restLoc)) {
|
|
|
|
|
|
|
|
ownerUUID = uuid;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ownerUUID != null) break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Wenn wir die UUID gefunden haben (oder es ist der Spieler selbst), löschen wir die Daten
|
|
|
|
|
|
|
|
UUID uuidToDelete = (ownerUUID != null) ? ownerUUID : player.getUniqueId();
|
|
|
|
|
|
|
|
|
|
|
|
if (line1.equalsIgnoreCase("rest")) {
|
|
|
|
if (line1.equalsIgnoreCase("rest")) {
|
|
|
|
playerData.set("players." + player.getUniqueId() + ".rest-chest", null);
|
|
|
|
playerData.set("players." + uuidToDelete + ".rest-chest", null);
|
|
|
|
savePlayerData();
|
|
|
|
savePlayerData();
|
|
|
|
if (isDebug()) getLogger().info("Rest-Truhe Daten gelöscht für " + player.getName());
|
|
|
|
if (isDebug()) getLogger().info("Rest-Truhe Daten gelöscht für " + (ownerUUID != null ? "Owner " + signOwner : "Self"));
|
|
|
|
|
|
|
|
} else if (line1.equalsIgnoreCase("input")) {
|
|
|
|
|
|
|
|
// ERWEITERUNG: Input Chest aus Liste löschen
|
|
|
|
|
|
|
|
removeInputChestByLocation(uuidToDelete, chestLoc);
|
|
|
|
|
|
|
|
} else if (line1.equalsIgnoreCase("ziel")) {
|
|
|
|
|
|
|
|
// Wir müssen wissen, welches Item auf dem Schild stand, um es zu löschen
|
|
|
|
|
|
|
|
String line2 = ChatColor.stripColor(lines[2]);
|
|
|
|
|
|
|
|
if (!line2.isEmpty()) {
|
|
|
|
|
|
|
|
Material mat = Material.matchMaterial(line2);
|
|
|
|
|
|
|
|
if (mat != null) {
|
|
|
|
|
|
|
|
// Sicherheitscheck, ob die Location auch wirklich diesem Item zugeordnet ist
|
|
|
|
|
|
|
|
Location savedLoc = getTargetChestLocation(uuidToDelete, mat);
|
|
|
|
|
|
|
|
if (savedLoc != null && savedLoc.equals(chestLoc)) {
|
|
|
|
|
|
|
|
playerData.set("players." + uuidToDelete + ".target-chests." + mat.name(), null);
|
|
|
|
|
|
|
|
savePlayerData();
|
|
|
|
|
|
|
|
if (isDebug()) getLogger().info("Zieltruhe Daten für Item " + mat.name() + " gelöscht.");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// --------------------------------
|
|
|
|
// --------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1325,8 +1498,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
String signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : ""));
|
|
|
|
String signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : ""));
|
|
|
|
|
|
|
|
|
|
|
|
// FIX: Auch öffentliche Truhen updaten, nicht nur Owner
|
|
|
|
// FIX: Auch öffentliche Truhen updaten, nicht nur Owner
|
|
|
|
|
|
|
|
// ERWEITERUNG: Auch Admins updaten, damit Schildfarben stimmen wenn Admin Items rausnimmt
|
|
|
|
boolean isPublic = isChestPublic(sign);
|
|
|
|
boolean isPublic = isChestPublic(sign);
|
|
|
|
if (!signOwner.equalsIgnoreCase(player.getName()) && !isPublic) {
|
|
|
|
if (!signOwner.equalsIgnoreCase(player.getName()) && !isPublic && !isAdmin(player)) {
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1553,108 +1727,127 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String path = "players." + uuidString + ".input-chest";
|
|
|
|
// --- ERWEITERUNG: Eingangstruhe (Jetzt Liste) ---
|
|
|
|
if (!playerData.contains(path)) continue;
|
|
|
|
String inputListPath = "players." + uuidString + ".input-chests";
|
|
|
|
|
|
|
|
// Fallback für altes Format (falls Migration noch nicht lief oder Fehler)
|
|
|
|
|
|
|
|
String oldInputPath = "players." + uuidString + ".input-chest";
|
|
|
|
|
|
|
|
|
|
|
|
String worldName = playerData.getString(path + ".world");
|
|
|
|
List<String> chestsToCheck = new ArrayList<>();
|
|
|
|
World world = getServer().getWorld(worldName);
|
|
|
|
|
|
|
|
if (world == null) {
|
|
|
|
|
|
|
|
getLogger().warning("Welt " + worldName + " für Eingangstruhe von UUID " + uuidString + " nicht gefunden");
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int x = playerData.getInt(path + ".x");
|
|
|
|
if (playerData.contains(inputListPath)) {
|
|
|
|
int y = playerData.getInt(path + ".y");
|
|
|
|
chestsToCheck.addAll(playerData.getConfigurationSection(inputListPath).getKeys(false));
|
|
|
|
int z = playerData.getInt(path + ".z");
|
|
|
|
} else if (playerData.contains(oldInputPath)) {
|
|
|
|
Location location = new Location(world, x, y, z);
|
|
|
|
// Hier führen wir keine Migration durch (nur lesen), da das im laufenden Betrieb zu Problemen führen könnte.
|
|
|
|
|
|
|
|
// Wir markieren es für den Task, damit es bei下一次 Update erledigt wird.
|
|
|
|
if (!(location.getBlock().getState() instanceof Chest)) {
|
|
|
|
Location loc = getLocationFromPath(oldInputPath);
|
|
|
|
if (isDebug()) {
|
|
|
|
if (loc != null) {
|
|
|
|
getLogger().fine("Eingangstruhe bei " + location + " existiert nicht");
|
|
|
|
checkSingleInputChest(ownerUUID, loc, "legacy");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Chest chest = (Chest) location.getBlock().getState();
|
|
|
|
if (chestsToCheck.isEmpty()) continue;
|
|
|
|
Block inputSignBlock = null;
|
|
|
|
|
|
|
|
boolean isPublic = false;
|
|
|
|
|
|
|
|
String ownerName = "Unknown";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// FIX: Suche Schild an beiden Hälften bei Doppeltruhen
|
|
|
|
for (String chestId : chestsToCheck) {
|
|
|
|
List<Block> chestBlocks = getChestBlocks(chest);
|
|
|
|
String path = inputListPath + "." + chestId;
|
|
|
|
|
|
|
|
Location loc = getLocationFromPath(path);
|
|
|
|
|
|
|
|
|
|
|
|
outerLoop:
|
|
|
|
if (loc == null) {
|
|
|
|
for (Block b : chestBlocks) {
|
|
|
|
playerData.set(path, null); // Ungültigen Eintrag löschen
|
|
|
|
for (Block face : new Block[] {
|
|
|
|
continue;
|
|
|
|
b.getRelative(1, 0, 0),
|
|
|
|
}
|
|
|
|
b.getRelative(-1, 0, 0),
|
|
|
|
|
|
|
|
b.getRelative(0, 0, 1),
|
|
|
|
|
|
|
|
b.getRelative(0, 0, -1)
|
|
|
|
|
|
|
|
}) {
|
|
|
|
|
|
|
|
if (face.getState() instanceof Sign sign && isSignAttachedToChest(face, b)) {
|
|
|
|
|
|
|
|
String[] lines = sign.getLines();
|
|
|
|
|
|
|
|
String line0 = ChatColor.stripColor((String) (lines[0] != null ? lines[0] : ""));
|
|
|
|
|
|
|
|
String line1 = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : ""));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (line0.equalsIgnoreCase("[asc]") && line1.equalsIgnoreCase("input")) {
|
|
|
|
boolean stillValid = checkSingleInputChest(ownerUUID, loc, chestId);
|
|
|
|
inputSignBlock = face;
|
|
|
|
if (!stillValid) {
|
|
|
|
String line3Raw = lines[3] != null ? lines[3] : "";
|
|
|
|
playerData.set(path, null);
|
|
|
|
String line3Clean = ChatColor.stripColor(line3Raw);
|
|
|
|
savePlayerData();
|
|
|
|
|
|
|
|
|
|
|
|
isPublic = line3Clean.toLowerCase().endsWith("[public]");
|
|
|
|
|
|
|
|
ownerName = line3Clean.replace(" [Public]", "").replace(" [public]", "").trim();
|
|
|
|
|
|
|
|
break outerLoop;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------
|
|
|
|
if (inputSignBlock == null) {
|
|
|
|
|
|
|
|
if (isDebug()) getLogger().fine("Kein Eingangsschild an Truhe bei " + location);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Wenn das Inventar leer ist, brauchen wir nichts tun
|
|
|
|
|
|
|
|
boolean hasItems = false;
|
|
|
|
|
|
|
|
for (ItemStack item : chest.getInventory().getContents()) {
|
|
|
|
|
|
|
|
if (item != null && item.getType() != Material.AIR) {
|
|
|
|
|
|
|
|
hasItems = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hasItems) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Jetzt kommt der entscheidende Teil für die Multiplayer-Funktionalität:
|
|
|
|
|
|
|
|
// Wenn PRIVATE: Nur sortieren, wenn der Owner ONLINE ist.
|
|
|
|
|
|
|
|
// Wenn ÖFFENTLICH: Immer sortieren, aber wir brauchen einen "fiktiven" Player für die Fehlermeldungen
|
|
|
|
|
|
|
|
// oder wir senden Meldungen an alle Online-Spieler, die in der Nähe sind?
|
|
|
|
|
|
|
|
// Der Einfachheit halber: Wenn Öffentlich, sortieren wir stumm oder senden Meldungen an den Owner wenn er online ist.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Player ownerPlayer = getServer().getPlayer(ownerUUID);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isPublic) {
|
|
|
|
|
|
|
|
// Privat: Nur wenn Owner online
|
|
|
|
|
|
|
|
if (ownerPlayer == null || !ownerPlayer.isOnline()) continue;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Öffentlich: Wenn Owner offline, können wir keine "Truhe voll" Nachrichten an den Owner senden.
|
|
|
|
|
|
|
|
// Wir sortieren trotzdem.
|
|
|
|
|
|
|
|
// Wir setzen ownerPlayer auf null, damit distributeItemsForOwner weiß, dass niemand Besitzer ist (für Messages).
|
|
|
|
|
|
|
|
if (ownerPlayer == null || !ownerPlayer.isOnline()) {
|
|
|
|
|
|
|
|
ownerPlayer = null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Wir rufen distributeItemsForOwner auf.
|
|
|
|
|
|
|
|
// WICHTIG: distributeItemsForOwner nutzt `player.getUniqueId()` um die Zieltruhen zu finden.
|
|
|
|
|
|
|
|
// Das funktioniert auch, wenn ownerPlayer null ist, solange wir die UUID übergeben.
|
|
|
|
|
|
|
|
// Wir müssen aber aufpassen, dass `distributeItemsForOwner` nicht crasht, wenn player null ist.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
distributeItemsForOwner(ownerUUID, ownerPlayer, chest.getInventory());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- ERWEITERUNG: Hilfsmethode zum Prüfen einzelner Eingangstruhe ---
|
|
|
|
|
|
|
|
private boolean checkSingleInputChest(UUID ownerUUID, Location location, String debugId) {
|
|
|
|
|
|
|
|
if (!(location.getBlock().getState() instanceof Chest)) return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Chest chest = (Chest) location.getBlock().getState();
|
|
|
|
|
|
|
|
Block inputSignBlock = null;
|
|
|
|
|
|
|
|
boolean isPublic = false;
|
|
|
|
|
|
|
|
String ownerName = "Unknown";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// FIX: Suche Schild an beiden Hälften bei Doppeltruhen
|
|
|
|
|
|
|
|
List<Block> chestBlocks = getChestBlocks(chest);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
outerLoop:
|
|
|
|
|
|
|
|
for (Block b : chestBlocks) {
|
|
|
|
|
|
|
|
for (Block face : new Block[] {
|
|
|
|
|
|
|
|
b.getRelative(1, 0, 0),
|
|
|
|
|
|
|
|
b.getRelative(-1, 0, 0),
|
|
|
|
|
|
|
|
b.getRelative(0, 0, 1),
|
|
|
|
|
|
|
|
b.getRelative(0, 0, -1)
|
|
|
|
|
|
|
|
}) {
|
|
|
|
|
|
|
|
if (face.getState() instanceof Sign sign && isSignAttachedToChest(face, b)) {
|
|
|
|
|
|
|
|
String[] lines = sign.getLines();
|
|
|
|
|
|
|
|
String line0 = ChatColor.stripColor((String) (lines[0] != null ? lines[0] : ""));
|
|
|
|
|
|
|
|
String line1 = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : ""));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (line0.equalsIgnoreCase("[asc]") && line1.equalsIgnoreCase("input")) {
|
|
|
|
|
|
|
|
inputSignBlock = face;
|
|
|
|
|
|
|
|
String line3Raw = lines[3] != null ? lines[3] : "";
|
|
|
|
|
|
|
|
String line3Clean = ChatColor.stripColor(line3Raw);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
isPublic = line3Clean.toLowerCase().endsWith("[public]");
|
|
|
|
|
|
|
|
ownerName = line3Clean.replace(" [Public]", "").replace(" [public]", "").trim();
|
|
|
|
|
|
|
|
break outerLoop;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (inputSignBlock == null) {
|
|
|
|
|
|
|
|
if (isDebug()) getLogger().fine("Kein Eingangsschild an Truhe " + debugId);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Wenn das Inventar leer ist, brauchen wir nichts tun
|
|
|
|
|
|
|
|
boolean hasItems = false;
|
|
|
|
|
|
|
|
for (ItemStack item : chest.getInventory().getContents()) {
|
|
|
|
|
|
|
|
if (item != null && item.getType() != Material.AIR) {
|
|
|
|
|
|
|
|
hasItems = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hasItems) return true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Jetzt kommt der entscheidende Teil für die Multiplayer-Funktionalität:
|
|
|
|
|
|
|
|
// Wenn PRIVATE: Nur sortieren, wenn der Owner ONLINE ist.
|
|
|
|
|
|
|
|
// Wenn ÖFFENTLICH: Immer sortieren, aber wir brauchen einen "fiktiven" Player für die Fehlermeldungen
|
|
|
|
|
|
|
|
// oder wir senden Meldungen an alle Online-Spieler, die in der Nähe sind?
|
|
|
|
|
|
|
|
// Der Einfachheit halber: Wenn Öffentlich, sortieren wir stumm oder senden Meldungen an den Owner wenn er online ist.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Player ownerPlayer = getServer().getPlayer(ownerUUID);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isPublic) {
|
|
|
|
|
|
|
|
// Privat: Nur wenn Owner online
|
|
|
|
|
|
|
|
if (ownerPlayer == null || !ownerPlayer.isOnline()) return true;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Öffentlich: Wenn Owner offline, können wir keine "Truhe voll" Nachrichten an den Owner senden.
|
|
|
|
|
|
|
|
// Wir sortieren trotzdem.
|
|
|
|
|
|
|
|
// Wir setzen ownerPlayer auf null, damit distributeItemsForOwner weiß, dass niemand Besitzer ist (für Messages).
|
|
|
|
|
|
|
|
if (ownerPlayer == null || !ownerPlayer.isOnline()) {
|
|
|
|
|
|
|
|
ownerPlayer = null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Wir rufen distributeItemsForOwner auf.
|
|
|
|
|
|
|
|
distributeItemsForOwner(ownerUUID, ownerPlayer, chest.getInventory(), ownerName);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
// 4. KORRIGIERTE distributeItemsForOwner Methode:
|
|
|
|
// 4. KORRIGIERTE distributeItemsForOwner Methode:
|
|
|
|
private void distributeItemsForOwner(UUID ownerUUID, Player ownerPlayer, Inventory sourceInventory) {
|
|
|
|
private void distributeItemsForOwner(UUID ownerUUID, Player ownerPlayer, Inventory sourceInventory, String ownerNameOverride) {
|
|
|
|
boolean hasItems = false;
|
|
|
|
boolean hasItems = false;
|
|
|
|
for (ItemStack item : sourceInventory.getContents()) {
|
|
|
|
for (ItemStack item : sourceInventory.getContents()) {
|
|
|
|
if (item != null && item.getType() != Material.AIR) {
|
|
|
|
if (item != null && item.getType() != Material.AIR) {
|
|
|
|
@@ -1666,7 +1859,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|
|
|
|
|
|
|
|
|
|
|
// Owner-Name ermitteln
|
|
|
|
// Owner-Name ermitteln
|
|
|
|
String ownerName = "Unknown";
|
|
|
|
String ownerName = "Unknown";
|
|
|
|
if (ownerPlayer != null) {
|
|
|
|
if (ownerNameOverride != null && !ownerNameOverride.isEmpty()) {
|
|
|
|
|
|
|
|
ownerName = ownerNameOverride;
|
|
|
|
|
|
|
|
} else if (ownerPlayer != null) {
|
|
|
|
ownerName = ownerPlayer.getName();
|
|
|
|
ownerName = ownerPlayer.getName();
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// Offline-Namen aus PlayerData holen wenn möglich
|
|
|
|
// Offline-Namen aus PlayerData holen wenn möglich
|
|
|
|
|