From eb0fd4013d86a3eecf1ecf3abfe4f0f99126d3e9 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 17 Apr 2025 18:26:26 -0400 Subject: [PATCH 1/8] implement component cmd --- .../conditions/CondHasCustomModelData.java | 58 ++- .../expressions/ExprCustomModelData.java | 353 +++++++++++++++--- .../ExprItemWithCustomModelData.java | 102 +++-- .../conditions/CondHasCustomModelData.sk | 28 ++ .../expressions/ExprCustomModelData.sk | 68 +++- 5 files changed, 500 insertions(+), 109 deletions(-) create mode 100644 src/test/skript/tests/syntaxes/conditions/CondHasCustomModelData.sk diff --git a/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java b/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java index e349157635f..fbbc9e30f83 100644 --- a/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java +++ b/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java @@ -1,32 +1,64 @@ package ch.njol.skript.conditions; -import org.bukkit.inventory.meta.ItemMeta; - import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; import ch.njol.skript.conditions.base.PropertyCondition; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.RequiredPlugins; -import ch.njol.skript.doc.Since; +import ch.njol.skript.doc.*; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.components.CustomModelDataComponent; + +import java.util.Locale; @Name("Has Custom Model Data") @Description("Check if an item has a custom model data tag") @Examples("player's tool has custom model data") -@RequiredPlugins("1.14+") -@Since("2.5") +@Since("2.5, INSERT VERSION (expanded data types)") +@RequiredPlugins("1.21.4+ (floats/flags/strings/colours)") public class CondHasCustomModelData extends PropertyCondition { static { - if (Skript.methodExists(ItemMeta.class, "hasCustomModelData")) { + if (Skript.methodExists(ItemMeta.class, "getCustomModelDataComponent")) { + // new style + register(CondHasCustomModelData.class, PropertyType.HAVE, "[custom] model data [1:floats|2:flags|3:strings|4:colo[u]rs]", "itemtypes"); + } else { + // old style register(CondHasCustomModelData.class, PropertyType.HAVE, "[custom] model data", "itemtypes"); } } - + + private enum CMDType { + ANY, + FLOATS, + FLAGS, + STRINGS, + COLORS + } + + private CMDType dataType; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + dataType = CMDType.values()[parseResult.mark]; + return super.init(expressions, matchedPattern, isDelayed, parseResult); + } + @Override + @SuppressWarnings("UnstableApiUsage") public boolean check(ItemType item) { - return item.getItemMeta().hasCustomModelData(); + ItemMeta meta = item.getItemMeta(); + if (dataType == CMDType.ANY) + return meta.hasCustomModelData(); + CustomModelDataComponent component = meta.getCustomModelDataComponent(); + return switch (dataType) { + case FLOATS -> !component.getFloats().isEmpty(); + case FLAGS -> !component.getFlags().isEmpty(); + case STRINGS -> !component.getStrings().isEmpty(); + case COLORS -> !component.getColors().isEmpty(); + case ANY -> throw new IllegalStateException("Wrong path for CMDType.ANY."); + }; } @Override @@ -36,7 +68,7 @@ protected PropertyType getPropertyType() { @Override protected String getPropertyName() { - return "custom model data"; + return "custom model data" + (dataType != CMDType.ANY ? " " + dataType.name().toLowerCase(Locale.ENGLISH) : ""); } } diff --git a/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java b/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java index 9b04e619f8c..9700a05bdd0 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java +++ b/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java @@ -1,88 +1,321 @@ package ch.njol.skript.expressions; -import org.bukkit.event.Event; -import org.bukkit.inventory.meta.ItemMeta; -import org.jetbrains.annotations.Nullable; - import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; -import ch.njol.skript.classes.Changer; +import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Example; import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; -import ch.njol.skript.expressions.base.SimplePropertyExpression; -import ch.njol.util.coll.CollectionUtils; +import ch.njol.skript.expressions.base.PropertyExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.util.Color; +import ch.njol.skript.util.ColorRGB; +import ch.njol.skript.util.Utils; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.components.CustomModelDataComponent; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; @Name("Custom Model Data") -@Description("Get/set the CustomModelData tag for an item. (Value is an integer between 0 and 99999999)") -@Examples({"set custom model data of player's tool to 3", - "set {_model} to custom model data of player's tool"}) -@RequiredPlugins("1.14+") -@Since("2.5") -public class ExprCustomModelData extends SimplePropertyExpression { - +@Description({ + "Get/set the custom model data of an item. Using just `custom model data` will return an integer. Items without model data will return 0.", + "In 1.21.4+, though, custom model data is extended to include a list of numbers (floats), a list of booleans (flags), a list of strings, and a list of colours. " + + "Accessing and modifying these lists can be done type-by-type, or all at once with `complete custom model data`. " + + "This is the more accurate and recommended method of using custom model data." +}) +@Example(""" + set custom model data of player's tool to 3 + set {_model} to custom model data of player's tool + """) +@Example(""" + set custom model data colours of {_flag} to red, white, and blue + add 10.5 to the model data floats of {_flag} + """) +@Example(""" + set the full custom model data of {_item} to 10, "sword", and rgb(100, 200, 30) + """) +@Since({"2.5","INSERT VERSION (component support)"}) +public class ExprCustomModelData extends PropertyExpression { + + private static final boolean USE_NEW_CMD = Skript.classExists("org.bukkit.inventory.meta.components.CustomModelDataComponent"); + static { - if (Skript.methodExists(ItemMeta.class, "hasCustomModelData")) { - register(ExprCustomModelData.class, Long.class, "[custom] model data", "itemtypes"); + if (USE_NEW_CMD) { + List patterns = new ArrayList<>(); + patterns.addAll(Arrays.asList(PropertyExpression.getPatterns("[custom] model data", "itemtypes"))); + patterns.addAll(Arrays.asList(PropertyExpression.getPatterns("[custom] model data (1:floats|2:flags|3:strings|4:colo[u]rs)", "itemtype"))); + patterns.addAll(Arrays.asList(PropertyExpression.getPatterns("(5:(complete|full)) [custom] model data", "itemtype"))); + Skript.registerExpression(ExprCustomModelData.class, Object.class, ExpressionType.PROPERTY, patterns.toArray(String[]::new)); + } else { + register(ExprCustomModelData.class, Object.class, "[custom] model data", "itemtypes"); } } - - @Override - public Long convert(ItemType item) { - ItemMeta meta = item.getItemMeta(); - assert meta != null; - if (meta.hasCustomModelData()) - return (long) meta.getCustomModelData(); - else - return 0L; + + private enum CMDType { + SINGLE_INT(Integer.class), + FLOATS(Float.class), + FLAGS(Boolean.class), + STRINGS(String.class), + COLORS(Color.class), + ALL(Float.class, Boolean.class, String.class, Color.class); + + private final Class supertype; + private final Class[] types; + + CMDType(Class... returns) { + this.types = returns; + this.supertype = Utils.getSuperType(returns); + } } - + + private CMDType dataType; + @Override - public Class getReturnType() { - return Long.class; + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + dataType = CMDType.values()[parseResult.mark]; + //noinspection unchecked + setExpr((Expression) expressions[0]); + return true; } - + + @Override - public Class[] acceptChange(Changer.ChangeMode mode) { - return CollectionUtils.array(Number.class); + @SuppressWarnings("UnstableApiUsage") + protected Object[] get(Event event, ItemType[] source) { + for (ItemType from : source) { + ItemMeta meta = from.getItemMeta(); + if (dataType == CMDType.SINGLE_INT) { + if (meta.hasCustomModelData() && (!USE_NEW_CMD || !meta.getCustomModelDataComponent().getFloats().isEmpty())) + return new Integer[]{meta.getCustomModelData()}; + return new Integer[]{0}; + } + + CustomModelDataComponent component = meta.getCustomModelDataComponent(); + return switch (dataType) { + case SINGLE_INT -> throw new IllegalStateException("unreachable state for SINGLE_INT!"); + case FLOATS -> component.getFloats().toArray(Float[]::new); + case FLAGS -> component.getFlags().toArray(Boolean[]::new); + case STRINGS -> component.getStrings().toArray(String[]::new); + case COLORS -> + component.getColors().stream().map(ColorRGB::fromBukkitColor).toList().toArray(ColorRGB[]::new); + case ALL -> { + List data = new ArrayList<>(); + data.addAll(component.getFloats()); + data.addAll(component.getFlags()); + data.addAll(component.getStrings()); + data.addAll(component.getColors().stream().map(ColorRGB::fromBukkitColor).toList()); + yield data.toArray(Object[]::new); + } + }; + } + throw new IllegalStateException("Unreachable state! Either source was an empty array or something horrible happened."); } - + @Override - protected String getPropertyName() { - return "custom model data"; + public Class @Nullable [] acceptChange(ChangeMode mode) { + return switch (mode) { + case ADD, REMOVE, REMOVE_ALL, SET, DELETE, RESET -> { + // convert to array types to allow plural changes. + Class[] arrayClasses = new Class[dataType.types.length]; + for (int i = 0; i < dataType.types.length; i++) { + arrayClasses[i] = dataType.types[i].arrayType(); + } + yield arrayClasses; + } + default -> null; + }; } - + @Override - public void change(Event e, @Nullable Object[] delta, Changer.ChangeMode mode) { - long data = delta == null ? 0 : ((Number) delta[0]).intValue(); - if (data > 99999999 || data < 0) data = 0; - for (ItemType item : getExpr().getArray(e)) { - long oldData = 0; + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + for (ItemType item : getExpr().getArray(event)) { ItemMeta meta = item.getItemMeta(); - if (meta.hasCustomModelData()) - oldData = meta.getCustomModelData(); - switch (mode) { - case ADD: - data = oldData + data; - break; - case REMOVE: - data = oldData - data; - break; - case DELETE: - case RESET: - case REMOVE_ALL: - data = 0; + switch (dataType) { + case SINGLE_INT -> { + long deltaValue = delta == null ? 0 : ((Number) delta[0]).intValue(); + changeOld(meta, mode, deltaValue); + } + case FLAGS, COLORS, STRINGS, FLOATS -> changeSingleType(meta, mode, delta); + case ALL -> changeAll(meta, mode, delta); } - meta.setCustomModelData((int) data); item.setItemMeta(meta); } } - + + /** + * Changes the custom model data of an ItemMeta using <=1.21.3 methods. + * @param meta The meta to change + * @param mode The mode to change with + * @param delta The delta value + */ + private void changeOld(ItemMeta meta, ChangeMode mode, long delta) { + // shortcut for delete/reset + if (mode == ChangeMode.DELETE || mode == ChangeMode.RESET) { + meta.setCustomModelData(null); + return; + } + long oldData = 0; + if (meta.hasCustomModelData()) { + //noinspection UnstableApiUsage + if (!USE_NEW_CMD || !meta.getCustomModelDataComponent().getFloats().isEmpty()) + oldData = meta.getCustomModelData(); + } + + switch (mode) { + case REMOVE, REMOVE_ALL: + delta = -delta; + case ADD: + delta = oldData + delta; + meta.setCustomModelData((int) delta); + break; + case SET: + meta.setCustomModelData((int) delta); + break; + } + } + + /** + * Changes a single type of custom model data of an ItemMeta. + * @param meta The meta to change + * @param mode The mode to change with + * @param delta The values to add/remove/set + */ + @SuppressWarnings("UnstableApiUsage") + private void changeSingleType(ItemMeta meta, ChangeMode mode, T @Nullable [] delta) { + if (delta == null && mode != ChangeMode.DELETE && mode != ChangeMode.RESET) + return; + + CustomModelDataComponent component = meta.getCustomModelDataComponent(); + // create the list from existing data + // we can be sure the values are of the proper types + //noinspection unchecked + List data = new ArrayList<>((List) switch (dataType) { + case FLOATS -> component.getFloats(); + case FLAGS -> component.getFlags(); + case STRINGS -> component.getStrings(); + case COLORS -> component.getColors().stream().map(ColorRGB::fromBukkitColor).toList(); + default -> throw new IllegalStateException("Wrong changemode for changeSingleType"); + }); + + // edit the list + switch (mode) { + case REMOVE -> data.removeAll(Arrays.asList(delta)); + case ADD -> data.addAll(Arrays.asList(delta)); + case SET -> data = Arrays.asList(delta); + case RESET, DELETE -> data.clear(); + } + + // edit the component + switch (dataType) { + case FLOATS -> //noinspection unchecked + component.setFloats((List) data); + case FLAGS -> //noinspection unchecked + component.setFlags((List) data); + case STRINGS -> //noinspection unchecked + component.setStrings((List) data); + case COLORS -> component.setColors(data.stream().map(colorRGB -> ((ColorRGB) colorRGB).asBukkitColor()).toList()); + } + meta.setCustomModelDataComponent(component); + } + + /** + * Changes all the types of custom model data of an ItemMeta. + * @param meta The meta to change + * @param mode The mode to change with + * @param delta The values to add/remove/set + */ + @SuppressWarnings("UnstableApiUsage") + private void changeAll(ItemMeta meta, ChangeMode mode, Object @Nullable [] delta) { + // shortcut for delete/reset + if (mode == ChangeMode.DELETE || mode == ChangeMode.RESET) { + meta.setCustomModelDataComponent(null); + return; + } + + if (delta == null) + return; + + CustomModelDataComponent component = meta.getCustomModelDataComponent(); + List floats = new ArrayList<>(component.getFloats()); + List flags = new ArrayList<>(component.getFlags()); + List strings = new ArrayList<>(component.getStrings()); + List colors = new ArrayList<>(component.getColors().stream().map(ColorRGB::fromBukkitColor).toList()); + + // sort delta into the necessary lists + switch (mode) { + case REMOVE: + for (Object deltaValue : delta) { + if (deltaValue instanceof Float) { + floats.remove(deltaValue); + } else if (deltaValue instanceof Boolean) { + flags.remove(deltaValue); + } else if (deltaValue instanceof String) { + strings.remove(deltaValue); + } else if (deltaValue instanceof Color) { + colors.remove(deltaValue); + } + } + break; + case SET: + floats.clear(); + flags.clear(); + strings.clear(); + colors.clear(); + case ADD: + for (Object deltaValue : delta) { + if (deltaValue instanceof Float aFloat) { + floats.addLast(aFloat); + } else if (deltaValue instanceof Boolean aBoolean) { + flags.addLast(aBoolean); + } else if (deltaValue instanceof String string) { + strings.addLast(string); + } else if (deltaValue instanceof Color color) { + colors.addLast(color); + } + } + break; + } + // reconstruct the component + component.setFloats(floats); + component.setFlags(flags); + component.setStrings(strings); + component.setColors(colors.stream().map(Color::asBukkitColor).toList()); + meta.setCustomModelDataComponent(component); + } + + @Override + public boolean isSingle() { + return dataType == CMDType.SINGLE_INT && getExpr().isSingle(); + } + @Override - public String toString(@Nullable Event e, boolean d) { - return "custom model data of " + getExpr().toString(e, d); + public Class getReturnType() { + return dataType.supertype; } - + + @Override + public Class[] possibleReturnTypes() { + return dataType.types; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return switch (dataType) { + case ALL -> "complete custom model data"; + case FLOATS -> "custom model data floats"; + case FLAGS -> "custom model data flags"; + case STRINGS -> "custom model data strings"; + case COLORS -> "custom model data colors"; + case SINGLE_INT -> "custom model data"; + } + " of " + getExpr().toString(event, debug); + } + } diff --git a/src/main/java/ch/njol/skript/expressions/ExprItemWithCustomModelData.java b/src/main/java/ch/njol/skript/expressions/ExprItemWithCustomModelData.java index b2818ebb807..de5fad641dc 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprItemWithCustomModelData.java +++ b/src/main/java/ch/njol/skript/expressions/ExprItemWithCustomModelData.java @@ -1,58 +1,98 @@ package ch.njol.skript.expressions; -import org.bukkit.event.Event; -import org.bukkit.inventory.meta.ItemMeta; -import org.jetbrains.annotations.Nullable; - import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.RequiredPlugins; -import ch.njol.skript.doc.Since; +import ch.njol.skript.doc.*; import ch.njol.skript.expressions.base.PropertyExpression; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.util.Color; import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; -@Name("Item with CustomModelData") -@Description("Get an item with a CustomModelData tag. (Value is an integer between 0 and 99999999)") -@Examples({"give player a diamond sword with custom model data 2", - "set slot 1 of inventory of player to wooden hoe with custom model data 357"}) -@RequiredPlugins("1.14+") -@Since("2.5") +@Name("Item with Custom Model Data") +@Description("Get an item with custom model data.") +@Example("give player a diamond sword with custom model data 2") +@Example("set slot 1 of inventory of player to wooden hoe with custom model data 357") +@Example("give player a diamond hoe with custom model data 2, true, true, \"scythe\", and rgb(0,0,100)") +@RequiredPlugins("1.21.4+ (boolean/string/color support)") +@Since({"2.5", "INSERT VERSION (boolean/string/color support)"}) public class ExprItemWithCustomModelData extends PropertyExpression { - + + private static final boolean USE_NEW_CMD = Skript.classExists("org.bukkit.inventory.meta.components.CustomModelDataComponent"); + static { - if (Skript.methodExists(ItemMeta.class, "hasCustomModelData")) { + if (USE_NEW_CMD) { + Skript.registerExpression(ExprItemWithCustomModelData.class, ItemType.class, ExpressionType.PROPERTY, + "%itemtype% with [custom] model data %numbers/booleans/strings/colors%"); + } else { Skript.registerExpression(ExprItemWithCustomModelData.class, ItemType.class, ExpressionType.PROPERTY, "%itemtype% with [custom] model data %number%"); } } @SuppressWarnings("null") - private Expression data; + private Expression data; @SuppressWarnings({"unchecked", "null"}) @Override - public boolean init(Expression[] exprs, int i, Kleenean kleenean, ParseResult parseResult) { + public boolean init(Expression[] exprs, int matchedPattern, Kleenean kleenean, ParseResult parseResult) { setExpr((Expression) exprs[0]); - data = (Expression) exprs[1]; + data = exprs[1]; return true; } - + @Override - protected ItemType[] get(Event e, ItemType[] source) { - Number data = this.data.getSingle(e); - if (data == null) + @SuppressWarnings("UnstableApiUsage") + protected ItemType[] get(Event event, ItemType[] source) { + Object[] data = this.data.getArray(event); + if (data.length == 0) return source; - return get(source.clone(), item -> { - ItemMeta meta = item.getItemMeta(); - meta.setCustomModelData(data.intValue()); - item.setItemMeta(meta); - return item; + if (!USE_NEW_CMD) { + return get(source, item -> { + ItemType clone = item.clone(); + ItemMeta meta = clone.getItemMeta(); + meta.setCustomModelData(((Number) data[0]).intValue()); + clone.setItemMeta(meta); + return clone; + }); + } + //create lists + List floats = new ArrayList<>(); + List flags = new ArrayList<>(); + List strings = new ArrayList<>(); + List colors = new ArrayList<>(); + // populate lists + //noinspection DuplicatedCode + for (Object dataValue : data) { + if (dataValue instanceof Number number) { + floats.addLast(number.floatValue()); + } else if (dataValue instanceof Boolean aBoolean) { + flags.addLast(aBoolean); + } else if (dataValue instanceof String string) { + strings.addLast(string); + } else if (dataValue instanceof Color color) { + colors.addLast(color); + } + } + // edit items + return get(source, item -> { + ItemType clone = item.clone(); + ItemMeta meta = clone.getItemMeta(); + var component = meta.getCustomModelDataComponent(); + component.setFloats(floats); + component.setFlags(flags); + component.setStrings(strings); + component.setColors(colors.stream().map(Color::asBukkitColor).toList()); + meta.setCustomModelDataComponent(component); + clone.setItemMeta(meta); + return clone; }); } @@ -62,8 +102,8 @@ public Class getReturnType() { } @Override - public String toString(@Nullable Event e, boolean d) { - return getExpr().toString(e, d) + " with custom model data " + data.toString(e, d); + public String toString(@Nullable Event event, boolean debug) { + return getExpr().toString(event, debug) + " with custom model data " + data.toString(event, debug); } } diff --git a/src/test/skript/tests/syntaxes/conditions/CondHasCustomModelData.sk b/src/test/skript/tests/syntaxes/conditions/CondHasCustomModelData.sk new file mode 100644 index 00000000000..a3c1353f86e --- /dev/null +++ b/src/test/skript/tests/syntaxes/conditions/CondHasCustomModelData.sk @@ -0,0 +1,28 @@ +test "old custom model data": + set {_item} to a diamond sword with model data 1 + assert {_item} has custom model data with "false negative for model data" + clear custom model data of {_item} + assert {_item} doesn't have custom model data with "false positive for model data" + +test "new custom model data" when running minecraft "1.21.4": + set {_item} to a diamond sword + + set full model data of {_item} to 1 + assert {_item} has custom model data with "false negative for float model data" + clear full model data of {_item} + assert {_item} doesn't have custom model data with "false positive for float model data" + + set full model data of {_item} to "1" + assert {_item} has custom model data with "false negative for string model data" + clear full model data of {_item} + assert {_item} doesn't have custom model data with "false positive for string model data" + + set full model data of {_item} to true + assert {_item} has custom model data with "false negative for boolean model data" + clear full model data of {_item} + assert {_item} doesn't have custom model data with "false positive for boolean model data" + + set full model data of {_item} to rgb(1,1,1) + assert {_item} has custom model data with "false negative for color model data" + clear full model data of {_item} + assert {_item} doesn't have custom model data with "false positive for color model data" diff --git a/src/test/skript/tests/syntaxes/expressions/ExprCustomModelData.sk b/src/test/skript/tests/syntaxes/expressions/ExprCustomModelData.sk index f1e24481f5f..f333c623b59 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprCustomModelData.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprCustomModelData.sk @@ -1,7 +1,65 @@ -test "custom model data expressions/condition": +test "old custom model data expression": set {_item} to a diamond sword with custom model data 456 assert {_item} has custom model data with "{_item} does not have custom model data" - if {_item} has custom model data: - assert custom model data of {_item} = 456 with "{_item}'s custom model data != 456: %custom model data of {_item}%" - set custom model data of {_item} to 987 - assert custom model data of {_item} = 987 with "{_item}'s custom model data != 987: %custom model data of {_item}%" + assert custom model data of {_item} = 456 with "{_item}'s custom model data != 456: %custom model data of {_item}%" + set custom model data of {_item} to 987 + assert custom model data of {_item} = 987 with "{_item}'s custom model data != 987: %custom model data of {_item}%" + +test "new custom model data expression" when running minecraft "1.21.4": + set {_item} to a diamond sword with custom model data 456 and 52 + + assert model data of {_item} is 456 with "wrong model data" + assert full model data of {_item} is 456 and 52 with "wrong full model data" + assert model data floats of {_item} is 456 and 52 with "wrong model data floats" + assert model data flags of {_item} is not set with "wrong model data flags" + assert model data strings of {_item} is not set with "wrong model data strings" + assert model data colours of {_item} is not set with "wrong model data colours" + + set model data strings of {_item} to "hello" and "world" + assert model data of {_item} is 456 with "wrong model data" + broadcast full model data of {_item} + assert full model data of {_item} is 456, 52, "hello", and "world" with "wrong full model data" + assert model data floats of {_item} is 456 and 52 with "wrong model data floats" + assert model data flags of {_item} is not set with "wrong model data flags" + assert model data strings of {_item} is "hello" and "world" with "wrong model data strings" + assert model data colours of {_item} is not set with "wrong model data colours" + + add true to model data flags of {_item} + assert model data of {_item} is 456 with "wrong model data" + assert full model data of {_item} is 456, 52, true, "hello" and "world" with "wrong full model data" + assert model data floats of {_item} is 456 and 52 with "wrong model data floats" + assert model data flags of {_item} is true with "wrong model data flags" + assert model data strings of {_item} is "hello" and "world" with "wrong model data strings" + assert model data colours of {_item} is not set with "wrong model data colours" + + remove "hello" from model data strings of {_item} + assert model data of {_item} is 456 with "wrong model data" + assert full model data of {_item} is 456, 52, true, and "world" with "wrong full model data" + assert model data floats of {_item} is 456 and 52 with "wrong model data floats" + assert model data flags of {_item} is true with "wrong model data flags" + assert model data strings of {_item} is "world" with "wrong model data strings" + assert model data colours of {_item} is not set with "wrong model data colours" + + clear model data strings of {_item} + assert model data of {_item} is 456 with "wrong model data" + assert full model data of {_item} is 456, 52, and true with "wrong full model data" + assert model data floats of {_item} is 456 and 52 with "wrong model data floats" + assert model data flags of {_item} is true with "wrong model data flags" + assert model data strings of {_item} is not set with "wrong model data strings" + assert model data colours of {_item} is not set with "wrong model data colours" + + set full model data of {_item} to true, false, 1.0, -5.4, "yes", no, rgb(1,0,1), and white + assert model data of {_item} is 1 with "wrong model data" + assert full model data of {_item} is 1.0, -5.4, true, false, false, "yes", rgb(1,0,1), and white with "wrong full model data" + assert model data floats of {_item} is 1.0 and -5.4 with "wrong model data floats" + assert model data flags of {_item} is true, false and false with "wrong model data flags" + assert model data strings of {_item} is "yes" with "wrong model data strings" + assert model data colours of {_item} is rgb(1,0,1) and white with "wrong model data colours" + + reset full model data of {_item} + assert model data of {_item} is 0 with "wrong model data" + assert full model data of {_item} is not set with "wrong full model data" + assert model data floats of {_item} is not set with "wrong model data floats" + assert model data flags of {_item} is not set with "wrong model data flags" + assert model data strings of {_item} is not set with "wrong model data strings" + assert model data colours of {_item} is not set with "wrong model data colours" From 7b08ccd0164fb586ceffbd959ec80269efc9c1e2 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 17 Apr 2025 18:39:20 -0400 Subject: [PATCH 2/8] Update ExprCustomModelData.java --- .../ch/njol/skript/expressions/ExprCustomModelData.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java b/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java index 9700a05bdd0..aa3f9e3daba 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java +++ b/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java @@ -3,10 +3,7 @@ import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; import ch.njol.skript.classes.Changer.ChangeMode; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Example; -import ch.njol.skript.doc.Name; -import ch.njol.skript.doc.Since; +import ch.njol.skript.doc.*; import ch.njol.skript.expressions.base.PropertyExpression; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; @@ -42,7 +39,8 @@ @Example(""" set the full custom model data of {_item} to 10, "sword", and rgb(100, 200, 30) """) -@Since({"2.5","INSERT VERSION (component support)"}) +@RequiredPlugins("1.21.4+ (floats/flags/strings/colours/full model data)") +@Since({"2.5","INSERT VERSION (floats/flags/strings/colours/full model data)"}) public class ExprCustomModelData extends PropertyExpression { private static final boolean USE_NEW_CMD = Skript.classExists("org.bukkit.inventory.meta.components.CustomModelDataComponent"); From 800c2aca9edd35938dee6333e6e58f71ed04a289 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:32:05 -0400 Subject: [PATCH 3/8] Apply suggestions from code review Co-authored-by: Efnilite <35348263+Efnilite@users.noreply.github.com> --- .../ch/njol/skript/conditions/CondHasCustomModelData.java | 2 +- .../java/ch/njol/skript/expressions/ExprCustomModelData.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java b/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java index fbbc9e30f83..3c91bb3762a 100644 --- a/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java +++ b/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java @@ -14,7 +14,7 @@ @Name("Has Custom Model Data") @Description("Check if an item has a custom model data tag") -@Examples("player's tool has custom model data") +@Example("player's tool has custom model data") @Since("2.5, INSERT VERSION (expanded data types)") @RequiredPlugins("1.21.4+ (floats/flags/strings/colours)") public class CondHasCustomModelData extends PropertyCondition { diff --git a/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java b/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java index aa3f9e3daba..f9f9a6abfbb 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java +++ b/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java @@ -24,7 +24,7 @@ @Name("Custom Model Data") @Description({ "Get/set the custom model data of an item. Using just `custom model data` will return an integer. Items without model data will return 0.", - "In 1.21.4+, though, custom model data is extended to include a list of numbers (floats), a list of booleans (flags), a list of strings, and a list of colours. " + + "Since 1.21.4, custom model data instead consists of a list of numbers (floats), a list of booleans (flags), a list of strings, and a list of colours. " + "Accessing and modifying these lists can be done type-by-type, or all at once with `complete custom model data`. " + "This is the more accurate and recommended method of using custom model data." }) @@ -40,7 +40,7 @@ set the full custom model data of {_item} to 10, "sword", and rgb(100, 200, 30) """) @RequiredPlugins("1.21.4+ (floats/flags/strings/colours/full model data)") -@Since({"2.5","INSERT VERSION (floats/flags/strings/colours/full model data)"}) +@Since({"2.5", "INSERT VERSION (floats/flags/strings/colours/full model data)"}) public class ExprCustomModelData extends PropertyExpression { private static final boolean USE_NEW_CMD = Skript.classExists("org.bukkit.inventory.meta.components.CustomModelDataComponent"); From 8fd0b329ec8defe07dfabbd3cf8ed60f64288f0a Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Tue, 6 May 2025 14:07:10 -0700 Subject: [PATCH 4/8] Apply suggestions from code review Co-authored-by: Efnilite <35348263+Efnilite@users.noreply.github.com> --- .../java/ch/njol/skript/conditions/CondHasCustomModelData.java | 2 +- .../java/ch/njol/skript/expressions/ExprCustomModelData.java | 2 +- .../ch/njol/skript/expressions/ExprItemWithCustomModelData.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java b/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java index 3c91bb3762a..b32b9c2f503 100644 --- a/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java +++ b/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java @@ -16,7 +16,7 @@ @Description("Check if an item has a custom model data tag") @Example("player's tool has custom model data") @Since("2.5, INSERT VERSION (expanded data types)") -@RequiredPlugins("1.21.4+ (floats/flags/strings/colours)") +@RequiredPlugins("Minecraft 1.21.4+ (floats/flags/strings/colours)") public class CondHasCustomModelData extends PropertyCondition { static { diff --git a/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java b/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java index f9f9a6abfbb..3e66f9ddef3 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java +++ b/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java @@ -39,7 +39,7 @@ @Example(""" set the full custom model data of {_item} to 10, "sword", and rgb(100, 200, 30) """) -@RequiredPlugins("1.21.4+ (floats/flags/strings/colours/full model data)") +@RequiredPlugins("Minecraft 1.21.4+ (floats/flags/strings/colours/full model data)") @Since({"2.5", "INSERT VERSION (floats/flags/strings/colours/full model data)"}) public class ExprCustomModelData extends PropertyExpression { diff --git a/src/main/java/ch/njol/skript/expressions/ExprItemWithCustomModelData.java b/src/main/java/ch/njol/skript/expressions/ExprItemWithCustomModelData.java index de5fad641dc..271c3d3ee4b 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprItemWithCustomModelData.java +++ b/src/main/java/ch/njol/skript/expressions/ExprItemWithCustomModelData.java @@ -21,7 +21,7 @@ @Example("give player a diamond sword with custom model data 2") @Example("set slot 1 of inventory of player to wooden hoe with custom model data 357") @Example("give player a diamond hoe with custom model data 2, true, true, \"scythe\", and rgb(0,0,100)") -@RequiredPlugins("1.21.4+ (boolean/string/color support)") +@RequiredPlugins("Minecraft 1.21.4+ (boolean/string/color support)") @Since({"2.5", "INSERT VERSION (boolean/string/color support)"}) public class ExprItemWithCustomModelData extends PropertyExpression { From 6d7721a7a20a76efdd4fdb5c72f7c8eaa95beace Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Tue, 13 May 2025 16:56:12 -0700 Subject: [PATCH 5/8] Fix checks for 1.21.5+ --- .../ch/njol/skript/conditions/CondHasCustomModelData.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java b/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java index b32b9c2f503..d188aaf9f7a 100644 --- a/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java +++ b/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java @@ -18,8 +18,12 @@ @Since("2.5, INSERT VERSION (expanded data types)") @RequiredPlugins("Minecraft 1.21.4+ (floats/flags/strings/colours)") public class CondHasCustomModelData extends PropertyCondition { - + + // 1.21.5+ + private static final boolean HAS_HAS_COMPONENT = Skript.methodExists(ItemMeta.class, "hasCustomModelDataComponent"); + static { + // 1.21.4+ if (Skript.methodExists(ItemMeta.class, "getCustomModelDataComponent")) { // new style register(CondHasCustomModelData.class, PropertyType.HAVE, "[custom] model data [1:floats|2:flags|3:strings|4:colo[u]rs]", "itemtypes"); @@ -50,7 +54,7 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is public boolean check(ItemType item) { ItemMeta meta = item.getItemMeta(); if (dataType == CMDType.ANY) - return meta.hasCustomModelData(); + return HAS_HAS_COMPONENT ? meta.hasCustomModelDataComponent() : meta.hasCustomModelData(); CustomModelDataComponent component = meta.getCustomModelDataComponent(); return switch (dataType) { case FLOATS -> !component.getFloats().isEmpty(); From d69db197774508c02ad675f3ff96ae8baa1b3197 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Tue, 3 Jun 2025 19:20:32 -0700 Subject: [PATCH 6/8] Update src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java Co-authored-by: cheeezburga <47320303+cheeezburga@users.noreply.github.com> --- .../java/ch/njol/skript/expressions/ExprCustomModelData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java b/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java index 3e66f9ddef3..d0fc646bd41 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java +++ b/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java @@ -98,7 +98,7 @@ protected Object[] get(Event event, ItemType[] source) { CustomModelDataComponent component = meta.getCustomModelDataComponent(); return switch (dataType) { - case SINGLE_INT -> throw new IllegalStateException("unreachable state for SINGLE_INT!"); + case SINGLE_INT -> throw new IllegalStateException("Unreachable state for SINGLE_INT!"); case FLOATS -> component.getFloats().toArray(Float[]::new); case FLAGS -> component.getFlags().toArray(Boolean[]::new); case STRINGS -> component.getStrings().toArray(String[]::new); From 588a13e854f0d715871aa617c66c5daf0683ac43 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Tue, 3 Jun 2025 21:30:36 -0700 Subject: [PATCH 7/8] Requested Changes --- .../ch/njol/skript/conditions/CondHasCustomModelData.java | 6 ++++++ .../tests/syntaxes/conditions/CondHasCustomModelData.sk | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java b/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java index d188aaf9f7a..993cba28582 100644 --- a/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java +++ b/src/main/java/ch/njol/skript/conditions/CondHasCustomModelData.java @@ -15,6 +15,12 @@ @Name("Has Custom Model Data") @Description("Check if an item has a custom model data tag") @Example("player's tool has custom model data") +@Example(""" + if player's tool has custom model data flags: + loop custom model data flags of player's tool: + send "Flag %loop-index%: %loop-value%" + """) +@Example("set {_coloured} to whether player's tool has model data colours") @Since("2.5, INSERT VERSION (expanded data types)") @RequiredPlugins("Minecraft 1.21.4+ (floats/flags/strings/colours)") public class CondHasCustomModelData extends PropertyCondition { diff --git a/src/test/skript/tests/syntaxes/conditions/CondHasCustomModelData.sk b/src/test/skript/tests/syntaxes/conditions/CondHasCustomModelData.sk index a3c1353f86e..35d42a14199 100644 --- a/src/test/skript/tests/syntaxes/conditions/CondHasCustomModelData.sk +++ b/src/test/skript/tests/syntaxes/conditions/CondHasCustomModelData.sk @@ -9,20 +9,28 @@ test "new custom model data" when running minecraft "1.21.4": set full model data of {_item} to 1 assert {_item} has custom model data with "false negative for float model data" + assert {_item} has custom model data floats with "false negative for specifically float model data" clear full model data of {_item} assert {_item} doesn't have custom model data with "false positive for float model data" + assert {_item} doesn't have custom model data floats with "false positive for specifically float model data" set full model data of {_item} to "1" assert {_item} has custom model data with "false negative for string model data" + assert {_item} has custom model data strings with "false negative for specifically string model data" clear full model data of {_item} assert {_item} doesn't have custom model data with "false positive for string model data" + assert {_item} doesn't have custom model data strings with "false positive for specifically string model data" set full model data of {_item} to true assert {_item} has custom model data with "false negative for boolean model data" + assert {_item} has custom model data flags with "false negative for specifically boolean model data" clear full model data of {_item} assert {_item} doesn't have custom model data with "false positive for boolean model data" + assert {_item} doesn't have custom model data flags with "false positive for specifically boolean model data" set full model data of {_item} to rgb(1,1,1) assert {_item} has custom model data with "false negative for color model data" + assert {_item} has custom model data colors with "false negative for specifically color model data" clear full model data of {_item} assert {_item} doesn't have custom model data with "false positive for color model data" + assert {_item} doesn't have custom model data colors with "false positive for specifically color model data" From 723039d3777cc21f1e2dd6ec235339cf3098fa0d Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Sun, 29 Jun 2025 16:08:37 -0700 Subject: [PATCH 8/8] requested changes --- .../expressions/ExprCustomModelData.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java b/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java index d0fc646bd41..3e62761e44d 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java +++ b/src/main/java/ch/njol/skript/expressions/ExprCustomModelData.java @@ -8,18 +8,20 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.registrations.Classes; import ch.njol.skript.util.Color; import ch.njol.skript.util.ColorRGB; -import ch.njol.skript.util.Utils; import ch.njol.util.Kleenean; import org.bukkit.event.Event; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.components.CustomModelDataComponent; import org.jetbrains.annotations.Nullable; +import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.function.IntFunction; @Name("Custom Model Data") @Description({ @@ -65,20 +67,20 @@ private enum CMDType { COLORS(Color.class), ALL(Float.class, Boolean.class, String.class, Color.class); - private final Class supertype; private final Class[] types; CMDType(Class... returns) { this.types = returns; - this.supertype = Utils.getSuperType(returns); } } private CMDType dataType; + private Class returnType; @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { dataType = CMDType.values()[parseResult.mark]; + returnType = Classes.getSuperClassInfo(dataType.types).getC(); //noinspection unchecked setExpr((Expression) expressions[0]); return true; @@ -97,11 +99,12 @@ protected Object[] get(Event event, ItemType[] source) { } CustomModelDataComponent component = meta.getCustomModelDataComponent(); + IntFunction arrayConstructor = n -> (Object[]) Array.newInstance(getReturnType(), n); return switch (dataType) { case SINGLE_INT -> throw new IllegalStateException("Unreachable state for SINGLE_INT!"); - case FLOATS -> component.getFloats().toArray(Float[]::new); - case FLAGS -> component.getFlags().toArray(Boolean[]::new); - case STRINGS -> component.getStrings().toArray(String[]::new); + case FLOATS -> component.getFloats().toArray(arrayConstructor); + case FLAGS -> component.getFlags().toArray(arrayConstructor); + case STRINGS -> component.getStrings().toArray(arrayConstructor); case COLORS -> component.getColors().stream().map(ColorRGB::fromBukkitColor).toList().toArray(ColorRGB[]::new); case ALL -> { @@ -110,17 +113,17 @@ protected Object[] get(Event event, ItemType[] source) { data.addAll(component.getFlags()); data.addAll(component.getStrings()); data.addAll(component.getColors().stream().map(ColorRGB::fromBukkitColor).toList()); - yield data.toArray(Object[]::new); + yield data.toArray(arrayConstructor); } }; } - throw new IllegalStateException("Unreachable state! Either source was an empty array or something horrible happened."); + return (Object[]) Array.newInstance(getReturnType(), 0); } @Override public Class @Nullable [] acceptChange(ChangeMode mode) { return switch (mode) { - case ADD, REMOVE, REMOVE_ALL, SET, DELETE, RESET -> { + case ADD, REMOVE, SET, DELETE, RESET -> { // convert to array types to allow plural changes. Class[] arrayClasses = new Class[dataType.types.length]; for (int i = 0; i < dataType.types.length; i++) { @@ -296,7 +299,7 @@ public boolean isSingle() { @Override public Class getReturnType() { - return dataType.supertype; + return returnType; } @Override