From 58e35bb3dddbf8e99901ceb61562ae54ba1311bd Mon Sep 17 00:00:00 2001 From: tastybento Date: Fri, 8 May 2026 15:25:02 -0700 Subject: [PATCH] fix: show custom-block icon and display name in value panel (#426) The /is value panel rendered Oraxen/Nexo/ItemsAdder blocks as paper with the prettified config key as the name. Look up the real ItemStack from the plugin's registry and use it as the icon, plus the item meta display name when present. Lookup helper is extracted to Utils so DetailsPanel and ValuePanel share it. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../bentobox/level/panels/DetailsPanel.java | 34 +------------- .../bentobox/level/panels/ValuePanel.java | 38 ++++++++++----- .../java/world/bentobox/level/util/Utils.java | 47 +++++++++++++++++++ 3 files changed, 75 insertions(+), 44 deletions(-) diff --git a/src/main/java/world/bentobox/level/panels/DetailsPanel.java b/src/main/java/world/bentobox/level/panels/DetailsPanel.java index 2445cc9..3bd84fd 100644 --- a/src/main/java/world/bentobox/level/panels/DetailsPanel.java +++ b/src/main/java/world/bentobox/level/panels/DetailsPanel.java @@ -12,10 +12,8 @@ import org.bukkit.inventory.ItemStack; import com.google.common.base.Enums; -import com.nexomc.nexo.api.NexoItems; import lv.id.bonne.panelutils.PanelUtils; -import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.panels.PanelItem; import world.bentobox.bentobox.api.panels.TemplatedPanel; @@ -24,8 +22,6 @@ import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; -import world.bentobox.bentobox.hooks.ItemsAdderHook; -import world.bentobox.bentobox.hooks.OraxenHook; import world.bentobox.level.Level; import world.bentobox.level.objects.IslandLevels; import world.bentobox.level.util.Utils; @@ -742,12 +738,9 @@ private BlockDataRec getBlockData(Object key) { Utils.prettifyObject(key, this.user), this.user.getTranslation(this.world, "level.gui.buttons.spawner.block-name")); } else if (key instanceof String s) { - Optional optItem = getCustomBlockItemStack(s); + Optional optItem = Utils.getCustomBlockItemStack(addon, s); ItemStack icon = optItem.orElse(new ItemStack(Material.PAPER)); - String disp = optItem - .filter(is -> is.getItemMeta() != null && is.getItemMeta().hasDisplayName()) - .map(is -> is.getItemMeta().getDisplayName()) - .orElse(Utils.prettifyObject(s, this.user)); + String disp = Utils.getCustomBlockDisplayName(optItem, s, this.user); return new BlockDataRec(icon, this.user.getTranslationOrNothing(ref + "id", "[id]", s), @@ -758,29 +751,6 @@ private BlockDataRec getBlockData(Object key) { return new BlockDataRec(new ItemStack(Material.PAPER), "", 0, 0, Utils.prettifyObject(key, this.user), ""); } - /** - * Returns the best available ItemStack for a custom-block string ID. - * Checks Oraxen, Nexo, and ItemsAdder in order; returns empty when none matches. - * - * @param id the custom block ID (e.g. "oraxen:my_block", "nexo:my_block", or an ItemsAdder ID) - * @return an Optional containing the representative ItemStack, or empty - */ - private Optional getCustomBlockItemStack(String id) { - if (id.startsWith("oraxen:") && BentoBox.getInstance().getHooks().getHook("Oraxen").isPresent()) { - return OraxenHook.getOptionalItemById(id.substring(7)) - .map(itemBuilder -> itemBuilder.build()); - } - if (id.startsWith("nexo:") && addon.isNexo()) { - com.nexomc.nexo.items.ItemBuilder nexoBuilder = NexoItems.itemFromId(id.substring(5)); - return nexoBuilder != null ? Optional.of(nexoBuilder.build()) : Optional.empty(); - } - if (addon.isItemsAdder() && ItemsAdderHook.isInRegistry(id)) { - return ItemsAdderHook.getItemStack(id); - } - return Optional.empty(); - } - - // --------------------------------------------------------------------- // Section: Other Methods // --------------------------------------------------------------------- diff --git a/src/main/java/world/bentobox/level/panels/ValuePanel.java b/src/main/java/world/bentobox/level/panels/ValuePanel.java index 23361ed..7a7695f 100644 --- a/src/main/java/world/bentobox/level/panels/ValuePanel.java +++ b/src/main/java/world/bentobox/level/panels/ValuePanel.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.Optional; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -668,6 +669,16 @@ private PanelItem createMaterialButton(ItemTemplateRecord template, TemplatedPan return this.createMaterialButton(template, this.elementList.get(index)); } + private static String stripCustomPrefix(String key) { + if (key.startsWith("oraxen:")) { + return key.substring(7); + } + if (key.startsWith("nexo:")) { + return key.substring(5); + } + return key; + } + private Material getIcon(String key) { // Filter out some names key = key.replaceAll("wall_", ""); @@ -773,18 +784,21 @@ private PanelItem createMaterialButton(ItemTemplateRecord template, BlockRecord ? this.user.getTranslationOrNothing(baseKey + "limit", TextVariables.NUMBER, String.valueOf(blockLimit)) : ""; - // Determine icon and display material text - Material icon = getIcon(key); - builder.icon((icon == null || icon == Material.AIR) ? Material.PAPER : icon); - if (key.startsWith("oraxen:")) { - key = key.substring(7); - } else if (key.startsWith("nexo:")) { - key = key.substring(5); - } - String displayMaterial = (icon == null) ? Util.prettifyText(key) : Utils.prettifyObject(key, user); - // Special handling for spawn eggs - if (icon != null && icon.name().endsWith("_SPAWN_EGG")) { - displayMaterial = Util.prettifyText(key); + // Prefer the actual custom-block ItemStack (real texture + display name) over a fallback Material icon. + Optional customStack = Utils.getCustomBlockItemStack(addon, key); + String displayMaterial; + if (customStack.isPresent()) { + builder.icon(customStack.get().clone()); + displayMaterial = Utils.getCustomBlockDisplayName(customStack, stripCustomPrefix(key), user); + } else { + Material icon = getIcon(key); + builder.icon((icon == null || icon == Material.AIR) ? Material.PAPER : icon); + String stripped = stripCustomPrefix(key); + displayMaterial = (icon == null) ? Util.prettifyText(stripped) : Utils.prettifyObject(stripped, user); + // Special handling for spawn eggs + if (icon != null && icon.name().endsWith("_SPAWN_EGG")) { + displayMaterial = Util.prettifyText(stripped); + } } // Set button title if available diff --git a/src/main/java/world/bentobox/level/util/Utils.java b/src/main/java/world/bentobox/level/util/Utils.java index b807cb9..2a40434 100644 --- a/src/main/java/world/bentobox/level/util/Utils.java +++ b/src/main/java/world/bentobox/level/util/Utils.java @@ -9,13 +9,21 @@ import java.text.NumberFormat; import java.util.List; +import java.util.Optional; import org.bukkit.Material; import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; import org.bukkit.permissions.PermissionAttachmentInfo; +import com.nexomc.nexo.api.NexoItems; + +import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.hooks.ItemsAdderHook; import world.bentobox.bentobox.hooks.LangUtilsHook; +import world.bentobox.bentobox.hooks.OraxenHook; +import world.bentobox.level.Level; public class Utils @@ -216,6 +224,45 @@ public static String prettifyObject(Object object, User user) { return ""; } + /** + * Returns the best available ItemStack for a custom-block string ID. + * Checks Oraxen, Nexo, and ItemsAdder in order; returns empty when none matches. + * + * @param addon the Level addon + * @param id the custom block ID (e.g. "oraxen:my_block", "nexo:my_block", or an ItemsAdder ID) + * @return an Optional containing the representative ItemStack, or empty + */ + public static Optional getCustomBlockItemStack(Level addon, String id) { + if (id == null) { + return Optional.empty(); + } + if (id.startsWith("oraxen:") && BentoBox.getInstance().getHooks().getHook("Oraxen").isPresent()) { + return OraxenHook.getOptionalItemById(id.substring(7)).map(itemBuilder -> itemBuilder.build()); + } + if (id.startsWith("nexo:") && addon.isNexo()) { + com.nexomc.nexo.items.ItemBuilder nexoBuilder = NexoItems.itemFromId(id.substring(5)); + return nexoBuilder != null ? Optional.of(nexoBuilder.build()) : Optional.empty(); + } + if (addon.isItemsAdder() && ItemsAdderHook.isInRegistry(id)) { + return ItemsAdderHook.getItemStack(id); + } + return Optional.empty(); + } + + /** + * Returns the display name from an ItemStack's meta when present, otherwise falls back to + * {@link #prettifyObject(Object, User)} on the original key. + * + * @param itemStack the optional ItemStack (typically from a custom-block plugin) + * @param key the raw key used as a fallback for prettification + * @param user the user for translation lookups + * @return the human-readable display name + */ + public static String getCustomBlockDisplayName(Optional itemStack, String key, User user) { + return itemStack.filter(is -> is.getItemMeta() != null && is.getItemMeta().hasDisplayName()) + .map(is -> is.getItemMeta().getDisplayName()).orElse(prettifyObject(key, user)); + } + public static String prettifyDescription(Object object, User user) { if (object instanceof String key) { String translation = user.getTranslationOrNothing(LEVEL_MATERIALS + key + DESCRIPTION);