Skip to content

Added support for the new CustomModelDataComponent #195

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[versions]
# Compile only
spigot = "1.21.4-R0.1-SNAPSHOT"
spigot = "1.21.5-R0.1-SNAPSHOT"
vault = "1.7.1"
authlib = "1.5.25"
headdb = "1.3.2"
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/com/extendedclip/deluxemenus/DeluxeMenus.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ public void onLoad() {
return;
}

this.debug(DebugLevel.HIGHEST, Level.WARNING, "Could not setup a NMS hook for your server version!");
this.debug(
DebugLevel.HIGHEST,
Level.WARNING,
"Could not setup a NMS hook for your server version! The following Item options will not work: nbt_int, nbt_ints, nbt_string and nbt_strings."
);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
import com.extendedclip.deluxemenus.action.ClickActionTask;
import com.extendedclip.deluxemenus.action.ClickHandler;
import com.extendedclip.deluxemenus.hooks.ItemHook;
import com.extendedclip.deluxemenus.menu.options.LoreAppendMode;
import com.extendedclip.deluxemenus.menu.Menu;
import com.extendedclip.deluxemenus.menu.MenuHolder;
import com.extendedclip.deluxemenus.menu.MenuItem;
import com.extendedclip.deluxemenus.menu.options.CustomModelDataComponent;
import com.extendedclip.deluxemenus.menu.options.LoreAppendMode;
import com.extendedclip.deluxemenus.menu.options.MenuItemOptions;
import com.extendedclip.deluxemenus.menu.options.MenuOptions;
import com.extendedclip.deluxemenus.requirement.HasExpRequirement;
Expand Down Expand Up @@ -632,6 +633,13 @@ private Map<Integer, TreeMap<Integer, MenuItem>> loadMenuItems(FileConfiguration
.tooltipStyle(c.getString(currentPath + "tooltip_style", null))
.itemModel(c.getString(currentPath + "item_model", null));

if (c.contains(currentPath + "model_data_component") && c.isConfigurationSection(currentPath + "model_data_component")) {
final ConfigurationSection modelDataComponent = c.getConfigurationSection(currentPath + "model_data_component");
if (modelDataComponent != null) {
builder.customModelDataComponent(CustomModelDataComponent.builder().colors(modelDataComponent.getStringList("colors")).flags(modelDataComponent.getStringList("flags")).floats(modelDataComponent.getStringList("floats")).strings(modelDataComponent.getStringList("strings")));
}
}

// Lore Append Mode
if (c.contains(currentPath + "lore_append_mode")) {
String loreAppendMode = c.getString(currentPath + "lore_append_mode", "OVERRIDE").toUpperCase();
Expand Down Expand Up @@ -907,6 +915,18 @@ private RequirementList getRequirements(FileConfiguration c, String path) {
wrapper.setCustomData(c.getInt(rPath + ".modeldata", 0));
}

if (c.contains(rPath + ".model_data_component") && c.isConfigurationSection(rPath + ".model_data_component")) {
final ConfigurationSection modelDataComponent = c.getConfigurationSection(rPath + ".model_data_component");
if (modelDataComponent != null) {
wrapper.setCustomModelDataComponent(
CustomModelDataComponent.builder()
.colors(modelDataComponent.getStringList("colors"))
.flags(modelDataComponent.getStringList("flags"))
.floats(modelDataComponent.getStringList("floats"))
.strings(modelDataComponent.getStringList("strings")));
}
}

if (c.contains(rPath + ".name_contains")) {
wrapper.setNameContains(c.getBoolean(rPath + ".name_contains"));
} else {
Expand Down Expand Up @@ -968,7 +988,7 @@ private RequirementList getRequirements(FileConfiguration c, String path) {
plugin.debug(
DebugLevel.HIGHEST,
Level.WARNING,
"Has Permissions requirement at path: " + rPath + " has a minimum higher than the amount of permissions. Using "+permissions.size()+" instead"
"Has Permissions requirement at path: " + rPath + " has a minimum higher than the amount of permissions. Using " + permissions.size() + " instead"
);
minimum = permissions.size();
}
Expand Down Expand Up @@ -1252,9 +1272,14 @@ public void debug(String... messages) {
public File getMenuDirector() {
return menuDirectory;
}
public void addEnchantmentsOptionToBuilder(final FileConfiguration c, final String currentPath,
final String itemKey, final String menuName,
final MenuItemOptions.MenuItemOptionsBuilder builder) {

public void addEnchantmentsOptionToBuilder(
final FileConfiguration c,
final String currentPath,
final String itemKey,
final String menuName,
final MenuItemOptions.MenuItemOptionsBuilder builder
) {
if (!c.contains(currentPath + "enchantments")) {
return;
}
Expand All @@ -1267,9 +1292,7 @@ public void addEnchantmentsOptionToBuilder(final FileConfiguration c, final Stri
plugin.debug(
DebugLevel.HIGHEST,
Level.WARNING,
"Enchantment format '" + configEnchantment + "' is incorrect for item " + itemKey +
" in GUI " + menuName + "!",
"Correct format: - '<Enchantment name>;<level>"
"Enchantment format '" + configEnchantment + "' is incorrect for item " + itemKey + " in GUI " + menuName + "!", "Correct format: - '<Enchantment name>;<level>"
);
continue;
}
Expand All @@ -1279,9 +1302,7 @@ public void addEnchantmentsOptionToBuilder(final FileConfiguration c, final Stri
plugin.debug(
DebugLevel.HIGHEST,
Level.WARNING,
"Enchantment format '" + configEnchantment + "' is incorrect for item " + itemKey +
" in GUI " + menuName + "!",
"Correct format: - '<Enchantment name>;<level>"
"Enchantment format '" + configEnchantment + "' is incorrect for item " + itemKey + " in GUI " + menuName + "!", "Correct format: - '<Enchantment name>;<level>"
);
continue;
}
Expand All @@ -1291,8 +1312,7 @@ public void addEnchantmentsOptionToBuilder(final FileConfiguration c, final Stri
plugin.debug(
DebugLevel.HIGHEST,
Level.WARNING,
"Enchantment '" + parts[0].strip() + "' for item " + itemKey +
" in menu " + menuName + " is not a valid enchantment name!"
"Enchantment '" + parts[0].strip() + "' for item " + itemKey + " in menu " + menuName + " is not a valid enchantment name!"
);
}

Expand All @@ -1302,17 +1322,21 @@ public void addEnchantmentsOptionToBuilder(final FileConfiguration c, final Stri
plugin.debug(
DebugLevel.HIGHEST,
Level.WARNING,
"Enchantment level '" + parts[1].strip() + "' is incorrect for item " + itemKey +
" in menu " + menuName + "!"
"Enchantment level '" + parts[1].strip() + "' is incorrect for item " + itemKey + " in menu " + menuName + "!"
);
}
parsedEnchantments.put(enchantment, level);
}
builder.enchantments(parsedEnchantments);
}

public void addDamageOptionToBuilder(final FileConfiguration c, final String currentPath, final String itemKey,
final String menuName, final MenuItemOptions.MenuItemOptionsBuilder builder) {
public void addDamageOptionToBuilder(
final FileConfiguration c,
final String currentPath,
final String itemKey,
final String menuName,
final MenuItemOptions.MenuItemOptionsBuilder builder
) {
boolean damageOptionIsPresent = false;
String damageValue = null;

Expand Down
116 changes: 85 additions & 31 deletions src/main/java/com/extendedclip/deluxemenus/menu/MenuItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.extendedclip.deluxemenus.menu.options.HeadType;
import com.extendedclip.deluxemenus.menu.options.LoreAppendMode;
import com.extendedclip.deluxemenus.menu.options.MenuItemOptions;
import com.extendedclip.deluxemenus.menu.options.CustomModelDataComponent;
import com.extendedclip.deluxemenus.nbt.NbtProvider;
import com.extendedclip.deluxemenus.utils.DebugLevel;
import com.extendedclip.deluxemenus.utils.ItemUtils;
Expand Down Expand Up @@ -39,6 +40,7 @@
import org.bukkit.inventory.meta.trim.TrimPattern;
import org.bukkit.potion.PotionEffect;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.ArrayList;
Expand Down Expand Up @@ -158,13 +160,9 @@ public ItemStack getItemStack(@NotNull final MenuHolder holder) {

if (meta != null) {
if (this.options.rgb().isPresent()) {
final String rgbString = holder.setPlaceholdersAndArguments(this.options.rgb().get());
final String[] parts = rgbString.split(",");

try {
meta.setColor(Color.fromRGB(Integer.parseInt(parts[0].trim()), Integer.parseInt(parts[1].trim()),
Integer.parseInt(parts[2].trim())));
} catch (Exception ignored) {
final Color color = parseRGBColor(holder.setPlaceholdersAndArguments(this.options.rgb().get()));
if (color != null) {
meta.setColor(color);
}
}

Expand Down Expand Up @@ -224,14 +222,18 @@ public ItemStack getItemStack(@NotNull final MenuHolder holder) {
return itemStack;
}

if (this.options.customModelData().isPresent() && VersionHelper.IS_CUSTOM_MODEL_DATA) {
if (VersionHelper.IS_CUSTOM_MODEL_DATA && this.options.customModelData().isPresent()) {
try {
final int modelData = Integer.parseInt(holder.setPlaceholdersAndArguments(this.options.customModelData().get()));
itemMeta.setCustomModelData(modelData);
} catch (final Exception ignored) {
}
}

if (VersionHelper.IS_CUSTOM_MODEL_DATA_COMPONENT && this.options.customModelDataComponent().isPresent()) {
itemMeta.setCustomModelDataComponent(parseCustomModelDataComponent(this.options.customModelDataComponent().get(), itemMeta.getCustomModelDataComponent(), holder));
}

if (this.options.displayName().isPresent()) {
final String displayName = holder.setPlaceholdersAndArguments(this.options.displayName().get());
itemMeta.setDisplayName(StringUtils.color(displayName));
Expand Down Expand Up @@ -346,37 +348,33 @@ public ItemStack getItemStack(@NotNull final MenuHolder holder) {
}

if (itemMeta instanceof LeatherArmorMeta && this.options.rgb().isPresent()) {
final String rgbString = holder.setPlaceholdersAndArguments(this.options.rgb().get());
final String[] parts = rgbString.split(",");
final LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) itemMeta;

try {
leatherArmorMeta.setColor(Color.fromRGB(Integer.parseInt(parts[0].trim()), Integer.parseInt(parts[1].trim()),
Integer.parseInt(parts[2].trim())));
itemStack.setItemMeta(leatherArmorMeta);
} catch (final Exception exception) {
plugin.printStacktrace(
"Invalid rgb colors found for leather armor: " + parts[0].trim() + ", " + parts[1].trim() + ", " +
parts[2].trim(),
exception
final Color color = parseRGBColor(holder.setPlaceholdersAndArguments(this.options.rgb().get()));
if (color != null) {
leatherArmorMeta.setColor(color);
} else {
plugin.debug(
DebugLevel.HIGHEST,
Level.WARNING,
"Invalid rgb colors found for leather armor: " + this.options.rgb().get()
);
}

itemStack.setItemMeta(leatherArmorMeta);
} else if (itemMeta instanceof FireworkEffectMeta && this.options.rgb().isPresent()) {
final String rgbString = holder.setPlaceholdersAndArguments(this.options.rgb().get());
final String[] parts = rgbString.split(",");
final FireworkEffectMeta fireworkEffectMeta = (FireworkEffectMeta) itemMeta;

try {
fireworkEffectMeta.setEffect(FireworkEffect.builder().withColor(Color.fromRGB(Integer.parseInt(parts[0].trim()),
Integer.parseInt(parts[1].trim()), Integer.parseInt(parts[2].trim()))).build());
itemStack.setItemMeta(fireworkEffectMeta);
} catch (final Exception exception) {
plugin.printStacktrace(
"Invalid rgb colors found for firework or firework star: " + parts[0].trim() + ", "
+ parts[1].trim() + ", " + parts[2].trim(),
exception
final Color color = parseRGBColor(holder.setPlaceholdersAndArguments(this.options.rgb().get()));
if (color != null) {
fireworkEffectMeta.setEffect(FireworkEffect.builder().withColor(color).build());
} else {
plugin.debug(
DebugLevel.HIGHEST,
Level.WARNING,
"Invalid RGB color found for firework or firework star: " + this.options.rgb().get()
);
}
itemStack.setItemMeta(fireworkEffectMeta);
} else if (itemMeta instanceof EnchantmentStorageMeta && !this.options.enchantments().isEmpty()) {
final EnchantmentStorageMeta enchantmentStorageMeta = (EnchantmentStorageMeta) itemMeta;
for (final Map.Entry<Enchantment, Integer> entry : this.options.enchantments().entrySet()) {
Expand Down Expand Up @@ -547,6 +545,62 @@ protected List<String> getMenuItemLore(@NotNull final MenuHolder holder, @NotNul
.collect(Collectors.toList());
}

private @NotNull org.bukkit.inventory.meta.components.CustomModelDataComponent parseCustomModelDataComponent(
@NotNull final CustomModelDataComponent unparsedComponent,
@NotNull final org.bukkit.inventory.meta.components.CustomModelDataComponent component,
@NotNull final MenuHolder holder
) {
if (!unparsedComponent.colors().isEmpty()) {
final List<Color> colors = unparsedComponent.colors()
.stream()
.map(holder::setPlaceholdersAndArguments)
.map(this::parseRGBColor)
.filter(Objects::nonNull)
.collect(Collectors.toList());
component.setColors(colors);
}

if (!unparsedComponent.flags().isEmpty()) {
final List<Boolean> flags = unparsedComponent.flags()
.stream()
.map(holder::setPlaceholdersAndArguments)
.map(Boolean::parseBoolean)
.collect(Collectors.toList());
component.setFlags(flags);
}

if (!unparsedComponent.floats().isEmpty()) {
final List<Float> floats = unparsedComponent.floats()
.stream()
.map(holder::setPlaceholdersAndArguments)
.map(Float::parseFloat)
.collect(Collectors.toList());
component.setFloats(floats);
}

if (!unparsedComponent.strings().isEmpty()) {
final List<String> strings = unparsedComponent.strings()
.stream()
.map(holder::setPlaceholdersAndArguments)
.collect(Collectors.toList());
component.setStrings(strings);
}

return component;
}

private @Nullable Color parseRGBColor(@NotNull final String input) {
final Color color = StringUtils.parseRGBColor(input);
if (color == null) {
plugin.debug(
DebugLevel.HIGHEST,
Level.WARNING,
"Invalid RGB color found: " + input
);
}
return color;
}

public @NotNull MenuItemOptions options() {
return options;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.extendedclip.deluxemenus.menu.options;

import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

public class CustomModelDataComponent {
private List<String> colors = new ArrayList<>();
private List<String> flags = new ArrayList<>();
private List<String> floats = new ArrayList<>();
private List<String> strings = new ArrayList<>();

private CustomModelDataComponent() {
// Private constructor to force builder usage
}

@NotNull
public CustomModelDataComponent colors(@NotNull final List<@NotNull String> colors) {
this.colors = colors;
return this;
}

@NotNull
public List<@NotNull String> colors() {
return colors;
}

@NotNull
public CustomModelDataComponent flags(@NotNull final List<@NotNull String> flags) {
this.flags = flags;
return this;
}

@NotNull
public List<@NotNull String> flags() {
return flags;
}

@NotNull
public CustomModelDataComponent floats(@NotNull final List<@NotNull String> floats) {
this.floats = floats;
return this;
}

@NotNull
public List<@NotNull String> floats() {
return floats;
}

@NotNull
public CustomModelDataComponent strings(@NotNull final List<@NotNull String> strings) {
this.strings = strings;
return this;
}

@NotNull
public List<@NotNull String> strings() {
return strings;
}

public static @NotNull CustomModelDataComponent builder() {
return new CustomModelDataComponent();
}
}
Loading
Loading