From 8de26f6dc3110615dd1c6e33c8fedbd364a88803 Mon Sep 17 00:00:00 2001 From: M_Viper Date: Sun, 27 Jul 2025 13:43:31 +0000 Subject: [PATCH] Dateien nach "src/main/java/com/viper/autosortchest" hochladen --- .../java/com/viper/autosortchest/Main.java | 1113 +++++++++++++++++ 1 file changed, 1113 insertions(+) create mode 100644 src/main/java/com/viper/autosortchest/Main.java diff --git a/src/main/java/com/viper/autosortchest/Main.java b/src/main/java/com/viper/autosortchest/Main.java new file mode 100644 index 0000000..a54577b --- /dev/null +++ b/src/main/java/com/viper/autosortchest/Main.java @@ -0,0 +1,1113 @@ +package com.viper.autosortchest; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.block.Sign; +import org.bukkit.block.data.type.WallSign; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.ChatColor; +import org.bukkit.Material; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.*; + +public class Main extends JavaPlugin implements Listener, CommandExecutor { + private File playerDataFile; + private FileConfiguration playerData; + 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.2"; + + @Override + public void onEnable() { + // Lade Standard-Konfiguration + saveDefaultConfig(); + config = getConfig(); + + // Lade players.yml + playerDataFile = new File(getDataFolder(), "players.yml"); + if (!playerDataFile.exists()) { + saveResource("players.yml", false); + } + loadPlayerData(); + + // Registriere Events + getServer().getPluginManager().registerEvents(this, this); + + // Registriere Befehle + this.getCommand("asc").setExecutor(this); + + // Starte periodischen Task + new BukkitRunnable() { + @Override + public void run() { + checkInputChests(); + } + }.runTaskTimer(this, 20L, 20L); // Alle 1 Sekunde (20 Ticks) + + // Starte Task zum Bereinigen des Message-Trackers + new BukkitRunnable() { + @Override + public void run() { + cleanMessageTracker(); + } + }.runTaskTimer(this, 20L * 60, 20L * 60); // Alle Minute + + // Aktualisiere Konfiguration und Schilder + updateConfig(); + updateExistingSigns(); + + getLogger().info("AutoSortChest Plugin aktiviert! Version: " + getDescription().getVersion()); + } + + @Override + public void onDisable() { + savePlayerData(); + getLogger().info("AutoSortChest Plugin deaktiviert!"); + } + + private void savePlayerData() { + if (playerData == null || playerDataFile == null) { + getLogger().warning("Kann players.yml nicht speichern: playerData oder playerDataFile ist null"); + return; + } + try { + playerData.save(playerDataFile); + getLogger().info("players.yml erfolgreich gespeichert"); + } catch (IOException e) { + getLogger().warning("Fehler beim Speichern der players.yml: " + e.getMessage()); + } + } + + private void loadPlayerData() { + if (playerDataFile == null) { + playerDataFile = new File(getDataFolder(), "players.yml"); + } + try { + if (!playerDataFile.exists()) { + saveResource("players.yml", false); + getLogger().info("Neue players.yml erstellt"); + } + playerData = YamlConfiguration.loadConfiguration(playerDataFile); + if (playerData.getConfigurationSection("players") == null) { + getLogger().warning("Abschnitt 'players' in players.yml fehlt. Initialisiere leer."); + playerData.createSection("players"); + savePlayerData(); + } else { + int playerCount = playerData.getConfigurationSection("players").getKeys(false).size(); + getLogger().info("players.yml geladen mit " + playerCount + " Spieler-Einträgen"); + } + } catch (Exception e) { + getLogger().warning("Fehler beim Laden von players.yml: " + e.getMessage()); + playerData = new YamlConfiguration(); + playerData.createSection("players"); + savePlayerData(); + } + } + + private void updateConfig() { + File configFile = new File(getDataFolder(), "config.yml"); + InputStream defaultConfigStream = getResource("config.yml"); + FileConfiguration defaultConfig; + + // Lade Standardkonfiguration + if (defaultConfigStream == null) { + getLogger().warning("Standard-config.yml nicht gefunden in Plugin-Ressourcen! Verwende Fallback-Werte."); + defaultConfig = new YamlConfiguration(); + } else { + try { + defaultConfig = YamlConfiguration.loadConfiguration(new InputStreamReader(defaultConfigStream)); + getLogger().info("Standard-config.yml erfolgreich geladen."); + } catch (Exception e) { + getLogger().warning("Fehler beim Laden von Standard-config.yml: " + e.getMessage()); + defaultConfig = new YamlConfiguration(); + } + } + + // Prüfe Konfigurationsversion + String currentVersion = config.getString("version", "1.0"); + boolean versionUpdated = false; + if (!currentVersion.equals(CONFIG_VERSION)) { + getLogger().info("Aktualisiere config.yml von Version " + currentVersion + " auf " + CONFIG_VERSION); + config.set("version", CONFIG_VERSION); + versionUpdated = true; + } + + // Setze Standardwerte für fehlende Schlüssel + if (!config.contains("debug")) { + config.set("debug", defaultConfig.getBoolean("debug", false)); + getLogger().info("Setze Standardwert: debug = " + config.getBoolean("debug")); + } + + // Prüfe und setze sign-colors.input + if (!config.contains("sign-colors.input")) { + 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")); + getLogger().info("Setze Standardwerte für sign-colors.input"); + } else { + if (!config.contains("sign-colors.input.line1")) { + config.set("sign-colors.input.line1", defaultConfig.getString("sign-colors.input.line1", "&6")); + getLogger().info("Setze Standardwert: sign-colors.input.line1 = " + config.getString("sign-colors.input.line1")); + } + if (!config.contains("sign-colors.input.line2")) { + config.set("sign-colors.input.line2", defaultConfig.getString("sign-colors.input.line2", "&0")); + 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")); + getLogger().info("Setze Standardwert: sign-colors.input.line4 = " + config.getString("sign-colors.input.line4")); + } + } + + // Prüfe und setze sign-colors.target + if (!config.contains("sign-colors.target")) { + config.createSection("sign-colors.target"); + 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")); + getLogger().info("Setze Standardwerte für sign-colors.target"); + } else { + if (!config.contains("sign-colors.target.line1")) { + config.set("sign-colors.target.line1", defaultConfig.getString("sign-colors.target.line1", "&6")); + getLogger().info("Setze Standardwert: sign-colors.target.line1 = " + config.getString("sign-colors.target.line1")); + } + if (!config.contains("sign-colors.target.line2")) { + config.set("sign-colors.target.line2", defaultConfig.getString("sign-colors.target.line2", "&0")); + getLogger().info("Setze Standardwert: sign-colors.target.line2 = " + config.getString("sign-colors.target.line2")); + } + if (!config.contains("sign-colors.target.line3")) { + config.set("sign-colors.target.line3", defaultConfig.getString("sign-colors.target.line3", "&f")); + 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")); + getLogger().info("Setze Standardwert: sign-colors.target.line4 = " + config.getString("sign-colors.target.line4")); + } + } + + // Prüfe und setze sign-colors.full + if (!config.contains("sign-colors.full")) { + config.createSection("sign-colors.full"); + 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")); + getLogger().info("Setze Standardwerte für sign-colors.full"); + } else { + if (!config.contains("sign-colors.full.line1")) { + config.set("sign-colors.full.line1", defaultConfig.getString("sign-colors.full.line1", "&c")); + getLogger().info("Setze Standardwert: sign-colors.full.line1 = " + config.getString("sign-colors.full.line1")); + } + if (!config.contains("sign-colors.full.line2")) { + config.set("sign-colors.full.line2", defaultConfig.getString("sign-colors.full.line2", "&4")); + getLogger().info("Setze Standardwert: sign-colors.full.line2 = " + config.getString("sign-colors.full.line2")); + } + if (!config.contains("sign-colors.full.line3")) { + config.set("sign-colors.full.line3", defaultConfig.getString("sign-colors.full.line3", "&e")); + 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")); + getLogger().info("Setze Standardwert: sign-colors.full.line4 = " + config.getString("sign-colors.full.line4")); + } + } + + // Prüfe und setze messages + 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"); + } + if (!config.contains("messages.no-item-in-hand")) { + config.set("messages.no-item-in-hand", defaultConfig.getString("messages.no-item-in-hand", "&cDu musst ein Item in der Hand halten!")); + getLogger().info("Setze Standardwert: messages.no-item-in-hand"); + } + if (!config.contains("messages.not-your-chest")) { + config.set("messages.not-your-chest", defaultConfig.getString("messages.not-your-chest", "&cDiese Truhe gehört dir nicht!")); + getLogger().info("Setze Standardwert: messages.not-your-chest"); + } + if (!config.contains("messages.input-chest-set")) { + config.set("messages.input-chest-set", defaultConfig.getString("messages.input-chest-set", "&aEingangstruhe erfolgreich gesetzt!")); + getLogger().info("Setze Standardwert: messages.input-chest-set"); + } + if (!config.contains("messages.target-chest-set")) { + 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"); + } + 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"); + } + String targetChestFull = config.getString("messages.target-chest-full", ""); + String defaultTargetChestFull = defaultConfig.getString("messages.target-chest-full", "&cZieltruhe für %item% ist voll! Koordinaten: (%x%, %y%, %z%)"); + if (!config.contains("messages.target-chest-full") || !targetChestFull.equals(defaultTargetChestFull)) { + config.set("messages.target-chest-full", defaultTargetChestFull); + getLogger().info("Setze oder aktualisiere Standardwert: messages.target-chest-full = " + defaultTargetChestFull); + } + if (!config.contains("messages.help")) { + String helpMessage = "&6&l=== AutoSortChest Hilfe ===\n" + + "&eEingangstruhe erstellen:\n" + + "&f1. Platziere ein Schild an einer Truhe.\n" + + "&f2. Schreibe:\n" + + " &7[asc]\n" + + " &7input\n" + + "&fDein Name wird automatisch in Zeile 4 eingetragen.\n" + + "&eZieltruhe erstellen:\n" + + "&f1. Platziere ein Schild an einer Truhe.\n" + + "&f2. Schreibe:\n" + + " &7[asc]\n" + + " &7ziel\n" + + "&f3. Rechtsklicke mit einem Item in der Hand.\n" + + "&eBefehle:\n" + + "&f- &b/asc help &f- Zeigt diese Hilfe.\n" + + "&f- &b/asc info &f- Zeigt Plugin-Informationen.\n" + + "&f- &b/asc reload &f- Lädt die Konfiguration neu (OP).\n" + + "&6&l===================="; + config.set("messages.help", defaultConfig.getString("messages.help", helpMessage)); + getLogger().info("Setze Standardwert: messages.help"); + } + if (!config.contains("messages.info")) { + String infoMessage = "&6&l=== AutoSortChest Info ===\n" + + "&ePlugin: &fAutoSortChest\n" + + "&eVersion: &f%version%\n" + + "&eKonfigurationsversion: &f%config_version%\n" + + "&eErsteller: &f%author%\n" + + "&eBeschreibung: &fAutomatisches Sortieren von Items in Truhen.\n" + + "&6&l===================="; + config.set("messages.info", defaultConfig.getString("messages.info", infoMessage)); + getLogger().info("Setze Standardwert: messages.info"); + } + if (!config.contains("messages.no-permission")) { + config.set("messages.no-permission", defaultConfig.getString("messages.no-permission", "&cDu hast keine Berechtigung für diesen Befehl!")); + getLogger().info("Setze Standardwert: messages.no-permission"); + } + if (!config.contains("messages.reload-success")) { + config.set("messages.reload-success", defaultConfig.getString("messages.reload-success", "&aKonfiguration erfolgreich neu geladen!")); + getLogger().info("Setze Standardwert: messages.reload-success"); + } + if (!config.contains("messages.sign-break-denied")) { + config.set("messages.sign-break-denied", defaultConfig.getString("messages.sign-break-denied", "&cDu musst Shift gedrückt halten, um dieses Schild oder die Truhe abzubauen!")); + getLogger().info("Setze Standardwert: messages.sign-break-denied"); + } + + // Logge die Konfiguration vor dem Speichern + getLogger().info("Konfiguration vor dem Speichern: " + config.saveToString()); + + // Speichere die aktualisierte Konfiguration + try { + config.save(configFile); + if (configFile.exists() && configFile.length() > 0) { + getLogger().info("config.yml erfolgreich aktualisiert und gespeichert auf Version " + CONFIG_VERSION); + FileConfiguration savedConfig = YamlConfiguration.loadConfiguration(configFile); + getLogger().info("Gespeicherte config.yml: " + savedConfig.saveToString()); + } else { + getLogger().warning("config.yml wurde nicht korrekt gespeichert (Datei existiert nicht oder ist leer)"); + } + } catch (IOException e) { + getLogger().warning("Fehler beim Speichern der config.yml: " + e.getMessage()); + } + } + + private void updateExistingSigns() { + if (playerData == null) { + getLogger().warning("playerData ist null. Kann bestehende Schilder nicht aktualisieren."); + return; + } + if (playerData.getConfigurationSection("players") == null) { + getLogger().warning("Abschnitt 'players' in players.yml fehlt. Keine Schilder zum Aktualisieren."); + return; + } + + for (String uuidString : playerData.getConfigurationSection("players").getKeys(false)) { + UUID playerUUID; + try { + playerUUID = UUID.fromString(uuidString); + } catch (IllegalArgumentException e) { + getLogger().warning("Ungültige UUID in players.yml: " + uuidString); + continue; + } + + String path = "players." + uuidString; + + // Eingangstruhe + String inputPath = path + ".input-chest"; + if (playerData.contains(inputPath)) { + String worldName = playerData.getString(inputPath + ".world"); + World world = getServer().getWorld(worldName); + if (world == null) { + getLogger().warning("Welt " + worldName + " für Eingangstruhe von Spieler UUID " + uuidString + " nicht gefunden"); + continue; + } + int x = playerData.getInt(inputPath + ".x"); + int y = playerData.getInt(inputPath + ".y"); + int z = playerData.getInt(inputPath + ".z"); + Location chestLocation = new Location(world, x, y, z); + Block chestBlock = chestLocation.getBlock(); + + if (!(chestBlock.getState() instanceof Chest)) { + getLogger().warning("Eingangstruhe bei " + chestLocation + " ist keine Truhe"); + continue; + } + + 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("input")) { + sign.setLine(0, getSignColor("input", "line1") + "[asc]"); + sign.setLine(1, getSignColor("input", "line2") + "input"); + sign.setLine(3, getSignColor("input", "line4") + line3); + sign.update(); + if (isDebug()) { + getLogger().fine("Eingangsschild bei " + face.getLocation() + " für Spieler UUID " + uuidString + " aktualisiert"); + } + } + } + } + } + + // Zieltruhen + String targetPath = path + ".target-chests"; + if (playerData.contains(targetPath)) { + for (String itemType : playerData.getConfigurationSection(targetPath).getKeys(false)) { + String targetChestPath = targetPath + "." + itemType; + String worldName = playerData.getString(targetChestPath + ".world"); + World world = getServer().getWorld(worldName); + 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(); + + if (!(chestBlock.getState() instanceof Chest)) { + getLogger().warning("Zieltruhe für Item " + itemType + " 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 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"; + sign.setLine(0, getSignColor(colorType, "line1") + "[asc]"); + sign.setLine(1, getSignColor(colorType, "line2") + "ziel"); + sign.setLine(2, getSignColor(colorType, "line3") + line2); + sign.setLine(3, getSignColor(colorType, "line4") + line3); + sign.update(); + if (isDebug()) { + getLogger().fine("Zieltruhe-Schild für Item " + itemType + " bei " + face.getLocation() + " aktualisiert (voll: " + isFull + ")"); + } + } + } + } + } + } + } + } + + private boolean isInventoryFull(Inventory inventory) { + for (ItemStack item : inventory.getContents()) { + if (item == null || item.getAmount() < item.getMaxStackSize()) { + return false; + } + } + return true; + } + + private boolean isDebug() { + return config != null && config.getBoolean("debug", false); + } + + private String getMessage(String key) { + if (config == null) { + return ChatColor.RED + "Fehlende Konfiguration: " + key; + } + String message = config.getString("messages." + key, "Fehlende Nachricht: " + key); + return ChatColor.translateAlternateColorCodes('&', message); + } + + private String getSignColor(String type, String line) { + if (config == null) { + return "&f"; + } + String color = config.getString("sign-colors." + type + "." + line, "&f"); + return ChatColor.translateAlternateColorCodes('&', color); + } + + private boolean isSignAttachedToChest(Block signBlock, Block chestBlock) { + if (!(signBlock.getBlockData() instanceof WallSign)) { + if (isDebug()) getLogger().fine("Schild bei " + signBlock.getLocation() + " ist kein Wandschild"); + return false; + } + WallSign wallSign = (WallSign) signBlock.getBlockData(); + Block attachedBlock = signBlock.getRelative(wallSign.getFacing().getOppositeFace()); + boolean attached = attachedBlock.equals(chestBlock); + if (!attached && isDebug()) { + getLogger().fine("Schild bei " + signBlock.getLocation() + " ist nicht an Truhe bei " + chestBlock.getLocation() + " angebracht"); + } + return attached; + } + + private void setInputChestLocation(UUID playerUUID, Location location) { + String path = "players." + playerUUID + ".input-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(); + } + + private void setTargetChestLocation(UUID playerUUID, Location location, Material itemType) { + String path = "players." + playerUUID + ".target-chests." + itemType.name(); + 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("Zieltruhe für " + getServer().getPlayer(playerUUID).getName() + " (" + itemType.name() + ") gesetzt bei " + location); + } + + private Location getTargetChestLocation(UUID playerUUID, Material itemType) { + String path = "players." + playerUUID + ".target-chests." + itemType.name(); + if (!playerData.contains(path)) { + if (isDebug()) getLogger().fine("Keine Zieltruhe für Item " + itemType.name() + " für Spieler UUID " + playerUUID); + return null; + } + + String worldName = playerData.getString(path + ".world"); + World world = getServer().getWorld(worldName); + if (world == null) { + getLogger().warning("Welt " + worldName + " für Zieltruhe von Item " + itemType.name() + " nicht gefunden"); + 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 void cleanMessageTracker() { + long currentTime = System.currentTimeMillis(); + fullChestMessageTracker.entrySet().removeIf(entry -> { + Map messages = entry.getValue(); + messages.entrySet().removeIf(msg -> currentTime - msg.getValue() > MESSAGE_COOLDOWN); + return messages.isEmpty(); + }); + } + + private boolean canSendFullChestMessage(UUID playerUUID, Material material) { + Map playerMessages = fullChestMessageTracker.computeIfAbsent(playerUUID, k -> new HashMap<>()); + Long lastMessageTime = playerMessages.get(material); + long currentTime = System.currentTimeMillis(); + + if (lastMessageTime == null || currentTime - lastMessageTime > MESSAGE_COOLDOWN) { + playerMessages.put(material, currentTime); + return true; + } + return false; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!command.getName().equalsIgnoreCase("asc")) return false; + + if (!(sender instanceof Player)) { + sender.sendMessage(ChatColor.RED + "Dieser Befehl ist nur für Spieler!"); + return true; + } + + Player player = (Player) sender; + + if (args.length == 0 || args[0].equalsIgnoreCase("help")) { + String helpMessage = getMessage("help"); + player.sendMessage(helpMessage.split("\n")); + return true; + } + + if (args[0].equalsIgnoreCase("info")) { + String infoMessage = getMessage("info") + .replace("%version%", getDescription().getVersion()) + .replace("%config_version%", config != null ? config.getString("version", CONFIG_VERSION) : CONFIG_VERSION) + .replace("%author%", String.join(", ", getDescription().getAuthors())); + player.sendMessage(infoMessage.split("\n")); + return true; + } + + if (args[0].equalsIgnoreCase("reload")) { + if (!player.hasPermission("autosortchest.reload")) { + player.sendMessage(getMessage("no-permission")); + return true; + } + reloadConfig(); + config = getConfig(); + loadPlayerData(); + updateConfig(); + updateExistingSigns(); + player.sendMessage(getMessage("reload-success")); + getLogger().info("Konfiguration und Spielerdaten neu geladen durch " + player.getName()); + return true; + } + + String helpMessage = getMessage("help"); + player.sendMessage(helpMessage.split("\n")); + return true; + } + + @EventHandler + public void onSignChange(SignChangeEvent event) { + Player player = event.getPlayer(); + UUID playerUUID = player.getUniqueId(); + Block signBlock = event.getBlock(); + String[] lines = event.getLines(); + + if (lines.length >= 2 && lines[0].equalsIgnoreCase("[asc]") && lines[1].equalsIgnoreCase("input")) { + 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("input", "line1") + "[asc]"); + event.setLine(1, getSignColor("input", "line2") + "input"); + event.setLine(3, getSignColor("input", "line4") + player.getName()); + setInputChestLocation(playerUUID, chestBlock.getLocation()); + player.sendMessage(getMessage("input-chest-set")); + getLogger().info("Eingangstruhe für " + player.getName() + " gesetzt bei " + chestBlock.getLocation()); + } + } + + @EventHandler + public void onPlayerInteract(org.bukkit.event.player.PlayerInteractEvent event) { + if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; + + Player player = event.getPlayer(); + UUID playerUUID = player.getUniqueId(); + Block clickedBlock = event.getClickedBlock(); + ItemStack itemInHand = event.getItem(); + + if (clickedBlock == null) return; + + // Schild-Interaktion + if (clickedBlock.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("ziel")) { + Block chestBlock = null; + if (sign.getBlockData() instanceof WallSign wallSign) { + Block attachedBlock = sign.getBlock().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 " + sign.getLocation() + " für Spieler " + player.getName()); + event.setCancelled(true); + return; + } + + String signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); + if (!signOwner.isEmpty() && !signOwner.equalsIgnoreCase(player.getName())) { + player.sendMessage(getMessage("not-your-chest")); + getLogger().warning("Schild bei " + sign.getLocation() + " gehört nicht Spieler " + player.getName() + " (Besitzer: " + signOwner + ")"); + event.setCancelled(true); + return; + } + + String line2 = ChatColor.stripColor((String) (lines[2] != null ? lines[2] : "")); + if (itemInHand == null || itemInHand.getType() == Material.AIR) { + if (line2.isEmpty()) { + player.sendMessage(getMessage("no-item-in-hand")); + event.setCancelled(true); + } + // Wenn line2 nicht leer ist, keine Aktion erforderlich (Schild nicht verändern, Event nicht abbrechen) + 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()); + sign.setLine(3, getSignColor(colorType, "line4") + player.getName()); + sign.update(); + setTargetChestLocation(playerUUID, chestBlock.getLocation(), itemInHand.getType()); + player.sendMessage(getMessage("target-chest-set").replace("%item%", itemInHand.getType().name())); + event.setCancelled(true); + return; + } + return; + } + + // Truhe-Interaktion + if (clickedBlock.getState() instanceof Chest) { + Block chestBlock = clickedBlock; + Block signBlock = null; + 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(); + if (lines.length >= 2 && ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")).equalsIgnoreCase("[asc]") && ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("ziel")) { + signBlock = face; + break; + } + } + } + + if (signBlock == null) { + if (isDebug()) getLogger().fine("Kein [asc]-Zielschild an Truhe bei " + chestBlock.getLocation()); + return; + } + + Sign sign = (Sign) signBlock.getState(); + String[] lines = sign.getLines(); + String signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); + if (!signOwner.isEmpty() && !signOwner.equalsIgnoreCase(player.getName())) { + player.sendMessage(getMessage("not-your-chest")); + getLogger().warning("Schild bei " + sign.getLocation() + " gehört nicht Spieler " + player.getName() + " (Besitzer: " + signOwner + ")"); + event.setCancelled(true); + return; + } + + String line2 = ChatColor.stripColor((String) (lines[2] != null ? lines[2] : "")); + if (itemInHand == null || itemInHand.getType() == Material.AIR) { + if (line2.isEmpty()) { + player.sendMessage(getMessage("no-item-in-hand")); + event.setCancelled(true); + } + // Wenn line2 nicht leer ist, Truhe normal öffnen lassen (Event nicht abbrechen) + 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()); + sign.setLine(3, getSignColor(colorType, "line4") + player.getName()); + sign.update(); + setTargetChestLocation(playerUUID, chestBlock.getLocation(), itemInHand.getType()); + player.sendMessage(getMessage("target-chest-set").replace("%item%", itemInHand.getType().name())); + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onBlockBreak(BlockBreakEvent event) { + Block block = event.getBlock(); + Player player = event.getPlayer(); + Block signBlock = null; + String signOwner = ""; + boolean isAscChest = false; + + if (isDebug()) { + getLogger().fine("BlockBreakEvent ausgelöst bei " + block.getLocation() + " durch Spieler " + player.getName() + ", GameMode: " + player.getGameMode() + ", Sneaking: " + player.isSneaking() + ", OP: " + player.isOp() + ", Berechtigung autosortchest.bypass: " + player.hasPermission("autosortchest.bypass")); + } + + // Fall 1: Schild wird abgebaut + 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"))) { + signBlock = block; + signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); + if (isDebug()) { + getLogger().fine("Schild erkannt bei " + block.getLocation() + ", Besitzer: " + signOwner); + } + } + } + + // Fall 2: Truhe wird abgebaut + if (block.getState() instanceof Chest chestBlock) { + for (Block face : new Block[] { + block.getRelative(1, 0, 0), + block.getRelative(-1, 0, 0), + block.getRelative(0, 0, 1), + block.getRelative(0, 0, -1) + }) { + 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"))) { + signBlock = face; + signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); + isAscChest = true; + if (isDebug()) { + getLogger().fine("Truhe mit [asc]-Schild erkannt bei " + block.getLocation() + ", Schild bei " + face.getLocation() + ", Besitzer: " + signOwner); + } + break; + } + } + } + } + + // Kein [asc]-Schild oder keine Truhe mit [asc]-Schild + if (signBlock == null) { + if (isDebug()) { + getLogger().fine("Kein [asc]-Schild oder Truhe mit [asc]-Schild bei " + block.getLocation()); + } + return; + } + + // Prüfe Besitzer + boolean isOwner = signOwner.isEmpty() || signOwner.equalsIgnoreCase(player.getName()); + + if (!isOwner) { + player.sendMessage(getMessage("not-your-chest")); + event.setCancelled(true); + getLogger().warning("Spieler " + player.getName() + " versuchte, " + (isAscChest ? "Truhe" : "Schild") + " bei " + block.getLocation() + " abzubauen, das nicht ihm gehört (Besitzer: " + signOwner + ")"); + return; + } + + // Prüfe Shift-Taste (Berechtigungen ignorieren) + if (!player.isSneaking()) { + player.sendMessage(getMessage("sign-break-denied")); + event.setCancelled(true); + if (isDebug()) { + getLogger().fine("Spieler " + player.getName() + " versuchte, " + (isAscChest ? "Truhe" : "Schild") + " bei " + block.getLocation() + " ohne Shift abzubauen"); + } + return; + } + + if (isDebug()) { + getLogger().fine("Spieler " + player.getName() + " hat " + (isAscChest ? "Truhe" : "Schild") + " bei " + block.getLocation() + " erfolgreich abgebaut"); + } + } + + @EventHandler + public void onInventoryClose(InventoryCloseEvent event) { + if (!(event.getInventory().getHolder() instanceof Chest chest)) return; + + Player player = (Player) event.getPlayer(); + Block chestBlock = chest.getBlock(); + Block signBlock = null; + + // Suche nach einem an die Truhe angehängten Schild + 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(); + if (lines.length >= 2 && ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")).equalsIgnoreCase("[asc]") && ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("ziel")) { + signBlock = face; + break; + } + } + } + + if (signBlock == null) { + if (isDebug()) getLogger().fine("Keine Zieltruhe-Schild an Truhe bei " + chestBlock.getLocation()); + return; + } + + Sign sign = (Sign) signBlock.getState(); + String[] lines = sign.getLines(); + String signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); + if (!signOwner.equalsIgnoreCase(player.getName())) { + if (isDebug()) getLogger().fine("Schild bei " + signBlock.getLocation() + " gehört nicht Spieler " + player.getName() + " (Besitzer: " + signOwner + ")"); + return; + } + + boolean isFull = isInventoryFull(chest.getInventory()); + String colorType = isFull ? "full" : "target"; + + 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")) { + sign.setLine(0, getSignColor(colorType, "line1") + "[asc]"); + sign.setLine(1, getSignColor(colorType, "line2") + "ziel"); + sign.setLine(2, getSignColor(colorType, "line3") + currentLine2); + 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 + ")"); + } + } + } + + private void distributeItems(Player player, Inventory sourceInventory) { + UUID playerUUID = player.getUniqueId(); + Block chestBlock = ((Chest) sourceInventory.getHolder()).getBlock(); + + // Prüfe, ob die Truhe leer ist + boolean hasItems = false; + for (ItemStack item : sourceInventory.getContents()) { + if (item != null && item.getType() != Material.AIR) { + hasItems = true; + break; + } + } + if (!hasItems) { + if (isDebug()) getLogger().fine("Eingangstruhe bei " + chestBlock.getLocation() + " ist leer"); + return; + } + + for (int slot = 0; slot < sourceInventory.getSize(); slot++) { + ItemStack item = sourceInventory.getItem(slot); + if (item == null || item.getType() == Material.AIR) continue; + + Location targetChestLocation = getTargetChestLocation(playerUUID, item.getType()); + if (targetChestLocation == null) { + if (isDebug()) getLogger().fine("Keine Zieltruhe für Item " + item.getType().name() + " für Spieler " + player.getName()); + continue; + } + + if (!(targetChestLocation.getBlock().getState() instanceof Chest)) { + if (canSendFullChestMessage(playerUUID, item.getType())) { + player.sendMessage(getMessage("target-chest-missing").replace("%item%", item.getType().name())); + } + playerData.set("players." + playerUUID + ".target-chests." + item.getType().name(), null); + savePlayerData(); + getLogger().warning("Zieltruhe für " + item.getType().name() + " fehlt bei " + targetChestLocation); + continue; + } + + Chest targetChest = (Chest) targetChestLocation.getBlock().getState(); + Inventory targetInventory = targetChest.getInventory(); + + boolean isValidTarget = false; + String signOwner = "Unbekannt"; + 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 line3 = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); + 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")) { + signOwner = line3.isEmpty() ? "Unbekannt" : line3; + if (line3.equalsIgnoreCase(player.getName())) { + isValidTarget = true; + signBlock = face; + if (isDebug()) { + getLogger().fine("Gültiges Zieltruhe-Schild gefunden bei " + face.getLocation() + " für Spieler " + player.getName()); + } + break; + } + } else if (isDebug()) { + getLogger().fine("Zieltruhe-Schild bei " + face.getLocation() + " hat ungültige Zeilen: [asc]=" + line0 + ", ziel=" + line1); + } + } + } + + if (!isValidTarget) { + if (canSendFullChestMessage(playerUUID, item.getType())) { + player.sendMessage(getMessage("not-your-chest")); + } + getLogger().warning("Zieltruhe bei " + targetChestLocation + " gehört nicht Spieler " + player.getName() + " (Besitzer: " + signOwner + ")"); + 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 line3 = 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, getSignColor(colorType, "line4") + line3); + sign.update(); + if (isDebug()) { + getLogger().fine("Zieltruhe-Schild bei " + signBlock.getLocation() + " aktualisiert (voll: " + isFull + ")"); + } + } + } + + if (leftover.isEmpty()) { + sourceInventory.setItem(slot, null); + } else { + if (canSendFullChestMessage(playerUUID, 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())); + player.sendMessage(message); + } + for (ItemStack leftoverItem : leftover.values()) { + if (leftoverItem != null && leftoverItem.getType() == item.getType()) { + item.setAmount(leftoverItem.getAmount()); + sourceInventory.setItem(slot, item); + break; + } + } + } + } + } + + private void checkInputChests() { + if (playerData == null) { + getLogger().warning("playerData ist null. Kann Eingangstruchen nicht prüfen."); + return; + } + if (playerData.getConfigurationSection("players") == null) { + getLogger().warning("Abschnitt 'players' in players.yml fehlt. Keine Eingangstruchen zu prüfen."); + return; + } + + for (String uuidString : playerData.getConfigurationSection("players").getKeys(false)) { + UUID playerUUID; + try { + playerUUID = UUID.fromString(uuidString); + } catch (IllegalArgumentException e) { + getLogger().warning("Ungültige UUID in players.yml: " + uuidString); + continue; + } + + Player player = getServer().getPlayer(playerUUID); + if (player == null || !player.isOnline()) continue; + + String path = "players." + uuidString + ".input-chest"; + if (!playerData.contains(path)) continue; + + String worldName = playerData.getString(path + ".world"); + World world = getServer().getWorld(worldName); + if (world == null) { + getLogger().warning("Welt " + worldName + " für Eingangstruhe von Spieler " + player.getName() + " nicht gefunden"); + continue; + } + + int x = playerData.getInt(path + ".x"); + int y = playerData.getInt(path + ".y"); + int z = playerData.getInt(path + ".z"); + Location location = new Location(world, x, y, z); + + if (!(location.getBlock().getState() instanceof Chest)) { + if (isDebug()) { + getLogger().fine("Eingangstruhe für Spieler " + player.getName() + " bei " + location + " existiert nicht"); + } + continue; + } + + Chest chest = (Chest) location.getBlock().getState(); + boolean isValidInput = false; + for (Block face : new Block[] { + chest.getBlock().getRelative(1, 0, 0), + chest.getBlock().getRelative(-1, 0, 0), + chest.getBlock().getRelative(0, 0, 1), + chest.getBlock().getRelative(0, 0, -1) + }) { + if (face.getState() instanceof Sign sign && isSignAttachedToChest(face, chest.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 line3 = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); + if (isDebug()) { + getLogger().fine("Prüfe Eingangsschild bei " + face.getLocation() + ": Zeile 1='" + line0 + "', Zeile 2='" + line1 + "', Zeile 4='" + line3 + "' für Spieler " + player.getName()); + } + if (line0.equalsIgnoreCase("[asc]") && line1.equalsIgnoreCase("input")) { + if (line3.equalsIgnoreCase(player.getName())) { + isValidInput = true; + if (isDebug()) { + getLogger().fine("Gültiges Eingangsschild gefunden bei " + face.getLocation() + " für Spieler " + player.getName()); + } + break; + } else if (isDebug()) { + getLogger().fine("Eingangsschild bei " + face.getLocation() + " gehört nicht Spieler " + player.getName() + " (Besitzer: " + line3 + ")"); + } + } else if (isDebug()) { + getLogger().fine("Eingangsschild bei " + face.getLocation() + " hat ungültige Zeilen: [asc]=" + line0 + ", input=" + line1); + } + } + } + + if (!isValidInput) { + if (isDebug()) { + getLogger().fine("Truhe bei " + location + " ist keine gültige Eingangstruhe für Spieler " + player.getName()); + } + continue; + } + + distributeItems(player, chest.getInventory()); + } + } +} \ No newline at end of file