6 Commits
1.8 ... main

5 changed files with 613 additions and 161 deletions

View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.viper</groupId> <groupId>com.viper</groupId>
<artifactId>AutoSortChest</artifactId> <artifactId>AutoSortChest</artifactId>
<version>1.8</version> <version>1.9</version>
<name>AutoSortChest</name> <name>AutoSortChest</name>
<repositories> <repositories>

View File

@@ -2,9 +2,13 @@ package com.viper.autosortchest;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Color;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.Particle;
import org.bukkit.Particle.DustOptions;
import org.bukkit.Sound;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.Chest; import org.bukkit.block.Chest;
@@ -24,11 +28,14 @@ import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -42,7 +49,82 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
private FileConfiguration config; private FileConfiguration config;
private final Map<UUID, Map<Material, Long>> fullChestMessageTracker = new HashMap<>(); private final Map<UUID, Map<Material, Long>> fullChestMessageTracker = new HashMap<>();
private static final long MESSAGE_COOLDOWN = 5 * 60 * 1000; // 5 Minuten in Millisekunden private static final long MESSAGE_COOLDOWN = 5 * 60 * 1000; // 5 Minuten in Millisekunden
private static final String CONFIG_VERSION = "1.7"; // Version erhöht für das Update private static final String CONFIG_VERSION = "1.8";
// --- NEU: Update Checker Variabben ---
private boolean updateAvailable = false;
private String latestVersion = "";
// --------------------------------------------------
// --- Hardcodierte Nachrichten (DE & EN) für Hilfe und Info (Safe in Java) ---
private static final String HELP_DE =
"&6&l=== AutoSortChest Hilfe ===\n" +
"&eEingangstruhe erstellen:\n" +
"&f1. Platziere ein Schild an einer Truhe.\n" +
"&f2. Schreibe:\n" +
" &7[asc]\n" +
" &7input\n" +
"&f3. Fülle die Truhe mit Items.\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" +
"&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" +
"&f- &b/asc reload &f- Lädt die Konfiguration neu (OP).\n" +
"&6&l========================";
private static final String HELP_EN =
"&6&l=== AutoSortChest Help ===\n" +
"&eCreate Input Chest:\n" +
"&f1. Place a sign on a chest.\n" +
"&f2. Write:\n" +
" &7[asc]\n" +
" &7input\n" +
"&f3. Fill the chest with items.\n" +
"&eCreate Target Chest:\n" +
"&f1. Place a sign on a chest.\n" +
"&f2. Write:\n" +
" &7[asc]\n" +
" &7target\n" +
"&f3. Right-click with an item in hand.\n" +
"&eCreate Rest Chest (Fallback):\n" +
"&f1. Place a sign on a chest.\n" +
"&f2. Write:\n" +
" &7[asc]\n" +
" &7rest\n" +
"&eCommands:\n" +
"&f- &b/asc help &f- Shows this help.\n" +
"&f- &b/asc info &f- Shows plugin info.\n" +
"&f- &b/asc reload &f- Reloads the config (OP only).\n" +
"&6&l========================";
private static final String INFO_DE =
"&6&l=== AutoSortChest Info ===\n" +
"&ePlugin: &fAutoSortChest\n" +
"&eVersion: &f%version%\n" +
"&eConfig-Version: &f%config_version%\n" +
"&eErsteller: &f%author%\n" +
"&eBeschreibung: &fAutomatisches Sortieren von Items in Truhen.\n" +
"&6&l========================";
private static final String INFO_EN =
"&6&l=== AutoSortChest Info ===\n" +
"&ePlugin: &fAutoSortChest\n" +
"&eVersion: &f%version%\n" +
"&eConfig-Version: &f%config_version%\n" +
"&eAuthor: &f%author%\n" +
"&eDescription: &fAutomatically sorts items into chests.\n" +
"&6&l========================";
// ----------------------------------------------------------------------------------
@Override @Override
public void onEnable() { public void onEnable() {
@@ -86,6 +168,29 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
// ERWEITERUNG: Migration alter Daten in das neue Listen-System // ERWEITERUNG: Migration alter Daten in das neue Listen-System
migrateInputChests(); migrateInputChests();
// --- NEU: Update Checker Start (Ganz oben in onEnable) ---
new UpdateChecker(this, 131309).getVersion(version -> {
Bukkit.getScheduler().runTask(this, () -> {
if (this.getDescription().getVersion().equals(version)) {
this.updateAvailable = false;
this.latestVersion = version;
getLogger().info("Es ist kein neues Update verfügbar.");
} else {
this.updateAvailable = true;
this.latestVersion = version;
getLogger().info(" ");
getLogger().info("========================================");
getLogger().info("Eine neue Version ist verfügbar: " + version);
getLogger().info("Deine Version: " + this.getDescription().getVersion());
getLogger().info("Download: https://www.spigotmc.org/resources/" + 131309 + "/");
getLogger().info("========================================");
getLogger().info(" ");
}
});
});
// ----------------------------------------------------
// ASCII ART LOGO // ASCII ART LOGO
getLogger().info(""); getLogger().info("");
getLogger().info(" ___ _ _____ _ _____ _ _ "); getLogger().info(" ___ _ _____ _ _____ _ _ ");
@@ -105,6 +210,38 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
getLogger().info("AutoSortChest Plugin deaktiviert!"); getLogger().info("AutoSortChest Plugin deaktiviert!");
} }
// --- NEU: In-Game Update Nachricht (Hier platziert wie gewünscht) ---
@EventHandler
public void onPlayerJoin(org.bukkit.event.player.PlayerJoinEvent event) {
// Nur wenn ein Update verfügbar ist
if (!updateAvailable) return;
Player player = event.getPlayer();
// Nur an Admins senden
if (!isAdmin(player)) return;
// Kurze Verzögerung (1 Sekunde), damit die Chat-Nachricht nicht im "Welcome" Spam untergeht
new BukkitRunnable() {
@Override
public void run() {
player.sendMessage(ChatColor.GOLD + "========================================");
player.sendMessage(ChatColor.GOLD + "[AutoSortChest] " + ChatColor.YELLOW + "Es ist ein Update verfügbar!");
player.sendMessage(ChatColor.GRAY + "Deine Version: " + ChatColor.RED + getDescription().getVersion());
player.sendMessage(ChatColor.GRAY + "Neue Version: " + ChatColor.GREEN + latestVersion);
player.sendMessage(ChatColor.GRAY + "Download: " + ChatColor.AQUA + "https://www.spigotmc.org/resources/" + 131309 + "/");
player.sendMessage(ChatColor.GOLD + "========================================");
}
}.runTaskLater(this, 20L * 1); // 1 Sekunde Verzögerung
}
// --------------------------------------------------------------
// --- NEU: Admin Prüfung ---
private boolean isAdmin(Player player) {
return player.isOp() || player.hasPermission("autosortchest.admin");
}
// ------------------------
// --- HILFSMETHODE FÜR DOPPELTRUHEN --- // --- HILFSMETHODE FÜR DOPPELTRUHEN ---
private List<Block> getChestBlocks(Chest chest) { private List<Block> getChestBlocks(Chest chest) {
List<Block> blocks = new ArrayList<>(); List<Block> blocks = new ArrayList<>();
@@ -199,12 +336,29 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
getLogger().info("Setze Standardwert: debug = " + config.getBoolean("debug")); getLogger().info("Setze Standardwert: debug = " + config.getBoolean("debug"));
} }
// --- NEU: Sprache ---
if (!config.contains("language")) {
config.set("language", defaultConfig.getString("language", "de"));
getLogger().info("Setze Standardwert: language = " + config.getString("language"));
}
// -------------------
// --- NEU: Effekte Konfiguration (Partikel + Sound) ---
if (!config.contains("effects")) {
config.createSection("effects");
config.set("effects.enabled", defaultConfig.getBoolean("effects.enabled", true));
config.set("effects.sound", defaultConfig.getBoolean("effects.sound", true));
config.set("effects.type", defaultConfig.getString("effects.type", "DUST"));
getLogger().info("Setze Standardwerte für effects");
}
// ----------------------------------
// Prüfe und setze sign-colors.input // Prüfe und setze sign-colors.input
if (!config.contains("sign-colors.input")) { if (!config.contains("sign-colors.input")) {
config.createSection("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.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.line2", defaultConfig.getString("sign-colors.input.line2", "&0"));
config.set("sign-colors.input.line4", defaultConfig.getString("sign-colors.input.line4", "&1")); // Korrigiert auf &1 basierend auf user Config config.set("sign-colors.input.line4", defaultConfig.getString("sign-colors.input.line4", "&1"));
getLogger().info("Setze Standardwerte für sign-colors.input"); getLogger().info("Setze Standardwerte für sign-colors.input");
} else { } else {
if (!config.contains("sign-colors.input.line1")) { if (!config.contains("sign-colors.input.line1")) {
@@ -227,7 +381,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.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.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.line3", defaultConfig.getString("sign-colors.target.line3", "&f"));
config.set("sign-colors.target.line4", defaultConfig.getString("sign-colors.target.line4", "&1")); // Korrigiert auf &1 config.set("sign-colors.target.line4", defaultConfig.getString("sign-colors.target.line4", "&1"));
getLogger().info("Setze Standardwerte für sign-colors.target"); getLogger().info("Setze Standardwerte für sign-colors.target");
} else { } else {
if (!config.contains("sign-colors.target.line1")) { if (!config.contains("sign-colors.target.line1")) {
@@ -254,7 +408,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.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.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.line3", defaultConfig.getString("sign-colors.full.line3", "&e"));
config.set("sign-colors.full.line4", defaultConfig.getString("sign-colors.full.line4", "&1")); // Korrigiert auf &1 config.set("sign-colors.full.line4", defaultConfig.getString("sign-colors.full.line4", "&1"));
getLogger().info("Setze Standardwerte für sign-colors.full"); getLogger().info("Setze Standardwerte für sign-colors.full");
} else { } else {
if (!config.contains("sign-colors.full.line1")) { if (!config.contains("sign-colors.full.line1")) {
@@ -281,7 +435,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
config.set("sign-colors.rest.line1", defaultConfig.getString("sign-colors.rest.line1", "&6")); 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.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.line3", defaultConfig.getString("sign-colors.rest.line3", "&f"));
config.set("sign-colors.rest.line4", defaultConfig.getString("sign-colors.rest.line4", "&1")); // Korrigiert auf &1 config.set("sign-colors.rest.line4", defaultConfig.getString("sign-colors.rest.line4", "&1"));
getLogger().info("Setze Standardwerte für sign-colors.rest"); getLogger().info("Setze Standardwerte für sign-colors.rest");
} else { } else {
if (!config.contains("sign-colors.rest.line1")) { if (!config.contains("sign-colors.rest.line1")) {
@@ -320,7 +474,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
getLogger().info("Setze Standardwert: messages.input-chest-set"); getLogger().info("Setze Standardwert: messages.input-chest-set");
} }
if (!config.contains("messages.target-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!")); config.set("messages.target-chest-set", defaultConfig.getString("messages.target-chest-set", "&aZieltruhe erfolgreich für %item% eingerichtet!"));
getLogger().info("Setze Standardwert: messages.target-chest-set"); getLogger().info("Setze Standardwert: messages.target-chest-set");
} }
// --- NEU: Message für Rest-Truhe --- // --- NEU: Message für Rest-Truhe ---
@@ -356,44 +510,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
} }
// ---------------------------------------------- // ----------------------------------------------
if (!config.contains("messages.help")) { // HILFE UND INFO NICHT MEHR IN CONFIG SPEICHERN!
String helpMessage = "&6&l=== AutoSortChest Hilfe ===\n" + // Wir benutzen jetzt die statischen Strings HELP_DE, HELP_EN, INFO_DE, INFO_EN aus der Java-Datei.
"&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" +
"&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" +
"&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")) { if (!config.contains("messages.no-permission")) {
config.set("messages.no-permission", defaultConfig.getString("messages.no-permission", "&cDu hast keine Berechtigung für diesen Befehl!")); 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"); getLogger().info("Setze Standardwert: messages.no-permission");
@@ -784,54 +903,76 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
return false; return false;
} }
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!command.getName().equalsIgnoreCase("asc")) return false; if (!command.getName().equalsIgnoreCase("asc")) return false;
if (!(sender instanceof Player)) { if (!(sender instanceof Player)) {
sender.sendMessage(ChatColor.RED + "Dieser Befehl ist nur für Spieler!"); 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; return true;
} }
reloadConfig();
config = getConfig();
loadPlayerData();
updateConfig();
updateExistingSigns();
migrateInputChests(); // ERWEITERUNG: Migration erneut aufrufen
player.sendMessage(getMessage("reload-success"));
getLogger().info("Konfiguration und Spielerdaten neu geladen durch " + player.getName());
return true;
}
String helpMessage = getMessage("help"); Player player = (Player) sender;
// --- NEU: Sprache aus Config lesen ---
String lang = config.getString("language", "de"); // Standard Deutsch
if (lang == null) lang = "de";
if (args.length == 0 || args[0].equalsIgnoreCase("help")) {
// Sprache prüfen und statischen String wählen
String helpMessage = lang.equalsIgnoreCase("en") ? HELP_EN : HELP_DE;
// --- FIX: Farben übersetzen (&6 -> §6) ---
// Bukkit versteht & nicht als Farbe, wir müssen es umwandeln
helpMessage = ChatColor.translateAlternateColorCodes('&', helpMessage);
// ----------------------------------------
player.sendMessage(helpMessage.split("\n"));
return true;
}
if (args[0].equalsIgnoreCase("info")) {
// Sprache prüfen und statischen String wählen
String infoMessage = lang.equalsIgnoreCase("en") ? INFO_EN : INFO_DE;
// Platzhalter ersetzen
infoMessage = infoMessage
.replace("%version%", getDescription().getVersion())
.replace("%config_version%", config != null ? config.getString("version", CONFIG_VERSION) : CONFIG_VERSION)
.replace("%author%", String.join(", ", getDescription().getAuthors()));
// --- FIX: Farben übersetzen (&6 -> §6) ---
infoMessage = ChatColor.translateAlternateColorCodes('&', infoMessage);
// ----------------------------------------
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();
migrateInputChests();
player.sendMessage(getMessage("reload-success"));
getLogger().info("Konfiguration und Spielerdaten neu geladen durch " + player.getName());
return true;
}
// Default: Hilfe zeigen
String helpMessage = lang.equalsIgnoreCase("en") ? HELP_EN : HELP_DE;
helpMessage = ChatColor.translateAlternateColorCodes('&', helpMessage);
player.sendMessage(helpMessage.split("\n")); player.sendMessage(helpMessage.split("\n"));
return true; return true;
} }
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) // <- Geändert: Priorität erhöht und Cancel ignoriert @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onSignChange(SignChangeEvent event) { public void onSignChange(SignChangeEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
UUID playerUUID = player.getUniqueId(); UUID playerUUID = player.getUniqueId();
@@ -886,14 +1027,14 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
event.setLine(0, getSignColor("input", "line1") + "[asc]"); event.setLine(0, getSignColor("input", "line1") + "[asc]");
event.setLine(1, getSignColor("input", "line2") + "input"); event.setLine(1, getSignColor("input", "line2") + "input");
event.setLine(3, getSignColor("input", "line4") + player.getName()); event.setLine(3, getSignColor("input", "line4") + player.getName());
setInputChestLocation(playerUUID, chestBlock.getLocation()); // Ruft nun addInputChestLocation auf setInputChestLocation(playerUUID, chestBlock.getLocation());
player.sendMessage(getMessage("input-chest-set")); player.sendMessage(getMessage("input-chest-set"));
getLogger().info("Eingangstruhe für " + player.getName() + " gesetzt bei " + chestBlock.getLocation()); getLogger().info("Eingangstruhe für " + player.getName() + " gesetzt bei " + chestBlock.getLocation());
} }
} }
@EventHandler @EventHandler
public void onPlayerInteract(org.bukkit.event.player.PlayerInteractEvent event) { public void onPlayerInteract(PlayerInteractEvent event) {
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
Player player = event.getPlayer(); Player player = event.getPlayer();
@@ -934,9 +1075,10 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
boolean isOwner = pureOwnerName.equalsIgnoreCase(player.getName()); boolean isOwner = pureOwnerName.equalsIgnoreCase(player.getName());
// 1. FALL: MODUS WECHSELN (Shift + Klick + Leere Hand) // 1. FALL: MODUS WECHSELN (Shift + Klick + Leere hand)
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) { if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) {
if (isOwner) { // Admin Check hinzugefügt
if (isOwner || isAdmin(player)) {
boolean isPublic = isChestPublic(sign); boolean isPublic = isChestPublic(sign);
String newModeText; String newModeText;
String newLine4; String newLine4;
@@ -968,8 +1110,8 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
// 2. FALL: ITEM ZUWEISEN / AKTUALISIEREN (Nur bei ZIEL, nicht bei REST) // 2. FALL: ITEM ZUWEISEN / AKTUALISIEREN (Nur bei ZIEL, nicht bei REST)
if (line1Clean.equalsIgnoreCase("ziel")) { if (line1Clean.equalsIgnoreCase("ziel")) {
if (itemInHand != null && itemInHand.getType() != Material.AIR) { if (itemInHand != null && itemInHand.getType() != Material.AIR) {
// Prüfe, ob der Spieler das Recht hat (Owner oder unbeansprucht) // Admin Check hinzugefügt für Modifikation
if (!pureOwnerName.isEmpty() && !pureOwnerName.equalsIgnoreCase("Unknown") && !isOwner) { if (!pureOwnerName.isEmpty() && !pureOwnerName.equalsIgnoreCase("Unknown") && !isOwner && !isAdmin(player)) {
player.sendMessage(getMessage("not-your-chest")); player.sendMessage(getMessage("not-your-chest"));
event.setCancelled(true); event.setCancelled(true);
return; return;
@@ -985,9 +1127,8 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
sign.setLine(0, getSignColor(colorType, "line1") + "[asc]"); sign.setLine(0, getSignColor(colorType, "line1") + "[asc]");
sign.setLine(1, getSignColor(colorType, "line2") + "ziel"); sign.setLine(1, getSignColor(colorType, "line2") + "ziel");
sign.setLine(2, getSignColor(colorType, "line3") + itemInHand.getType().name()); // Item wird überschrieben sign.setLine(2, getSignColor(colorType, "line3") + itemInHand.getType().name());
// Wenn noch kein Name da war, setze ihn
String finalLine4 = line3Raw; String finalLine4 = line3Raw;
if (pureOwnerName.isEmpty() || pureOwnerName.equalsIgnoreCase("Unknown")) { if (pureOwnerName.isEmpty() || pureOwnerName.equalsIgnoreCase("Unknown")) {
finalLine4 = getSignColor("target", "line4") + player.getName(); finalLine4 = getSignColor("target", "line4") + player.getName();
@@ -1004,15 +1145,21 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
} }
// Zugriffsschutz für konfigurierte Truhen (wenn kein Item in Hand zum Updaten) // Zugriffsschutz für konfigurierte Truhen (wenn kein Item in Hand zum Updaten)
// Wenn nicht Owner und NICHT öffentlich -> Zugriff verweigern // Wenn nicht Owner und NICHT öffentlich UND NICHT Admin -> Zugriff verweigern
if (!isOwner && !isChestPublic(sign)) { if (!isOwner && !isChestPublic(sign) && !isAdmin(player)) {
player.sendMessage(getMessage("not-your-chest")); player.sendMessage(getMessage("not-your-chest"));
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
// Wenn Owner oder Öffentlich -> Truhe öffnen lassen (Event nicht canceln) // --- FIX: Zugriff erlaubt -> Event canceln und Truhe öffnen ---
// Dies verhindert das Öffnen des Schild-Editors und erzwingt das Öffnen der Truhe
event.setCancelled(true);
if (chestBlock.getState() instanceof Chest) {
player.openInventory(((Chest) chestBlock.getState()).getInventory());
}
return; return;
// -----------------------------------------------------------
} }
// --- LOGIK FÜR EINGANGSTRUHEN (INPUT) --- // --- LOGIK FÜR EINGANGSTRUHEN (INPUT) ---
@@ -1024,7 +1171,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
// 1. FALL: MODUS WECHSELN (Shift + Klick + Leere Hand) // 1. FALL: MODUS WECHSELN (Shift + Klick + Leere Hand)
if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) { if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) {
if (isOwner) { if (isOwner || isAdmin(player)) {
boolean isPublic = isChestPublic(sign); boolean isPublic = isChestPublic(sign);
String newModeText; String newModeText;
String newLine4; String newLine4;
@@ -1049,12 +1196,20 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
} }
} }
// Zugriffsschutz // Zugriffsschutz - Admin Check hinzugefügt
if (!isOwner && !isChestPublic(sign)) { if (!isOwner && !isChestPublic(sign) && !isAdmin(player)) {
player.sendMessage(getMessage("not-your-chest")); player.sendMessage(getMessage("not-your-chest"));
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
// --- FIX: Zugriff erlaubt -> Event canceln und Truhe öffnen ---
event.setCancelled(true);
if (chestBlock.getState() instanceof Chest) {
player.openInventory(((Chest) chestBlock.getState()).getInventory());
}
return;
// -----------------------------------------------------------
} }
} }
return; return;
@@ -1080,7 +1235,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
String[] lines = sign.getLines(); String[] lines = sign.getLines();
if (lines.length >= 2 && ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")).equalsIgnoreCase("[asc]")) { if (lines.length >= 2 && ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")).equalsIgnoreCase("[asc]")) {
signBlock = face; signBlock = face;
break outerLoop; // Schild gefunden break outerLoop;
} }
} }
} }
@@ -1091,16 +1246,16 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
String[] lines = sign.getLines(); String[] lines = sign.getLines();
String line1Clean = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")); String line1Clean = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : ""));
// NUR FÜR ZIELTRUHEN und REST (hier nur Moduswechsel) // NUR FÜR ZIELTRUHEN und REST (hier nur Moduswechsel und Item zuweisen)
if (line1Clean.equalsIgnoreCase("ziel") || line1Clean.equalsIgnoreCase("rest")) { if (line1Clean.equalsIgnoreCase("ziel") || line1Clean.equalsIgnoreCase("rest")) {
String line3Raw = lines[3] != null ? lines[3] : ""; String line3Raw = lines[3] != null ? lines[3] : "";
String line3Clean = ChatColor.stripColor(line3Raw); String line3Clean = ChatColor.stripColor(line3Raw);
String pureOwnerName = line3Clean.replace("[public]", "").replace("[Public]", "").trim(); String pureOwnerName = line3Clean.replace("[public]", "").replace("[public]", "").trim();
boolean isOwner = pureOwnerName.equalsIgnoreCase(player.getName()); boolean isOwner = pureOwnerName.equalsIgnoreCase(player.getName());
// 1. FALL: MODUS WECHSELN // 1. FALL: MODUS WECHSELN
if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) { if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) {
if (isOwner) { if (isOwner || isAdmin(player)) {
boolean isPublic = isChestPublic(sign); boolean isPublic = isChestPublic(sign);
String newModeText; String newModeText;
String newLine4; String newLine4;
@@ -1138,7 +1293,8 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
return; return;
} }
if (!pureOwnerName.isEmpty() && !pureOwnerName.equalsIgnoreCase("Unknown") && !isOwner) { // Admin Check für Modifikation
if (!pureOwnerName.isEmpty() && !pureOwnerName.equalsIgnoreCase("Unknown") && !isOwner && !isAdmin(player)) {
player.sendMessage(getMessage("not-your-chest")); player.sendMessage(getMessage("not-your-chest"));
event.setCancelled(true); event.setCancelled(true);
return; return;
@@ -1171,24 +1327,25 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
} }
} }
// Wenn nicht Owner und nicht öffentlich -> Zugriff verweigern // Wenn nicht Owner und nicht öffentlich und nicht Admin -> Zugriff verweigern
if (!isOwner && !isChestPublic(sign)) { if (!isOwner && !isChestPublic(sign) && !isAdmin(player)) {
player.sendMessage(getMessage("not-your-chest")); player.sendMessage(getMessage("not-your-chest"));
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
// Wenn erlaubt, machen wir nichts, damit die Truhe ganz normal geöffnet wird
} }
// FALL: EINGANGSTRUHE // FALL: EINGANGSTRUHE
if (line1Clean.equalsIgnoreCase("input")) { if (line1Clean.equalsIgnoreCase("input")) {
String line3Raw = lines[3] != null ? lines[3] : ""; String line3Raw = lines[3] != null ? lines[3] : "";
String line3Clean = ChatColor.stripColor(line3Raw); String line3Clean = ChatColor.stripColor(line3Raw);
String pureOwnerName = line3Clean.replace("[public]", "").replace("[Public]", "").trim(); String pureOwnerName = line3Clean.replace("[Public]", "").replace("[public]", "").trim();
boolean isOwner = pureOwnerName.equalsIgnoreCase(player.getName()); boolean isOwner = pureOwnerName.equalsIgnoreCase(player.getName());
// Moduswechsel // Moduswechsel
if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) { if (player.isSneaking() && (itemInHand == null || itemInHand.getType() == Material.AIR)) {
if (isOwner) { if (isOwner || isAdmin(player)) {
boolean isPublic = isChestPublic(sign); boolean isPublic = isChestPublic(sign);
String newModeText; String newModeText;
String newLine4; String newLine4;
@@ -1214,11 +1371,13 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
} }
} }
if (!isOwner && !isChestPublic(sign)) { // Admin Check für Zugriff
if (!isOwner && !isChestPublic(sign) && !isAdmin(player)) {
player.sendMessage(getMessage("not-your-chest")); player.sendMessage(getMessage("not-your-chest"));
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
// Wenn erlaubt, lassen wir die Truhe ganz normal öffnen
} }
} }
} }
@@ -1272,7 +1431,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
if (lines.length >= 2 && ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")).equalsIgnoreCase("[asc]") && 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("input") ||
ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("ziel") || ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("ziel") ||
ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("rest"))) { // REST hinzugefügt ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("rest"))) {
signBlock = block; signBlock = block;
signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : ""));
if (isDebug()) { if (isDebug()) {
@@ -1299,7 +1458,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
if (lines.length >= 2 && ChatColor.stripColor((String) (lines[0] != null ? lines[0] : "")).equalsIgnoreCase("[asc]") && 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("input") ||
ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("ziel") || ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("ziel") ||
ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("rest"))) { // REST hinzugefügt ChatColor.stripColor((String) (lines[1] != null ? lines[1] : "")).equalsIgnoreCase("rest"))) {
signBlock = face; signBlock = face;
signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : ""));
isAscChest = true; isAscChest = true;
@@ -1321,18 +1480,18 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
return; return;
} }
// Prüfe Besitzer // Prüfe Besitzer - Admin Check hinzugefügt
boolean isOwner = signOwner.isEmpty() || signOwner.equalsIgnoreCase(player.getName()); boolean isOwner = signOwner.isEmpty() || signOwner.equalsIgnoreCase(player.getName());
if (!isOwner) { if (!isOwner && !isAdmin(player)) {
player.sendMessage(getMessage("not-your-chest")); player.sendMessage(getMessage("not-your-chest"));
event.setCancelled(true); event.setCancelled(true);
getLogger().warning("Spieler " + player.getName() + " versuchte, " + (isAscChest ? "Truhe" : "Schild") + " bei " + block.getLocation() + " abzubauen, das nicht ihm gehört (Besitzer: " + signOwner + ")"); getLogger().warning("Spieler " + player.getName() + " versuchte, " + (isAscChest ? "Truhe" : "Schild") + " bei " + block.getLocation() + " abzubauen, das nicht ihm gehört (Besitzer: " + signOwner + ")");
return; return;
} }
// Prüfe Shift-Taste (Berechtigungen ignorieren) // Prüfe Shift-Taste (Berechtigungen ignorieren) - Admin Check hinzugefügt
if (!player.isSneaking()) { if (!player.isSneaking() && !isAdmin(player)) {
player.sendMessage(getMessage("sign-break-denied")); player.sendMessage(getMessage("sign-break-denied"));
event.setCancelled(true); event.setCancelled(true);
if (isDebug()) { if (isDebug()) {
@@ -1348,13 +1507,80 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
// Hole Location der Truhe, die abgebaut wird (für Datenabgleich) // Hole Location der Truhe, die abgebaut wird (für Datenabgleich)
Location chestLoc = isAscChest ? block.getLocation() : ((Sign)block.getState()).getBlock().getRelative(((WallSign)((Sign)block.getState()).getBlockData()).getFacing().getOppositeFace()).getLocation(); Location chestLoc = isAscChest ? block.getLocation() : ((Sign)block.getState()).getBlock().getRelative(((WallSign)((Sign)block.getState()).getBlockData()).getFacing().getOppositeFace()).getLocation();
// Wenn Admin abbaut, müssen wir wissen, WEM die Truhe gehört, um die richtigen Daten zu löschen.
// signOwner ist der Name auf dem Schild.
UUID ownerUUID = null;
if (!signOwner.isEmpty() && !signOwner.equalsIgnoreCase("Unknown")) {
OfflinePlayer op = Bukkit.getOfflinePlayer(signOwner);
if (op.hasPlayedBefore()) {
ownerUUID = op.getUniqueId();
}
} else {
// Fallback: Wenn Name "Unknown" ist, versuchen wir es über den aktuellen Spieler (wenn er Owner ist) oder wir iterieren (teuer).
// Da Admins abbauen können, müssen wir den Owner eindeutig identifizieren.
// Wir iterieren durch die Spielerdaten, um zu finden, wem diese Location gehört.
if (playerData.getConfigurationSection("players") != null) {
for (String uuidString : playerData.getConfigurationSection("players").getKeys(false)) {
UUID uuid = UUID.fromString(uuidString);
// Check inputs
String inputListPath = "players." + uuidString + ".input-chests";
if (playerData.contains(inputListPath)) {
for (String chestId : playerData.getConfigurationSection(inputListPath).getKeys(false)) {
if (chestLoc.equals(getLocationFromPath(inputListPath + "." + chestId))) {
ownerUUID = uuid;
break;
}
}
}
// Check targets
if (ownerUUID == null) {
String targetPath = "players." + uuidString + ".target-chests";
if (playerData.contains(targetPath)) {
for (String itemType : playerData.getConfigurationSection(targetPath).getKeys(false)) {
if (chestLoc.equals(getLocationFromPath(targetPath + "." + itemType))) {
ownerUUID = uuid;
break;
}
}
}
}
// Check rest
if (ownerUUID == null) {
Location restLoc = getRestChestLocation(uuid);
if (chestLoc.equals(restLoc)) {
ownerUUID = uuid;
}
}
if (ownerUUID != null) break;
}
}
}
// Wenn wir die UUID gefunden haben (oder es ist der Spieler selbst), löschen wir die Daten
UUID uuidToDelete = (ownerUUID != null) ? ownerUUID : player.getUniqueId();
if (line1.equalsIgnoreCase("rest")) { if (line1.equalsIgnoreCase("rest")) {
playerData.set("players." + player.getUniqueId() + ".rest-chest", null); playerData.set("players." + uuidToDelete + ".rest-chest", null);
savePlayerData(); savePlayerData();
if (isDebug()) getLogger().info("Rest-Truhe Daten gelöscht für " + player.getName()); if (isDebug()) getLogger().info("Rest-Truhe Daten gelöscht für " + (ownerUUID != null ? "Owner " + signOwner : "Self"));
} else if (line1.equalsIgnoreCase("input")) { } else if (line1.equalsIgnoreCase("input")) {
// ERWEITERUNG: Input Chest aus Liste löschen // ERWEITERUNG: Input Chest aus Liste löschen
removeInputChestByLocation(player.getUniqueId(), chestLoc); removeInputChestByLocation(uuidToDelete, chestLoc);
} else if (line1.equalsIgnoreCase("ziel")) {
// Wir müssen wissen, welches Item auf dem Schild stand, um es zu löschen
String line2 = ChatColor.stripColor(lines[2]);
if (!line2.isEmpty()) {
Material mat = Material.matchMaterial(line2);
if (mat != null) {
// Sicherheitscheck, ob die Location auch wirklich diesem Item zugeordnet ist
Location savedLoc = getTargetChestLocation(uuidToDelete, mat);
if (savedLoc != null && savedLoc.equals(chestLoc)) {
playerData.set("players." + uuidToDelete + ".target-chests." + mat.name(), null);
savePlayerData();
if (isDebug()) getLogger().info("Zieltruhe Daten für Item " + mat.name() + " gelöscht.");
}
}
}
} }
// -------------------------------- // --------------------------------
@@ -1413,8 +1639,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
String signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : "")); String signOwner = ChatColor.stripColor((String) (lines[3] != null ? lines[3] : ""));
// FIX: Auch öffentliche Truhen updaten, nicht nur Owner // FIX: Auch öffentliche Truhen updaten, nicht nur Owner
// ERWEITERUNG: Auch Admins updaten, damit Schildfarben stimmen wenn Admin Items rausnimmt
boolean isPublic = isChestPublic(sign); boolean isPublic = isChestPublic(sign);
if (!signOwner.equalsIgnoreCase(player.getName()) && !isPublic) { if (!signOwner.equalsIgnoreCase(player.getName()) && !isPublic && !isAdmin(player)) {
continue; continue;
} }
@@ -1622,6 +1849,55 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
} }
} }
// --- NEU: BUNTE PARTIKEL UM DIE TRUHE (NUR ZIELTRUHE) ---
private void spawnTransferParticles(Location start, Location end) {
if (!config.getBoolean("effects.enabled", true)) return;
if (end.getWorld() == null) return;
// 1. Sound abspielen (am Zielort)
if (config.getBoolean("effects.sound", true)) {
end.getWorld().playSound(end, Sound.ENTITY_ITEM_PICKUP, 0.2f, 1.2f);
}
// 2. Bunter Kreis aus Partikeln am Zielort
Location center = end.clone().add(0.5, 0.5, 0.5); // Zentrum der Truhe (etwas erhöht)
// Wir spawnen einen Kreis aus Partikeln
int count = 12; // Anzahl der Partikel im Kreis
double radius = 0.8; // Radius um den Block herum
float size = 1.2f;
// Farbpalette (Rot, Grün, Blau, Gelb, Cyan, Magenta)
Color[] colors = {
Color.fromRGB(255, 0, 0), // Rot
Color.fromRGB(0, 255, 0), // Grün
Color.fromRGB(0, 0, 255), // Blau
Color.fromRGB(255, 255, 0), // Gelb
Color.fromRGB(0, 255, 255), // Cyan
Color.fromRGB(255, 0, 255) // Magenta
};
for (int i = 0; i < count; i++) {
double angle = (2 * Math.PI / count) * i;
double dx = Math.cos(angle) * radius;
double dz = Math.sin(angle) * radius;
// Partikel am Boden oder leicht erhöht
Location particleLoc = center.clone().add(dx, -0.1, dz);
// Zufällige Farbe aus der Liste für "Bunt"
Color color = colors[(int)(Math.random() * colors.length)];
// Wir mischen ein wenig Offset, damit es nicht so perfekt wirkt
double offsetX = (Math.random() - 0.5) * 0.2;
double offsetZ = (Math.random() - 0.5) * 0.2;
DustOptions options = new DustOptions(color, size);
end.getWorld().spawnParticle(Particle.DUST, particleLoc.clone().add(offsetX, 0, offsetZ), 1, 0, 0, 0, 0.02, options);
}
}
// -----------------------------------
private void checkInputChests() { private void checkInputChests() {
if (playerData == null) { if (playerData == null) {
getLogger().warning("playerData ist null. Kann Eingangstruhe nicht prüfen."); getLogger().warning("playerData ist null. Kann Eingangstruhe nicht prüfen.");
@@ -1651,8 +1927,6 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
if (playerData.contains(inputListPath)) { if (playerData.contains(inputListPath)) {
chestsToCheck.addAll(playerData.getConfigurationSection(inputListPath).getKeys(false)); chestsToCheck.addAll(playerData.getConfigurationSection(inputListPath).getKeys(false));
} else if (playerData.contains(oldInputPath)) { } else if (playerData.contains(oldInputPath)) {
// Hier führen wir keine Migration durch (nur lesen), da das im laufenden Betrieb zu Problemen führen könnte.
// Wir markieren es für den Task, damit es bei下一次 Update erledigt wird.
Location loc = getLocationFromPath(oldInputPath); Location loc = getLocationFromPath(oldInputPath);
if (loc != null) { if (loc != null) {
checkSingleInputChest(ownerUUID, loc, "legacy"); checkSingleInputChest(ownerUUID, loc, "legacy");
@@ -1755,13 +2029,13 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
} }
// Wir rufen distributeItemsForOwner auf. // Wir rufen distributeItemsForOwner auf.
distributeItemsForOwner(ownerUUID, ownerPlayer, chest.getInventory(), ownerName); distributeItemsForOwner(ownerUUID, ownerPlayer, chest.getInventory(), ownerName, location);
return true; return true;
} }
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// 4. KORRIGIERTE distributeItemsForOwner Methode: // 4. KORRIGIERTE distributeItemsForOwner Methode:
private void distributeItemsForOwner(UUID ownerUUID, Player ownerPlayer, Inventory sourceInventory, String ownerNameOverride) { private void distributeItemsForOwner(UUID ownerUUID, Player ownerPlayer, Inventory sourceInventory, String ownerNameOverride, Location sourceLocation) {
boolean hasItems = false; boolean hasItems = false;
for (ItemStack item : sourceInventory.getContents()) { for (ItemStack item : sourceInventory.getContents()) {
if (item != null && item.getType() != Material.AIR) { if (item != null && item.getType() != Material.AIR) {
@@ -1887,6 +2161,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
if (leftover.isEmpty()) { if (leftover.isEmpty()) {
sourceInventory.setItem(slot, null); sourceInventory.setItem(slot, null);
// --- NEU: Effekte (Nur am Zielort) ---
spawnTransferParticles(null, targetChestLocation);
// ------------------------
} else { } else {
if (ownerPlayer != null && canSendFullChestMessage(ownerUUID, item.getType())) { if (ownerPlayer != null && canSendFullChestMessage(ownerUUID, item.getType())) {
String message = getMessage("target-chest-full") String message = getMessage("target-chest-full")
@@ -1906,4 +2183,86 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
} }
} }
} }
// --- NEU: Hopper-Automatisierung ---
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryMoveItem(InventoryMoveItemEvent event) {
Inventory destination = event.getDestination();
// Prüfen, ob das Ziel eine Truhe ist
if (!(destination.getHolder() instanceof Chest)) {
return;
}
final Chest destChest = (Chest) destination.getHolder();
// Wir müssen herausfinden, ob diese Truhe eine Input-Truhe ist.
// Wir scannen die Blöcke der Truhe nach einem [asc] input Schild.
// Unterstützung für Doppeltruhen
List<Block> blocksToScan = new ArrayList<>();
InventoryHolder holder = destination.getHolder();
if (holder instanceof DoubleChest) {
DoubleChest dc = (DoubleChest) holder;
if (dc.getLeftSide() instanceof Chest) blocksToScan.add(((Chest) dc.getLeftSide()).getBlock());
if (dc.getRightSide() instanceof Chest) blocksToScan.add(((Chest) dc.getRightSide()).getBlock());
} else if (holder instanceof Chest) {
blocksToScan.add(destChest.getBlock());
}
UUID ownerUUID = null;
String ownerName = null;
boolean isPublic = false;
outerLoop:
for (Block b : blocksToScan) {
for (Block face : new Block[] {
b.getRelative(1, 0, 0),
b.getRelative(-1, 0, 0),
b.getRelative(0, 0, 1),
b.getRelative(0, 0, -1)
}) {
if (face.getState() instanceof Sign sign && isSignAttachedToChest(face, b)) {
String[] lines = sign.getLines();
String line0 = ChatColor.stripColor((String) (lines[0] != null ? lines[0] : ""));
String line1 = ChatColor.stripColor((String) (lines[1] != null ? lines[1] : ""));
if (line0.equalsIgnoreCase("[asc]") && line1.equalsIgnoreCase("input")) {
// Schild gefunden! Ermittle Owner aus Zeile 4
String line3Raw = lines[3] != null ? lines[3] : "";
String line3Clean = ChatColor.stripColor(line3Raw);
isPublic = line3Clean.toLowerCase().endsWith("[public]");
ownerName = line3Clean.replace(" [Public]", "").replace(" [public]", "").trim();
// Name zu UUID auflösen
OfflinePlayer op = Bukkit.getOfflinePlayer(ownerName);
if (op.hasPlayedBefore()) {
ownerUUID = op.getUniqueId();
}
break outerLoop; // Wir haben alles was wir brauchen
}
}
}
}
// Wenn kein [asc] input Schild oder Owner unbekannt -> Abbruch
if (ownerUUID == null || ownerName == null || ownerName.isEmpty()) {
return;
}
// Schedule Task um sicherzustellen, dass der Hopper das Item fertig platziert hat
final UUID finalOwnerUUID = ownerUUID;
final String finalOwnerName = ownerName;
new BukkitRunnable() {
@Override
public void run() {
// Wir sortieren auch, wenn der Owner Offline ist (Automation)
// ownerPlayer wird übergeben als null, da es keinen aktiven Spielerkontext gibt
distributeItemsForOwner(finalOwnerUUID, null, destChest.getInventory(), finalOwnerName, destChest.getLocation());
}
}.runTaskLater(this, 1L);
}
// -----------------------------------
} }

View File

@@ -0,0 +1,33 @@
package com.viper.autosortchest;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Scanner;
import java.util.function.Consumer;
public class UpdateChecker {
private final JavaPlugin plugin;
private final int resourceId;
public UpdateChecker(JavaPlugin plugin, int resourceId) {
this.plugin = plugin;
this.resourceId = resourceId;
}
public void getVersion(final Consumer<String> consumer) {
Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> {
try (InputStream is = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + this.resourceId + "/~").openStream(); Scanner scann = new Scanner(is)) {
if (scann.hasNext()) {
consumer.accept(scann.next());
}
} catch (IOException e) {
plugin.getLogger().info("Konnte nicht nach Updates suchen: " + e.getMessage());
}
});
}
}

View File

@@ -1,34 +1,91 @@
version: "1.6" # ============================================================
# _ _ __ _ ___ _ _
# /_\ _ _| |_ ___ / _\ ___ _ __| |_ / __\ |__ ___ ___| |_
# //_\\| | | | __/ _ \\ \ / _ \| '__| __|/ / | '_ \ / _ \/ __| __|
# / _ \ |_| | || (_) |\ \ (_) | | | |_/ /___| | | | __/\__ \ |_
# \_/ \_/\__,_|\__\___/\__/\___/|_| \__\____/|_| |_|\___||___/\__|
#
# ============================================================
# --- GRUNDLEGUNG ---
# Version der Konfigurationsdatei. Nicht ändern, um Fehler zu vermeiden!
version: "1.8"
# Debug-Modus (true = Ausführliche Logs in der Server-Konsole, nur zum Entwickeln nutzen)
debug: false debug: false
# ---------------------------------------------------
# SPRACHE (Language)
# ---------------------------------------------------
# Mögliche Werte: 'de' für Deutsch oder 'en' für Englisch
# Ändert den Text von /asc help und /asc info
language: "de"
# ---------------------------------------------------
# VISUELLE EFFEKTE (PARTIKEL & TÖNE)
# ---------------------------------------------------
# Einstellungen für den Regenbogen-Effekt beim Sortieren
effects:
# Sollen Effekte angezeigt werden?
enabled: false
# Soll ein Ton gespielt werden, wenn Items ankommen?
sound: false
# Der Partikel-Typ.
# 'DUST' ist zwingend für den bunten Regenbogen-Effekt im aktuellen Code.
type: "DUST"
# ---------------------------------------------------
# SCHILDFARBEN (Farbcodes wie im Chat)
# &c = Rot, &a = Grün, &e = Gelb, &6 = Gold, &f = Weiß, &0 = Schwarz
# ---------------------------------------------------
sign-colors:
# Farben für die Eingangstruhe ([asc] / input)
input:
line1: "&6" # Zeile 1: [asc]
line2: "&0" # Zeile 2: input
line4: "&1" # Zeile 4: Spielername
# Farben für die Zieltruhe ([asc] / ziel)
target:
line1: "&6" # Zeile 1: [asc]
line2: "&0" # Zeile 2: ziel
line3: "&f" # Zeile 3: Item-Name
line4: "&1" # Zeile 4: Spielername
# Farben für volle Truhen (Automatische Erkennung)
full:
line1: "&c" # Zeile 1: [asc]
line2: "&4" # Zeile 2: ziel / rest (Rot)
line3: "&e" # Zeile 3: Item-Name (Gelb)
line4: "&1" # Zeile 4: Spielername
# Farben für die Rest-Truhe ([asc] / rest)
rest:
line1: "&6" # Zeile 1: [asc]
line2: "&0" # Zeile 2: rest
line3: "&f" # Zeile 3: (Leer)
line4: "&1" # Zeile 4: Spielername
# ---------------------------------------------------
# SYSTEM NACHRICHTEN (Spieler-Feedback)
# Platzhalter: %player%, %item%, %x%, %y%, %z%, %mode%
# ---------------------------------------------------
messages: messages:
# --- FEHLERMELDUNGEN ---
no-chest-near-sign: "&cKeine Truhe in der Nähe des Schildes!" no-chest-near-sign: "&cKeine Truhe in der Nähe des Schildes!"
no-item-in-hand: "&cDu musst ein Item in der Hand halten!" no-item-in-hand: "&cDu musst ein Item in der Hand halten!"
not-your-chest: "&cDiese Truhe gehört dir nicht!" not-your-chest: "&cDiese Truhe gehört dir nicht!"
target-chest-missing: "&cZieltruhe für %item% fehlt!"
sign-break-denied: "&cDu musst Shift gedrückt halten, um dieses Schild oder die Truhe abzubauen!"
no-permission: "&cDu hast keine Berechtigung für diesen Befehl!"
# --- ERFOLGSMELDUNGEN ---
input-chest-set: "&aEingangstruhe erfolgreich gesetzt!" input-chest-set: "&aEingangstruhe erfolgreich gesetzt!"
target-chest-set: "&aZieltruhe erfolgreich für %item% eingerichtet!" target-chest-set: "&aZieltruhe erfolgreich für %item% eingerichtet!"
target-chest-missing: "&cZieltruhe für %item% fehlt!" rest-chest-set: "&aRest-Truhe (Fallback) erfolgreich gesetzt!"
target-chest-full: "&cZieltruhe für %item% ist voll! Koordinaten: (%x%, %y%, %z%)"
help: "&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===================="
info: "&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===================="
no-permission: "&cDu hast keine Berechtigung für diesen Befehl!"
reload-success: "&aKonfiguration erfolgreich neu geladen!" reload-success: "&aKonfiguration erfolgreich neu geladen!"
sign-break-denied: "&cDu musst Shift gedrückt halten, um dieses Schild oder die Truhe abzubauen!"
sign-colors: # --- HINWEIS MELDUNGEN ---
input: target-chest-full: "&cZieltruhe für %item% ist voll! Koordinaten: (%x%, %y%, %z%)"
line1: "&6" # [asc] mode-changed: "&aModus gewechselt: &e%mode%"
line2: "&0" # input mode-public: "&aÖffentlich"
line4: "&1" # Spielername mode-private: "&cPrivat"
target:
line1: "&6" # [asc]
line2: "&0" # ziel
line3: "&f" # Item
line4: "&1" # Spielername
full:
line1: "&c" # [asc] für volle Truhe
line2: "&4" # ziel für volle Truhe
line3: "&e" # Item für volle Truhe
line4: "&1" # Spielername
rest:
line1: "&6" # Farbe für [asc] bei der Rest-Truhe
line2: "&0" # Farbe für 'rest'
line4: "&1" # Farbe für den Spielernamen

View File

@@ -1,5 +1,5 @@
name: AutoSortChest name: AutoSortChest
version: 1.8 version: 1.9
main: com.viper.autosortchest.Main main: com.viper.autosortchest.Main
api-version: 1.21 api-version: 1.21
authors: [M_Viper] authors: [M_Viper]
@@ -16,3 +16,6 @@ permissions:
autosortchest.bypass: autosortchest.bypass:
description: Erlaubt das Abbauen von ASC-Schildern ohne Shift-Taste und unabhängig vom Besitzer description: Erlaubt das Abbauen von ASC-Schildern ohne Shift-Taste und unabhängig vom Besitzer
default: op default: op
autosortchest.admin:
description: Erlaubt OPs/Admins Zugriff auf fremde AutoSortChest-Truhen (Öffnen, Entnehmen, Abbauen)
default: op