diff --git a/src/main/java/com/viper/autosortchest/Main.java b/src/main/java/com/viper/autosortchest/Main.java index 92702b6..e8a7621 100644 --- a/src/main/java/com/viper/autosortchest/Main.java +++ b/src/main/java/com/viper/autosortchest/Main.java @@ -25,6 +25,7 @@ import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.ChatColor; import org.bukkit.Material; +import org.bukkit.OfflinePlayer; import java.io.File; import java.io.IOException; @@ -38,14 +39,14 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { private FileConfiguration config; private final Map> fullChestMessageTracker = new HashMap<>(); private static final long MESSAGE_COOLDOWN = 5 * 60 * 1000; // 5 Minuten in Millisekunden - private static final String CONFIG_VERSION = "1.4"; + private static final String CONFIG_VERSION = "1.5"; @Override public void onEnable() { // Lade Standard-Konfiguration saveDefaultConfig(); config = getConfig(); - + // Lade players.yml playerDataFile = new File(getDataFolder(), "players.yml"); if (!playerDataFile.exists()) { @@ -137,7 +138,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { } } - private void updateConfig() { + private void updateConfig() { File configFile = new File(getDataFolder(), "config.yml"); InputStream defaultConfigStream = getResource("config.yml"); FileConfiguration defaultConfig; @@ -176,7 +177,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { config.createSection("sign-colors.input"); config.set("sign-colors.input.line1", defaultConfig.getString("sign-colors.input.line1", "&6")); config.set("sign-colors.input.line2", defaultConfig.getString("sign-colors.input.line2", "&0")); - config.set("sign-colors.input.line4", defaultConfig.getString("sign-colors.input.line4", "&f")); + config.set("sign-colors.input.line4", defaultConfig.getString("sign-colors.input.line4", "&1")); // Korrigiert auf &1 basierend auf user Config getLogger().info("Setze Standardwerte für sign-colors.input"); } else { if (!config.contains("sign-colors.input.line1")) { @@ -188,7 +189,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { getLogger().info("Setze Standardwert: sign-colors.input.line2 = " + config.getString("sign-colors.input.line2")); } if (!config.contains("sign-colors.input.line4")) { - config.set("sign-colors.input.line4", defaultConfig.getString("sign-colors.input.line4", "&f")); + config.set("sign-colors.input.line4", defaultConfig.getString("sign-colors.input.line4", "&1")); getLogger().info("Setze Standardwert: sign-colors.input.line4 = " + config.getString("sign-colors.input.line4")); } } @@ -199,7 +200,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { config.set("sign-colors.target.line1", defaultConfig.getString("sign-colors.target.line1", "&6")); config.set("sign-colors.target.line2", defaultConfig.getString("sign-colors.target.line2", "&0")); config.set("sign-colors.target.line3", defaultConfig.getString("sign-colors.target.line3", "&f")); - config.set("sign-colors.target.line4", defaultConfig.getString("sign-colors.target.line4", "&f")); + config.set("sign-colors.target.line4", defaultConfig.getString("sign-colors.target.line4", "&1")); // Korrigiert auf &1 getLogger().info("Setze Standardwerte für sign-colors.target"); } else { if (!config.contains("sign-colors.target.line1")) { @@ -215,7 +216,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { getLogger().info("Setze Standardwert: sign-colors.target.line3 = " + config.getString("sign-colors.target.line3")); } if (!config.contains("sign-colors.target.line4")) { - config.set("sign-colors.target.line4", defaultConfig.getString("sign-colors.target.line4", "&f")); + config.set("sign-colors.target.line4", defaultConfig.getString("sign-colors.target.line4", "&1")); getLogger().info("Setze Standardwert: sign-colors.target.line4 = " + config.getString("sign-colors.target.line4")); } } @@ -226,7 +227,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { config.set("sign-colors.full.line1", defaultConfig.getString("sign-colors.full.line1", "&c")); config.set("sign-colors.full.line2", defaultConfig.getString("sign-colors.full.line2", "&4")); config.set("sign-colors.full.line3", defaultConfig.getString("sign-colors.full.line3", "&e")); - config.set("sign-colors.full.line4", defaultConfig.getString("sign-colors.full.line4", "&e")); + config.set("sign-colors.full.line4", defaultConfig.getString("sign-colors.full.line4", "&1")); // Korrigiert auf &1 getLogger().info("Setze Standardwerte für sign-colors.full"); } else { if (!config.contains("sign-colors.full.line1")) { @@ -242,12 +243,39 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { getLogger().info("Setze Standardwert: sign-colors.full.line3 = " + config.getString("sign-colors.full.line3")); } if (!config.contains("sign-colors.full.line4")) { - config.set("sign-colors.full.line4", defaultConfig.getString("sign-colors.full.line4", "&e")); + config.set("sign-colors.full.line4", defaultConfig.getString("sign-colors.full.line4", "&1")); getLogger().info("Setze Standardwert: sign-colors.full.line4 = " + config.getString("sign-colors.full.line4")); } } - // Prüfe und setze messages + // --- NEU: Prüfe und setze sign-colors.rest --- + if (!config.contains("sign-colors.rest")) { + config.createSection("sign-colors.rest"); + config.set("sign-colors.rest.line1", defaultConfig.getString("sign-colors.rest.line1", "&6")); + config.set("sign-colors.rest.line2", defaultConfig.getString("sign-colors.rest.line2", "&0")); + config.set("sign-colors.rest.line3", defaultConfig.getString("sign-colors.rest.line3", "&f")); + config.set("sign-colors.rest.line4", defaultConfig.getString("sign-colors.rest.line4", "&1")); // Korrigiert auf &1 + getLogger().info("Setze Standardwerte für sign-colors.rest"); + } else { + if (!config.contains("sign-colors.rest.line1")) { + config.set("sign-colors.rest.line1", defaultConfig.getString("sign-colors.rest.line1", "&6")); + getLogger().info("Setze Standardwert: sign-colors.rest.line1 = " + config.getString("sign-colors.rest.line1")); + } + if (!config.contains("sign-colors.rest.line2")) { + config.set("sign-colors.rest.line2", defaultConfig.getString("sign-colors.rest.line2", "&0")); + getLogger().info("Setze Standardwert: sign-colors.rest.line2 = " + config.getString("sign-colors.rest.line2")); + } + if (!config.contains("sign-colors.rest.line3")) { + config.set("sign-colors.rest.line3", defaultConfig.getString("sign-colors.rest.line3", "&f")); + getLogger().info("Setze Standardwert: sign-colors.rest.line3 = " + config.getString("sign-colors.rest.line3")); + } + if (!config.contains("sign-colors.rest.line4")) { + config.set("sign-colors.rest.line4", defaultConfig.getString("sign-colors.rest.line4", "&1")); + getLogger().info("Setze Standardwert: sign-colors.rest.line4 = " + config.getString("sign-colors.rest.line4")); + } + } + // ---------------------------------------------- + if (!config.contains("messages.no-chest-near-sign")) { config.set("messages.no-chest-near-sign", defaultConfig.getString("messages.no-chest-near-sign", "&cKeine Truhe in der Nähe des Schildes!")); getLogger().info("Setze Standardwert: messages.no-chest-near-sign"); @@ -268,6 +296,13 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { config.set("messages.target-chest-set", defaultConfig.getString("messages.target-chest-set", "&aZieltruhe für %item% erfolgreich gesetzt!")); getLogger().info("Setze Standardwert: messages.target-chest-set"); } + // --- NEU: Message für Rest-Truhe --- + if (!config.contains("messages.rest-chest-set")) { + config.set("messages.rest-chest-set", defaultConfig.getString("messages.rest-chest-set", "&aRest-Truhe (Fallback) erfolgreich gesetzt!")); + getLogger().info("Setze Standardwert: messages.rest-chest-set"); + } + // ---------------------------------- + if (!config.contains("messages.target-chest-missing")) { config.set("messages.target-chest-missing", defaultConfig.getString("messages.target-chest-missing", "&cZieltruhe für %item% fehlt!")); getLogger().info("Setze Standardwert: messages.target-chest-missing"); @@ -278,7 +313,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { config.set("messages.target-chest-full", defaultTargetChestFull); getLogger().info("Setze oder aktualisiere Standardwert: messages.target-chest-full = " + defaultTargetChestFull); } - + // --- NEUE NACHRICHTEN FÜR ÖFFENTLICHEN MODUS --- if (!config.contains("messages.mode-changed")) { config.set("messages.mode-changed", defaultConfig.getString("messages.mode-changed", "&aModus gewechselt: &e%mode%")); @@ -308,6 +343,11 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { " &7[asc]\n" + " &7ziel\n" + "&f3. Rechtsklicke mit einem Item in der Hand.\n" + + "&eRest-Truhe (Fallback) erstellen:\n" + + "&f1. Platziere ein Schild an einer Truhe.\n" + + "&f2. Schreibe:\n" + + " &7[asc]\n" + + " &7rest\n" + "&eBefehle:\n" + "&f- &b/asc help &f- Zeigt diese Hilfe.\n" + "&f- &b/asc info &f- Zeigt Plugin-Informationen.\n" + @@ -471,6 +511,56 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { } } } + + // --- NEU: Rest-Truhe aktualisieren --- + String restPath = path + ".rest-chest"; + if (playerData.contains(restPath)) { + String worldName = playerData.getString(restPath + ".world"); + World world = getServer().getWorld(worldName); + 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(); + + if (!(chestBlock.getState() instanceof Chest)) { + getLogger().warning("Rest-Truhe bei " + chestLocation + " ist keine Truhe"); + continue; + } + + Chest chest = (Chest) chestBlock.getState(); + Inventory inventory = chest.getInventory(); + boolean isFull = isInventoryFull(inventory); + + for (Block face : new Block[] { + chestBlock.getRelative(1, 0, 0), + chestBlock.getRelative(-1, 0, 0), + chestBlock.getRelative(0, 0, 1), + chestBlock.getRelative(0, 0, -1) + }) { + if (face.getState() instanceof Sign sign && isSignAttachedToChest(face, chestBlock)) { + String[] lines = sign.getLines(); + String line0 = ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")); + String line1 = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")); + String line3 = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); + if (line0.equalsIgnoreCase("[asc]") && line1.equalsIgnoreCase("rest")) { + String colorType = isFull ? "full" : "rest"; + sign.setLine(0, getSignColor(colorType, "line1") + "[asc]"); + sign.setLine(1, getSignColor(colorType, "line2") + "rest"); + sign.setLine(3, getSignColor(colorType, "line4") + line3); + sign.update(); + if (isDebug()) { + getLogger().fine("Rest-Truhe-Schild bei " + face.getLocation() + " für Spieler UUID " + uuidString + " aktualisiert"); + } + } + } + } + } + // ------------------------------- } } @@ -542,6 +632,33 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { getLogger().info("Zieltruhe für " + getServer().getPlayer(playerUUID).getName() + " (" + itemType.name() + ") gesetzt bei " + location); } + // --- NEU: Methoden für Rest-Truhe --- + private void setRestChestLocation(UUID playerUUID, Location location) { + String path = "players." + playerUUID + ".rest-chest"; + playerData.set(path + ".world", location.getWorld().getName()); + playerData.set(path + ".x", location.getBlockX()); + playerData.set(path + ".y", location.getBlockY()); + playerData.set(path + ".z", location.getBlockZ()); + savePlayerData(); + getLogger().info("Rest-Truhe für " + getServer().getPlayer(playerUUID).getName() + " gesetzt bei " + location); + } + + private Location getRestChestLocation(UUID playerUUID) { + String path = "players." + playerUUID + ".rest-chest"; + if (!playerData.contains(path)) { + return null; + } + 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); + } + // ---------------------------------- + private Location getTargetChestLocation(UUID playerUUID, Material itemType) { String path = "players." + playerUUID + ".target-chests." + itemType.name(); if (!playerData.contains(path)) { @@ -637,6 +754,32 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { Block signBlock = event.getBlock(); String[] lines = event.getLines(); + // --- NEU: Sign Change für Rest-Truhe --- + if (lines.length >= 2 && lines[0].equalsIgnoreCase("[asc]") && lines[1].equalsIgnoreCase("rest")) { + Block chestBlock = null; + if (signBlock.getBlockData() instanceof WallSign wallSign) { + Block attachedBlock = signBlock.getRelative(wallSign.getFacing().getOppositeFace()); + if (attachedBlock.getState() instanceof Chest) { + chestBlock = attachedBlock; + } + } + + if (chestBlock == null) { + player.sendMessage(getMessage("no-chest-near-sign")); + getLogger().warning("Keine Truhe an Schild bei " + signBlock.getLocation() + " für Spieler " + player.getName()); + return; + } + + event.setLine(0, getSignColor("rest", "line1") + "[asc]"); + event.setLine(1, getSignColor("rest", "line2") + "rest"); + event.setLine(3, getSignColor("rest", "line4") + player.getName()); + setRestChestLocation(playerUUID, chestBlock.getLocation()); + player.sendMessage(getMessage("rest-chest-set")); + getLogger().info("Rest-Truhe für " + player.getName() + " gesetzt bei " + chestBlock.getLocation()); + return; // Wichtig, damit nicht input/target Logik auch greift + } + // ------------------------------- + if (lines.length >= 2 && lines[0].equalsIgnoreCase("[asc]") && lines[1].equalsIgnoreCase("input")) { Block chestBlock = null; if (signBlock.getBlockData() instanceof WallSign wallSign) { @@ -661,7 +804,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { } } - @EventHandler + @EventHandler public void onPlayerInteract(org.bukkit.event.player.PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; @@ -676,7 +819,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { if (clickedBlock.getState() instanceof Sign sign) { String[] lines = sign.getLines(); if (lines.length >= 2 && ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")).equalsIgnoreCase("[asc]")) { - + // Truhe finden Block chestBlock = null; if (sign.getBlockData() instanceof WallSign wallSign) { @@ -693,13 +836,14 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { } String line1Clean = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")); + boolean isTargetOrRest = line1Clean.equalsIgnoreCase("ziel") || line1Clean.equalsIgnoreCase("rest"); - // --- LOGIK FÜR ZIELTRUHEN (ZIEL) --- - if (line1Clean.equalsIgnoreCase("ziel")) { + // --- LOGIK FÜR ZIELTRUHEN (ZIEL) UND REST-TRUHEN --- + if (isTargetOrRest) { String line3Raw = lines[3] != null ? lines[3] : ""; String line3Clean = ChatColor.stripColor(line3Raw); String pureOwnerName = line3Clean.replace("[Public]", "").replace("[public]", "").trim(); - + boolean isOwner = pureOwnerName.equalsIgnoreCase(player.getName()); // 1. FALL: MODUS WECHSELN (Shift + Klick + Leere Hand) @@ -709,14 +853,16 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { String newModeText; String newLine4; + String colorType = line1Clean.equalsIgnoreCase("rest") ? "rest" : "target"; + if (isPublic) { // Wechsel zu Privat newModeText = getMessage("mode-private"); - newLine4 = getSignColor("target", "line4") + pureOwnerName; + newLine4 = getSignColor(colorType, "line4") + pureOwnerName; } else { // Wechsel zu Öffentlich newModeText = getMessage("mode-public"); - newLine4 = getSignColor("target", "line4") + pureOwnerName + " " + ChatColor.RESET + "[Public]"; + newLine4 = getSignColor(colorType, "line4") + pureOwnerName + " " + ChatColor.RESET + "[Public]"; } sign.setLine(3, newLine4); @@ -730,40 +876,45 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { return; } } - - // 2. FALL: ITEM ZUWEISEN / AKTUALISIEREN (Klick + Item in Hand) - // ERWEITERUNG: Wir prüfen nicht mehr, ob Zeile 2 leer ist. Wenn ein Item in der Hand ist, wird es aktualisiert. - if (itemInHand != null && itemInHand.getType() != Material.AIR) { - // Prüfe, ob der Spieler das Recht hat (Owner oder unbeansprucht) - if (!pureOwnerName.isEmpty() && !pureOwnerName.equalsIgnoreCase("Unknown") && !isOwner) { - player.sendMessage(getMessage("not-your-chest")); + + // 2. FALL: ITEM ZUWEISEN / AKTUALISIEREN (Nur bei ZIEL, nicht bei REST) + if (line1Clean.equalsIgnoreCase("ziel")) { + if (itemInHand != null && itemInHand.getType() != Material.AIR) { + // Prüfe, ob der Spieler das Recht hat (Owner oder unbeansprucht) + if (!pureOwnerName.isEmpty() && !pureOwnerName.equalsIgnoreCase("Unknown") && !isOwner) { + player.sendMessage(getMessage("not-your-chest")); + event.setCancelled(true); + return; + } + + // --- FIX: Alten Eintrag für diese Truhe löschen --- + removeOldTargetEntry(player.getUniqueId(), chestBlock.getLocation(), itemInHand.getType().name()); + // ------------------------------------------------ + + Chest chest = (Chest) chestBlock.getState(); + boolean isFull = isInventoryFull(chest.getInventory()); + String colorType = isFull ? "full" : "target"; + + sign.setLine(0, getSignColor(colorType, "line1") + "[asc]"); + sign.setLine(1, getSignColor(colorType, "line2") + "ziel"); + sign.setLine(2, getSignColor(colorType, "line3") + itemInHand.getType().name()); // Item wird überschrieben + + // Wenn noch kein Name da war, setze ihn + String finalLine4 = line3Raw; + if (pureOwnerName.isEmpty() || pureOwnerName.equalsIgnoreCase("Unknown")) { + finalLine4 = getSignColor("target", "line4") + player.getName(); + } + + sign.setLine(3, finalLine4); + sign.update(); + + setTargetChestLocation(player.getUniqueId(), chestBlock.getLocation(), itemInHand.getType()); + player.sendMessage(getMessage("target-chest-set").replace("%item%", itemInHand.getType().name())); event.setCancelled(true); return; } - - Chest chest = (Chest) chestBlock.getState(); - boolean isFull = isInventoryFull(chest.getInventory()); - String colorType = isFull ? "full" : "target"; - - sign.setLine(0, getSignColor(colorType, "line1") + "[asc]"); - sign.setLine(1, getSignColor(colorType, "line2") + "ziel"); - sign.setLine(2, getSignColor(colorType, "line3") + itemInHand.getType().name()); // Item wird überschrieben - - // Wenn noch kein Name da war, setze ihn - String finalLine4 = line3Raw; - if (pureOwnerName.isEmpty() || pureOwnerName.equalsIgnoreCase("Unknown")) { - finalLine4 = getSignColor("target", "line4") + player.getName(); - } - - sign.setLine(3, finalLine4); - sign.update(); - - setTargetChestLocation(player.getUniqueId(), chestBlock.getLocation(), itemInHand.getType()); - player.sendMessage(getMessage("target-chest-set").replace("%item%", itemInHand.getType().name())); - event.setCancelled(true); - return; } - + // Zugriffsschutz für konfigurierte Truhen (wenn kein Item in Hand zum Updaten) // Wenn nicht Owner und NICHT öffentlich -> Zugriff verweigern if (!isOwner && !isChestPublic(sign)) { @@ -771,9 +922,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { event.setCancelled(true); return; } - + // Wenn Owner oder Öffentlich -> Truhe öffnen lassen (Event nicht canceln) - return; + return; } // --- LOGIK FÜR EINGANGSTRUHEN (INPUT) --- @@ -810,12 +961,12 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { } } - // Zugriffsschutz - if (!isOwner && !isChestPublic(sign)) { - player.sendMessage(getMessage("not-your-chest")); - event.setCancelled(true); - return; - } + // Zugriffsschutz + if (!isOwner && !isChestPublic(sign)) { + player.sendMessage(getMessage("not-your-chest")); + event.setCancelled(true); + return; + } } } return; @@ -825,7 +976,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { if (clickedBlock.getState() instanceof Chest) { Block chestBlock = clickedBlock; Block signBlock = null; - + // Suche Schild for (Block face : new Block[] { chestBlock.getRelative(1, 0, 0), @@ -847,8 +998,8 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { String[] lines = sign.getLines(); String line1Clean = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")); - // NUR FÜR ZIELTRUHEN - if (line1Clean.equalsIgnoreCase("ziel")) { + // NUR FÜR ZIELTRUHEN und REST (hier nur Moduswechsel) + if (line1Clean.equalsIgnoreCase("ziel") || line1Clean.equalsIgnoreCase("rest")) { String line3Raw = lines[3] != null ? lines[3] : ""; String line3Clean = ChatColor.stripColor(line3Raw); String pureOwnerName = line3Clean.replace("[public]", "").replace("[Public]", "").trim(); @@ -860,8 +1011,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { boolean isPublic = isChestPublic(sign); String newModeText; String newLine4; - - String baseName = getSignColor("target", "line4") + pureOwnerName; + + String colorType = line1Clean.equalsIgnoreCase("rest") ? "rest" : "target"; + String baseName = getSignColor(colorType, "line4") + pureOwnerName; if (isPublic) { newModeText = getMessage("mode-private"); @@ -883,43 +1035,47 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { } } - // 2. FALL: ITEM ZUWEISEN (Nur wenn Zeile 2 leer ist - Logik beibehalten für Klick auf Truhe) - // Hinweis: Um das Item zu aktualisieren, sollte das Schild angeklickt werden, nicht die Truhe direkt. - // Dies verhindert, dass man versehentlich die Sortierung ändert, wenn man Items in die Truhe legen will. - String line2Clean = ChatColor.stripColor((String) (lines[2] != null ? lines[2] : "")); - if (line2Clean.isEmpty()) { - if (itemInHand == null || itemInHand.getType() == Material.AIR) { - player.sendMessage(getMessage("no-item-in-hand")); + // 2. FALL: ITEM ZUWEISEN (Nur bei ZIEL, nicht bei REST, und nur wenn Zeile 2 leer ist) + if (line1Clean.equalsIgnoreCase("ziel")) { + String line2Clean = ChatColor.stripColor((String) (lines[2] != null ? lines[2] : "")); + if (line2Clean.isEmpty()) { + if (itemInHand == null || itemInHand.getType() == Material.AIR) { + player.sendMessage(getMessage("no-item-in-hand")); + event.setCancelled(true); + return; + } + + if (!pureOwnerName.isEmpty() && !pureOwnerName.equalsIgnoreCase("Unknown") && !isOwner) { + player.sendMessage(getMessage("not-your-chest")); + event.setCancelled(true); + return; + } + + // --- FIX: Alten Eintrag auch beim Klick auf die Truhe löschen --- + removeOldTargetEntry(player.getUniqueId(), chestBlock.getLocation(), itemInHand.getType().name()); + // ----------------------------------------------------------- + + Chest chest = (Chest) chestBlock.getState(); + boolean isFull = isInventoryFull(chest.getInventory()); + String colorType = isFull ? "full" : "target"; + + sign.setLine(0, getSignColor(colorType, "line1") + "[asc]"); + sign.setLine(1, getSignColor(colorType, "line2") + "ziel"); + sign.setLine(2, getSignColor(colorType, "line3") + itemInHand.getType().name()); + + String finalLine4 = line3Raw; + if (pureOwnerName.isEmpty() || pureOwnerName.equalsIgnoreCase("Unknown")) { + finalLine4 = getSignColor("target", "line4") + player.getName(); + } + + sign.setLine(3, finalLine4); + sign.update(); + + setTargetChestLocation(player.getUniqueId(), chestBlock.getLocation(), itemInHand.getType()); + player.sendMessage(getMessage("target-chest-set").replace("%item%", itemInHand.getType().name())); event.setCancelled(true); return; } - - if (!pureOwnerName.isEmpty() && !pureOwnerName.equalsIgnoreCase("Unknown") && !isOwner) { - player.sendMessage(getMessage("not-your-chest")); - event.setCancelled(true); - return; - } - - Chest chest = (Chest) chestBlock.getState(); - boolean isFull = isInventoryFull(chest.getInventory()); - String colorType = isFull ? "full" : "target"; - - sign.setLine(0, getSignColor(colorType, "line1") + "[asc]"); - sign.setLine(1, getSignColor(colorType, "line2") + "ziel"); - sign.setLine(2, getSignColor(colorType, "line3") + itemInHand.getType().name()); - - String finalLine4 = line3Raw; - if (pureOwnerName.isEmpty() || pureOwnerName.equalsIgnoreCase("Unknown")) { - finalLine4 = getSignColor("target", "line4") + player.getName(); - } - - sign.setLine(3, finalLine4); - sign.update(); - - setTargetChestLocation(player.getUniqueId(), chestBlock.getLocation(), itemInHand.getType()); - player.sendMessage(getMessage("target-chest-set").replace("%item%", itemInHand.getType().name())); - event.setCancelled(true); - return; } // Wenn nicht Owner und nicht öffentlich -> Zugriff verweigern @@ -929,21 +1085,21 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { return; } } - + // FALL: EINGANGSTRUHE if (line1Clean.equalsIgnoreCase("input")) { - String line3Raw = lines[3] != null ? lines[3] : ""; - String line3Clean = ChatColor.stripColor(line3Raw); - String pureOwnerName = line3Clean.replace("[public]", "").replace("[Public]", "").trim(); - boolean isOwner = pureOwnerName.equalsIgnoreCase(player.getName()); + String line3Raw = lines[3] != null ? lines[3] : ""; + String line3Clean = ChatColor.stripColor(line3Raw); + String pureOwnerName = line3Clean.replace("[public]", "").replace("[Public]", "").trim(); + boolean isOwner = pureOwnerName.equalsIgnoreCase(player.getName()); - // Moduswechsel - if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) { + // Moduswechsel + if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) { if (isOwner) { boolean isPublic = isChestPublic(sign); String newModeText; String newLine4; - + String baseName = getSignColor("input", "line4") + pureOwnerName; if (isPublic) { @@ -963,19 +1119,19 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { event.setCancelled(true); return; } - } + } - if (!isOwner && !isChestPublic(sign)) { - player.sendMessage(getMessage("not-your-chest")); - event.setCancelled(true); - return; - } + if (!isOwner && !isChestPublic(sign)) { + player.sendMessage(getMessage("not-your-chest")); + event.setCancelled(true); + return; + } } } } } - @EventHandler(priority = EventPriority.HIGHEST) + @EventHandler(priority = EventPriority.HIGHEST) public void onBlockBreak(BlockBreakEvent event) { Block block = event.getBlock(); Player player = event.getPlayer(); @@ -991,7 +1147,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { if (block.getState() instanceof Sign sign) { String[] lines = sign.getLines(); if (lines.length >= 2 && ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")).equalsIgnoreCase("[asc]") && - (ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("input") || ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("ziel"))) { + (ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("input") || + ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("ziel") || + ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("rest"))) { // REST hinzugefügt signBlock = block; signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); if (isDebug()) { @@ -1011,7 +1169,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { if (face.getState() instanceof Sign sign && isSignAttachedToChest(face, block)) { String[] lines = sign.getLines(); if (lines.length >= 2 && ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")).equalsIgnoreCase("[asc]") && - (ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("input") || ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("ziel"))) { + (ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("input") || + ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("ziel") || + ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("rest"))) { // REST hinzugefügt signBlock = face; signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); isAscChest = true; @@ -1052,6 +1212,16 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { return; } + // --- Daten bereinigen beim Abbauen --- + String[] lines = ((Sign) (isAscChest ? signBlock.getState() : block.getState())).getLines(); + String line1 = ChatColor.stripColor(lines[1]); + if (line1.equalsIgnoreCase("rest")) { + playerData.set("players." + player.getUniqueId() + ".rest-chest", null); + savePlayerData(); + if (isDebug()) getLogger().info("Rest-Truhe Daten gelöscht für " + player.getName()); + } + // -------------------------------- + if (isDebug()) { getLogger().fine("Spieler " + player.getName() + " hat " + (isAscChest ? "Truhe" : "Schild") + " bei " + block.getLocation() + " erfolgreich abgebaut"); } @@ -1064,6 +1234,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { Player player = (Player) event.getPlayer(); Block chestBlock = chest.getBlock(); Block signBlock = null; + String signType = "target"; // default // Suche nach einem an die Truhe angehängten Schild for (Block face : new Block[] { @@ -1074,15 +1245,17 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { }) { if (face.getState() instanceof Sign sign && isSignAttachedToChest(face, chestBlock)) { String[] lines = sign.getLines(); - if (lines.length >= 2 && ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")).equalsIgnoreCase("[asc]") && ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("ziel")) { + String line1 = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")); + if (lines.length >= 2 && ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")).equalsIgnoreCase("[asc]") && (line1.equalsIgnoreCase("ziel") || line1.equalsIgnoreCase("rest"))) { signBlock = face; + if (line1.equalsIgnoreCase("rest")) signType = "rest"; break; } } } if (signBlock == null) { - if (isDebug()) getLogger().fine("Keine Zieltruhe-Schild an Truhe bei " + chestBlock.getLocation()); + if (isDebug()) getLogger().fine("Keine Zieltruhe/Rest-Truhe Schild an Truhe bei " + chestBlock.getLocation()); return; } @@ -1095,25 +1268,50 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { } boolean isFull = isInventoryFull(chest.getInventory()); - String colorType = isFull ? "full" : "target"; + + // FIX: Mapping 'ziel' -> 'target' + String configType = signType.equalsIgnoreCase("rest") ? "rest" : "target"; + String colorType = isFull ? "full" : configType; String currentLine0 = ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")); String currentLine1 = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")); - String currentLine2 = ChatColor.stripColor((String) (lines[2] != null ? lines[2] : "")); String currentLine3 = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); - if (currentLine0.equalsIgnoreCase("[asc]") && currentLine1.equalsIgnoreCase("ziel")) { + if (currentLine0.equalsIgnoreCase("[asc]") && (currentLine1.equalsIgnoreCase("ziel") || currentLine1.equalsIgnoreCase("rest"))) { sign.setLine(0, getSignColor(colorType, "line1") + "[asc]"); - sign.setLine(1, getSignColor(colorType, "line2") + "ziel"); - sign.setLine(2, getSignColor(colorType, "line3") + currentLine2); + sign.setLine(1, getSignColor(colorType, "line2") + currentLine1); // Behält "ziel" oder "rest" bei + sign.setLine(2, getSignColor(colorType, "line3") + lines[2]); // Zeile 2 (Item bei Ziel, leer bei Rest) sign.setLine(3, getSignColor(colorType, "line4") + currentLine3); sign.update(); if (isDebug()) { - getLogger().fine("Zieltruhe-Schild bei " + signBlock.getLocation() + " aktualisiert nach Inventar-Schließung (voll: " + isFull + ")"); + getLogger().fine(signType + "-Truhe Schild bei " + signBlock.getLocation() + " aktualisiert nach Inventar-Schließung (voll: " + isFull + ")"); } } } + // --- HILFSMETHODE zum Entfernen alter Einträge --- + private void removeOldTargetEntry(UUID uuid, Location loc, String newItemType) { + String basePath = "players." + uuid + ".target-chests"; + if (!playerData.contains(basePath)) return; + + for (String existingType : playerData.getConfigurationSection(basePath).getKeys(false)) { + if (existingType.equalsIgnoreCase(newItemType)) continue; // Gleiches Item ignorieren + + String path = basePath + "." + existingType; + if (playerData.getString(path + ".world").equals(loc.getWorld().getName()) && + playerData.getInt(path + ".x") == loc.getBlockX() && + playerData.getInt(path + ".y") == loc.getBlockY() && + playerData.getInt(path + ".z") == loc.getBlockZ()) { + + playerData.set(path, null); + if (isDebug()) getLogger().info("Altes Zieltruhen-Item '" + existingType + "' für " + uuid + " entfernt (Update)."); + // Nicht speichern hier, savePlayerData() wird am Ende von setTargetChestLocation aufgerufen + break; // Eine Truhe kann nur ein Item sein (nicht Rest) + } + } + } + // ---------------------------------------------- + private void distributeItems(Player player, Inventory sourceInventory) { UUID playerUUID = player.getUniqueId(); Block chestBlock = ((Chest) sourceInventory.getHolder()).getBlock(); @@ -1136,18 +1334,34 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { if (item == null || item.getType() == Material.AIR) continue; Location targetChestLocation = getTargetChestLocation(playerUUID, item.getType()); + boolean isRestChest = false; + + // Wenn kein spezifisches Ziel, versuche Rest-Truhe if (targetChestLocation == null) { - if (isDebug()) getLogger().fine("Keine Zieltruhe für Item " + item.getType().name() + " für Spieler " + player.getName()); + targetChestLocation = getRestChestLocation(playerUUID); + if (targetChestLocation != null) { + isRestChest = true; + } + } + + if (targetChestLocation == null) { + if (isDebug()) getLogger().fine("Keine Zieltruhe und keine Rest-Truhe für Item " + item.getType().name() + " für Spieler " + player.getName()); continue; } if (!(targetChestLocation.getBlock().getState() instanceof Chest)) { + String msgKey = isRestChest ? "target-chest-missing" : "target-chest-missing"; // Kann gleiche Nachricht nutzen if (canSendFullChestMessage(playerUUID, item.getType())) { - player.sendMessage(getMessage("target-chest-missing").replace("%item%", item.getType().name())); + player.sendMessage(getMessage(msgKey).replace("%item%", (isRestChest ? "Rest-Truhe" : item.getType().name()))); + } + + if (isRestChest) { + playerData.set("players." + playerUUID + ".rest-chest", null); + } else { + playerData.set("players." + playerUUID + ".target-chests." + item.getType().name(), null); } - playerData.set("players." + playerUUID + ".target-chests." + item.getType().name(), null); savePlayerData(); - getLogger().warning("Zieltruhe für " + item.getType().name() + " fehlt bei " + targetChestLocation); + getLogger().warning("Zieltruhe (" + (isRestChest ? "Rest" : item.getType().name()) + ") fehlt bei " + targetChestLocation); continue; } @@ -1157,6 +1371,8 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { boolean isValidTarget = false; String signOwner = "Unbekannt"; Block signBlock = null; + + // Sign Check erlaubt sowohl "ziel" als auch "rest" for (Block face : new Block[] { targetChest.getBlock().getRelative(1, 0, 0), targetChest.getBlock().getRelative(-1, 0, 0), @@ -1168,10 +1384,14 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { String line0 = ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")); String line1 = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")); String line3 = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); + + // Prüfen ob Schild-Typ zum erwarteten Ziel passt (Rest-Truhe muss "rest" Schild haben, Ziel muss "ziel" haben) + boolean typeMatches = isRestChest ? line1.equalsIgnoreCase("rest") : line1.equalsIgnoreCase("ziel"); + if (isDebug()) { getLogger().fine("Prüfe Zieltruhe-Schild bei " + face.getLocation() + ": Zeile 1='" + line0 + "', Zeile 2='" + line1 + "', Zeile 4='" + line3 + "' für Spieler " + player.getName()); } - if (line0.equalsIgnoreCase("[asc]") && line1.equalsIgnoreCase("ziel")) { + if (line0.equalsIgnoreCase("[asc]") && typeMatches) { signOwner = line3.isEmpty() ? "Unbekannt" : line3; if (line3.equalsIgnoreCase(player.getName())) { isValidTarget = true; @@ -1182,7 +1402,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { break; } } else if (isDebug()) { - getLogger().fine("Zieltruhe-Schild bei " + face.getLocation() + " hat ungültige Zeilen: [asc]=" + line0 + ", ziel=" + line1); + getLogger().fine("Zieltruhe-Schild bei " + face.getLocation() + " hat ungültige Zeilen oder Typ passt nicht: [asc]=" + line0 + ", typ=" + line1); } } } @@ -1206,10 +1426,14 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { String line1 = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")); String line2 = ChatColor.stripColor((String) (lines[2] != null ? lines[2] : "")); String line3 = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); - if (line0.equalsIgnoreCase("[asc]") && line1.equalsIgnoreCase("ziel")) { - String colorType = isFull ? "full" : "target"; + + if (line0.equalsIgnoreCase("[asc]") && (line1.equalsIgnoreCase("ziel") || line1.equalsIgnoreCase("rest"))) { + // FIX: Mapping 'ziel' -> 'target' + String configType = line1.equalsIgnoreCase("rest") ? "rest" : "target"; + String colorType = isFull ? "full" : configType; + sign.setLine(0, getSignColor(colorType, "line1") + "[asc]"); - sign.setLine(1, getSignColor(colorType, "line2") + "ziel"); + sign.setLine(1, getSignColor(colorType, "line2") + line1); sign.setLine(2, getSignColor(colorType, "line3") + line2); sign.setLine(3, getSignColor(colorType, "line4") + line3); sign.update(); @@ -1241,7 +1465,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { } } - private void checkInputChests() { + private void checkInputChests() { if (playerData == null) { getLogger().warning("playerData ist null. Kann Eingangstruhe nicht prüfen."); return; @@ -1298,12 +1522,12 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { 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; @@ -1329,141 +1553,168 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor { // 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? + // 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 distributeItems weiß, dass niemand Besitzer ist (für Messages). + // Wir setzen ownerPlayer auf null, damit distributeItemsForOwner weiß, dass niemand Besitzer ist (für Messages). + if (ownerPlayer == null || !ownerPlayer.isOnline()) { + ownerPlayer = null; + } } - // Wir rufen distributeItems auf. - // WICHTIG: distributeItems nutzt `player.getUniqueId()` um die Zieltruhen zu finden. + // 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 `distributeItems` nicht crasht, wenn player null ist. - + // Wir müssen aber aufpassen, dass `distributeItemsForOwner` nicht crasht, wenn player null ist. + distributeItemsForOwner(ownerUUID, ownerPlayer, chest.getInventory()); } } - // 4. KORRIGIERTE distributeItemsForOwner Methode: - private void distributeItemsForOwner(UUID ownerUUID, Player ownerPlayer, Inventory sourceInventory) { - boolean hasItems = false; - for (ItemStack item : sourceInventory.getContents()) { - if (item != null && item.getType() != Material.AIR) { - hasItems = true; - break; - } + // 4. KORRIGIERTE distributeItemsForOwner Methode: + private void distributeItemsForOwner(UUID ownerUUID, Player ownerPlayer, Inventory sourceInventory) { + boolean hasItems = false; + for (ItemStack item : sourceInventory.getContents()) { + if (item != null && item.getType() != Material.AIR) { + hasItems = true; + break; } - if (!hasItems) return; + } + if (!hasItems) return; - // Owner-Name ermitteln - String ownerName = "Unknown"; - if (ownerPlayer != null) { - ownerName = ownerPlayer.getName(); - } else { - // Offline-Namen aus PlayerData holen wenn möglich - org.bukkit.OfflinePlayer offlinePlayer = getServer().getOfflinePlayer(ownerUUID); - if (offlinePlayer.hasPlayedBefore()) { - ownerName = offlinePlayer.getName(); + // Owner-Name ermitteln + String ownerName = "Unknown"; + if (ownerPlayer != null) { + ownerName = ownerPlayer.getName(); + } else { + // Offline-Namen aus PlayerData holen wenn möglich + OfflinePlayer offlinePlayer = getServer().getOfflinePlayer(ownerUUID); + if (offlinePlayer.hasPlayedBefore()) { + ownerName = offlinePlayer.getName(); + } + } + + for (int slot = 0; slot < sourceInventory.getSize(); slot++) { + ItemStack item = sourceInventory.getItem(slot); + if (item == null || item.getType() == Material.AIR) continue; + + Location targetChestLocation = getTargetChestLocation(ownerUUID, item.getType()); + boolean isRestChest = false; + + // FALLBACK LOGIK: Wenn kein Ziel definiert, suche Rest-Truhe + if (targetChestLocation == null) { + targetChestLocation = getRestChestLocation(ownerUUID); + if (targetChestLocation != null) { + isRestChest = true; } } - for (int slot = 0; slot < sourceInventory.getSize(); slot++) { - ItemStack item = sourceInventory.getItem(slot); - if (item == null || item.getType() == Material.AIR) continue; + if (targetChestLocation == null) { + if (isDebug()) getLogger().fine("Kein Ziel und keine Rest-Truhe für Item " + item.getType().name()); + continue; + } - Location targetChestLocation = getTargetChestLocation(ownerUUID, item.getType()); - if (targetChestLocation == null) continue; + if (!(targetChestLocation.getBlock().getState() instanceof Chest)) { + if (ownerPlayer != null && canSendFullChestMessage(ownerUUID, item.getType())) { + ownerPlayer.sendMessage(getMessage("target-chest-missing").replace("%item%", (isRestChest ? "Rest-Truhe" : item.getType().name()))); + } - if (!(targetChestLocation.getBlock().getState() instanceof Chest)) { - if (ownerPlayer != null && canSendFullChestMessage(ownerUUID, item.getType())) { - ownerPlayer.sendMessage(getMessage("target-chest-missing").replace("%item%", item.getType().name())); - } + if (isRestChest) { + playerData.set("players." + ownerUUID + ".rest-chest", null); + } else { playerData.set("players." + ownerUUID + ".target-chests." + item.getType().name(), null); - savePlayerData(); - continue; } + savePlayerData(); + continue; + } - Chest targetChest = (Chest) targetChestLocation.getBlock().getState(); - Inventory targetInventory = targetChest.getInventory(); + Chest targetChest = (Chest) targetChestLocation.getBlock().getState(); + Inventory targetInventory = targetChest.getInventory(); - boolean isValidTarget = false; - Block signBlock = null; + boolean isValidTarget = false; + Block signBlock = null; - for (Block face : new Block[] { - targetChest.getBlock().getRelative(1, 0, 0), - targetChest.getBlock().getRelative(-1, 0, 0), - targetChest.getBlock().getRelative(0, 0, 1), - targetChest.getBlock().getRelative(0, 0, -1) - }) { - if (face.getState() instanceof Sign sign && isSignAttachedToChest(face, targetChest.getBlock())) { - String[] lines = sign.getLines(); - String line0 = ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")); - String line1 = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")); - String line3Clean = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); - - String signOwnerName = line3Clean.replace("[Public]", "").replace("[public]", "").trim(); - - if (line0.equalsIgnoreCase("[asc]") && line1.equalsIgnoreCase("ziel")) { - if (signOwnerName.equalsIgnoreCase(ownerName) || signOwnerName.equalsIgnoreCase("Unknown")) { - isValidTarget = true; - signBlock = face; - break; - } - } - } - } - - if (!isValidTarget) continue; - - ItemStack itemToTransfer = item.clone(); - Map leftover = targetInventory.addItem(itemToTransfer); - boolean isFull = isInventoryFull(targetInventory); - - if (signBlock != null) { - Sign sign = (Sign) signBlock.getState(); + for (Block face : new Block[] { + targetChest.getBlock().getRelative(1, 0, 0), + targetChest.getBlock().getRelative(-1, 0, 0), + targetChest.getBlock().getRelative(0, 0, 1), + targetChest.getBlock().getRelative(0, 0, -1) + }) { + if (face.getState() instanceof Sign sign && isSignAttachedToChest(face, targetChest.getBlock())) { String[] lines = sign.getLines(); String line0 = ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")); String line1 = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")); - String line2 = ChatColor.stripColor((String) (lines[2] != null ? lines[2] : "")); - String line3Raw = lines[3] != null ? lines[3] : ""; + String line3Clean = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); - if (line0.equalsIgnoreCase("[asc]") && line1.equalsIgnoreCase("ziel")) { - String colorType = isFull ? "full" : "target"; - sign.setLine(0, getSignColor(colorType, "line1") + "[asc]"); - sign.setLine(1, getSignColor(colorType, "line2") + "ziel"); - sign.setLine(2, getSignColor(colorType, "line3") + line2); - sign.setLine(3, line3Raw); - sign.update(); - } - } + // Typ-Check: Wenn isRestChest true, muss Schild "rest" sagen, sonst "ziel" + boolean typeMatches = isRestChest ? line1.equalsIgnoreCase("rest") : line1.equalsIgnoreCase("ziel"); - if (leftover.isEmpty()) { - sourceInventory.setItem(slot, null); - } else { - if (ownerPlayer != null && canSendFullChestMessage(ownerUUID, item.getType())) { - String message = getMessage("target-chest-full") - .replace("%item%", item.getType().name()) - .replace("%x%", String.valueOf(targetChestLocation.getBlockX())) - .replace("%y%", String.valueOf(targetChestLocation.getBlockY())) - .replace("%z%", String.valueOf(targetChestLocation.getBlockZ())); - ownerPlayer.sendMessage(message); - } - for (ItemStack leftoverItem : leftover.values()) { - if (leftoverItem != null && leftoverItem.getType() == item.getType()) { - item.setAmount(leftoverItem.getAmount()); - sourceInventory.setItem(slot, item); + String signOwnerName = line3Clean.replace("[Public]", "").replace("[public]", "").trim(); + + if (line0.equalsIgnoreCase("[asc]") && typeMatches) { + if (signOwnerName.equalsIgnoreCase(ownerName) || signOwnerName.equalsIgnoreCase("Unknown")) { + isValidTarget = true; + signBlock = face; break; } } } } + + if (!isValidTarget) continue; + + ItemStack itemToTransfer = item.clone(); + Map leftover = targetInventory.addItem(itemToTransfer); + boolean isFull = isInventoryFull(targetInventory); + + if (signBlock != null) { + Sign sign = (Sign) signBlock.getState(); + String[] lines = sign.getLines(); + String line0 = ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")); + String line1 = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")); + String line2 = ChatColor.stripColor((String) (lines[2] != null ? lines[2] : "")); + String line3Raw = lines[3] != null ? lines[3] : ""; + + if (line0.equalsIgnoreCase("[asc]") && (line1.equalsIgnoreCase("ziel") || line1.equalsIgnoreCase("rest"))) { + // FIX: Mapping 'ziel' -> 'target' + String configType = line1.equalsIgnoreCase("rest") ? "rest" : "target"; + String colorType = isFull ? "full" : configType; + + sign.setLine(0, getSignColor(colorType, "line1") + "[asc]"); + sign.setLine(1, getSignColor(colorType, "line2") + line1); + sign.setLine(2, getSignColor(colorType, "line3") + line2); + sign.setLine(3, line3Raw); // Original behalten (mit Farbe) + sign.update(); + } + } + + if (leftover.isEmpty()) { + sourceInventory.setItem(slot, null); + } else { + if (ownerPlayer != null && canSendFullChestMessage(ownerUUID, item.getType())) { + String message = getMessage("target-chest-full") + .replace("%item%", item.getType().name()) + .replace("%x%", String.valueOf(targetChestLocation.getBlockX())) + .replace("%y%", String.valueOf(targetChestLocation.getBlockY())) + .replace("%z%", String.valueOf(targetChestLocation.getBlockZ())); + ownerPlayer.sendMessage(message); + } + for (ItemStack leftoverItem : leftover.values()) { + if (leftoverItem != null && leftoverItem.getType() == item.getType()) { + item.setAmount(leftoverItem.getAmount()); + sourceInventory.setItem(slot, item); + break; + } + } + } } + } } \ No newline at end of file