From 7e0e865a86dd8b551fffa3359057213a7e74f029 Mon Sep 17 00:00:00 2001 From: Maxence Simon <32517160+Maxlego08@users.noreply.github.com> Date: Mon, 1 Dec 2025 12:47:10 +0100 Subject: [PATCH] Refactor menu item stack and document interface --- .../fr/maxlego08/menu/api/MenuItemStack.java | 425 ++++++++++++++++++ .../fr/maxlego08/menu/ZMenuItemStack.java | 220 +++++---- 2 files changed, 560 insertions(+), 85 deletions(-) diff --git a/API/src/main/java/fr/maxlego08/menu/api/MenuItemStack.java b/API/src/main/java/fr/maxlego08/menu/api/MenuItemStack.java index 887c6324..351b9e5e 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/MenuItemStack.java +++ b/API/src/main/java/fr/maxlego08/menu/api/MenuItemStack.java @@ -97,171 +97,596 @@ public interface MenuItemStack { */ void setTargetPlayer(String targetPlayer); + /** + * Retrieves the configured amount placeholder for the item stack. + * + * @return the amount expression as a string. + */ String getAmount(); + /** + * Updates the configured amount placeholder for the item stack. + * + * @param amount the amount expression to set. + */ void setAmount(String amount); + /** + * Returns the skull texture URL associated with this item stack, when applicable. + * + * @return the skull URL or {@code null} if none is set. + */ String getUrl(); + /** + * Defines the skull texture URL for this item stack. + * + * @param url the skull URL to use. + */ void setUrl(String url); + /** + * Retrieves the legacy data value configured for this item stack. + * + * @return the data value. + */ String getData(); + /** + * Sets the legacy data value for this item stack. + * + * @param data the data value to apply. + */ void setData(String data); + /** + * Returns the custom durability configured for this item stack. + * + * @return the durability value. + */ int getDurability(); + /** + * Sets the durability of the item stack. + * + * @param durability the durability to apply. + */ void setDurability(int durability); + /** + * Retrieves the potion configuration applied to this item stack. + * + * @return the potion descriptor, or {@code null} when none is set. + */ Potion getPotion(); + /** + * Applies a potion configuration to this item stack. + * + * @param potion the potion descriptor to use. + */ void setPotion(Potion potion); + /** + * Returns the lore lines attached to this item stack. + * + * @return the lore lines. + */ List getLore(); + /** + * Replaces the lore lines attached to this item stack. + * + * @param lore the lore lines to apply. + */ void setLore(List lore); + /** + * Retrieves the item flags applied to this item stack. + * + * @return the list of item flags. + */ List getFlags(); + /** + * Sets the item flags applied to this item stack. + * + * @param flags the flags to set. + */ void setFlags(List flags); + /** + * Returns the display name configured for the item stack. + * + * @return the display name. + */ String getDisplayName(); + /** + * Defines the display name for the item stack. + * + * @param displayName the display name to set. + */ void setDisplayName(String displayName); + /** + * Indicates whether the item should appear with a glowing effect. + * + * @return {@code true} if the glowing effect is enabled. + */ boolean isGlowing(); + /** + * Enables or disables the glowing effect on the item. + * + * @param isGlowing {@code true} to enable the effect. + */ void setGlowing(boolean isGlowing); + /** + * Retrieves the custom model data identifier as a string. + * + * @return the model identifier. + */ String getModelID(); + /** + * Sets the custom model data identifier using a string value. + * + * @param modelID the identifier to use. + */ void setModelID(String modelID); + /** + * Sets the custom model data identifier using an integer value. + * + * @param modelID the identifier to use. + */ void setModelID(int modelID); + /** + * Returns the enchantments configured for this item stack. + * + * @return the enchantments map. + */ Map getEnchantments(); + /** + * Applies the provided enchantments to this item stack. + * + * @param enchantments the enchantments to set. + */ void setEnchantments(Map enchantments); + /** + * Retrieves the attributes configured for this item stack. + * + * @return the list of attributes. + */ List getAttributes(); + /** + * Sets the attributes applied to this item stack. + * + * @param attributes the attributes to apply. + */ void setAttributes(List attributes); + /** + * Returns the banner configuration attached to this item stack. + * + * @return the banner descriptor, or {@code null} when none is set. + */ Banner getBanner(); + /** + * Applies a banner configuration to this item stack. + * + * @param banner the banner descriptor to use. + */ void setBanner(Banner banner); + /** + * Retrieves the firework configuration attached to this item stack. + * + * @return the firework descriptor, or {@code null} when none is set. + */ Firework getFirework(); + /** + * Applies a firework configuration to this item stack. + * + * @param firework the firework descriptor to use. + */ void setFirework(Firework firework); + /** + * Retrieves the leather armor configuration attached to this item stack. + * + * @return the leather armor descriptor, or {@code null} when none is set. + */ LeatherArmor getLeatherArmor(); + /** + * Applies a leather armor configuration to this item stack. + * + * @param leatherArmor the leather armor descriptor to use. + */ void setLeatherArmor(LeatherArmor leatherArmor); + /** + * Returns the tooltip style identifier applied to this item stack. + * + * @return the tooltip style key. + */ String getToolTipStyle(); + /** + * Sets the tooltip style identifier applied to this item stack. + * + * @param toolTipStyle the tooltip style key to use. + */ void setToolTipStyle(String toolTipStyle); + /** + * Retrieves the translated display names available for this item stack. + * + * @return the map of locale to display name. + */ Map getTranslatedDisplayName(); + /** + * Sets the translated display names available for this item stack. + * + * @param translatedDisplayName the map of locale to display name. + */ void setTranslatedDisplayName(Map translatedDisplayName); + /** + * Retrieves the translated lore entries available for this item stack. + * + * @return the map of locale to lore lines. + */ Map> getTranslatedLore(); + /** + * Sets the translated lore entries available for this item stack. + * + * @param translatedLore the map of locale to lore lines. + */ void setTranslatedLore(Map> translatedLore); + /** + * Indicates whether PlaceholderAPI is required for this item stack. + * + * @return {@code true} if PlaceholderAPI is needed. + */ boolean isNeedPlaceholderAPI(); + /** + * Marks whether PlaceholderAPI is required for this item stack. + * + * @param needPlaceholderAPI {@code true} when PlaceholderAPI is needed. + */ void setNeedPlaceholderAPI(boolean needPlaceholderAPI); + /** + * Retrieves the cached item stack when caching is enabled. + * + * @return the cached ItemStack, or {@code null} when none exists. + */ ItemStack getCacheItemStack(); + /** + * Sets the cached item stack value used when caching is enabled. + * + * @param cacheItemStack the ItemStack to cache. + */ void setCacheItemStack(ItemStack cacheItemStack); + /** + * Retrieves the configured maximum stack size for the item. + * + * @return the maximum stack size. + */ int getMaxStackSize(); + /** + * Sets the maximum stack size for the item. + * + * @param maxStackSize the new maximum stack size. + */ void setMaxStackSize(int maxStackSize); + /** + * Retrieves the configured maximum damage for the item. + * + * @return the maximum damage value. + */ int getMaxDamage(); + /** + * Sets the maximum damage for the item. + * + * @param maxDamage the maximum damage value. + */ void setMaxDamage(int maxDamage); + /** + * Retrieves the current damage value for the item. + * + * @return the damage value. + */ int getDamage(); + /** + * Sets the current damage value for the item. + * + * @param damage the damage to apply. + */ void setDamage(int damage); + /** + * Retrieves the repair cost associated with the item. + * + * @return the repair cost. + */ int getRepairCost(); + /** + * Sets the repair cost associated with the item. + * + * @param repairCost the repair cost value. + */ void setRepairCost(int repairCost); + /** + * Indicates whether the item is unbreakable. + * + * @return {@code true} if unbreakable is enabled. + */ boolean isUnbreakableEnabled(); + /** + * Enables or disables the unbreakable flag on the item. + * + * @param unbreakableEnabled {@code true} to enable the flag. + */ void setUnbreakableEnabled(Boolean unbreakableEnabled); + /** + * Indicates whether the unbreakable tooltip should be shown. + * + * @return {@code true} if the tooltip is shown. + */ boolean isUnbreakableShowInTooltip(); + /** + * Controls the visibility of the unbreakable tooltip. + * + * @param unbreakableShowInTooltip {@code true} to show the tooltip. + */ void setUnbreakableShowInTooltip(Boolean unbreakableShowInTooltip); + /** + * Indicates whether the item is fire resistant. + * + * @return {@code true} if fire resistance is enabled. + */ boolean isFireResistant(); + /** + * Enables or disables fire resistance on the item. + * + * @param fireResistant {@code true} to enable fire resistance. + */ void setFireResistant(Boolean fireResistant); + /** + * Indicates whether the tooltip should be hidden. + * + * @return {@code true} if the tooltip is hidden. + */ boolean isHideTooltip(); + /** + * Controls the visibility of the tooltip. + * + * @param hideTooltip {@code true} to hide the tooltip. + */ void setHideTooltip(Boolean hideTooltip); + /** + * Indicates whether additional tooltip information should be hidden. + * + * @return {@code true} if additional tooltip content is hidden. + */ boolean isHideAdditionalTooltip(); + /** + * Controls whether additional tooltip information is hidden. + * + * @param hideAdditionalTooltip {@code true} to hide additional tooltip content. + */ void setHideAdditionalTooltip(Boolean hideAdditionalTooltip); + /** + * Indicates whether the enchantment glint is enabled. + * + * @return {@code true} if the glint is enabled. + */ boolean isEnchantmentGlint(); + /** + * Enables or disables the enchantment glint. + * + * @param enchantmentGlint {@code true} to enable the glint. + */ void setEnchantmentGlint(Boolean enchantmentGlint); + /** + * Indicates whether enchantments should be visible in the tooltip. + * + * @return {@code true} if enchantments are visible. + */ boolean isEnchantmentShowInTooltip(); + /** + * Controls the visibility of enchantments in the tooltip. + * + * @param enchantmentShowInTooltip {@code true} to show enchantments. + */ void setEnchantmentShowInTooltip(Boolean enchantmentShowInTooltip); + /** + * Indicates whether attributes should be visible in the tooltip. + * + * @return {@code true} if attributes are visible. + */ boolean isAttributeShowInTooltip(); + /** + * Controls the visibility of attributes in the tooltip. + * + * @param attributeShowInTooltip {@code true} to show attributes. + */ void setAttributeShowInTooltip(Boolean attributeShowInTooltip); + /** + * Retrieves the trim configuration applied to armor items. + * + * @return the trim configuration, or {@code null} when none is set. + */ TrimConfiguration getTrimConfiguration(); + /** + * Sets the trim configuration applied to armor items. + * + * @param trimConfiguration the trim configuration to apply. + */ void setTrimConfiguration(TrimConfiguration trimConfiguration); + /** + * Retrieves the rarity assigned to this item stack. + * + * @return the item rarity value. + */ MenuItemRarity getItemRarity(); + /** + * Sets the rarity assigned to this item stack. + * + * @param itemRarity the rarity to apply. + */ void setItemRarity(MenuItemRarity itemRarity); + /** + * Indicates whether the lore should be centered when displayed. + * + * @return {@code true} if lore centering is enabled. + */ boolean isCenterLore(); + /** + * Enables or disables lore centering. + * + * @param centerLore {@code true} to center lore. + */ void setCenterLore(boolean centerLore); + /** + * Indicates whether the display name should be centered when displayed. + * + * @return {@code true} if name centering is enabled. + */ boolean isCenterName(); + /** + * Enables or disables display name centering. + * + * @param centerName {@code true} to center the name. + */ void setCenterName(boolean centerName); + /** + * Retrieves how lore should be merged when applied. + * + * @return the lore merge strategy. + */ LoreType getLoreType(); + /** + * Sets how lore should be merged when applied. + * + * @param loreType the lore merge strategy. + */ void setLoreType(LoreType loreType); + /** + * Parses the configured amount for the provided player. + * + * @param player the player context. + * @return the parsed amount. + */ int parseAmount(Player player); + /** + * Parses the configured amount for the provided player using placeholders. + * + * @param player the player context. + * @param placeholders placeholder values to apply. + * @return the parsed amount. + */ int parseAmount(Player player, Placeholders placeholders); + /** + * Parses the configured amount for the provided offline player using placeholders. + * + * @param offlinePlayer the offline player context. + * @param placeholders placeholder values to apply. + * @return the parsed amount. + */ int parseAmount(OfflinePlayer offlinePlayer, Placeholders placeholders); + /** + * Retrieves the item model identifier used for newer rendering APIs. + * + * @return the item model identifier. + */ String getItemModel(); + /** + * Sets the item model identifier used for newer rendering APIs. + * + * @param itemModel the item model identifier to set. + */ void setItemModel(String itemModel); + /** + * Sets the equipped model identifier used for wearable items. + * + * @param equippedModel the equipped model identifier to set. + */ void setEquippedModel(String equippedModel); + /** + * Retrieves the equipped model identifier used for wearable items. + * + * @return the equipped model identifier. + */ String getEquippedModel(); + /** + * Indicates whether default attributes should be cleared on the item. + * + * @return {@code true} if default attributes are cleared. + */ boolean isClearDefaultAttributes(); + /** + * Controls whether default attributes should be cleared on the item. + * + * @param clearDefaultAttributes {@code true} to clear default attributes. + */ void setClearDefaultAttributes(boolean clearDefaultAttributes); } diff --git a/src/main/java/fr/maxlego08/menu/ZMenuItemStack.java b/src/main/java/fr/maxlego08/menu/ZMenuItemStack.java index f3ff745a..f8e58cd4 100644 --- a/src/main/java/fr/maxlego08/menu/ZMenuItemStack.java +++ b/src/main/java/fr/maxlego08/menu/ZMenuItemStack.java @@ -131,66 +131,106 @@ public ItemStack build(Player player, boolean useCache) { @Override public ItemStack build(Player player, boolean useCache, Placeholders placeholders) { - // If we don’t need PlaceHolderApi, then we use the cache - if (!this.needPlaceholderAPI && this.cacheItemStack != null && Config.enableCacheItemStack && useCache) { + if (shouldUseCache(useCache)) { return this.cacheItemStack; } - ItemStack itemStack = null; - Material material = null; - - // If the material is null, then by default it will be stone, stone is a - // material present in all versions, so no conflict problem. if (this.material == null) { this.material = "STONE"; } - OfflinePlayer offlinePlayer = this.targetPlayer != null ? OfflinePlayerCache.get(papi(placeholders.parse(this.targetPlayer), player, false)) : null; - - String papiMaterial = papi(placeholders.parse(this.material), offlinePlayer == null ? player : offlinePlayer, true); + OfflinePlayer offlinePlayer = resolveOfflinePlayer(player, placeholders); int amount = this.parseAmount(offlinePlayer == null ? player : offlinePlayer, placeholders); - try { - material = getMaterial(Integer.parseInt(papiMaterial)); - } catch (Exception ignored) { + ItemStack itemStack = createItemStack(player, placeholders, offlinePlayer, amount); + if (itemStack == null) { + return null; } - if (material == null && papiMaterial != null) { - try { - material = Material.getMaterial(papiMaterial.toUpperCase()); - } catch (Exception ignored) { - } + applyItemMeta(player, placeholders, offlinePlayer, useCache, itemStack); + applyAttributes(itemStack); + + if (!needPlaceholderAPI && Config.enableCacheItemStack) { + this.cacheItemStack = itemStack; + } + + return itemStack; + } + + private boolean shouldUseCache(boolean useCache) { + return !this.needPlaceholderAPI && this.cacheItemStack != null && Config.enableCacheItemStack && useCache; + } + + private OfflinePlayer resolveOfflinePlayer(Player player, Placeholders placeholders) { + return this.targetPlayer != null ? OfflinePlayerCache.get(papi(placeholders.parse(this.targetPlayer), player, false)) : null; + } + + private ItemStack createItemStack(Player player, Placeholders placeholders, OfflinePlayer offlinePlayer, int amount) { + Material material = resolveMaterial(player, placeholders, offlinePlayer); + ItemStack itemStack = resolveCustomItem(player, placeholders, material); + + if (itemStack == null) { + itemStack = createDefaultItemStack(player, material, amount); } - if (material == null || material.equals(Material.AIR)) { + itemStack = applySpecialItemStack(player, amount, itemStack); + if (itemStack == null) { + return null; + } - if (papiMaterial.contains(":")) { + itemStack.setAmount(Math.max(1, amount)); + if (this.durability != 0) { + itemStack.setDurability((short) this.durability); + } - String[] values = papiMaterial.split(":", 2); + return itemStack; + } - if (values.length == 2) { + private Material resolveMaterial(Player player, Placeholders placeholders, OfflinePlayer offlinePlayer) { + String papiMaterial = papi(placeholders.parse(this.material), offlinePlayer == null ? player : offlinePlayer, true); + + try { + return getMaterial(Integer.parseInt(papiMaterial)); + } catch (Exception ignored) { + } + + try { + return papiMaterial != null ? Material.getMaterial(papiMaterial.toUpperCase()) : null; + } catch (Exception ignored) { + return null; + } + } + + private ItemStack resolveCustomItem(Player player, Placeholders placeholders, Material material) { + String papiMaterial = papi(placeholders.parse(this.material), player, true); + if (material != null && !material.equals(Material.AIR)) { + return null; + } - String key = values[0]; - String value = values[1]; + if (papiMaterial != null && papiMaterial.contains(":")) { + String[] values = papiMaterial.split(":", 2); + if (values.length == 2) { + String key = values[0]; + String value = values[1]; - Optional optional = this.inventoryManager.getMaterialLoader(key); - if (optional.isPresent()) { - MaterialLoader loader = optional.get(); - itemStack = loader.load(player, null, path, value); - } + Optional optional = this.inventoryManager.getMaterialLoader(key); + if (optional.isPresent()) { + MaterialLoader loader = optional.get(); + return loader.load(player, null, path, value); } } } + return null; + } - // Final check + private ItemStack createDefaultItemStack(Player player, Material material, int amount) { if (material == null) { material = Material.STONE; } + return data != null && !data.isEmpty() ? new ItemStack(material, amount, Byte.parseByte(this.papi(this.data, player, false))) : new ItemStack(material); + } - if (itemStack == null) { - itemStack = data != null && !data.isEmpty() ? new ItemStack(material, amount, Byte.parseByte(this.papi(this.data, player, false))) : new ItemStack(material); - } - + private ItemStack applySpecialItemStack(Player player, int amount, ItemStack itemStack) { if (this.url != null && !url.equalsIgnoreCase("null")) { String urlResult = this.papi(this.url, player, false); if (urlResult != null) { @@ -213,80 +253,90 @@ public ItemStack build(Player player, boolean useCache, Placeholders placeholder if (this.leatherArmor != null) { itemStack = leatherArmor.toItemStack(amount); } + return itemStack; + } - if (itemStack == null) { - return null; - } - - itemStack.setAmount(amount <= 0 ? 1 : amount); - - if (this.durability != 0) { - itemStack.setDurability((short) this.durability); + private void applyItemMeta(Player player, Placeholders placeholders, OfflinePlayer offlinePlayer, boolean useCache, ItemStack itemStack) { + ItemMeta itemMeta = itemStack.getItemMeta(); + if (itemMeta == null) { + return; } Material finalMaterial = itemStack.getType(); - ItemMeta itemMeta = itemStack.getItemMeta(); String locale = findPlayerLocale(player); FontImage fontImage = this.inventoryManager.getFontImage(); - if (itemMeta != null) { - this.applyDisplayNameLore(player, placeholders, itemMeta, offlinePlayer, locale, fontImage, useCache); - - Enchantments helperEnchantments = inventoryManager.getEnchantments(); - if (this.isGlowing) { - - Optional optional = helperEnchantments.getEnchantments("power"); - if (optional.isPresent()) { - MenuEnchantment menuEnchantment = optional.get(); - itemMeta.addEnchant(menuEnchantment.enchantment(), 1, true); - itemMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); - } - } + applyDisplayNameLore(player, placeholders, itemMeta, offlinePlayer, locale, fontImage, useCache); + applyGlowing(itemMeta); + applyCustomModelData(player, placeholders, offlinePlayer, itemMeta); + applyEnchantments(finalMaterial, itemMeta); + applyFlags(itemMeta); + applyVersionSpecificMeta(itemStack, itemMeta, player, placeholders); - try { + itemStack.setItemMeta(itemMeta); + } - int customModelData = Integer.parseInt(papi(placeholders.parse(this.modelID), offlinePlayer == null ? player : offlinePlayer, true)); - if (customModelData != 0) itemMeta.setCustomModelData(customModelData); - } catch (NumberFormatException ignored) { - } + private void applyGlowing(ItemMeta itemMeta) { + if (!this.isGlowing) { + return; + } - this.enchantments.forEach((enchantment, level) -> { - if (finalMaterial.equals(Material.ENCHANTED_BOOK)) { - ((EnchantmentStorageMeta) itemMeta).addStoredEnchant(enchantment, level, true); - } else { - itemMeta.addEnchant(enchantment, level, true); - } - }); + Enchantments helperEnchantments = inventoryManager.getEnchantments(); + helperEnchantments.getEnchantments("power").ifPresent(menuEnchantment -> { + itemMeta.addEnchant(menuEnchantment.enchantment(), 1, true); + itemMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + }); + } - for (ItemFlag flag : this.flags) { - if (flag != null) { - itemMeta.addItemFlags(flag); - } + private void applyCustomModelData(Player player, Placeholders placeholders, OfflinePlayer offlinePlayer, ItemMeta itemMeta) { + try { + int customModelData = Integer.parseInt(papi(placeholders.parse(this.modelID), offlinePlayer == null ? player : offlinePlayer, true)); + if (customModelData != 0) { + itemMeta.setCustomModelData(customModelData); } + } catch (NumberFormatException ignored) { + } + } - if (NmsVersion.getCurrentVersion().isNewItemStackAPI()) { - this.buildNewItemStackAPI(itemStack, itemMeta, player, placeholders); + private void applyEnchantments(Material finalMaterial, ItemMeta itemMeta) { + this.enchantments.forEach((enchantment, level) -> { + if (finalMaterial.equals(Material.ENCHANTED_BOOK)) { + ((EnchantmentStorageMeta) itemMeta).addStoredEnchant(enchantment, level, true); + } else { + itemMeta.addEnchant(enchantment, level, true); } + }); + } - if (NmsVersion.getCurrentVersion().isNewHeadApi()) { - this.buildTrimAPI(itemStack, itemMeta, player, placeholders); + private void applyFlags(ItemMeta itemMeta) { + for (ItemFlag flag : this.flags) { + if (flag != null) { + itemMeta.addItemFlags(flag); } + } + } - if (this.clearDefaultAttributes && attributes.isEmpty() && NmsVersion.getCurrentVersion().getVersion() >= NmsVersion.V_1_20_4.getVersion()) { - itemMeta.setAttributeModifiers(ArrayListMultimap.create()); - } + private void applyVersionSpecificMeta(ItemStack itemStack, ItemMeta itemMeta, Player player, Placeholders placeholders) { + if (NmsVersion.getCurrentVersion().isNewItemStackAPI()) { + this.buildNewItemStackAPI(itemStack, itemMeta, player, placeholders); + } - itemStack.setItemMeta(itemMeta); + if (NmsVersion.getCurrentVersion().isNewHeadApi()) { + this.buildTrimAPI(itemStack, itemMeta, player, placeholders); } - if (itemStack.getType() != Material.AIR) { - AttributeApplier attributeApplier = new AttributeApplier(attributes); - attributeApplier.apply(itemStack); + if (this.clearDefaultAttributes && attributes.isEmpty() && NmsVersion.getCurrentVersion().getVersion() >= NmsVersion.V_1_20_4.getVersion()) { + itemMeta.setAttributeModifiers(ArrayListMultimap.create()); } + } - if (!needPlaceholderAPI && Config.enableCacheItemStack) this.cacheItemStack = itemStack; + private void applyAttributes(ItemStack itemStack) { + if (itemStack.getType() == Material.AIR) { + return; + } - return itemStack; + AttributeApplier attributeApplier = new AttributeApplier(attributes); + attributeApplier.apply(itemStack); } /**