Update from Git Manager GUI
This commit is contained in:
@@ -368,6 +368,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|||||||
"&f- &b/asc reload &f- Lädt die Konfiguration neu (OP).\n" +
|
"&f- &b/asc reload &f- Lädt die Konfiguration neu (OP).\n" +
|
||||||
"&f- &b/asc import &f- Importiert Daten aus players.yml in MySQL (OP).\n" +
|
"&f- &b/asc import &f- Importiert Daten aus players.yml in MySQL (OP).\n" +
|
||||||
"&f- &b/asc export &f- Exportiert Daten aus MySQL in players.yml (OP).\n" +
|
"&f- &b/asc export &f- Exportiert Daten aus MySQL in players.yml (OP).\n" +
|
||||||
|
"&f- &b/asc list <Spieler> &f- Zeigt Truhen-Übersicht eines Spielers (Admin).\n" +
|
||||||
"&6&l========================";
|
"&6&l========================";
|
||||||
|
|
||||||
private static final String HELP_EN =
|
private static final String HELP_EN =
|
||||||
@@ -403,6 +404,7 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|||||||
"&f- &b/asc reload &f- Reloads the config (OP only).\n" +
|
"&f- &b/asc reload &f- Reloads the config (OP only).\n" +
|
||||||
"&f- &b/asc import &f- Imports data from players.yml into MySQL (OP only).\n" +
|
"&f- &b/asc import &f- Imports data from players.yml into MySQL (OP only).\n" +
|
||||||
"&f- &b/asc export &f- Exports data from MySQL into players.yml (OP only).\n" +
|
"&f- &b/asc export &f- Exports data from MySQL into players.yml (OP only).\n" +
|
||||||
|
"&f- &b/asc list <player> &f- Shows chest overview of a player (Admin).\n" +
|
||||||
"&6&l========================";
|
"&6&l========================";
|
||||||
|
|
||||||
private static final String INFO_DE =
|
private static final String INFO_DE =
|
||||||
@@ -1673,9 +1675,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|||||||
case "target.line1": fallback = config.getString("sign-colors.target.line3", "&f"); break;
|
case "target.line1": fallback = config.getString("sign-colors.target.line3", "&f"); break;
|
||||||
case "target.line2": fallback = config.getString("sign-colors.target.line4", "&1"); break;
|
case "target.line2": fallback = config.getString("sign-colors.target.line4", "&1"); break;
|
||||||
case "target.line3": fallback = config.getString("sign-colors.target.line4", "&1"); break;
|
case "target.line3": fallback = config.getString("sign-colors.target.line4", "&1"); break;
|
||||||
case "full.line1": fallback = config.getString("sign-colors.full.line3", "&c"); break;
|
case "full.line1": fallback = config.getString("sign-colors.full.line1", "&c"); break;
|
||||||
case "full.line2": fallback = config.getString("sign-colors.full.line4", "&1"); break;
|
case "full.line2": fallback = config.getString("sign-colors.full.line2", "&4"); break;
|
||||||
case "full.line3": fallback = config.getString("sign-colors.full.line4", "&1"); break;
|
case "full.line3": fallback = config.getString("sign-colors.full.line3", "&e"); break;
|
||||||
case "rest.line1": fallback = config.getString("sign-colors.rest.line4", "&1"); break;
|
case "rest.line1": fallback = config.getString("sign-colors.rest.line4", "&1"); break;
|
||||||
case "rest.line2": fallback = config.getString("sign-colors.rest.line2", "&0"); break;
|
case "rest.line2": fallback = config.getString("sign-colors.rest.line2", "&0"); break;
|
||||||
case "rest.line3": fallback = "&f"; break;
|
case "rest.line3": fallback = "&f"; break;
|
||||||
@@ -2080,8 +2082,9 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|||||||
if (!isPlayer) {
|
if (!isPlayer) {
|
||||||
if (args.length == 0 || (!args[0].equalsIgnoreCase("reload")
|
if (args.length == 0 || (!args[0].equalsIgnoreCase("reload")
|
||||||
&& !args[0].equalsIgnoreCase("import")
|
&& !args[0].equalsIgnoreCase("import")
|
||||||
&& !args[0].equalsIgnoreCase("export"))) {
|
&& !args[0].equalsIgnoreCase("export")
|
||||||
sender.sendMessage(ChatColor.RED + "Dieser Befehl ist nur für Spieler! (Konsole: reload, import, export)");
|
&& !args[0].equalsIgnoreCase("list"))) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "Dieser Befehl ist nur für Spieler! (Konsole: reload, import, export, list)");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2180,6 +2183,149 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
// /asc list [Spieler] – Admin-Truhen-Übersicht
|
||||||
|
// -------------------------------------------------------
|
||||||
|
if (args[0].equalsIgnoreCase("list")) {
|
||||||
|
if (!sender.hasPermission("autosortchest.list")) {
|
||||||
|
sender.sendMessage(getMessage("no-permission"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isEn = lang.equalsIgnoreCase("en");
|
||||||
|
|
||||||
|
if (args.length < 2) {
|
||||||
|
sender.sendMessage(ChatColor.RED + (isEn
|
||||||
|
? "Usage: /asc list <player>"
|
||||||
|
: "Verwendung: /asc list <Spieler>"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String targetName = args[1];
|
||||||
|
|
||||||
|
// Spieler suchen (online bevorzugt, dann offline)
|
||||||
|
OfflinePlayer target = null;
|
||||||
|
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||||
|
if (p.getName() != null && p.getName().equalsIgnoreCase(targetName)) {
|
||||||
|
target = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (target == null) {
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
OfflinePlayer offline = Bukkit.getOfflinePlayer(targetName);
|
||||||
|
if (offline != null && offline.hasPlayedBefore()) {
|
||||||
|
target = offline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (target == null) {
|
||||||
|
sender.sendMessage(ChatColor.RED + (isEn
|
||||||
|
? "Player '" + targetName + "' was not found!"
|
||||||
|
: "Spieler '" + targetName + "' wurde nicht gefunden!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final OfflinePlayer finalTarget = target;
|
||||||
|
final String uuidStr = finalTarget.getUniqueId().toString();
|
||||||
|
final String displayName = finalTarget.getName() != null ? finalTarget.getName() : targetName;
|
||||||
|
|
||||||
|
// Zählen (async, da ggf. DB-Abfragen)
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
int inputCount, targetCount, restCount, trashCount;
|
||||||
|
|
||||||
|
if (mysqlEnabled && mysqlManager != null) {
|
||||||
|
inputCount = mysqlManager.getInputChests(uuidStr).size();
|
||||||
|
targetCount = mysqlManager.getTargetChests(uuidStr).size();
|
||||||
|
restCount = mysqlManager.countRestChests(uuidStr);
|
||||||
|
trashCount = mysqlManager.getTrashChest(uuidStr, serverName) != null ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
String inputPath = "players." + uuidStr + ".input-chests";
|
||||||
|
inputCount = (playerData.contains(inputPath) && playerData.isConfigurationSection(inputPath))
|
||||||
|
? playerData.getConfigurationSection(inputPath).getKeys(false).size() : 0;
|
||||||
|
|
||||||
|
String tPath = "players." + uuidStr + ".target-chests";
|
||||||
|
int tc = 0;
|
||||||
|
if (playerData.contains(tPath) && playerData.isConfigurationSection(tPath)) {
|
||||||
|
for (String item : playerData.getConfigurationSection(tPath).getKeys(false)) {
|
||||||
|
String itemBase = tPath + "." + item;
|
||||||
|
if (playerData.contains(itemBase + ".world")) {
|
||||||
|
tc++;
|
||||||
|
} else if (playerData.isConfigurationSection(itemBase)) {
|
||||||
|
tc += playerData.getConfigurationSection(itemBase).getKeys(false).size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targetCount = tc;
|
||||||
|
|
||||||
|
String restPath = "players." + uuidStr + ".rest-chests";
|
||||||
|
restCount = (playerData.contains(restPath) && playerData.isConfigurationSection(restPath))
|
||||||
|
? playerData.getConfigurationSection(restPath).getKeys(false).size() : 0;
|
||||||
|
|
||||||
|
trashCount = playerData.contains("players." + uuidStr + ".trash-chest.world") ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limits bestimmen
|
||||||
|
// Spieler ist offline → Limits können nicht per Permission geprüft werden
|
||||||
|
// → nur die Anzahl anzeigen, kein " / X"
|
||||||
|
final boolean isOffline = !finalTarget.isOnline();
|
||||||
|
|
||||||
|
String inputMax, targetMax, restMax;
|
||||||
|
final String trashMax = "1";
|
||||||
|
|
||||||
|
if (isOffline || !chestLimitsEnabled) {
|
||||||
|
// Offline: kein Limit anzeigen
|
||||||
|
// Limits deaktiviert: unbegrenzt
|
||||||
|
inputMax = isOffline ? null : "*";
|
||||||
|
targetMax = isOffline ? null : "*";
|
||||||
|
restMax = isOffline ? null : "*";
|
||||||
|
} else {
|
||||||
|
Player onlineTarget = (Player) finalTarget;
|
||||||
|
if (onlineTarget.isOp() || onlineTarget.hasPermission("autosortchest.limit.bypass")) {
|
||||||
|
inputMax = "*";
|
||||||
|
targetMax = "*";
|
||||||
|
restMax = "*";
|
||||||
|
} else {
|
||||||
|
int iMax = getChestLimitForPlayer(onlineTarget, "input");
|
||||||
|
int tMax = getChestLimitForPlayer(onlineTarget, "target");
|
||||||
|
int rMax = getChestLimitForPlayer(onlineTarget, "rest");
|
||||||
|
inputMax = (iMax == Integer.MAX_VALUE) ? "*" : String.valueOf(iMax);
|
||||||
|
targetMax = (tMax == Integer.MAX_VALUE) ? "*" : String.valueOf(tMax);
|
||||||
|
restMax = (rMax == Integer.MAX_VALUE) ? "*" : String.valueOf(rMax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprachabhängige Label
|
||||||
|
final String labelPlayer = isEn ? "Player: " : "Spieler: ";
|
||||||
|
final String labelTarget = isEn ? "Target: " : "Ziel: ";
|
||||||
|
final String labelTrash = isEn ? "Trash: " : "Müll: ";
|
||||||
|
|
||||||
|
final String fInputMax = inputMax, fTargetMax = targetMax, fRestMax = restMax;
|
||||||
|
final int fIn = inputCount, fTa = targetCount, fRe = restCount, fTr = trashCount;
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
sender.sendMessage(ChatColor.GOLD + "================================");
|
||||||
|
sender.sendMessage(ChatColor.GOLD + "" + ChatColor.BOLD + "==== AutoSortChest Info ====");
|
||||||
|
sender.sendMessage(ChatColor.YELLOW + labelPlayer + ChatColor.WHITE + displayName
|
||||||
|
+ (isOffline ? ChatColor.GRAY + " (offline)" : ""));
|
||||||
|
sender.sendMessage(ChatColor.YELLOW + "Input: " + ChatColor.WHITE
|
||||||
|
+ (fInputMax != null ? fIn + " / " + fInputMax : String.valueOf(fIn)));
|
||||||
|
sender.sendMessage(ChatColor.YELLOW + labelTarget + ChatColor.WHITE
|
||||||
|
+ (fTargetMax != null ? fTa + " / " + fTargetMax : String.valueOf(fTa)));
|
||||||
|
sender.sendMessage(ChatColor.YELLOW + "Rest: " + ChatColor.WHITE
|
||||||
|
+ (fRestMax != null ? fRe + " / " + fRestMax : String.valueOf(fRe)));
|
||||||
|
sender.sendMessage(ChatColor.YELLOW + labelTrash + ChatColor.WHITE
|
||||||
|
+ (isOffline ? String.valueOf(fTr) : fTr + " / " + trashMax));
|
||||||
|
sender.sendMessage(ChatColor.GOLD + "================================");
|
||||||
|
}
|
||||||
|
}.runTask(Main.this);
|
||||||
|
}
|
||||||
|
}.runTaskAsynchronously(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------
|
// -------------------------------------------------------
|
||||||
// /asc import – YAML → MySQL
|
// /asc import – YAML → MySQL
|
||||||
// -------------------------------------------------------
|
// -------------------------------------------------------
|
||||||
@@ -2971,13 +3117,20 @@ public class Main extends JavaPlugin implements Listener, CommandExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Filter-Info in der Action-Bar anzeigen
|
// Filter-Info in der Action-Bar anzeigen
|
||||||
List<String> filter = trashChestManager.getFilter(trashOwnerDirect);
|
List<org.bukkit.inventory.ItemStack> filter = trashChestManager.getFilter(trashOwnerDirect);
|
||||||
String filterInfo;
|
String filterInfo;
|
||||||
if (filter.isEmpty()) {
|
if (filter.isEmpty()) {
|
||||||
filterInfo = getMessage("trash-info-empty");
|
filterInfo = getMessage("trash-info-empty");
|
||||||
} else {
|
} else {
|
||||||
String itemList = String.join(", ",
|
String itemList = String.join(", ",
|
||||||
filter.stream().map(TrashChestManager::formatMaterialName).collect(java.util.stream.Collectors.toList()));
|
filter.stream()
|
||||||
|
.map(fi -> {
|
||||||
|
if (fi.hasItemMeta() && fi.getItemMeta().hasDisplayName()) {
|
||||||
|
return ChatColor.stripColor(fi.getItemMeta().getDisplayName());
|
||||||
|
}
|
||||||
|
return TrashChestManager.formatMaterialName(fi.getType().name());
|
||||||
|
})
|
||||||
|
.collect(java.util.stream.Collectors.toList()));
|
||||||
filterInfo = getMessage("trash-info-filter").replace("%items%", itemList);
|
filterInfo = getMessage("trash-info-filter").replace("%items%", itemList);
|
||||||
}
|
}
|
||||||
player.sendMessage(filterInfo);
|
player.sendMessage(filterInfo);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import org.bukkit.Material;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Chest;
|
import org.bukkit.block.Chest;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
@@ -14,16 +15,26 @@ import org.bukkit.event.inventory.InventoryClickEvent;
|
|||||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.inventory.meta.PotionMeta;
|
||||||
import org.bukkit.inventory.meta.SkullMeta;
|
import org.bukkit.inventory.meta.SkullMeta;
|
||||||
|
import org.bukkit.inventory.meta.SuspiciousStewMeta;
|
||||||
|
import org.bukkit.potion.PotionEffect;
|
||||||
|
import org.bukkit.potion.PotionEffectType;
|
||||||
import org.bukkit.profile.PlayerProfile;
|
import org.bukkit.profile.PlayerProfile;
|
||||||
import org.bukkit.profile.PlayerTextures;
|
import org.bukkit.profile.PlayerTextures;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
import org.bukkit.util.io.BukkitObjectInputStream;
|
||||||
|
import org.bukkit.util.io.BukkitObjectOutputStream;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -32,38 +43,48 @@ import java.util.UUID;
|
|||||||
/**
|
/**
|
||||||
* Verwaltet Mülltruhen für das AutoSortChest-Plugin.
|
* Verwaltet Mülltruhen für das AutoSortChest-Plugin.
|
||||||
*
|
*
|
||||||
* Speicherung:
|
* Filter-Logik:
|
||||||
* MySQL (wenn aktiv):
|
* Jedes Item wird exakt erkannt (Typ + Verzauberungen + Name + Lore).
|
||||||
* asc_trash_chests : uuid, world, x, y, z, server
|
* Ein verzaubertes Item ist ein eigener Filter-Eintrag.
|
||||||
* asc_trash_items : uuid, item
|
* Vergleich über ItemStack.isSimilar() – ignoriert nur die Stapelmenge.
|
||||||
* YAML (Fallback):
|
*
|
||||||
* players.<uuid>.trash-chest.world / x / y / z
|
* Speicherung (Base64-serialisierte ItemStacks):
|
||||||
* players.<uuid>.trash-items (StringList)
|
* MySQL: asc_trash_items (item-Spalte = Base64-String)
|
||||||
|
* YAML: players.<uuid>.trash-items (Liste von Base64-Strings)
|
||||||
|
*
|
||||||
|
* Legacy-Fallback:
|
||||||
|
* Alte Material-Name-Einträge (z.B. "IRON_SWORD") werden beim Laden
|
||||||
|
* automatisch als normaler ItemStack ohne Meta importiert.
|
||||||
*/
|
*/
|
||||||
public class TrashChestManager {
|
public class TrashChestManager {
|
||||||
|
|
||||||
private static final String SKULL_TEXTURE =
|
private static final String SKULL_TEXTURE =
|
||||||
"http://textures.minecraft.net/texture/942e7fb9b8eae22d55e32b8222f38eca7b2c41948b15d769b716d80f9d113611";
|
"http://textures.minecraft.net/texture/32518d04f9c06c95dd0edad617abb93d3d8657f01e659079d330cca6f65bccf7";
|
||||||
|
|
||||||
/** Gibt den sprachabhängigen GUI-Titel zurück (Farbe aus chest-titles.trash). */
|
|
||||||
private String getGuiTitle() {
|
private String getGuiTitle() {
|
||||||
boolean isEn = "en".equalsIgnoreCase(plugin.getConfig().getString("language", "de"));
|
|
||||||
String colorPrefix = getChestTitleColor();
|
String colorPrefix = getChestTitleColor();
|
||||||
String label = isEn ? "Configure Trash Chest" : "Mülltruhe konfigurieren";
|
String label = isEnglish() ? "Configure Trash Chest" : "Mülltruhe konfigurieren";
|
||||||
return colorPrefix + ChatColor.BOLD + label;
|
return colorPrefix + ChatColor.BOLD + label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isEnglish() {
|
||||||
|
return "en".equalsIgnoreCase(plugin.getConfig().getString("language", "de"));
|
||||||
|
}
|
||||||
|
|
||||||
private final Main plugin;
|
private final Main plugin;
|
||||||
|
|
||||||
/** UUID → Truhen-Location (In-Memory-Cache für diesen Server) */
|
/** UUID → Truhen-Location */
|
||||||
private final Map<UUID, Location> trashChestLocations = new HashMap<>();
|
private final Map<UUID, Location> trashChestLocations = new HashMap<>();
|
||||||
/** UUID → Filter-Liste */
|
/** UUID → Filter-Liste (echte ItemStacks, Menge immer 1) */
|
||||||
private final Map<UUID, List<String>> trashFilterLists = new HashMap<>();
|
private final Map<UUID, List<ItemStack>> trashFilterLists = new HashMap<>();
|
||||||
/** Location-Key → Besitzer-UUID */
|
/** Location-Key → Besitzer-UUID */
|
||||||
private final Map<String, UUID> locationToOwner = new HashMap<>();
|
private final Map<String, UUID> locationToOwner = new HashMap<>();
|
||||||
/** Spieler-UUID → Truhen-Besitzer-UUID (offene GUIs) */
|
/** Spieler-UUID → Truhen-Besitzer-UUID (offene GUIs) */
|
||||||
private final Map<UUID, UUID> openGuiOwners = new HashMap<>();
|
private final Map<UUID, UUID> openGuiOwners = new HashMap<>();
|
||||||
|
/** Spieler-UUID → aktuelle GUI-Seite (0-basiert) */
|
||||||
|
private final Map<UUID, Integer> playerPages = new HashMap<>();
|
||||||
|
|
||||||
|
private static final int ITEMS_PER_PAGE = 45;
|
||||||
private BukkitTask autoTrashTask = null;
|
private BukkitTask autoTrashTask = null;
|
||||||
|
|
||||||
public TrashChestManager(Main plugin) {
|
public TrashChestManager(Main plugin) {
|
||||||
@@ -72,6 +93,63 @@ public class TrashChestManager {
|
|||||||
plugin.getServer().getPluginManager().registerEvents(new GuiListener(), plugin);
|
plugin.getServer().getPluginManager().registerEvents(new GuiListener(), plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ══════════════════════════════════════════════════════════════════════════
|
||||||
|
// SERIALISIERUNG (Base64 ↔ ItemStack)
|
||||||
|
// ══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
/** Serialisiert einen ItemStack (Menge = 1) in einen Base64-String. */
|
||||||
|
private static String itemToBase64(ItemStack item) {
|
||||||
|
try {
|
||||||
|
ItemStack copy = item.clone();
|
||||||
|
copy.setAmount(1);
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
BukkitObjectOutputStream dataOut = new BukkitObjectOutputStream(out);
|
||||||
|
dataOut.writeObject(copy);
|
||||||
|
dataOut.close();
|
||||||
|
return Base64.getEncoder().encodeToString(out.toByteArray());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deserialisiert einen Base64-String zurück in einen ItemStack. Null bei Fehler. */
|
||||||
|
private static ItemStack itemFromBase64(String data) {
|
||||||
|
try {
|
||||||
|
byte[] bytes = Base64.getDecoder().decode(data);
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
|
||||||
|
BukkitObjectInputStream dataIn = new BukkitObjectInputStream(in);
|
||||||
|
ItemStack item = (ItemStack) dataIn.readObject();
|
||||||
|
dataIn.close();
|
||||||
|
return item;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Konvertiert einen gespeicherten String in einen ItemStack.
|
||||||
|
* Unterstützt Base64 (neu) und rohe Materialnamen (Legacy).
|
||||||
|
*/
|
||||||
|
private static ItemStack parseFilterEntry(String entry) {
|
||||||
|
if (entry == null || entry.isEmpty()) return null;
|
||||||
|
// Base64 versuchen
|
||||||
|
ItemStack fromBase64 = itemFromBase64(entry);
|
||||||
|
if (fromBase64 != null) return fromBase64;
|
||||||
|
// Legacy: reiner Materialname
|
||||||
|
Material mat = Material.matchMaterial(entry);
|
||||||
|
return (mat != null && mat != Material.AIR) ? new ItemStack(mat, 1) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Konvertiert die interne Filter-Liste in Base64-Strings zur Speicherung. */
|
||||||
|
private static List<String> serializeFilter(List<ItemStack> items) {
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
for (ItemStack item : items) {
|
||||||
|
String b64 = itemToBase64(item);
|
||||||
|
if (b64 != null) result.add(b64);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// ══════════════════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════════════════
|
||||||
// LADEN
|
// LADEN
|
||||||
// ══════════════════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════════════════
|
||||||
@@ -94,10 +172,17 @@ public class TrashChestManager {
|
|||||||
UUID uuid = UUID.fromString((String) row.get("uuid"));
|
UUID uuid = UUID.fromString((String) row.get("uuid"));
|
||||||
World world = Bukkit.getWorld((String) row.get("world"));
|
World world = Bukkit.getWorld((String) row.get("world"));
|
||||||
if (world == null) continue;
|
if (world == null) continue;
|
||||||
Location loc = new Location(world, (int) row.get("x"), (int) row.get("y"), (int) row.get("z"));
|
Location loc = new Location(world,
|
||||||
|
(int) row.get("x"), (int) row.get("y"), (int) row.get("z"));
|
||||||
trashChestLocations.put(uuid, loc);
|
trashChestLocations.put(uuid, loc);
|
||||||
locationToOwner.put(locKey(loc), uuid);
|
locationToOwner.put(locKey(loc), uuid);
|
||||||
trashFilterLists.put(uuid, new ArrayList<>(db.getTrashItems(uuid.toString())));
|
|
||||||
|
List<ItemStack> items = new ArrayList<>();
|
||||||
|
for (String entry : db.getTrashItems(uuid.toString())) {
|
||||||
|
ItemStack parsed = parseFilterEntry(entry);
|
||||||
|
if (parsed != null) items.add(parsed);
|
||||||
|
}
|
||||||
|
trashFilterLists.put(uuid, items);
|
||||||
} catch (IllegalArgumentException ignored) {}
|
} catch (IllegalArgumentException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,10 +198,18 @@ public class TrashChestManager {
|
|||||||
World world = Bukkit.getWorld(data.getString(base + ".world"));
|
World world = Bukkit.getWorld(data.getString(base + ".world"));
|
||||||
if (world == null) continue;
|
if (world == null) continue;
|
||||||
Location loc = new Location(world,
|
Location loc = new Location(world,
|
||||||
data.getInt(base + ".x"), data.getInt(base + ".y"), data.getInt(base + ".z"));
|
data.getInt(base + ".x"),
|
||||||
|
data.getInt(base + ".y"),
|
||||||
|
data.getInt(base + ".z"));
|
||||||
trashChestLocations.put(uuid, loc);
|
trashChestLocations.put(uuid, loc);
|
||||||
locationToOwner.put(locKey(loc), uuid);
|
locationToOwner.put(locKey(loc), uuid);
|
||||||
trashFilterLists.put(uuid, new ArrayList<>(data.getStringList("players." + uuidStr + ".trash-items")));
|
|
||||||
|
List<ItemStack> items = new ArrayList<>();
|
||||||
|
for (String entry : data.getStringList("players." + uuidStr + ".trash-items")) {
|
||||||
|
ItemStack parsed = parseFilterEntry(entry);
|
||||||
|
if (parsed != null) items.add(parsed);
|
||||||
|
}
|
||||||
|
trashFilterLists.put(uuid, items);
|
||||||
} catch (IllegalArgumentException ignored) {}
|
} catch (IllegalArgumentException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,7 +238,8 @@ public class TrashChestManager {
|
|||||||
} else {
|
} else {
|
||||||
db.removeTrashChest(uuidStr);
|
db.removeTrashChest(uuidStr);
|
||||||
}
|
}
|
||||||
db.setTrashItems(uuidStr, trashFilterLists.getOrDefault(uuid, new ArrayList<>()));
|
db.setTrashItems(uuidStr, serializeFilter(
|
||||||
|
trashFilterLists.getOrDefault(uuid, new ArrayList<>())));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveYaml(UUID uuid) {
|
private void saveYaml(UUID uuid) {
|
||||||
@@ -162,7 +256,7 @@ public class TrashChestManager {
|
|||||||
data.set("players." + uuidStr + ".trash-chest", null);
|
data.set("players." + uuidStr + ".trash-chest", null);
|
||||||
}
|
}
|
||||||
data.set("players." + uuidStr + ".trash-items",
|
data.set("players." + uuidStr + ".trash-items",
|
||||||
trashFilterLists.getOrDefault(uuid, new ArrayList<>()));
|
serializeFilter(trashFilterLists.getOrDefault(uuid, new ArrayList<>())));
|
||||||
plugin.savePlayerDataPublic();
|
plugin.savePlayerDataPublic();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,37 +288,45 @@ public class TrashChestManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UUID getTrashChestOwner(Location loc) {
|
public UUID getTrashChestOwner(Location loc) { return locationToOwner.get(locKey(loc)); }
|
||||||
return locationToOwner.get(locKey(loc));
|
public Location getTrashChestLocation(UUID uuid) { return trashChestLocations.get(uuid); }
|
||||||
}
|
public Map<UUID, Location> getAllTrashChests() { return new HashMap<>(trashChestLocations); }
|
||||||
|
|
||||||
public Location getTrashChestLocation(UUID uuid) {
|
|
||||||
return trashChestLocations.get(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<UUID, Location> getAllTrashChests() {
|
|
||||||
return new HashMap<>(trashChestLocations);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schneller Typ-Check: prüft ob ein Material überhaupt im Filter vorkommt.
|
||||||
|
* Wird vom Sortier-System benutzt (kein isSimilar nötig, nur Typ).
|
||||||
|
*/
|
||||||
public boolean isTrashItem(UUID uuid, Material mat) {
|
public boolean isTrashItem(UUID uuid, Material mat) {
|
||||||
if (!trashChestLocations.containsKey(uuid)) return false;
|
if (!trashChestLocations.containsKey(uuid)) return false;
|
||||||
List<String> filter = trashFilterLists.getOrDefault(uuid, new ArrayList<>());
|
List<ItemStack> filter = trashFilterLists.getOrDefault(uuid, new ArrayList<>());
|
||||||
// Leerer Filter = keine Items werden weitergeleitet (Mülltruhe deaktiviert)
|
if (filter.isEmpty()) return false;
|
||||||
return !filter.isEmpty() && filter.contains(mat.name());
|
for (ItemStack fi : filter) {
|
||||||
|
if (fi.getType() == mat) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ══════════════════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════════════════
|
||||||
// ITEM-VERARBEITUNG
|
// ITEM-VERARBEITUNG
|
||||||
// ══════════════════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Löscht alle Items aus der Truhen-Inventory die exakt einem Filter-Eintrag entsprechen.
|
||||||
|
* Vergleich: ItemStack.isSimilar() → Typ + Verzauberungen + Name + Lore müssen passen.
|
||||||
|
* Die Stapelmenge wird beim Vergleich ignoriert.
|
||||||
|
*/
|
||||||
public void processTrashChestInventory(UUID ownerUUID, Inventory inv) {
|
public void processTrashChestInventory(UUID ownerUUID, Inventory inv) {
|
||||||
List<String> filter = trashFilterLists.getOrDefault(ownerUUID, new ArrayList<>());
|
List<ItemStack> filter = trashFilterLists.getOrDefault(ownerUUID, new ArrayList<>());
|
||||||
// Leerer Filter = keine Items löschen (Mülltruhe deaktiviert bis Items konfiguriert sind)
|
|
||||||
if (filter.isEmpty()) return;
|
if (filter.isEmpty()) return;
|
||||||
for (int i = 0; i < inv.getSize(); i++) {
|
for (int i = 0; i < inv.getSize(); i++) {
|
||||||
ItemStack item = inv.getItem(i);
|
ItemStack item = inv.getItem(i);
|
||||||
if (item == null || item.getType() == Material.AIR) continue;
|
if (item == null || item.getType() == Material.AIR) continue;
|
||||||
if (filter.contains(item.getType().name())) inv.setItem(i, null);
|
for (ItemStack filterItem : filter) {
|
||||||
|
if (filterItem.isSimilar(item)) {
|
||||||
|
inv.setItem(i, null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,34 +340,76 @@ public class TrashChestManager {
|
|||||||
// FILTER-LISTE
|
// FILTER-LISTE
|
||||||
// ══════════════════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
public boolean addToFilter(UUID uuid, Material mat) {
|
/**
|
||||||
List<String> filter = trashFilterLists.computeIfAbsent(uuid, k -> new ArrayList<>());
|
* Fügt ein Item exakt (inkl. Verzauberungen, Name, Lore) zum Filter hinzu.
|
||||||
if (filter.contains(mat.name())) return false;
|
* Menge wird auf 1 normiert. Duplikate (isSimilar) werden abgelehnt.
|
||||||
filter.add(mat.name());
|
*
|
||||||
|
* @return true wenn neu hinzugefügt, false wenn bereits vorhanden
|
||||||
|
*/
|
||||||
|
public boolean addToFilter(UUID uuid, ItemStack item) {
|
||||||
|
ItemStack normalized = item.clone();
|
||||||
|
normalized.setAmount(1);
|
||||||
|
|
||||||
|
List<ItemStack> filter = trashFilterLists.computeIfAbsent(uuid, k -> new ArrayList<>());
|
||||||
|
for (ItemStack existing : filter) {
|
||||||
|
if (existing.isSimilar(normalized)) return false; // Duplikat
|
||||||
|
}
|
||||||
|
|
||||||
|
filter.add(normalized);
|
||||||
|
String b64 = itemToBase64(normalized);
|
||||||
|
if (b64 != null) {
|
||||||
if (plugin.isMysqlEnabled() && plugin.getMysqlManager() != null) {
|
if (plugin.isMysqlEnabled() && plugin.getMysqlManager() != null) {
|
||||||
plugin.getMysqlManager().addTrashItem(uuid.toString(), mat.name());
|
plugin.getMysqlManager().addTrashItem(uuid.toString(), b64);
|
||||||
|
} else {
|
||||||
|
saveTrashChest(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entfernt den ersten Filter-Eintrag der isSimilar zum übergebenen Item ist.
|
||||||
|
*
|
||||||
|
* @return true wenn ein Eintrag entfernt wurde
|
||||||
|
*/
|
||||||
|
public boolean removeFromFilter(UUID uuid, ItemStack item) {
|
||||||
|
List<ItemStack> filter = trashFilterLists.get(uuid);
|
||||||
|
if (filter == null) return false;
|
||||||
|
|
||||||
|
ItemStack toRemove = null;
|
||||||
|
for (ItemStack existing : filter) {
|
||||||
|
if (existing.isSimilar(item)) { toRemove = existing; break; }
|
||||||
|
}
|
||||||
|
if (toRemove == null) return false;
|
||||||
|
|
||||||
|
filter.remove(toRemove);
|
||||||
|
if (plugin.isMysqlEnabled() && plugin.getMysqlManager() != null) {
|
||||||
|
// Komplette Liste neu schreiben (kein "remove single by item" in MySQLManager)
|
||||||
|
plugin.getMysqlManager().setTrashItems(uuid.toString(), serializeFilter(filter));
|
||||||
} else {
|
} else {
|
||||||
saveTrashChest(uuid);
|
saveTrashChest(uuid);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean removeFromFilter(UUID uuid, Material mat) {
|
public List<ItemStack> getFilter(UUID uuid) {
|
||||||
List<String> filter = trashFilterLists.get(uuid);
|
return trashFilterLists.getOrDefault(uuid, new ArrayList<>());
|
||||||
if (filter == null) return false;
|
}
|
||||||
boolean removed = filter.remove(mat.name());
|
|
||||||
if (removed) {
|
/**
|
||||||
|
* Entfernt einen Filter-Eintrag direkt per Index (0-basiert).
|
||||||
|
* Wird vom GUI-Listener genutzt um das modifizierte Display-Item sicher zu entfernen.
|
||||||
|
*/
|
||||||
|
public boolean removeFromFilterByIndex(UUID uuid, int index) {
|
||||||
|
List<ItemStack> filter = trashFilterLists.get(uuid);
|
||||||
|
if (filter == null || index < 0 || index >= filter.size()) return false;
|
||||||
|
filter.remove(index);
|
||||||
if (plugin.isMysqlEnabled() && plugin.getMysqlManager() != null) {
|
if (plugin.isMysqlEnabled() && plugin.getMysqlManager() != null) {
|
||||||
plugin.getMysqlManager().removeTrashItem(uuid.toString(), mat.name());
|
plugin.getMysqlManager().setTrashItems(uuid.toString(), serializeFilter(filter));
|
||||||
} else {
|
} else {
|
||||||
saveTrashChest(uuid);
|
saveTrashChest(uuid);
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
return removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getFilter(UUID uuid) {
|
|
||||||
return trashFilterLists.getOrDefault(uuid, new ArrayList<>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ══════════════════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════════════════
|
||||||
@@ -300,57 +444,198 @@ public class TrashChestManager {
|
|||||||
// ══════════════════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
public void openConfigGui(Player player, UUID ownerUUID) {
|
public void openConfigGui(Player player, UUID ownerUUID) {
|
||||||
|
openConfigGui(player, ownerUUID, playerPages.getOrDefault(player.getUniqueId(), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openConfigGui(Player player, UUID ownerUUID, int page) {
|
||||||
openGuiOwners.put(player.getUniqueId(), ownerUUID);
|
openGuiOwners.put(player.getUniqueId(), ownerUUID);
|
||||||
|
boolean isEn = isEnglish();
|
||||||
|
|
||||||
|
List<ItemStack> filter = trashFilterLists.getOrDefault(ownerUUID, new ArrayList<>());
|
||||||
|
|
||||||
|
// Gültige Items vorfiltern
|
||||||
|
List<ItemStack> validItems = new ArrayList<>();
|
||||||
|
for (ItemStack fi : filter) {
|
||||||
|
if (fi != null && fi.getType() != Material.AIR) validItems.add(fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalPages = Math.max(1, (int) Math.ceil(validItems.size() / (double) ITEMS_PER_PAGE));
|
||||||
|
if (page < 0) page = 0;
|
||||||
|
if (page >= totalPages) page = totalPages - 1;
|
||||||
|
playerPages.put(player.getUniqueId(), page);
|
||||||
|
|
||||||
Inventory gui = Bukkit.createInventory(null, 54, getGuiTitle());
|
Inventory gui = Bukkit.createInventory(null, 54, getGuiTitle());
|
||||||
|
|
||||||
List<String> filter = trashFilterLists.getOrDefault(ownerUUID, new ArrayList<>());
|
// ── Items der aktuellen Seite ────────────────────────────────────────
|
||||||
int displaySlot = 0;
|
int startIndex = page * ITEMS_PER_PAGE;
|
||||||
for (String matName : filter) {
|
int endIndex = Math.min(startIndex + ITEMS_PER_PAGE, validItems.size());
|
||||||
if (displaySlot >= 45) break;
|
for (int i = startIndex; i < endIndex; i++) {
|
||||||
Material mat = Material.matchMaterial(matName);
|
ItemStack filterItem = validItems.get(i);
|
||||||
if (mat == null || mat == Material.AIR) continue;
|
// Clone mit Menge 1
|
||||||
ItemStack display = new ItemStack(mat, 1);
|
ItemStack display = filterItem.clone();
|
||||||
|
display.setAmount(1);
|
||||||
|
|
||||||
ItemMeta meta = display.getItemMeta();
|
ItemMeta meta = display.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.setDisplayName(getSignColor("trash", "line1") + formatMaterialName(matName));
|
// Anzeige-Namen setzen wenn kein eigener vorhanden
|
||||||
meta.setLore(Arrays.asList(getSignColor("trash", "line4") + "Rechtsklick: Entfernen"));
|
if (!meta.hasDisplayName()) {
|
||||||
display.setItemMeta(meta);
|
meta.setDisplayName(getSignColor("trash", "line1") + "" + ChatColor.BOLD
|
||||||
}
|
+ formatMaterialName(filterItem.getType().name()));
|
||||||
gui.setItem(displaySlot++, display);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> lore = new ArrayList<>();
|
||||||
|
|
||||||
|
// ── Verzauberungen (normale Items) ─────────────────────────────
|
||||||
|
Map<Enchantment, Integer> enchants = meta.getEnchants();
|
||||||
|
if (!enchants.isEmpty()) {
|
||||||
|
for (Map.Entry<Enchantment, Integer> entry : enchants.entrySet()) {
|
||||||
|
String enchName = formatEnchantmentName(entry.getKey().getKey().getKey());
|
||||||
|
lore.add(ChatColor.AQUA + enchName + " " + toRoman(entry.getValue()));
|
||||||
|
}
|
||||||
|
lore.add("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Verzauberungen (Zauberbücher: EnchantmentStorageMeta) ───────
|
||||||
|
if (meta instanceof EnchantmentStorageMeta esm) {
|
||||||
|
Map<Enchantment, Integer> stored = esm.getStoredEnchants();
|
||||||
|
if (!stored.isEmpty()) {
|
||||||
|
for (Map.Entry<Enchantment, Integer> entry : stored.entrySet()) {
|
||||||
|
String enchName = formatEnchantmentName(entry.getKey().getKey().getKey());
|
||||||
|
lore.add(ChatColor.AQUA + enchName + " " + toRoman(entry.getValue()));
|
||||||
|
}
|
||||||
|
lore.add("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Tränkeffekte (Trank, Wurftrank, Pfeil: PotionMeta) ──────────
|
||||||
|
if (meta instanceof PotionMeta pm) {
|
||||||
|
List<PotionEffect> effects = pm.getCustomEffects();
|
||||||
|
if (!effects.isEmpty()) {
|
||||||
|
for (PotionEffect effect : effects) {
|
||||||
|
lore.add(ChatColor.LIGHT_PURPLE + formatEffectName(effect.getType())
|
||||||
|
+ " " + toRoman(effect.getAmplifier() + 1)
|
||||||
|
+ ChatColor.GRAY + " (" + formatDuration(effect.getDuration()) + ")");
|
||||||
|
}
|
||||||
|
lore.add("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Seltsame Suppe (SuspiciousStewMeta) ─────────────────────────
|
||||||
|
if (meta instanceof SuspiciousStewMeta ssm) {
|
||||||
|
List<PotionEffect> effects = ssm.getCustomEffects();
|
||||||
|
if (!effects.isEmpty()) {
|
||||||
|
for (PotionEffect effect : effects) {
|
||||||
|
lore.add(ChatColor.LIGHT_PURPLE + formatEffectName(effect.getType())
|
||||||
|
+ " " + toRoman(effect.getAmplifier() + 1)
|
||||||
|
+ ChatColor.GRAY + " (" + formatDuration(effect.getDuration()) + ")");
|
||||||
|
}
|
||||||
|
lore.add("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Bestehende Item-Lore ─────────────────────────────────────────
|
||||||
|
if (meta.hasLore()) {
|
||||||
|
lore.addAll(meta.getLore());
|
||||||
|
lore.add("");
|
||||||
|
}
|
||||||
|
|
||||||
|
lore.add(ChatColor.RED + (isEn ? "▶ Right-click: Remove" : "▶ Rechtsklick: Entfernen"));
|
||||||
|
meta.setLore(lore);
|
||||||
|
display.setItemMeta(meta);
|
||||||
|
}
|
||||||
|
gui.setItem(i - startIndex, display);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Trennleiste (Zeile 6) ─────────────────────────────────────────────
|
||||||
ItemStack filler = new ItemStack(Material.BLACK_STAINED_GLASS_PANE);
|
ItemStack filler = new ItemStack(Material.BLACK_STAINED_GLASS_PANE);
|
||||||
ItemMeta fillerMeta = filler.getItemMeta();
|
ItemMeta fillerMeta = filler.getItemMeta();
|
||||||
if (fillerMeta != null) { fillerMeta.setDisplayName(" "); filler.setItemMeta(fillerMeta); }
|
if (fillerMeta != null) { fillerMeta.setDisplayName(" "); filler.setItemMeta(fillerMeta); }
|
||||||
for (int i = 45; i <= 53; i++) gui.setItem(i, filler.clone());
|
for (int i = 45; i <= 53; i++) gui.setItem(i, filler.clone());
|
||||||
|
|
||||||
ItemStack modeInfo = new ItemStack(filter.isEmpty() ? Material.BARRIER : Material.WATER_BUCKET);
|
// ── Vorherige Seite (Slot 45) ──────────────────────────────────────────
|
||||||
|
if (page > 0) {
|
||||||
|
ItemStack prev = new ItemStack(Material.ARROW);
|
||||||
|
ItemMeta prevMeta = prev.getItemMeta();
|
||||||
|
if (prevMeta != null) {
|
||||||
|
prevMeta.setDisplayName(ChatColor.YELLOW + "" + ChatColor.BOLD
|
||||||
|
+ (isEn ? "◀ Previous Page" : "◀ Vorherige Seite"));
|
||||||
|
prevMeta.setLore(Arrays.asList(ChatColor.GRAY
|
||||||
|
+ (isEn ? "Page " : "Seite ") + page + (isEn ? " of " : " von ") + totalPages));
|
||||||
|
prev.setItemMeta(prevMeta);
|
||||||
|
}
|
||||||
|
gui.setItem(45, prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Seitenanzeige (Slot 46) ────────────────────────────────────────────
|
||||||
|
ItemStack pageInfo = new ItemStack(Material.PAPER);
|
||||||
|
ItemMeta pageMeta = pageInfo.getItemMeta();
|
||||||
|
if (pageMeta != null) {
|
||||||
|
pageMeta.setDisplayName(ChatColor.WHITE + "" + ChatColor.BOLD
|
||||||
|
+ (isEn ? "Page " : "Seite ") + (page + 1) + " / " + totalPages);
|
||||||
|
pageMeta.setLore(Arrays.asList(ChatColor.GRAY + "" + validItems.size()
|
||||||
|
+ (isEn ? " items in filter" : " Items im Filter")));
|
||||||
|
pageInfo.setItemMeta(pageMeta);
|
||||||
|
}
|
||||||
|
gui.setItem(46, pageInfo);
|
||||||
|
|
||||||
|
// ── Nächste Seite (Slot 47) ────────────────────────────────────────────
|
||||||
|
if (page < totalPages - 1) {
|
||||||
|
ItemStack next = new ItemStack(Material.ARROW);
|
||||||
|
ItemMeta nextMeta = next.getItemMeta();
|
||||||
|
if (nextMeta != null) {
|
||||||
|
nextMeta.setDisplayName(ChatColor.YELLOW + "" + ChatColor.BOLD
|
||||||
|
+ (isEn ? "Next Page ▶" : "Nächste Seite ▶"));
|
||||||
|
nextMeta.setLore(Arrays.asList(ChatColor.GRAY
|
||||||
|
+ (isEn ? "Page " : "Seite ") + (page + 2) + (isEn ? " of " : " von ") + totalPages));
|
||||||
|
next.setItemMeta(nextMeta);
|
||||||
|
}
|
||||||
|
gui.setItem(47, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Modus-Info (Slot 48) ───────────────────────────────────────────────
|
||||||
|
ItemStack modeInfo = new ItemStack(filter.isEmpty() ? Material.BARRIER : Material.HOPPER);
|
||||||
ItemMeta modeMeta = modeInfo.getItemMeta();
|
ItemMeta modeMeta = modeInfo.getItemMeta();
|
||||||
if (modeMeta != null) {
|
if (modeMeta != null) {
|
||||||
if (filter.isEmpty()) {
|
if (filter.isEmpty()) {
|
||||||
modeMeta.setDisplayName(getSignColor("trash", "line2") + "" + ChatColor.BOLD + "Modus: Deaktiviert");
|
modeMeta.setDisplayName(ChatColor.RED + "" + ChatColor.BOLD
|
||||||
|
+ (isEn ? "✗ Status: Disabled" : "✗ Status: Deaktiviert"));
|
||||||
modeMeta.setLore(Arrays.asList(
|
modeMeta.setLore(Arrays.asList(
|
||||||
ChatColor.GRAY + "Kein Filter gesetzt –",
|
ChatColor.GRAY + (isEn ? "No filter set –" : "Kein Filter gesetzt –"),
|
||||||
ChatColor.GRAY + "Items werden NICHT gelöscht.",
|
ChatColor.GRAY + (isEn ? "items will NOT be deleted." : "Items werden NICHT gelöscht."),
|
||||||
getSignColor("trash", "line1") + "Füge Items hinzu um die Mülltruhe",
|
ChatColor.YELLOW + (isEn
|
||||||
getSignColor("trash", "line1") + "zu aktivieren."));
|
? "Add items to activate the trash chest."
|
||||||
|
: "Füge Items hinzu um die Mülltruhe zu aktivieren.")));
|
||||||
} else {
|
} else {
|
||||||
modeMeta.setDisplayName(getSignColor("trash", "line4") + "" + ChatColor.BOLD + "Modus: Filter aktiv");
|
modeMeta.setDisplayName(ChatColor.GREEN + "" + ChatColor.BOLD
|
||||||
|
+ (isEn ? "✔ Status: Active" : "✔ Status: Aktiv"));
|
||||||
modeMeta.setLore(Arrays.asList(
|
modeMeta.setLore(Arrays.asList(
|
||||||
ChatColor.GRAY + "Nur gefilterte Items",
|
ChatColor.GRAY + (isEn
|
||||||
ChatColor.GRAY + "werden gelöscht."));
|
? "Items are matched exactly:"
|
||||||
|
: "Items werden exakt verglichen:"),
|
||||||
|
ChatColor.GRAY + (isEn
|
||||||
|
? "Type + enchantments + name must match."
|
||||||
|
: "Typ + Verzauberungen + Name müssen übereinstimmen.")));
|
||||||
}
|
}
|
||||||
modeInfo.setItemMeta(modeMeta);
|
modeInfo.setItemMeta(modeMeta);
|
||||||
}
|
}
|
||||||
gui.setItem(48, modeInfo);
|
gui.setItem(48, modeInfo);
|
||||||
|
|
||||||
|
// ── Item hinzufügen (Slot 49) ──────────────────────────────────────────
|
||||||
ItemStack addBtn = new ItemStack(Material.LIME_STAINED_GLASS_PANE);
|
ItemStack addBtn = new ItemStack(Material.LIME_STAINED_GLASS_PANE);
|
||||||
ItemMeta addMeta = addBtn.getItemMeta();
|
ItemMeta addMeta = addBtn.getItemMeta();
|
||||||
if (addMeta != null) {
|
if (addMeta != null) {
|
||||||
addMeta.setDisplayName(getSignColor("trash", "line1") + "" + ChatColor.BOLD + "Item hinzufügen");
|
addMeta.setDisplayName(ChatColor.GREEN + "" + ChatColor.BOLD
|
||||||
|
+ (isEn ? "✚ Add Item" : "✚ Item hinzufügen"));
|
||||||
addMeta.setLore(Arrays.asList(
|
addMeta.setLore(Arrays.asList(
|
||||||
ChatColor.GRAY + "Item in die Hand nehmen",
|
ChatColor.GRAY + (isEn
|
||||||
ChatColor.GRAY + "und diesen Button klicken."));
|
? "Hold the exact item in your main hand"
|
||||||
|
: "Genau das Item in die Haupthand nehmen"),
|
||||||
|
ChatColor.GRAY + (isEn
|
||||||
|
? "and click this button."
|
||||||
|
: "und diesen Button klicken."),
|
||||||
|
ChatColor.YELLOW + (isEn
|
||||||
|
? "Enchantments & name are saved exactly."
|
||||||
|
: "Verzauberungen & Name werden exakt gespeichert.")));
|
||||||
addBtn.setItemMeta(addMeta);
|
addBtn.setItemMeta(addMeta);
|
||||||
}
|
}
|
||||||
gui.setItem(49, addBtn);
|
gui.setItem(49, addBtn);
|
||||||
@@ -363,6 +648,11 @@ public class TrashChestManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ItemStack buildSkullButton() {
|
private ItemStack buildSkullButton() {
|
||||||
|
boolean isEn = isEnglish();
|
||||||
|
String label = isEn ? "Empty Trash Chest" : "Mülltruhe leeren";
|
||||||
|
String lore1 = isEn ? "Click to immediately" : "Klicken um alle Items";
|
||||||
|
String lore2 = isEn ? "delete all items." : "sofort zu löschen.";
|
||||||
|
|
||||||
ItemStack skull;
|
ItemStack skull;
|
||||||
try {
|
try {
|
||||||
skull = new ItemStack(Material.PLAYER_HEAD);
|
skull = new ItemStack(Material.PLAYER_HEAD);
|
||||||
@@ -373,20 +663,16 @@ public class TrashChestManager {
|
|||||||
textures.setSkin(new URL(SKULL_TEXTURE));
|
textures.setSkin(new URL(SKULL_TEXTURE));
|
||||||
profile.setTextures(textures);
|
profile.setTextures(textures);
|
||||||
meta.setOwnerProfile(profile);
|
meta.setOwnerProfile(profile);
|
||||||
meta.setDisplayName(getChestTitleColor() + "" + ChatColor.BOLD + "Mülltruhe leeren");
|
meta.setDisplayName(getChestTitleColor() + "" + ChatColor.BOLD + label);
|
||||||
meta.setLore(Arrays.asList(
|
meta.setLore(Arrays.asList(ChatColor.GRAY + lore1, ChatColor.GRAY + lore2));
|
||||||
ChatColor.GRAY + "Klicken um alle Items",
|
|
||||||
ChatColor.GRAY + "sofort zu löschen."));
|
|
||||||
skull.setItemMeta(meta);
|
skull.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
skull = new ItemStack(Material.RED_DYE);
|
skull = new ItemStack(Material.RED_DYE);
|
||||||
ItemMeta meta = skull.getItemMeta();
|
ItemMeta meta = skull.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.setDisplayName(getChestTitleColor() + "" + ChatColor.BOLD + "Mülltruhe leeren");
|
meta.setDisplayName(getChestTitleColor() + "" + ChatColor.BOLD + label);
|
||||||
meta.setLore(Arrays.asList(
|
meta.setLore(Arrays.asList(ChatColor.GRAY + lore1, ChatColor.GRAY + lore2));
|
||||||
ChatColor.GRAY + "Klicken um alle Items",
|
|
||||||
ChatColor.GRAY + "sofort zu löschen."));
|
|
||||||
skull.setItemMeta(meta);
|
skull.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -409,21 +695,39 @@ public class TrashChestManager {
|
|||||||
UUID ownerUUID = openGuiOwners.get(player.getUniqueId());
|
UUID ownerUUID = openGuiOwners.get(player.getUniqueId());
|
||||||
if (ownerUUID == null) return;
|
if (ownerUUID == null) return;
|
||||||
|
|
||||||
|
// ── Mülltruhe leeren ──────────────────────────────────────────────
|
||||||
if (clickedSlot == 53) {
|
if (clickedSlot == 53) {
|
||||||
clearTrashChest(ownerUUID);
|
clearTrashChest(ownerUUID);
|
||||||
player.sendMessage(getMessage("trash-cleared"));
|
player.sendMessage(getMessage("trash-cleared"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Vorherige Seite ───────────────────────────────────────────────
|
||||||
|
if (clickedSlot == 45) {
|
||||||
|
int currentPage = playerPages.getOrDefault(player.getUniqueId(), 0);
|
||||||
|
if (currentPage > 0) openConfigGui(player, ownerUUID, currentPage - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Nächste Seite ─────────────────────────────────────────────────
|
||||||
|
if (clickedSlot == 47) {
|
||||||
|
int currentPage = playerPages.getOrDefault(player.getUniqueId(), 0);
|
||||||
|
List<ItemStack> f = trashFilterLists.getOrDefault(ownerUUID, new ArrayList<>());
|
||||||
|
int totalPages = Math.max(1, (int) Math.ceil(f.size() / (double) ITEMS_PER_PAGE));
|
||||||
|
if (currentPage < totalPages - 1) openConfigGui(player, ownerUUID, currentPage + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Item hinzufügen ───────────────────────────────────────────────
|
||||||
if (clickedSlot == 49) {
|
if (clickedSlot == 49) {
|
||||||
ItemStack inHand = player.getInventory().getItemInMainHand();
|
ItemStack inHand = player.getInventory().getItemInMainHand();
|
||||||
if (inHand.getType() == Material.AIR) {
|
if (inHand.getType() == Material.AIR) {
|
||||||
player.sendMessage(getMessage("no-item-in-hand"));
|
player.sendMessage(getMessage("no-item-in-hand"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Material mat = inHand.getType();
|
if (addToFilter(ownerUUID, inHand)) {
|
||||||
if (addToFilter(ownerUUID, mat)) {
|
player.sendMessage(getMessage("trash-item-added")
|
||||||
player.sendMessage(getMessage("trash-item-added").replace("%item%", formatMaterialName(mat.name())));
|
.replace("%item%", getItemDisplayName(inHand)));
|
||||||
} else {
|
} else {
|
||||||
player.sendMessage(getMessage("trash-item-already"));
|
player.sendMessage(getMessage("trash-item-already"));
|
||||||
}
|
}
|
||||||
@@ -433,12 +737,24 @@ public class TrashChestManager {
|
|||||||
|
|
||||||
if (clickedSlot >= 45) return;
|
if (clickedSlot >= 45) return;
|
||||||
|
|
||||||
|
// ── Rechtsklick: Item per Index entfernen ─────────────────────────
|
||||||
|
// WICHTIG: Display-Item hat modifizierte Lore → isSimilar() würde fehlschlagen.
|
||||||
|
// Stattdessen: Slot-Position → Filter-Index berechnen und direkt entfernen.
|
||||||
if (event.isRightClick()) {
|
if (event.isRightClick()) {
|
||||||
ItemStack clicked = event.getCurrentItem();
|
ItemStack clicked = event.getCurrentItem();
|
||||||
if (clicked == null || clicked.getType() == Material.AIR) return;
|
if (clicked == null || clicked.getType() == Material.AIR) return;
|
||||||
Material mat = clicked.getType();
|
|
||||||
if (removeFromFilter(ownerUUID, mat)) {
|
int currentPage = playerPages.getOrDefault(player.getUniqueId(), 0);
|
||||||
player.sendMessage(getMessage("trash-item-removed").replace("%item%", formatMaterialName(mat.name())));
|
int filterIndex = currentPage * ITEMS_PER_PAGE + clickedSlot;
|
||||||
|
|
||||||
|
// Original-Item für die Chat-Nachricht holen (vor dem Entfernen)
|
||||||
|
List<ItemStack> filterList = trashFilterLists.getOrDefault(ownerUUID, new ArrayList<>());
|
||||||
|
String itemName = (filterIndex < filterList.size())
|
||||||
|
? getItemDisplayName(filterList.get(filterIndex))
|
||||||
|
: getItemDisplayName(clicked);
|
||||||
|
|
||||||
|
if (removeFromFilterByIndex(ownerUUID, filterIndex)) {
|
||||||
|
player.sendMessage(getMessage("trash-item-removed").replace("%item%", itemName));
|
||||||
openConfigGui(player, ownerUUID);
|
openConfigGui(player, ownerUUID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -447,7 +763,15 @@ public class TrashChestManager {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
public void onInventoryClose(InventoryCloseEvent event) {
|
public void onInventoryClose(InventoryCloseEvent event) {
|
||||||
if (event.getPlayer() instanceof Player player) {
|
if (event.getPlayer() instanceof Player player) {
|
||||||
openGuiOwners.remove(player.getUniqueId());
|
UUID playerUUID = player.getUniqueId();
|
||||||
|
// 1-Tick Verzögerung: verhindert Löschung beim Seitenwechsel
|
||||||
|
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||||
|
String openTitle = player.getOpenInventory().getTitle();
|
||||||
|
if (!getGuiTitle().equals(openTitle)) {
|
||||||
|
openGuiOwners.remove(playerUUID);
|
||||||
|
playerPages.remove(playerUUID);
|
||||||
|
}
|
||||||
|
}, 1L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -461,37 +785,39 @@ public class TrashChestManager {
|
|||||||
return org.bukkit.ChatColor.translateAlternateColorCodes('&', msg);
|
return org.bukkit.ChatColor.translateAlternateColorCodes('&', msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Liest eine Schildfarbe aus sign-colors.<type>.<line> in der Config.
|
|
||||||
* Gibt übersetzten §-Code zurück (z.B. §6 für &6).
|
|
||||||
*/
|
|
||||||
private String getSignColor(String type, String line) {
|
private String getSignColor(String type, String line) {
|
||||||
String raw = plugin.getConfig().getString("sign-colors." + type + "." + line, "&f");
|
String raw = plugin.getConfig().getString("sign-colors." + type + "." + line, "&f");
|
||||||
return ChatColor.translateAlternateColorCodes('&', raw);
|
return ChatColor.translateAlternateColorCodes('&', raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Liest nur den Farb-Präfix aus chest-titles.trash (ohne Titeltext).
|
|
||||||
* Gibt übersetzten §-Code zurück.
|
|
||||||
*/
|
|
||||||
private String getChestTitleColor() {
|
private String getChestTitleColor() {
|
||||||
boolean isEn = "en".equalsIgnoreCase(plugin.getConfig().getString("language", "de"));
|
boolean isEn = isEnglish();
|
||||||
String lang = isEn ? "en" : "de";
|
String lang = isEn ? "en" : "de";
|
||||||
String full = plugin.getConfig().getString("chest-titles.trash." + lang,
|
String full = plugin.getConfig().getString("chest-titles.trash." + lang,
|
||||||
isEn ? "&4Trash Chest" : "&4Mülltruhe");
|
isEn ? "&4Trash Chest" : "&4Mülltruhe");
|
||||||
// Nur die führenden &X / &l Codes extrahieren
|
|
||||||
StringBuilder codes = new StringBuilder();
|
StringBuilder codes = new StringBuilder();
|
||||||
for (int i = 0; i + 1 < full.length(); i++) {
|
for (int i = 0; i + 1 < full.length(); i++) {
|
||||||
if (full.charAt(i) == '&' && "0123456789abcdefklmnor".indexOf(full.charAt(i + 1)) >= 0) {
|
if (full.charAt(i) == '&' && "0123456789abcdefklmnor".indexOf(full.charAt(i + 1)) >= 0) {
|
||||||
codes.append(full, i, i + 2);
|
codes.append(full, i, i + 2);
|
||||||
i++; // Zeichen überspringen
|
i++;
|
||||||
} else {
|
} else {
|
||||||
break; // erster Nicht-Code-Zeichenblock → abbrechen
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ChatColor.translateAlternateColorCodes('&', codes.length() > 0 ? codes.toString() : "&4");
|
return ChatColor.translateAlternateColorCodes('&', codes.length() > 0 ? codes.toString() : "&4");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lesbarer Anzeige-Name für Chat-Nachrichten.
|
||||||
|
* Nutzt Custom Display Name falls vorhanden, sonst formatierten Material-Namen.
|
||||||
|
*/
|
||||||
|
private String getItemDisplayName(ItemStack item) {
|
||||||
|
if (item.hasItemMeta() && item.getItemMeta().hasDisplayName()) {
|
||||||
|
return ChatColor.stripColor(item.getItemMeta().getDisplayName());
|
||||||
|
}
|
||||||
|
return formatMaterialName(item.getType().name());
|
||||||
|
}
|
||||||
|
|
||||||
private String locKey(Location loc) {
|
private String locKey(Location loc) {
|
||||||
return loc.getWorld().getName() + ":" + loc.getBlockX() + ":" + loc.getBlockY() + ":" + loc.getBlockZ();
|
return loc.getWorld().getName() + ":" + loc.getBlockX() + ":" + loc.getBlockY() + ":" + loc.getBlockZ();
|
||||||
}
|
}
|
||||||
@@ -509,4 +835,79 @@ public class TrashChestManager {
|
|||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Formatiert einen Enchantment-Key wie "sharpness" → "Sharpness". */
|
||||||
|
private static String formatEnchantmentName(String key) {
|
||||||
|
if (key == null || key.isEmpty()) return "";
|
||||||
|
String[] parts = key.split("_");
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (String part : parts) {
|
||||||
|
if (sb.length() > 0) sb.append(' ');
|
||||||
|
if (!part.isEmpty()) {
|
||||||
|
sb.append(Character.toUpperCase(part.charAt(0)));
|
||||||
|
if (part.length() > 1) sb.append(part.substring(1).toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Formatiert einen PotionEffectType lesbar (z.B. "BLINDNESS" → "Blindheit" / "Blindness"). */
|
||||||
|
private String formatEffectName(PotionEffectType type) {
|
||||||
|
boolean isEn = isEnglish();
|
||||||
|
String key = type.getKey().getKey().toLowerCase();
|
||||||
|
if (!isEn) {
|
||||||
|
// Deutsche Übersetzungen der häufigsten Effekte
|
||||||
|
switch (key) {
|
||||||
|
case "speed": return "Geschwindigkeit";
|
||||||
|
case "slowness": return "Langsamkeit";
|
||||||
|
case "haste": return "Eile";
|
||||||
|
case "mining_fatigue": return "Schwere";
|
||||||
|
case "strength": return "Stärke";
|
||||||
|
case "instant_health": return "Sofortige Heilung";
|
||||||
|
case "instant_damage": return "Sofortiger Schaden";
|
||||||
|
case "jump_boost": return "Sprungkraft";
|
||||||
|
case "nausea": return "Übelkeit";
|
||||||
|
case "regeneration": return "Regeneration";
|
||||||
|
case "resistance": return "Resistenz";
|
||||||
|
case "fire_resistance": return "Feuerschutz";
|
||||||
|
case "water_breathing": return "Wasseratmung";
|
||||||
|
case "invisibility": return "Unsichtbarkeit";
|
||||||
|
case "blindness": return "Blindheit";
|
||||||
|
case "night_vision": return "Nachtsicht";
|
||||||
|
case "hunger": return "Hunger";
|
||||||
|
case "weakness": return "Schwäche";
|
||||||
|
case "poison": return "Gift";
|
||||||
|
case "wither": return "Wither";
|
||||||
|
case "health_boost": return "Gesundheitsschub";
|
||||||
|
case "absorption": return "Absorption";
|
||||||
|
case "saturation": return "Sättigung";
|
||||||
|
case "glowing": return "Leuchten";
|
||||||
|
case "levitation": return "Schweben";
|
||||||
|
case "luck": return "Glück";
|
||||||
|
case "unluck": return "Pech";
|
||||||
|
case "slow_falling": return "Langsamer Fall";
|
||||||
|
case "conduit_power": return "Leitungskraft";
|
||||||
|
case "dolphins_grace": return "Delfingnade";
|
||||||
|
case "bad_omen": return "Schlechtes Omen";
|
||||||
|
case "hero_of_the_village":return "Dorfheld";
|
||||||
|
case "darkness": return "Dunkelheit";
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return formatEnchantmentName(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Wandelt Ticks in ein lesbares mm:ss-Format um (z.B. 220 → "00:11"). */
|
||||||
|
private static String formatDuration(int ticks) {
|
||||||
|
int totalSeconds = ticks / 20;
|
||||||
|
int minutes = totalSeconds / 60;
|
||||||
|
int seconds = totalSeconds % 60;
|
||||||
|
return String.format("%02d:%02d", minutes, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Konvertiert eine Zahl in römische Ziffern (1–10). */
|
||||||
|
private static String toRoman(int level) {
|
||||||
|
String[] roman = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"};
|
||||||
|
return (level >= 1 && level <= 10) ? roman[level] : String.valueOf(level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: AutoSortChest
|
name: AutoSortChest
|
||||||
version: 2.5
|
version: 2.6
|
||||||
main: com.viper.autosortchest.Main
|
main: com.viper.autosortchest.Main
|
||||||
api-version: 1.21
|
api-version: 1.21
|
||||||
authors: [M_Viper]
|
authors: [M_Viper]
|
||||||
@@ -7,7 +7,7 @@ description: Ein Plugin zum automatischen Sortieren von Items in Truhen
|
|||||||
commands:
|
commands:
|
||||||
asc:
|
asc:
|
||||||
description: AutoSortChest Befehle
|
description: AutoSortChest Befehle
|
||||||
usage: /<command> [help|info|reload|import|export]
|
usage: /<command> [help|info|reload|import|export|list]
|
||||||
aliases: [autosortchest]
|
aliases: [autosortchest]
|
||||||
permissions:
|
permissions:
|
||||||
autosortchest.use:
|
autosortchest.use:
|
||||||
@@ -31,6 +31,9 @@ permissions:
|
|||||||
autosortchest.admin:
|
autosortchest.admin:
|
||||||
description: Erlaubt OPs/Admins Zugriff auf fremde AutoSortChest-Truhen
|
description: Erlaubt OPs/Admins Zugriff auf fremde AutoSortChest-Truhen
|
||||||
default: op
|
default: op
|
||||||
|
autosortchest.list:
|
||||||
|
description: Erlaubt die Verwendung von /asc list <Spieler> um Truhen-Statistiken einzusehen
|
||||||
|
default: op
|
||||||
autosortchest.limit.<gruppe>:
|
autosortchest.limit.<gruppe>:
|
||||||
description: >
|
description: >
|
||||||
Limits fuer eine benutzerdefinierte Gruppe aus der config.yml.
|
Limits fuer eine benutzerdefinierte Gruppe aus der config.yml.
|
||||||
|
|||||||
Reference in New Issue
Block a user