From 1073742f78a49bbfabd92aae91a620109a4798c9 Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Sat, 6 Sep 2025 18:02:58 -0400 Subject: [PATCH 1/8] Merge dev/EquippableComponents --- src/main/java/ch/njol/skript/Skript.java | 2 + .../ch/njol/skript/bukkitutil/ItemUtils.java | 3 +- .../skript/bukkitutil/NamespacedUtils.java | 92 ++++++ .../ch/njol/skript/registrations/Feature.java | 3 +- .../java/ch/njol/skript/util/ItemSource.java | 63 ++++ .../ch/njol/skript/util/ValidationResult.java | 58 ++++ .../itemcomponents/ComponentWrapper.java | 216 ++++++++++++++ .../itemcomponents/ItemComponentModule.java | 60 ++++ .../EquippableExperimentSyntax.java | 20 ++ .../equippable/EquippableModule.java | 76 +++++ .../equippable/EquippableWrapper.java | 245 ++++++++++++++++ .../elements/CondEquipCompDamage.java | 60 ++++ .../elements/CondEquipCompDispensable.java | 74 +++++ .../elements/CondEquipCompInteract.java | 42 +++ .../elements/CondEquipCompShearable.java | 49 ++++ .../elements/CondEquipCompSwapEquipment.java | 51 ++++ .../elements/EffEquipCompDamageable.java | 63 ++++ .../elements/EffEquipCompDispensable.java | 59 ++++ .../elements/EffEquipCompInteract.java | 60 ++++ .../elements/EffEquipCompShearable.java | 69 +++++ .../elements/EffEquipCompSwapEquipment.java | 57 ++++ .../elements/ExprEquipCompCameraOverlay.java | 85 ++++++ .../elements/ExprEquipCompEntities.java | 113 +++++++ .../elements/ExprEquipCompEquipSound.java | 79 +++++ .../elements/ExprEquipCompModel.java | 84 ++++++ .../elements/ExprEquipCompShearSound.java | 80 +++++ .../elements/ExprEquipCompSlot.java | 67 +++++ .../elements/ExprEquippableComponent.java | 112 +++++++ .../elements/ExprSecBlankEquipComp.java | 108 +++++++ .../generic/ExprItemCompCopy.java | 58 ++++ src/main/resources/lang/default.lang | 2 + src/main/resources/lang/english.lang | 5 + .../tests/general/EquippableComponents.sk | 275 ++++++++++++++++++ 33 files changed, 2488 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ch/njol/skript/bukkitutil/NamespacedUtils.java create mode 100644 src/main/java/ch/njol/skript/util/ItemSource.java create mode 100644 src/main/java/ch/njol/skript/util/ValidationResult.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentWrapper.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ItemComponentModule.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableExperimentSyntax.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableModule.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableWrapper.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDamage.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDispensable.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompInteract.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompShearable.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompSwapEquipment.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDamageable.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDispensable.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompInteract.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompShearable.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompSwapEquipment.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompCameraOverlay.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEntities.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEquipSound.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompModel.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompShearSound.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompSlot.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquippableComponent.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprSecBlankEquipComp.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/generic/ExprItemCompCopy.java create mode 100644 src/test/skript/tests/general/EquippableComponents.sk diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index 616c20b3e98..91395df401b 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -97,6 +97,7 @@ import org.skriptlang.skript.bukkit.furnace.FurnaceModule; import org.skriptlang.skript.bukkit.input.InputModule; import org.skriptlang.skript.bukkit.log.runtime.BukkitRuntimeErrorConsumer; +import org.skriptlang.skript.bukkit.itemcomponents.ItemComponentModule; import org.skriptlang.skript.bukkit.loottables.LootTableModule; import org.skriptlang.skript.bukkit.registration.BukkitRegistryKeys; import org.skriptlang.skript.bukkit.registration.BukkitSyntaxInfos; @@ -586,6 +587,7 @@ public void onEnable() { FurnaceModule.load(); LootTableModule.load(); skript.loadModules(new DamageSourceModule()); + skript.loadModules(new ItemComponentModule()); } catch (final Exception e) { exception(e, "Could not load required .class files: " + e.getLocalizedMessage()); setEnabled(false); diff --git a/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java b/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java index 6071616064b..19b935b3194 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java +++ b/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java @@ -401,8 +401,9 @@ public static void setItemMeta(Object object, @NotNull ItemMeta itemMeta) { itemType.setItemMeta(itemMeta); } else if (object instanceof ItemStack itemStack) { itemStack.setItemMeta(itemMeta); + } else { + throw new IllegalArgumentException("Object was not a Slot, ItemType or ItemStack."); } - throw new IllegalArgumentException("Object was not a Slot, ItemType or ItemStack."); } } diff --git a/src/main/java/ch/njol/skript/bukkitutil/NamespacedUtils.java b/src/main/java/ch/njol/skript/bukkitutil/NamespacedUtils.java new file mode 100644 index 00000000000..67e5e1812cb --- /dev/null +++ b/src/main/java/ch/njol/skript/bukkitutil/NamespacedUtils.java @@ -0,0 +1,92 @@ +package ch.njol.skript.bukkitutil; + +import ch.njol.skript.localization.ArgsMessage; +import ch.njol.skript.localization.Message; +import ch.njol.skript.util.ValidationResult; +import org.bukkit.NamespacedKey; + +/** + * Utility class for {@link NamespacedKey} + */ +public class NamespacedUtils { + + public static final Message NAMEDSPACED_FORMAT_MESSAGE = new ArgsMessage("misc.namespacedutils.format"); + + /** + * Check if {@code character} is a valid {@link Character} for the namespace section of a {@link NamespacedKey}. + * @param character The {@link Character} to check. + * @return {@code True} if valid, otherwise {@code false}. + */ + public static boolean isValidNamespaceChar(char character) { + return (character >= 'a' && character <= 'z') || (character >= '0' && character <= '9') || character == '.' || character == '_' || character == '-'; + } + + /** + * Check if {@code character} is a valid {@link Character} for the key section of a {@link NamespacedKey}. + * @param character The {@link Character} to check. + * @return {@code True} if valid, otherwise {@code false}. + */ + public static boolean isValidKeyChar(char character) { + return isValidNamespaceChar(character) || character == '/'; + } + + /** + * Check if the {@code string} is valid for a {@link NamespacedKey} and get a {@link ValidationResult} + * containing if it's valid, an error or warning message and the resulting {@link NamespacedKey}. + * @param string The {@link String} to check. + * @return {@link ValidationResult}. + */ + public static ValidationResult checkValidation(String string) { + if (string.length() > Short.MAX_VALUE) + return new ValidationResult<>(false, "A namespaced key can not be longer than " + Short.MAX_VALUE + " characters."); + String[] split = string.split(":"); + if (split.length > 2) + return new ValidationResult<>(false, "A namespaced key can not have more than one ':'."); + + String key = split.length == 2 ? split[1] : split[0]; + if (key.isEmpty()) + return new ValidationResult<>(false, "The key cannot be empty."); + for (char character : key.toCharArray()) { + if (!isValidKeyChar(character)) { + return new ValidationResult<>(false, "Invalid character '" + character + "'."); + } + } + + NamespacedKey namespacedKey; + boolean emptyNamespace = false; + if (split.length == 2) { + String namespace = split[0]; + if (!namespace.isEmpty()) { + for (char character : namespace.toCharArray()) { + if (!isValidNamespaceChar(character)) { + return new ValidationResult<>(false, "Invalid character '" + character + "'."); + } + } + namespacedKey = new NamespacedKey(namespace, key); + } else { + emptyNamespace = true; + namespacedKey = NamespacedKey.minecraft(key); + } + } else { + namespacedKey = NamespacedKey.minecraft(key); + } + + if (emptyNamespace) { + return new ValidationResult<>( + true, + "The namespace section of the key is empty. Consider removing the ':'.", + namespacedKey); + } + return new ValidationResult<>(true, namespacedKey); + } + + /** + * Check if {@code string} is valid for a {@link NamespacedKey}. + * @param string The {@link String} to check. + * @return {@code True} if valid, otherwise {@code false}. + */ + public static boolean isValid(String string) { + return checkValidation(string).valid(); + } + +} diff --git a/src/main/java/ch/njol/skript/registrations/Feature.java b/src/main/java/ch/njol/skript/registrations/Feature.java index eb2c2f0f9d7..e233c12ac01 100644 --- a/src/main/java/ch/njol/skript/registrations/Feature.java +++ b/src/main/java/ch/njol/skript/registrations/Feature.java @@ -17,7 +17,8 @@ public enum Feature implements Experiment { SCRIPT_REFLECTION("reflection", LifeCycle.EXPERIMENTAL, "[script] reflection"), CATCH_ERRORS("catch runtime errors", LifeCycle.EXPERIMENTAL, "error catching [section]"), TYPE_HINTS("type hints", LifeCycle.EXPERIMENTAL, "[local variable] type hints"), - DAMAGE_SOURCE("damage source", LifeCycle.EXPERIMENTAL, "damage source[s]") + DAMAGE_SOURCE("damage source", LifeCycle.EXPERIMENTAL, "damage source[s]"), + EQUIPPABLE_COMPONENTS("equippable components", LifeCycle.EXPERIMENTAL, "equippable components") ; private final String codeName; diff --git a/src/main/java/ch/njol/skript/util/ItemSource.java b/src/main/java/ch/njol/skript/util/ItemSource.java new file mode 100644 index 00000000000..d1ba3e3d6b9 --- /dev/null +++ b/src/main/java/ch/njol/skript/util/ItemSource.java @@ -0,0 +1,63 @@ +package ch.njol.skript.util; + +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.bukkitutil.ItemUtils; +import ch.njol.skript.util.slot.Slot; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.Nullable; + +/** + * Container class for containing the origin of a {@link Slot}, {@link ItemStack}, and {@link ItemType}. + */ +public class ItemSource { + + private final T source; + + public ItemSource(T source) { + this.source = source; + } + + /** + * Checks if the {@link ItemStack} in {@code slot} is a valid item. + * @param slot The {@link Slot} to check. + * @return {@link ItemSource} if the item is valid, otherwise {@code null}. + */ + public static @Nullable ItemSource fromSlot(Slot slot) { + ItemStack itemStack = slot.getItem(); + if (itemStack == null || itemStack.getType() == Material.AIR || itemStack.getItemMeta() == null) + return null; + return new ItemSource<>(slot); + } + + /** + * Get the source object, can be a {@link Slot}, {@link ItemStack}, or {@link ItemType}. + */ + public T getSource() { + return source; + } + + /** + * Get the {@link ItemStack} retrieved from {@link #source}. + */ + public ItemStack getItemStack() { + return ItemUtils.asItemStack(source); + } + + /** + * Get the {@link ItemMeta} retrieved from {@link #source}. + */ + public ItemMeta getItemMeta() { + return getItemStack().getItemMeta(); + } + + /** + * Appropriately update the {@link ItemMeta} of {@link #source}. + * @param itemMeta The {@link ItemMeta} to update {@link #source} + */ + public void setItemMeta(ItemMeta itemMeta) { + ItemUtils.setItemMeta(source, itemMeta); + } + +} diff --git a/src/main/java/ch/njol/skript/util/ValidationResult.java b/src/main/java/ch/njol/skript/util/ValidationResult.java new file mode 100644 index 00000000000..f93baa26760 --- /dev/null +++ b/src/main/java/ch/njol/skript/util/ValidationResult.java @@ -0,0 +1,58 @@ +package ch.njol.skript.util; + +import org.jetbrains.annotations.Nullable; + +/** + * Represents the result of a validation check. + *

+ * This record stores whether a check was valid, + * an optional message explaining the result (i.e., an error or warning message), + * and optional data returned from the check if it successfully passed. + *

+ * + * @param valid Whether the validation was successful. + * @param message An optional message describing the result. + * @param data Optional data returned from the validation. + * @param The type of data returned from a successful validation. + */ +public record ValidationResult( + boolean valid, + @Nullable String message, + @Nullable T data +) { + + /** + * Constructs a {@link ValidationResult} with only a validity flag. + * @param valid Whether the validation was successful. + */ + public ValidationResult(boolean valid) { + this(valid, null, null); + } + + /** + * Constructs a {@link ValidationResult} with a validity flag and message. + * @param valid Whether the validation was successful. + * @param message An optional message describing the result. + */ + public ValidationResult(boolean valid, @Nullable String message) { + this(valid, message, null); + } + + /** + * Constructs a {@link ValidationResult} with a validity flag and result data. + * @param valid Whether the validation was successful. + * @param data Optional data returned from the validation. + */ + public ValidationResult(boolean valid, @Nullable T data) { + this(valid, null, data); + } + + /** + * Constructs a {@link ValidationResult} with a validity flag, message and result data. + * @param valid Whether the validation was successful. + * @param message An optional message describing the result. + * @param data Optional data returned from the validation. + */ + public ValidationResult {} + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentWrapper.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentWrapper.java new file mode 100644 index 00000000000..87cbe87498b --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentWrapper.java @@ -0,0 +1,216 @@ +package org.skriptlang.skript.bukkit.itemcomponents; + +import ch.njol.skript.aliases.ItemData; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.util.ItemSource; +import ch.njol.skript.util.slot.Slot; +import io.papermc.paper.datacomponent.DataComponentBuilder; +import io.papermc.paper.datacomponent.DataComponentType; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Consumer; + +/** + * A wrapper that allows access and modification of a specific component from an {@link ItemStack} + * or a stand-alone component. + * @param The type of component + * @param The builder type of {@link T} + */ +@SuppressWarnings({"UnstableApiUsage", "NonExtendableApiUsage"}) +public abstract class ComponentWrapper> implements Cloneable { + + private final @Nullable ItemSource itemSource; + private T component; + + /** + * Constructs a {@link ComponentWrapper} that wraps the given {@link ItemStack} in an {@link ItemSource}. + * @see ComponentWrapper#ComponentWrapper(ItemSource) + * @param itemStack The original {@link ItemStack}. + */ + public ComponentWrapper(ItemStack itemStack) { + this(new ItemSource<>(itemStack)); + } + + /** + * Constructs a {@link ComponentWrapper} with the given {@link ItemSource}. + * Ensures up-to-date component data retrieval and modification on the {@link ItemStack} of the {@link ItemSource} . + * @param itemSource The {@link ItemSource} representing the original source of the {@link ItemStack}. + */ + public ComponentWrapper(ItemSource itemSource) { + if (itemSource.getItemStack() == null) + throw new IllegalArgumentException("ItemSource must have an ItemStack to retrieve"); + this.itemSource = itemSource; + this.component = this.getComponent(itemSource.getItemStack()); + } + + /** + * Constructs a {@link ComponentWrapper} that only references to a component. + */ + public ComponentWrapper(T component) { + this.component = component; + this.itemSource = null; + } + + /** + * Constructs a {@link ComponentWrapper} that only references to a built component. + */ + public ComponentWrapper(B builder) { + this.component = builder.build(); + this.itemSource = null; + } + + /** + * Returns the current component. + * If this {@link ComponentWrapper} was constructed with an {@link ItemSource}, the component is retrieved from + * the stored item. Otherwise, the stored {@link #component}. + */ + public T getComponent() { + if (itemSource != null) { + return this.getComponent(itemSource.getItemStack()); + } + return component; + } + + /** + * Returns the builder of the current component + * If this {@link ComponentWrapper} was constructed with an {@link ItemSource}, the builder is retrieved from + * the component of the stored item. Otherwise, the stored {@link #component}. + */ + public B getBuilder() { + if (itemSource != null) { + return this.getBuilder(itemSource.getItemStack()); + } + return toBuilder(component); + } + + /** + * Returns the {@link ItemStack} associated with this {@link ComponentWrapper}, if available. + */ + public @Nullable ItemStack getItemStack() { + return itemSource == null ? null : itemSource.getItemStack(); + } + + /** + * Returns the {@link ItemSource} the {@link ItemStack} is sourced from. + */ + public @Nullable ItemSource getItemSource() { + return itemSource; + } + + /** + * Returns the {@link DataComponentType} of this {@link ComponentWrapper}. + */ + public abstract DataComponentType.Valued getDataComponentType(); + + /** + * Returns the {@link T} component from {@code itemStack}. + */ + protected abstract T getComponent(ItemStack itemStack); + + /** + * Returns the {@link B} builder of the component from {@code itemStack}. + */ + protected abstract B getBuilder(ItemStack itemStack); + + /** + * Sets the {@link T} component on {@code itemStack}. + */ + protected abstract void setComponent(ItemStack itemStack, T component); + + /** + * Sets the {@link B} builder component on {@code itemStack}. + */ + protected void setBuilder(ItemStack itemStack, B builder) { + setComponent(itemStack, builder.build()); + } + + /** + * Apply the current {@link #component} to the {@link #itemSource}. + */ + public void applyComponent() { + applyComponent(getComponent()); + } + + /** + * Apply a new {@code component} or {@link #component} to the {@link #itemSource}. + */ + public void applyComponent(@NotNull T component) { + this.component = component; + if (itemSource == null) + return; + ItemStack itemStack = itemSource.getItemStack(); + setComponent(itemStack, component); + if (itemSource.getSource() instanceof ItemType itemType) { + for (ItemData itemData : itemType) { + ItemStack dataStack = itemData.getStack(); + if (dataStack == null) + continue; + dataStack.setData(getDataComponentType(), component); + } + } else if (itemSource.getSource() instanceof Slot slot) { + slot.setItem(itemStack); + } + } + + /** + * Apply a new {@code builder} to the {@link #itemSource}. + */ + public void applyBuilder(@NotNull B builder) { + applyComponent(builder.build()); + } + + /** + * Edit the {@link T} component of this {@link ComponentWrapper} and have changes applied. + */ + public void editBuilder(Consumer consumer) { + B builder = getBuilder(); + consumer.accept(builder); + applyComponent(builder.build()); + } + + /** + * Convert {@code component} to a builder. + * @param component The component. + * @return The builder. + */ + protected abstract B toBuilder(T component); + + /** + * Returns a clone of this {@link ComponentWrapper}. + */ + public abstract ComponentWrapper clone(); + + /** + * Returns a new component {@link T}. + */ + public abstract T newComponent(); + + /** + * Returns a new builder {@link B}. + */ + public abstract B newBuilder(); + + /** + * Returns a new {@link ComponentWrapper}. + */ + public abstract ComponentWrapper newWrapper(); + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ComponentWrapper other)) + return false; + boolean relation = true; + if (this.itemSource != null && other.itemSource != null) + relation = this.itemSource.getItemStack().equals(other.itemSource.getItemStack()); + relation &= this.getComponent().equals(other.getComponent()); + return relation; + } + + @Override + public String toString() { + return getComponent().toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ItemComponentModule.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ItemComponentModule.java new file mode 100644 index 00000000000..1e2183a969a --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ItemComponentModule.java @@ -0,0 +1,60 @@ +package org.skriptlang.skript.bukkit.itemcomponents; + +import ch.njol.skript.Skript; +import ch.njol.skript.classes.ClassInfo; +import ch.njol.skript.classes.Parser; +import ch.njol.skript.lang.ParseContext; +import ch.njol.skript.registrations.Classes; +import org.skriptlang.skript.addon.AddonModule; +import org.skriptlang.skript.addon.SkriptAddon; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableModule; + +import java.io.IOException; + +public class ItemComponentModule implements AddonModule { + + @Override + public boolean canLoad(SkriptAddon addon) { + return Skript.isRunningMinecraft(1, 21, 2); + } + + @Override + public void init(SkriptAddon addon) { + Classes.registerClass(new ClassInfo<>(ComponentWrapper.class, "itemcomponent") + .user("item ?components?") + .name("Item Component") + .description("Represents an item component for items. i.e. equippable components.") + .since("INSERT VERSION") + .requiredPlugins("Minecraft 1.21.2+") + .parser(new Parser<>() { + @Override + public boolean canParse(ParseContext context) { + return false; + } + + @Override + public String toString(ComponentWrapper wrapper, int flags) { + return "item component"; + } + + @Override + public String toVariableNameString(ComponentWrapper wrapper) { + return "item component#" + wrapper.hashCode(); + } + }) + .after("itemstack", "itemtype", "slot") + ); + } + + @Override + public void load(SkriptAddon addon) { + addon.loadModules(new EquippableModule()); + + try { + Skript.getAddonInstance().loadClasses("org.skriptlang.skript.bukkit.itemcomponents", "generic"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableExperimentSyntax.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableExperimentSyntax.java new file mode 100644 index 00000000000..30e3b14c4c3 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableExperimentSyntax.java @@ -0,0 +1,20 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable; + +import ch.njol.skript.lang.SyntaxElement; +import ch.njol.skript.registrations.Feature; +import org.skriptlang.skript.lang.experiment.ExperimentData; +import org.skriptlang.skript.lang.experiment.SimpleExperimentalSyntax; + +/** + * Typed {@link SimpleExperimentalSyntax} for {@link SyntaxElement}s that require {@link Feature#EQUIPPABLE_COMPONENTS}. + */ +public interface EquippableExperimentSyntax extends SimpleExperimentalSyntax { + + ExperimentData EXPERIMENT_DATA = ExperimentData.createSingularData(Feature.EQUIPPABLE_COMPONENTS); + + @Override + default ExperimentData getExperimentData() { + return EXPERIMENT_DATA; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableModule.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableModule.java new file mode 100644 index 00000000000..c1f1887295f --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableModule.java @@ -0,0 +1,76 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable; + +import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.classes.ClassInfo; +import ch.njol.skript.classes.Parser; +import ch.njol.skript.expressions.base.EventValueExpression; +import ch.njol.skript.lang.ParseContext; +import ch.njol.skript.registrations.Classes; +import ch.njol.skript.util.ItemSource; +import ch.njol.skript.util.slot.Slot; +import io.papermc.paper.datacomponent.item.Equippable; +import org.bukkit.inventory.ItemStack; +import org.skriptlang.skript.addon.AddonModule; +import org.skriptlang.skript.addon.SkriptAddon; +import org.skriptlang.skript.lang.converter.Converter; +import org.skriptlang.skript.lang.converter.Converters; + +import java.io.IOException; + +public class EquippableModule implements AddonModule { + + @Override + public boolean canLoad(SkriptAddon addon) { + return Skript.classExists("io.papermc.paper.datacomponent.item.Equippable"); + } + + @Override + public void init(SkriptAddon addon) { + Classes.registerClass(new ClassInfo<>(EquippableWrapper.class, "equippablecomponent") + .user("equippable ?components?") + .name("Equippable Components") + .description("Represents an equippable component used for items.") + .requiredPlugins("Minecraft 1.21.2+") + .since("INSERT VERSION") + .defaultExpression(new EventValueExpression<>(EquippableWrapper.class)) + .parser(new Parser<>() { + @Override + public boolean canParse(ParseContext context) { + return false; + } + + @Override + public String toString(EquippableWrapper wrapper, int flags) { + return "equippable component"; + } + + @Override + public String toVariableNameString(EquippableWrapper wrapper) { + return "equippable component#" + wrapper.hashCode(); + } + }) + .after("itemstack", "itemtype", "slot") + ); + + Converters.registerConverter(Equippable.class, EquippableWrapper.class, EquippableWrapper::new, Converter.NO_RIGHT_CHAINING); + Converters.registerConverter(ItemStack.class, EquippableWrapper.class, EquippableWrapper::new, Converter.NO_RIGHT_CHAINING); + Converters.registerConverter(ItemType.class, EquippableWrapper.class, itemType -> new EquippableWrapper(new ItemSource<>(itemType)), Converter.NO_RIGHT_CHAINING); + Converters.registerConverter(Slot.class, EquippableWrapper.class, slot -> { + ItemSource itemSource = ItemSource.fromSlot(slot); + if (itemSource == null) + return null; + return new EquippableWrapper(itemSource); + }, Converter.NO_RIGHT_CHAINING); + } + + @Override + public void load(SkriptAddon addon) { + try { + Skript.getAddonInstance().loadClasses("org.skriptlang.skript.bukkit.itemcomponents.equippable", "elements"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableWrapper.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableWrapper.java new file mode 100644 index 00000000000..82aa432fe2a --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableWrapper.java @@ -0,0 +1,245 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable; + +import ch.njol.skript.Skript; +import ch.njol.skript.util.ItemSource; +import io.papermc.paper.datacomponent.DataComponentType.Valued; +import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.Equippable; +import io.papermc.paper.datacomponent.item.Equippable.Builder; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.set.RegistryKeySet; +import io.papermc.paper.registry.set.RegistrySet; +import net.kyori.adventure.key.Key; +import org.bukkit.Registry; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.ComponentWrapper; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Collections; + +/** + * A {@link ComponentWrapper} for getting and setting data on an {@link Equippable} component. + */ +@SuppressWarnings("UnstableApiUsage") +public class EquippableWrapper extends ComponentWrapper { + + private static final boolean HAS_MODEL_METHOD = Skript.methodExists(Equippable.class, "model"); + private static final @Nullable Method COMPONENT_MODEL_METHOD; + private static final @Nullable Method BUILDER_MODEL_METHOD; + + public static final boolean HAS_EQUIP_ON_INTERACT = Skript.methodExists(Equippable.class, "equipOnInteract"); + public static final boolean HAS_CAN_BE_SHEARED = Skript.methodExists(Equippable.class, "canBeSheared"); + public static final boolean HAS_SHEAR_SOUND = Skript.methodExists(Equippable.class, "shearSound"); + + static { + // Paper changed '#model' to '#assetId' in 1.21.4 + Method componentModelMethod = null; + Method builderModelMethod = null; + if (HAS_MODEL_METHOD) { + try { + componentModelMethod = Equippable.class.getDeclaredMethod("model"); + builderModelMethod = Equippable.Builder.class.getDeclaredMethod("model", Key.class); + } catch (NoSuchMethodException ignored) {} + } + COMPONENT_MODEL_METHOD = componentModelMethod; + BUILDER_MODEL_METHOD = builderModelMethod; + } + + public EquippableWrapper(ItemStack itemStack) { + super(itemStack); + } + + public EquippableWrapper(ItemSource itemSource) { + super(itemSource); + } + + public EquippableWrapper(Equippable component) { + super(component); + } + + public EquippableWrapper(Builder builder) { + super(builder); + } + + @Override + public Valued getDataComponentType() { + return DataComponentTypes.EQUIPPABLE; + } + + @Override + protected Equippable getComponent(ItemStack itemStack) { + Equippable equippable = itemStack.getData(DataComponentTypes.EQUIPPABLE); + if (equippable != null) + return equippable; + return Equippable.equippable(EquipmentSlot.HEAD).build(); + } + + @Override + protected Builder getBuilder(ItemStack itemStack) { + Equippable equippable = itemStack.getData(DataComponentTypes.EQUIPPABLE); + if (equippable != null) + return equippable.toBuilder(); + return Equippable.equippable(EquipmentSlot.HEAD); + } + + @Override + protected void setComponent(ItemStack itemStack, Equippable component) { + itemStack.setData(DataComponentTypes.EQUIPPABLE, component); + } + + @Override + protected Builder toBuilder(Equippable component) { + return component.toBuilder(); + } + + @Override + public EquippableWrapper clone() { + EquippableWrapper clone = newWrapper(); + Equippable base = getComponent(); + clone.applyComponent(clone(base.slot())); + return clone; + } + + /** + * Returns a cloned {@link Equippable} of this {@link EquippableWrapper} with a new {@link EquipmentSlot}. + */ + public Equippable clone(EquipmentSlot slot) { + Equippable base = getComponent(); + Builder builder = Equippable.equippable(slot) + .allowedEntities(base.allowedEntities()) + .cameraOverlay(base.cameraOverlay()) + .damageOnHurt(base.damageOnHurt()) + .dispensable(base.dispensable()) + .equipSound(base.equipSound()) + .swappable(base.swappable()); + setModel(builder, getModel()); + if (HAS_EQUIP_ON_INTERACT) { + builder.equipOnInteract(base.equipOnInteract()); + } + if (HAS_CAN_BE_SHEARED) { + builder.canBeSheared(base.canBeSheared()); + } + if (HAS_SHEAR_SOUND) { + builder.shearSound(base.shearSound()); + } + return builder.build(); + } + + @Override + public Equippable newComponent() { + return newBuilder().build(); + } + + @Override + public Builder newBuilder() { + return Equippable.equippable(EquipmentSlot.HEAD); + } + + @Override + public EquippableWrapper newWrapper() { + return newInstance(); + } + + /** + * Returns a {@link Collection} of {@link EntityType}s that are allowed to wear with this {@link EquippableWrapper}. + */ + public Collection getAllowedEntities() { + return getAllowedEntities(getComponent()); + } + + /** + * Updates the model/assetId of this {@link EquippableWrapper} with {@code key}. + * @param key The {@link Key} to set to. + */ + public void setModel(Key key) { + Builder builder = getBuilder(); + setModel(builder, key); + applyBuilder(builder); + } + + /** + * Returns the model/assetId {@link Key} of this {@link EquippableWrapper}. + */ + public Key getModel() { + return getModel(getComponent()); + } + + /** + * Get an {@link EquippableWrapper} with a new {@link Equippable} component. + */ + public static EquippableWrapper newInstance() { + return new EquippableWrapper( + Equippable.equippable(EquipmentSlot.HEAD) + ); + } + + /** + * Returns the model/assetId {@link Key} of {@code component}. + *

+ * Paper 1.21.2 to 1.21.3 uses #model + * Paper 1.21.4+ uses #assetId + *

+ * @param component The {@link Equippable} component to retrieve. + * @return The {@link Key}. + */ + public static Key getModel(Equippable component) { + if (HAS_MODEL_METHOD) { + assert COMPONENT_MODEL_METHOD != null; + try { + return (Key) COMPONENT_MODEL_METHOD.invoke(component); + } catch (Exception ignored) {} + } + return component.assetId(); + } + + /** + * Updates the model/assetId of {@code builder} with {@code key}. + *

+ * Paper 1.21.2 to 1.21.3 uses #model + * Paper 1.21.4+ uses #assetId + *

+ * @param builder The {@link Builder} to update. + * @param key The {@link Key} to set to. + * @return {@code builder}. + */ + public static Builder setModel(Builder builder, Key key) { + if (HAS_MODEL_METHOD) { + assert BUILDER_MODEL_METHOD != null; + try { + BUILDER_MODEL_METHOD.invoke(builder, key); + } catch (Exception ignored) {} + } else { + builder.assetId(key); + } + return builder; + } + + /** + * Returns a {@link Collection} of {@link EntityType}s that are allowed to wear with this {@code component}. + *

+ * Paper originally returns {@link RegistryKeySet} but has no real modification capabilities. + *

+ * @param component The {@link Equippable} component to get from. + * @return The allowed {@link EntityType}s. + */ + public static Collection getAllowedEntities(Equippable component) { + RegistryKeySet keys = component.allowedEntities(); + if (keys == null) + return Collections.emptyList(); + return keys.resolve(Registry.ENTITY_TYPE); + } + + /** + * Converts {@code entityTypes} into a {@link RegistryKeySet} to update the allowed entities of an {@link Equippable} component. + * @param entityTypes The allowed {@link EntityType}s. + * @return {@link RegistryKeySet} representation of {@code entityTypes}. + */ + public static RegistryKeySet convertAllowedEntities(Collection entityTypes) { + return RegistrySet.keySetFromValues(RegistryKey.ENTITY_TYPE, entityTypes); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDamage.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDamage.java new file mode 100644 index 00000000000..03131667de2 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDamage.java @@ -0,0 +1,60 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.doc.Description; +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.lang.SyntaxStringBuilder; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Will Lose Durability") +@Description("Whether an item can be damaged when the wearer gets injured. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example(""" + if {_item} will lose durability when hurt: + add "Damageable on injury" to lore of {_item} + """) +@Example(""" + set {_component} to the equippable component of {_item} + if {_component} won't lose durability on injury: + make {_component} lose durability when injured + """) +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +public class CondEquipCompDamage extends PropertyCondition implements EquippableExperimentSyntax { + + static { + Skript.registerCondition(CondEquipCompDamage.class, ConditionType.PROPERTY, + "%equippablecomponents% will (lose durability|be damaged) (on [wearer['s]] injury|when [[the] wearer [is]] (hurt|injured|damaged))", + "%equippablecomponents% (will not|won't) (lose durability|be damaged) (on [wearer['s]] injury|when [[the] wearer [is]] (hurt|injured|damaged))" + ); + } + + @Override + public boolean check(EquippableWrapper wrapper) { + //noinspection UnstableApiUsage + return wrapper.getComponent().damageOnHurt(); + } + + @Override + protected String getPropertyName() { + return "lose durability when injured"; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug); + builder.append(getExpr(), "will"); + if (isNegated()) + builder.append("not"); + builder.append("lose durability when injured"); + return builder.toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDispensable.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDispensable.java new file mode 100644 index 00000000000..e455a89a4b8 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDispensable.java @@ -0,0 +1,74 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.doc.Description; +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.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Name("Equippable Component - Can Be Dispensed") +@Description("Whether an item can be dispensed by a dispenser. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example(""" + if {_item} can be dispensed: + add "Dispensable" to lore of {_item} + """) +@Example(""" + set {_component} to the equippable component of {_item} + if {_component} is not able to be dispensed: + allow {_component} to be dispensed + """) +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +public class CondEquipCompDispensable extends PropertyCondition implements EquippableExperimentSyntax { + + static { + List patterns = new ArrayList<>(Arrays.asList(getPatterns(PropertyType.CAN, "be dispensed", "equippablecomponents"))); + patterns.addAll(Arrays.asList(getPatterns(PropertyType.BE, "(able to be dispensed|dispensable)", "equippablecomponents"))); + + Skript.registerCondition(CondEquipCompDispensable.class, ConditionType.PROPERTY, patterns.toArray(String[]::new)); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + setExpr((Expression) exprs[0]); + setNegated(matchedPattern % 2 == 1); + return true; + } + + @Override + public boolean check(EquippableWrapper wrapper) { + return wrapper.getComponent().dispensable(); + } + + @Override + protected String getPropertyName() { + return "dispensable"; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug); + builder.append(getExpr(), "are"); + if (isNegated()) + builder.append("not"); + builder.append("able to be dispensed"); + return builder.toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompInteract.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompInteract.java new file mode 100644 index 00000000000..545b90c52c2 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompInteract.java @@ -0,0 +1,42 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.doc.Description; +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 org.bukkit.inventory.meta.components.EquippableComponent; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Can Equip On Entities") +@Description("Whether an entity should equip the item when right clicking on the entity with the item. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example("if {_item} can be equipped on entities:") +@Since("INSERT VERSION") +@RequiredPlugins("Minecraft 1.21.5+") +public class CondEquipCompInteract extends PropertyCondition implements EquippableExperimentSyntax { + + static { + if (Skript.methodExists(EquippableComponent.class, "isEquipOnInteract")) + register(CondEquipCompInteract.class, PropertyType.CAN, "be (equipped|put) on[to] entities", "equippablecomponents"); + } + + @Override + public boolean check(EquippableWrapper wrapper) { + return wrapper.getComponent().equipOnInteract(); + } + + @Override + protected PropertyType getPropertyType() { + return PropertyType.CAN; + } + + @Override + protected String getPropertyName() { + return "be equipped onto entities"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompShearable.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompShearable.java new file mode 100644 index 00000000000..eddec0e829e --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompShearable.java @@ -0,0 +1,49 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.doc.Description; +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 org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Can Be Sheared Off") +@Description("Whether an item can be sheared off of an entity. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example(""" + if {_item} can be sheared off: + add "Shearable" to lore of {_item} + """) +@Example(""" + set {_component} to the equippable component of {_item} + if {_component} can not be sheared off: + allow {_component} to be sheared off + """) +@RequiredPlugins("Minecraft 1.21.6+") +@Since("INSERT VERSION") +public class CondEquipCompShearable extends PropertyCondition implements EquippableExperimentSyntax { + + static { + if (EquippableWrapper.HAS_CAN_BE_SHEARED) + register(CondEquipCompShearable.class, PropertyType.CAN, "be sheared off [of entities]", "equippablecomponents"); + } + + @Override + public boolean check(EquippableWrapper wrapper) { + //noinspection UnstableApiUsage + return wrapper.getComponent().canBeSheared(); + } + + @Override + protected PropertyType getPropertyType() { + return PropertyType.CAN; + } + + @Override + protected String getPropertyName() { + return "be sheared off of entities"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompSwapEquipment.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompSwapEquipment.java new file mode 100644 index 00000000000..961a065c227 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompSwapEquipment.java @@ -0,0 +1,51 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.doc.Description; +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 org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Can Swap Equipment") +@Description({ + "Whether an item can swap equipment by right clicking with it in your hand.", + "The item will swap places of the set 'equipment slot' of the item. If an equipment slot is not set, defaults to helmet.", + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work aas intended." +}) +@Example(""" + if {_item} can swap equipment: + add "Swappable" to lore of {_item} + """) +@Example(""" + set {_component} to the equippable component of {_item} + if {_component} can not be equipped when right clicked: + make {_component} swappable + """) +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +public class CondEquipCompSwapEquipment extends PropertyCondition implements EquippableExperimentSyntax { + + static { + register(CondEquipCompSwapEquipment.class, PropertyType.CAN, + "swap equipment [on right click|when right clicked]", "equippablecomponents"); + } + + @Override + public boolean check(EquippableWrapper wrapper) { + return wrapper.getComponent().swappable(); + } + + @Override + protected PropertyType getPropertyType() { + return PropertyType.CAN; + } + + @Override + protected String getPropertyName() { + return "swap equipment"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDamageable.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDamageable.java new file mode 100644 index 00000000000..749c0f3b5ee --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDamageable.java @@ -0,0 +1,63 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.*; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Lose Durability") +@Description("If the item should take damage when the wearer gets injured. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example("make {_item} lose durability when hurt") +@Example(""" + set {_component} to the equippable component of {_item} + if {_component} will lose durability when injured: + make {_component} lose durability on injury + """) +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +public class EffEquipCompDamageable extends Effect implements EquippableExperimentSyntax { + + static { + Skript.registerEffect(EffEquipCompDamageable.class, + "(make|let) %equippablecomponents% (lose durability|be damaged) (on [wearer['s]] injury|when [[the] wearer [is]] (hurt|injured|damaged))", + "(allow|force) %equippablecomponents% to (lose durability|be damaged) (on [wearer['s]] injury|when [[the] wearer [is]] (hurt|injured|damaged))", + "make %equippablecomponents% not (lose durability|be damaged) (on [wearer['s]] injury|when [[the] wearer [is]] (hurt|injured|damaged))", + "(disallow|prevent) %equippablecomponents% from (lose durability|being damaged) (on [wearer['s]] injury|when [[the] wearer [is]] (hurt|injured|damaged))" + ); + } + + private Expression wrappers; + private boolean loseDurability; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + wrappers = (Expression) exprs[0]; + loseDurability = matchedPattern <= 1; + return true; + } + + @Override + protected void execute(Event event) { + wrappers.stream(event).forEach(wrapper -> wrapper.editBuilder(builder -> builder.damageOnHurt(loseDurability))); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug); + builder.append("make", wrappers); + if (loseDurability) + builder.append("not"); + builder.append("lose durability when injured"); + return builder.toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDispensable.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDispensable.java new file mode 100644 index 00000000000..b42f288a1af --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDispensable.java @@ -0,0 +1,59 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.*; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Dispense") +@Description("If the item can be dispensed by a dispenser. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example("allow {_item} to be dispensed") +@Example(""" + set {_component} to the equippable component of {_item} + prevent {_component} from being dispensed + """) +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +public class EffEquipCompDispensable extends Effect implements EquippableExperimentSyntax { + + static { + Skript.registerEffect(EffEquipCompDispensable.class, + "(allow|force) %equippablecomponents% to be dispensed", + "make %equippablecomponents% dispensable", + "let %equippablecomponents% be dispensed", + "(block|prevent|disallow) %equippablecomponents% from being dispensed", + "make %equippablecomponents% not dispensable" + ); + } + + private Expression wrappers; + private boolean dispensable; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + wrappers = (Expression) exprs[0]; + dispensable = matchedPattern < 3; + return true; + } + + @Override + protected void execute(Event event) { + wrappers.stream(event).forEach(wrapper -> wrapper.editBuilder(builder -> builder.dispensable(dispensable))); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + if (dispensable) + return "allow " + wrappers.toString(event, debug) + " to be dispensed"; + return "prevent " + wrappers.toString(event, debug) + " from being dispensed"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompInteract.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompInteract.java new file mode 100644 index 00000000000..afdc6c7f912 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompInteract.java @@ -0,0 +1,60 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +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.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Equip On Entities") +@Description("If an entity should equip the item when right clicking on the entity with the item. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example("allow {_item} to be equipped onto entities") +@Since("INSERT VERSION") +@RequiredPlugins("Minecraft 1.21.5+") +public class EffEquipCompInteract extends Effect implements EquippableExperimentSyntax { + + static { + if (EquippableWrapper.HAS_EQUIP_ON_INTERACT) + Skript.registerEffect(EffEquipCompInteract.class, + "(allow|force) %equippablecomponents% to be equipped on[to] entities", + "make %equippablecomponents% equippable on[to] entities", + "let %equippablecomponents% be equipped on[to] entities", + "(block|prevent|disallow) %equippablecomponents% from being equipped on[to] entities", + "make %equippablecomponents% not equippable on[to] entities" + ); + } + + private boolean equip; + private Expression wrappers; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + wrappers = (Expression) exprs[0]; + equip = matchedPattern < 3; + return true; + } + + @Override + protected void execute(Event event) { + wrappers.stream(event).forEach(wrapper -> wrapper.editBuilder(builder -> builder.equipOnInteract(equip))); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + if (equip) + return "allow " + wrappers.toString(event, debug) + " to be equipped onto entities"; + return "prevent " + wrappers.toString(event, debug) + " from being equipped onto entities"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompShearable.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompShearable.java new file mode 100644 index 00000000000..fc982b03e4e --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompShearable.java @@ -0,0 +1,69 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +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.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Shear Off") +@Description("If the item can be sheared off of entities. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example("allow {_item} to be sheared off") +@Example(""" + set {_component} to the equippable component of {_item} + if {_component} can be sheared off of entities: + prevent {_component} from being sheared off of entities + """) +@RequiredPlugins("Minecraft 1.21.6+") +@Since("INSERT VERSION") +public class EffEquipCompShearable extends Effect implements EquippableExperimentSyntax { + + static { + if (EquippableWrapper.HAS_CAN_BE_SHEARED) { + Skript.registerEffect(EffEquipCompShearable.class, + "(allow|force) %equippablecomponents% to be sheared off [of entities]", + "(disallow|prevent) %equippablecomponents% from being sheared off [of entities]" + ); + } + } + + private Expression wrappers; + private boolean shearable; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + wrappers = (Expression) exprs[0]; + shearable = matchedPattern == 0; + return true; + } + + @Override + protected void execute(Event event) { + wrappers.stream(event).forEach(wrapper -> wrapper.editBuilder(builder -> builder.canBeSheared(shearable))); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug); + if (shearable) { + builder.append("allow", wrappers, "to be"); + } else { + builder.append("prevent", wrappers, "from being"); + } + builder.append("sheared off of entities"); + return builder.toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompSwapEquipment.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompSwapEquipment.java new file mode 100644 index 00000000000..0e127791dbe --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompSwapEquipment.java @@ -0,0 +1,57 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.*; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Swap Equipment") +@Description("If the item can be swapped by right clicking with it in your hand. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example("allow {_item} to swap equipment") +@Example(""" + set {_component} to the equippable component of {_item} + prevent {_component} from swapping equipment on right click + """) +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +public class EffEquipCompSwapEquipment extends Effect implements EquippableExperimentSyntax { + + static { + Skript.registerEffect(EffEquipCompSwapEquipment.class, + "(allow|force) %equippablecomponents% to swap equipment [on right click|when right clicked]", + "(make|let) %equippablecomponents% swap equipment [on right click|when right clicked]", + "(block|prevent|disallow) %equippablecomponents% from swapping equipment [on right click|when right clicked]", + "make %equippablecomponents% not swap equipment [on right click|when right clicked]" + ); + } + + private Expression wrappers; + private boolean swappable; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + wrappers = (Expression) exprs[0]; + swappable = matchedPattern < 2; + return true; + } + + @Override + protected void execute(Event event) { + wrappers.stream(event).forEach(wrapper -> wrapper.editBuilder(builder -> builder.swappable(swappable))); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + if (swappable) + return "allow " + wrappers.toString(event, debug) + " to swap equipment"; + return "prevent " + wrappers.toString(event, debug) + " from swapping equipment"; + } +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompCameraOverlay.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompCameraOverlay.java new file mode 100644 index 00000000000..feef196d954 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompCameraOverlay.java @@ -0,0 +1,85 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.bukkitutil.NamespacedUtils; +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.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.util.ValidationResult; +import ch.njol.util.coll.CollectionUtils; +import net.kyori.adventure.key.Key; +import org.bukkit.NamespacedKey; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Camera Overlay") +@Description({ + "The camera overlay for the player when the item is equipped.", + "Example: The jack-o'-lantern view when having a jack-o'-lantern equipped as a helmet.", + "The camera overlay is represented as a namespaced key.", + "A namespaced key can be formatted as 'namespace:id' or 'id'. " + + "It can only contain one ':' to separate the namespace and the id. " + + "Only alphanumeric characters, periods, underscores, and dashes can be used.", + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended." +}) +@Example("set the camera overlay of {_item} to \"custom_overlay\"") +@Example(""" + set {_component} to the equippable component of {_item} + set the camera overlay of {_component} to "custom_overlay" + """) +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +public class ExprEquipCompCameraOverlay extends SimplePropertyExpression implements EquippableExperimentSyntax { + + static { + registerDefault(ExprEquipCompCameraOverlay.class, String.class, "camera overlay", "equippablecomponents"); + } + + @Override + public @Nullable String convert(EquippableWrapper wrapper) { + Key key = wrapper.getComponent().cameraOverlay(); + return key == null ? null : key.toString(); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.DELETE) + return CollectionUtils.array(String.class); + return null; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + NamespacedKey key = null; + if (delta != null && delta[0] instanceof String string) { + ValidationResult validationResult = NamespacedUtils.checkValidation(string); + String validationMessage = validationResult.message(); + if (!validationResult.valid()) { + error(validationMessage + ". " + NamespacedUtils.NAMEDSPACED_FORMAT_MESSAGE); + return; + } else if (validationMessage != null) { + warning(validationMessage); + } + key = validationResult.data(); + } + NamespacedKey finalKey = key; + + getExpr().stream(event).forEach(wrapper -> wrapper.editBuilder(builder -> builder.cameraOverlay(finalKey))); + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "camera overlay"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEntities.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEntities.java new file mode 100644 index 00000000000..c85f7aef778 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEntities.java @@ -0,0 +1,113 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.bukkitutil.EntityUtils; +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.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.entity.EntityData; +import ch.njol.skript.expressions.base.PropertyExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; +import io.papermc.paper.registry.set.RegistryKeySet; +import org.bukkit.entity.EntityType; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +@Name("Equippable Component - Allowed Entities") +@Description("The entities allowed to wear the item. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example("set the allowed entities of {_item} to a zombie and a skeleton") +@Example(""" + set {_component} to the equippable component of {_item} + clear the allowed entities of {_component} + """) +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +@SuppressWarnings({"rawtypes", "UnstableApiUsage"}) +public class ExprEquipCompEntities extends PropertyExpression implements EquippableExperimentSyntax { + + static { + registerDefault(ExprEquipCompEntities.class, EntityData.class, "allowed entities", "equippablecomponents"); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + setExpr((Expression) exprs[0]); + return true; + } + + @Override + protected EntityData @Nullable [] get(Event event, EquippableWrapper[] source) { + List types = new ArrayList<>(); + for (EquippableWrapper wrapper : source) { + Collection allowed = wrapper.getAllowedEntities(); + if (allowed.isEmpty()) + continue; + allowed.forEach(entityType -> types.add(EntityUtils.toSkriptEntityData(entityType))); + } + return types.toArray(EntityData[]::new); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + return switch (mode) { + case SET, DELETE, REMOVE, ADD -> CollectionUtils.array(EntityData[].class); + default -> null; + }; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + List converted = new ArrayList<>(); + if (delta != null) { + for (Object object : delta) { + if (object instanceof EntityData entityData) + converted.add(EntityUtils.toBukkitEntityType(entityData)); + } + } + RegistryKeySet keys = EquippableWrapper.convertAllowedEntities(converted); + + getExpr().stream(event).forEach(wrapper -> { + Collection allowed = wrapper.getAllowedEntities(); + List current = new ArrayList<>(allowed); + switch (mode) { + case SET -> { + current.clear(); + current.addAll(converted); + } + case ADD -> current.addAll(converted); + case REMOVE -> current.removeAll(converted); + case DELETE -> current.clear(); + } + wrapper.editBuilder(builder -> builder.allowedEntities(EquippableWrapper.convertAllowedEntities(current))); + }); + } + + @Override + public boolean isSingle() { + return false; + } + + @Override + public Class getReturnType() { + return EntityData.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "the allowed entities of " + getExpr().toString(event, debug); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEquipSound.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEquipSound.java new file mode 100644 index 00000000000..e1dc83d0d6c --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEquipSound.java @@ -0,0 +1,79 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.bukkitutil.SoundUtils; +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.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.coll.CollectionUtils; +import net.kyori.adventure.key.Key; +import org.bukkit.Registry; +import org.bukkit.Sound; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Equip Sound") +@Description("The sound to be played when the item is equipped. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example("set the equip sound of {_item} to \"entity.experience_orb.pickup\"") +@Example(""" + set {_component} to the equippable component of {_item} + set the equip sound of {_component} to "block.note_block.pling" + """) +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +public class ExprEquipCompEquipSound extends SimplePropertyExpression implements EquippableExperimentSyntax { + + static { + registerDefault(ExprEquipCompEquipSound.class, String.class, "equip sound", "equippablecomponents"); + } + + @Override + public @Nullable String convert(EquippableWrapper wrapper) { + return wrapper.getComponent().equipSound().toString(); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.DELETE) + return CollectionUtils.array(String.class); + return null; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + Sound enumSound = null; + if (delta != null) { + String soundString = (String) delta[0]; + enumSound = SoundUtils.getSound(soundString); + if (enumSound == null) { + error("Could not find a sound with the id '" + soundString + "'."); + return; + } + } + Key key; + if (enumSound != null) { + key = Registry.SOUNDS.getKey(enumSound); + } else { + key = null; + } + + getExpr().stream(event).forEach(wrapper -> wrapper.editBuilder(builder -> builder.equipSound(key))); + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "equip sound"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompModel.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompModel.java new file mode 100644 index 00000000000..316eb2d21ed --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompModel.java @@ -0,0 +1,84 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.bukkitutil.NamespacedUtils; +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.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.util.ValidationResult; +import ch.njol.util.coll.CollectionUtils; +import net.kyori.adventure.key.Key; +import org.bukkit.NamespacedKey; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Model") +@Description({ + "The model of the item when equipped.", + "The model key is represented as a namespaced key.", + "A namespaced key can be formatted as 'namespace:id' or 'id'. " + + "It can only contain one ':' to separate the namespace and the id. " + + "Only alphanumeric characters, periods, underscores, and dashes can be used.", + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended." +}) +@Example("set the equipped model key of {_item} to \"custom_model\"") +@Example(""" + set {_component} to the equippable component of {_item} + set the equipped model id of {_component} to "custom_model" + """) +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +public class ExprEquipCompModel extends SimplePropertyExpression implements EquippableExperimentSyntax { + + static { + registerDefault(ExprEquipCompModel.class, String.class, "equipped model (key|id)", "equippablecomponents"); + } + + @Override + public @Nullable String convert(EquippableWrapper wrapper) { + Key key = wrapper.getModel(); + return key == null ? null : key.toString(); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.DELETE) + return CollectionUtils.array(String.class); + return null; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + NamespacedKey key = null; + if (delta != null && delta[0] instanceof String string) { + ValidationResult validationResult = NamespacedUtils.checkValidation(string); + String validationMessage = validationResult.message(); + if (!validationResult.valid()) { + error(validationMessage + ". " + NamespacedUtils.NAMEDSPACED_FORMAT_MESSAGE); + return; + } else if (validationMessage != null) { + warning(validationMessage); + } + key = validationResult.data(); + } + NamespacedKey finalKey = key; + + getExpr().stream(event).forEach(wrapper -> wrapper.setModel(finalKey)); + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "equipped model key"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompShearSound.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompShearSound.java new file mode 100644 index 00000000000..c78edffcd80 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompShearSound.java @@ -0,0 +1,80 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.bukkitutil.SoundUtils; +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.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.coll.CollectionUtils; +import net.kyori.adventure.key.Key; +import org.bukkit.Registry; +import org.bukkit.Sound; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Shear Sound") +@Description("The sound to be played when the item is sheared off of an entity. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example("set the shear sound of {_item} to \"entity.experience_orb.pickup\"") +@Example(""" + set {_component} to the equippable component of {_item} + set the shear sound of {_component} to "block.note_block.pling" + """) +@RequiredPlugins("Minecraft 1.21.6+") +@Since("INSERT VERSION") +public class ExprEquipCompShearSound extends SimplePropertyExpression implements EquippableExperimentSyntax { + + static { + if (EquippableWrapper.HAS_SHEAR_SOUND) + registerDefault(ExprEquipCompShearSound.class, String.class, "shear[ed [off]] sound", "equippablecomponents"); + } + + @Override + public @Nullable String convert(EquippableWrapper wrapper) { + return wrapper.getComponent().shearSound().toString(); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.DELETE) + return CollectionUtils.array(String.class); + return null; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + Sound enumSound = null; + if (delta != null) { + String soundString = (String) delta[0]; + enumSound = SoundUtils.getSound(soundString); + if (enumSound == null) { + error("Could not find a sound with the id '" + soundString + "'."); + return; + } + } + Key key; + if (enumSound != null) { + key = Registry.SOUNDS.getKey(enumSound); + } else { + key = null; + } + + getExpr().stream(event).forEach(wrapper -> wrapper.editBuilder(builder -> builder.shearSound(key))); + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "shear sound"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompSlot.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompSlot.java new file mode 100644 index 00000000000..14c590d23e1 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompSlot.java @@ -0,0 +1,67 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +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.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.coll.CollectionUtils; +import io.papermc.paper.datacomponent.item.Equippable; +import org.bukkit.event.Event; +import org.bukkit.inventory.EquipmentSlot; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component - Equipment Slot") +@Description("The equipment slot an item can be equipped to. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example("set the equipment slot of {_item} to chest slot") +@Example(""" + set {_component} to the equippable component of {_item} + set the equipment slot of {_component} to boots slot + """) +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +public class ExprEquipCompSlot extends SimplePropertyExpression implements EquippableExperimentSyntax { + + static { + registerDefault(ExprEquipCompSlot.class, EquipmentSlot.class, "equipment slot", "equippablecomponents"); + } + + @Override + public @Nullable EquipmentSlot convert(EquippableWrapper wrapper) { + return wrapper.getComponent().slot(); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET) + return CollectionUtils.array(EquipmentSlot.class); + return null; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + assert delta != null; + EquipmentSlot providedSlot = (EquipmentSlot) delta[0]; + + getExpr().stream(event).forEach(wrapper -> { + Equippable changed = wrapper.clone(providedSlot); + wrapper.applyComponent(changed); + }); + } + + @Override + public Class getReturnType() { + return EquipmentSlot.class; + } + + @Override + protected String getPropertyName() { + return "equipment slot"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquippableComponent.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquippableComponent.java new file mode 100644 index 00000000000..a2181553983 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquippableComponent.java @@ -0,0 +1,112 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.aliases.ItemData; +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.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.util.ItemSource; +import ch.njol.skript.util.slot.Slot; +import ch.njol.util.coll.CollectionUtils; +import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.Equippable; +import org.bukkit.event.Event; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +@Name("Equippable Component") +@Description("The equippable component of an item. Any changes made to the equippable component will be present on the item. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Example(""" + set {_component} to the equippable component of {_item} + set the equipment slot of {_component} to helmet slot + """) +@Example("clear the equippable component of {_item}") +@Example("reset the equippable component of {_item}") +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +public class ExprEquippableComponent extends SimplePropertyExpression implements EquippableExperimentSyntax { + + static { + register(ExprEquippableComponent.class, EquippableWrapper.class, + "equippable component[s]", "slots/itemtypes"); + } + + @Override + public EquippableWrapper convert(Object object) { + ItemSource itemSource = null; + if (object instanceof ItemType itemType) { + itemSource = new ItemSource<>(itemType); + } else if (object instanceof Slot slot) { + itemSource = ItemSource.fromSlot(slot); + } + return itemSource == null ? null : new EquippableWrapper(itemSource); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + return switch (mode) { + case SET, DELETE, RESET -> CollectionUtils.array(EquippableWrapper.class); + default -> null; + }; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + Equippable component = null; + if (delta != null) + component = ((EquippableWrapper) delta[0]).getComponent(); + + for (Object object : getExpr().getArray(event)) { + if (object instanceof ItemType itemType) { + changeItemType(itemType, mode, component); + } else if (object instanceof Slot slot) { + changeSlot(slot, mode, component); + } + } + } + + public void changeItemType(ItemType itemType, ChangeMode mode, Equippable component) { + for (ItemData itemData : itemType) { + ItemStack dataStack = itemData.getStack(); + if (dataStack == null) + continue; + changeItemStack(dataStack, mode, component); + } + } + + public void changeSlot(Slot slot, ChangeMode mode, Equippable component) { + ItemStack itemStack = slot.getItem(); + if (itemStack == null) + return; + itemStack = changeItemStack(itemStack, mode, component); + slot.setItem(itemStack); + } + + @SuppressWarnings("UnstableApiUsage") + public ItemStack changeItemStack(ItemStack itemStack, ChangeMode mode, Equippable component) { + switch (mode) { + case SET -> itemStack.setData(DataComponentTypes.EQUIPPABLE, component); + case DELETE -> itemStack.unsetData(DataComponentTypes.EQUIPPABLE); + case RESET -> itemStack.resetData(DataComponentTypes.EQUIPPABLE); + } + return itemStack; + } + + @Override + public Class getReturnType() { + return EquippableWrapper.class; + } + + @Override + protected String getPropertyName() { + return "equippable component"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprSecBlankEquipComp.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprSecBlankEquipComp.java new file mode 100644 index 00000000000..b72a14cf06a --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprSecBlankEquipComp.java @@ -0,0 +1,108 @@ +package org.skriptlang.skript.bukkit.itemcomponents.equippable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.config.SectionNode; +import ch.njol.skript.doc.Description; +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.SectionExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.Trigger; +import ch.njol.skript.lang.TriggerItem; +import ch.njol.skript.lang.util.SectionUtils; +import ch.njol.skript.registrations.EventValues; +import ch.njol.skript.variables.Variables; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +@Name("New Equippable Component") +@Description("Gets a blank equippable component. " + + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work aas intended.") +@Example(""" + set {_component} to a blank equippable component + set the equippable component of {_item} to {_component} + """) +@Example(""" + set {_component} to a blank equippable component: + set the equipment slot to chest slot + """) +@RequiredPlugins("Minecraft 1.21.2+") +@Since("INSERT VERSION") +public class ExprSecBlankEquipComp extends SectionExpression implements EquippableExperimentSyntax { + + private static class BlankEquippableSectionEvent extends Event { + + private final EquippableWrapper wrapper; + + public BlankEquippableSectionEvent(EquippableWrapper wrapper) { + this.wrapper = wrapper; + } + + public EquippableWrapper getWrapper() { + return wrapper; + } + + @Override + public @NotNull HandlerList getHandlers() { + throw new IllegalStateException(); + } + } + + static { + Skript.registerExpression(ExprSecBlankEquipComp.class, EquippableWrapper.class, ExpressionType.SIMPLE, + "a (blank|empty) equippable component"); + EventValues.registerEventValue(BlankEquippableSectionEvent.class, EquippableWrapper.class, BlankEquippableSectionEvent::getWrapper); + } + + private Trigger trigger; + + @Override + public boolean init(Expression[] exprs, int pattern, Kleenean delayed, ParseResult result, @Nullable SectionNode node, @Nullable List triggerItems) { + if (node != null) { + AtomicBoolean isDelayed = new AtomicBoolean(false); + trigger = SectionUtils.loadLinkedCode("blank equippable component", (beforeLoading, afterLoading) -> + loadCode(node, "blank equippable component", beforeLoading, afterLoading, BlankEquippableSectionEvent.class) + ); + return trigger != null; + } + return true; + } + + @Override + protected EquippableWrapper @Nullable [] get(Event event) { + EquippableWrapper wrapper = EquippableWrapper.newInstance(); + if (trigger != null) { + BlankEquippableSectionEvent sectionEvent = new BlankEquippableSectionEvent(wrapper); + Variables.withLocalVariables(event, sectionEvent, () -> TriggerItem.walk(trigger, sectionEvent)); + } + return new EquippableWrapper[] {wrapper}; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return EquippableWrapper.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "a blank equippable component"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/generic/ExprItemCompCopy.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/generic/ExprItemCompCopy.java new file mode 100644 index 00000000000..d66d69c13c9 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/generic/ExprItemCompCopy.java @@ -0,0 +1,58 @@ +package org.skriptlang.skript.bukkit.itemcomponents.generic; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +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.skript.lang.ExpressionType; +import ch.njol.skript.lang.SyntaxStringBuilder; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.ComponentWrapper; + +@Name("Item Component - Copy") +@Description("Grab a copy of an item component of an item. Any changes made to the copy will not be present on the item.") +@Example("set {_component} to the item component copy of (the equippable component of {_item})") +@Since("INSERT VERSION") +@RequiredPlugins("Minecraft 1.21.2+") +@SuppressWarnings("rawtypes") +public class ExprItemCompCopy extends SimplePropertyExpression { + + static { + Skript.registerExpression(ExprItemCompCopy.class, ComponentWrapper.class, ExpressionType.PROPERTY, + "[the|a[n]] [item] component copy of %itemcomponents%", + "[the] [item] component copies of %itemcomponents%"); + } + + @Override + public @Nullable ComponentWrapper convert(ComponentWrapper wrapper) { + return wrapper.clone(); + } + + @Override + public Class getReturnType() { + return ComponentWrapper.class; + } + + @Override + protected String getPropertyName() { + return "the item component copies"; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug); + builder.append("the item component"); + if (isSingle()) { + builder.append("copy"); + } else { + builder.append("copies"); + } + builder.append("of", getExpr()); + return builder.toString(); + } + +} diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang index d050ec1fa9a..9b85a110200 100644 --- a/src/main/resources/lang/default.lang +++ b/src/main/resources/lang/default.lang @@ -2797,6 +2797,8 @@ types: villagercareerchangereason: villager career change reason¦s @a damagesource: damage source¦s @a damagetype: damage type¦s @a + itemcomponent: item component¦s @an + equippablecomponent: equippable component¦s @an # Skript weathertype: weather type¦s @a diff --git a/src/main/resources/lang/english.lang b/src/main/resources/lang/english.lang index 9350961b1b4..e5ee8862223 100644 --- a/src/main/resources/lang/english.lang +++ b/src/main/resources/lang/english.lang @@ -218,3 +218,8 @@ time: io exceptions: unknownhostexception: Cannot connect to %s accessdeniedexception: Access denied for %s + +# -- Misc -- +misc: + namespacedutils: + format: A namespaced key can be formatted as 'namespace:id' or 'id'. It can only contain one ':' to separate the namespace and the id. Only alphanumeric characters, periods, underscores, and dashes can be used. diff --git a/src/test/skript/tests/general/EquippableComponents.sk b/src/test/skript/tests/general/EquippableComponents.sk new file mode 100644 index 00000000000..00ac2c5a9d3 --- /dev/null +++ b/src/test/skript/tests/general/EquippableComponents.sk @@ -0,0 +1,275 @@ +options: + equipSound: "minecraft:item.armor.equip_generic" + slot: chest slot + model: "skript:model_key" + camera: "skript:camera_key" + allowed: a zombie and a skeleton + shearSound: "minecraft:block.note_block.pling" + +using equippable components + +test "equippable components - new" when running minecraft "1.21.2": + set {_component} to a blank equippable component + set the equip sound of {_component} to {@equipSound} + assert the equip sound of {_component} is {@equipSound} with "Equip sound of component was not set" + set the equipment slot of {_component} to {@slot} + assert the equipment slot of {_component} is {@slot} with "Equipment slot of component was not set" + set the equipped model key of {_component} to {@model} + assert the equipped model key of {_component} is {@model} with "Model of component was not set" + set the allowed entities of {_component} to {@allowed} + assert the allowed entities of {_component} is {@allowed} with "Allowed entities of component was not set" + set the camera overlay of {_component} to {@camera} + assert the camera overlay of {_component} is {@camera} with "Camera overlay of component was not set" + allow {_component} to swap equipment + assert {_component} can swap equipment with "Component should be swappable" + prevent {_component} from swapping equipment + assert {_component} can not swap equipment with "Component should not be swappable" + allow {_component} to be dispensed + assert {_component} can be dispensed with "Component should be dispensable" + prevent {_component} from being dispensed + assert {_component} can not be dispensed with "Component should not be dispensable" + make {_component} lose durability when hurt + assert {_component} will lose durability when hurt with "Component should lose durability when hurt" + make {_component} not lose durability when hurt + assert {_component} will not lose durability when hurt with "Component should not lose durability when hurt" + + parse if running minecraft "1.21.5": + allow {_component} to be equipped onto entities + assert {_component} can be equipped onto entities with "Component should equip onto entities" + prevent {_component} from being equipped onto entities + assert {_component} can not be equipped onto entities with "Component should not equip onto entities" + + parse if running minecraft "1.21.6": + set the shear sound of {_component} to {@shearSound} + assert the shear sound of {_component} is {@shearSound} with "Shear sound of component was not set" + allow {_component} to be sheared off + assert {_component} can be sheared off with "Component should be shearable" + prevent {_component} from being sheared off + assert {_component} can not be sheared off with "Component should not be shearable" + +test "equippable components - itemtype" when running minecraft "1.21.2": + set {_item} to a leather helmet (item type) + set the equip sound of {_item} to {@equipSound} + assert the equip sound of {_item} is {@equipSound} with "Equip sound of itemtype was not set" + set the equipment slot of {_item} to {@slot} + assert the equipment slot of {_item} is {@slot} with "Equipment slot of itemtype was not set" + set the equipped model key of {_item} to {@model} + assert the equipped model key of {_item} is {@model} with "Model of itemtype was not set" + set the allowed entities of {_item} to {@allowed} + assert the allowed entities of {_item} is {@allowed} with "Allowed entities of itemtype was not set" + set the camera overlay of {_item} to {@camera} + assert the camera overlay of {_item} is {@camera} with "Camera overlay of itemtype was not set" + allow {_item} to swap equipment + assert {_item} can swap equipment with "ItemType should be swappable" + prevent {_item} from swapping equipment + assert {_item} can not swap equipment with "ItemType should not be swappable" + allow {_item} to be dispensed + assert {_item} can be dispensed with "ItemType should be dispensable" + prevent {_item} from being dispensed + assert {_item} can not be dispensed with "ItemType should not be dispensable" + make {_item} lose durability when hurt + assert {_item} will lose durability when hurt with "ItemType should lose durability when hurt" + make {_item} not lose durability when hurt + assert {_item} will not lose durability when hurt with "ItemType should not lose durability when hurt" + + parse if running minecraft "1.21.5": + allow {_item} to be equipped onto entities + assert {_item} can be equipped onto entities with "ItemType should equip onto entities" + prevent {_item} from being equipped onto entities + assert {_item} can not be equipped onto entities with "ItemType should not equip onto entities" + + parse if running minecraft "1.21.6": + set the shear sound of {_item} to {@shearSound} + assert the shear sound of {_item} is {@shearSound} with "Shear sound of itemtype was not set" + allow {_item} to be sheared off + assert {_item} can be sheared off with "ItemType should be shearable" + prevent {_item} from being sheared off + assert {_item} can not be sheared off with "ItemType should not be shearable" + +test "equippable components - itemstack" when running minecraft "1.21.2": + set {_item} to a iron helmet (item stack) + set the equip sound of {_item} to {@equipSound} + assert the equip sound of {_item} is {@equipSound} with "Equip sound of itemstack was not set" + set the equipment slot of {_item} to {@slot} + assert the equipment slot of {_item} is {@slot} with "Equipment slot of itemstack was not set" + set the equipped model key of {_item} to {@model} + assert the equipped model key of {_item} is {@model} with "Model of itemstack was not set" + set the allowed entities of {_item} to {@allowed} + assert the allowed entities of {_item} is {@allowed} with "Allowed entities of itemstack was not set" + set the camera overlay of {_item} to {@camera} + assert the camera overlay of {_item} is {@camera} with "Camera overlay of itemstack was not set" + allow {_item} to swap equipment + assert {_item} can swap equipment with "ItemStack should be swappable" + prevent {_item} from swapping equipment + assert {_item} can not swap equipment with "ItemStack should not be swappable" + allow {_item} to be dispensed + assert {_item} can be dispensed with "ItemStack should be dispensable" + prevent {_item} from being dispensed + assert {_item} can not be dispensed with "ItemStack should not be dispensable" + make {_item} lose durability when hurt + assert {_item} will lose durability when hurt with "ItemStack should lose durability when hurt" + make {_item} not lose durability when hurt + assert {_item} will not lose durability when hurt with "ItemStack should not lose durability when hurt" + + parse if running minecraft "1.21.5": + allow {_item} to be equipped onto entities + assert {_item} can be equipped onto entities with "ItemStack should equip onto entities" + prevent {_item} from being equipped onto entities + assert {_item} can not be equipped onto entities with "ItemStack should not equip onto entities" + + parse if running minecraft "1.21.6": + set the shear sound of {_item} to {@shearSound} + assert the shear sound of {_item} is {@shearSound} with "Shear sound of itemstack was not set" + allow {_item} to be sheared off + assert {_item} can be sheared off with "ItemStack should be shearable" + prevent {_item} from being sheared off + assert {_item} can not be sheared off with "ItemStack should not be shearable" + +test "equippable components - copy" when running minecraft "1.21.2": + set {_component} to a blank equippable component + set the equip sound of {_component} to {@equipSound} + assert the equip sound of {_component} is {@equipSound} with "Equip sound of component was not set" + set the equipment slot of {_component} to {@slot} + assert the equipment slot of {_component} is {@slot} with "Equipment slot of component was not set" + set the equipped model key of {_component} to {@model} + assert the equipped model key of {_component} is {@model} with "Model of component was not set" + set the allowed entities of {_component} to {@allowed} + assert the allowed entities of {_component} is {@allowed} with "Allowed entities of component was not set" + set the camera overlay of {_component} to {@camera} + assert the camera overlay of {_component} is {@camera} with "Camera overlay of component was not set" + allow {_component} to swap equipment + assert {_component} can swap equipment with "Component should be swappable" + prevent {_component} from swapping equipment + assert {_component} can not swap equipment with "Component should not be swappable" + allow {_component} to be dispensed + assert {_component} can be dispensed with "Component should be dispensable" + prevent {_component} from being dispensed + assert {_component} can not be dispensed with "Component should not be dispensable" + make {_component} lose durability when hurt + assert {_component} will lose durability when hurt with "Component should lose durability when hurt" + make {_component} not lose durability when hurt + assert {_component} will not lose durability when hurt with "Component should not lose durability when hurt" + + parse if running minecraft "1.21.5": + allow {_component} to be equipped onto entities + assert {_component} can be equipped onto entities with "Component should equip onto entities" + prevent {_component} from being equipped onto entities + assert {_component} can not be equipped onto entities with "Component should not equip onto entities" + + parse if running minecraft "1.21.6": + set the shear sound of {_component} to {@shearSound} + assert the shear sound of {_component} is {@shearSound} with "Shear sound of component was not set" + allow {_component} to be sheared off + assert {_component} can be sheared off with "Component should be shearable" + prevent {_component} from being sheared off + assert {_component} can not be sheared off with "Component should not be shearable" + set {_original} to {_component} + + set {_copy} to a item component copy of {_original} + set the equip sound of {_copy} to "minecraft:item.armor.equip_diamond" + assert the equip sound of {_copy} is "minecraft:item.armor.equip_diamond" with "Equip sound of copy was not set" + assert the equip sound of {_original} is {@equipSound} with "Equip sound of original should not have changed" + set the equipment slot of {_copy} to helmet slot + assert the equipment slot of {_copy} is helmet slot with "Equipment slot of copy was not set" + assert the equipment slot of {_original} is {@slot} with "Equipment slot of original should not have changed" + set the equipped model key of {_copy} to "skript:model_key_copy" + assert the equipped model key of {_copy} is "skript:model_key_copy" with "Model of copy was not set" + assert the equipped model key of {_original} is {@model} with "Model of original should not have changed" + set the allowed entities of {_copy} to a villager and a zombie villager + assert the allowed entities of {_copy} is a villager and a zombie villager with "Allowed entities of copy was not set" + assert the allowed entities of {_original} is {@allowed} with "Allowed entities of original should not have changed" + set the camera overlay of {_copy} to "skript:camera_key_copy" + assert the camera overlay of {_copy} is "skript:camera_key_copy" with "Camera overlay of copy was not set" + assert the camera overlay of {_original} is {@camera} with "Camera overlay of original should not have changed" + allow {_copy} to swap equipment + assert {_copy} can swap equipment with "Copy should be swappable" + assert {_original} can not swap equipment with "Original should still be non swappable" + prevent {_copy} from swapping equipment + assert {_copy} can not swap equipment with "Copy should not be swappable" + allow {_copy} to be dispensed + assert {_copy} can be dispensed with "Copy should be dispensable" + assert {_original} can not be dispensed with "Original should still be non dispensable" + prevent {_copy} from being dispensed + assert {_copy} can not be dispensed with "Copy should not be dispensable" + make {_copy} lose durability when hurt + assert {_copy} will lose durability when hurt with "Copy should lose durability when hurt" + assert {_original} will not lose durability when hurt with "Original should still not lose durability" + make {_copy} not lose durability when hurt + assert {_copy} will not lose durability when hurt with "Copy should not lose durability when hurt" + + parse if running minecraft "1.21.5": + allow {_copy} to be equipped onto entities + assert {_copy} can be equipped onto entities with "Copy should equip onto entities" + assert {_original} can not be equipped onto entities with "Original should still not equip onto entities" + prevent {_copy} from being equipped onto entities + assert {_copy} can not be equipped onto entities with "Copy should not equip onto entities" + + parse if running minecraft "1.21.6": + set the shear sound of {_copy} to "minecraft:block.note_block.snare" + assert the shear sound of {_copy} is "minecraft:block.note_block.snare" with "Shear sound of copy was not set" + assert the shear sound of {_original} is {@shearSound} with "Shear sound of original should not have changed" + allow {_copy} to be sheared off + assert {_copy} can be sheared off with "Copy should be shearable" + assert {_original} can not be sheared off with "Original should still not be shearable" + prevent {_copy} from being sheared off + assert {_copy} can not be sheared off with "Copy should not be shearable" + +test "equippable components - slot" when running minecraft "1.21.2": + set {_gui} to a chest inventory with 1 row + set slot 1 of {_gui} to a diamond helmet + + set the equip sound of (slot 1 of {_gui}) to {@equipSound} + assert the equip sound of (slot 1 of {_gui}) is {@equipSound} with "Equip sound of slot was not set" + set the equipment slot of (slot 1 of {_gui}) to {@slot} + assert the equipment slot of (slot 1 of {_gui}) is {@slot} with "Equipment slot of slot was not set" + set the equipped model key of (slot 1 of {_gui}) to {@model} + assert the equipped model key of (slot 1 of {_gui}) is {@model} with "Model of slot was not set" + set the allowed entities of (slot 1 of {_gui}) to {@allowed} + assert the allowed entities of (slot 1 of {_gui}) is {@allowed} with "Allowed entities of slot was not set" + set the camera overlay of (slot 1 of {_gui}) to {@camera} + assert the camera overlay of (slot 1 of {_gui}) is {@camera} with "Camera overlay of slot was not set" + allow (slot 1 of {_gui}) to swap equipment + assert (slot 1 of {_gui}) can swap equipment with "Slot should be swappable" + prevent (slot 1 of {_gui}) from swapping equipment + assert (slot 1 of {_gui}) can not swap equipment with "Slot should not be swappable" + allow (slot 1 of {_gui}) to be dispensed + assert (slot 1 of {_gui}) can be dispensed with "Slot should be dispensable" + prevent (slot 1 of {_gui}) from being dispensed + assert (slot 1 of {_gui}) can not be dispensed with "Slot should not be dispensable" + make (slot 1 of {_gui}) lose durability when hurt + assert (slot 1 of {_gui}) will lose durability when hurt with "Slot should lose durability when hurt" + make (slot 1 of {_gui}) not lose durability when hurt + assert (slot 1 of {_gui}) will not lose durability when hurt with "Slot should not lose durability when hurt" + + parse if running minecraft "1.21.5": + allow (slot 1 of {_gui}) to be equipped onto entities + assert (slot 1 of {_gui}) can be equipped onto entities with "Slot should equip onto entities" + prevent (slot 1 of {_gui}) from being equipped onto entities + assert (slot 1 of {_gui}) can not be equipped onto entities with "Slot should not equip onto entities" + + parse if running minecraft "1.21.6": + set the shear sound of (slot 1 of {_gui}) to {@shearSound} + assert the shear sound of (slot 1 of {_gui}) is {@shearSound} with "Shear sound of slot was not set" + allow (slot 1 of {_gui}) to be sheared off + assert (slot 1 of {_gui}) can be sheared off with "Slot should be shearable" + prevent (slot 1 of {_gui}) from being sheared off + assert (slot 1 of {_gui}) can not be sheared off with "Slot should not be shearable" + +test "equippable components - source" when running minecraft "1.21.2": + set {_itemType} to a diamond helmet + set {_itemStack} to a netherite helmet (item stack) + + set {_gui} to a chest inventory with 1 row + set slot 1 of {_gui} to an iron helmet + + set {_typeComponent} to equippable component of {_itemType} + set {_stackComponent} to equippable component of {_itemStack} + set {_slotComponent} to equippable component of (slot 1 of {_gui}) + + set the equipment slot of {_typeComponent} to chest slot + set the equipment slot of {_stackComponent} to chest slot + set the equipment slot of {_slotComponent} to chest slot + + assert the equipment slot of {_itemType} is chest slot with "ItemType did not retain changes from component" + assert the equipment slot of {_itemStack} is chest slot with "ItemStack did not retain changes from component" + assert the equipment slot of (slot 1 of {_gui}) is chest slot with "Slot did not retain changes from component" From 285a2d34b2ed59f403ab53a08eef11ce46735e1a Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Sun, 7 Sep 2025 01:31:03 -0400 Subject: [PATCH 2/8] Initial Commit --- .../ch/njol/skript/registrations/Feature.java | 3 +- .../ConsumableExperimentSyntax.java | 20 +++ .../consumable/ConsumableModule.java | 115 ++++++++++++++++++ .../consumable/ConsumableWrapper.java | 87 +++++++++++++ .../consumable/ConsumeEffectType.java | 35 ++++++ .../elements/CondConsCompParticles.java | 39 ++++++ .../elements/EffConsCompParticles.java | 66 ++++++++++ .../consumable/elements/ExprApplyEffect.java | 43 +++++++ .../elements/ExprConsCompAnimation.java | 64 ++++++++++ .../elements/ExprConsCompEffects.java | 102 ++++++++++++++++ .../elements/ExprConsCompSeconds.java | 75 ++++++++++++ .../elements/ExprConsCompSound.java | 80 ++++++++++++ .../elements/ExprConsumableComponent.java | 110 +++++++++++++++++ .../elements/ExprSecBlankConsComp.java | 110 +++++++++++++++++ src/main/resources/lang/default.lang | 26 ++++ 15 files changed, 974 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableExperimentSyntax.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableModule.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableWrapper.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumeEffectType.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/CondConsCompParticles.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/EffConsCompParticles.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprApplyEffect.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompAnimation.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompEffects.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSeconds.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSound.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumableComponent.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprSecBlankConsComp.java diff --git a/src/main/java/ch/njol/skript/registrations/Feature.java b/src/main/java/ch/njol/skript/registrations/Feature.java index e233c12ac01..1331ca24983 100644 --- a/src/main/java/ch/njol/skript/registrations/Feature.java +++ b/src/main/java/ch/njol/skript/registrations/Feature.java @@ -18,7 +18,8 @@ public enum Feature implements Experiment { CATCH_ERRORS("catch runtime errors", LifeCycle.EXPERIMENTAL, "error catching [section]"), TYPE_HINTS("type hints", LifeCycle.EXPERIMENTAL, "[local variable] type hints"), DAMAGE_SOURCE("damage source", LifeCycle.EXPERIMENTAL, "damage source[s]"), - EQUIPPABLE_COMPONENTS("equippable components", LifeCycle.EXPERIMENTAL, "equippable components") + EQUIPPABLE_COMPONENTS("equippable components", LifeCycle.EXPERIMENTAL, "equippable components"), + CONSUMABLE_COMPONENTS("consumable components", LifeCycle.EXPERIMENTAL, "consumable components") ; private final String codeName; diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableExperimentSyntax.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableExperimentSyntax.java new file mode 100644 index 00000000000..5239ff03922 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableExperimentSyntax.java @@ -0,0 +1,20 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable; + +import ch.njol.skript.lang.SyntaxElement; +import ch.njol.skript.registrations.Feature; +import org.skriptlang.skript.lang.experiment.ExperimentData; +import org.skriptlang.skript.lang.experiment.SimpleExperimentalSyntax; + +/** + * Typed {@link SimpleExperimentalSyntax} for {@link SyntaxElement}s that require {@link Feature#CONSUMABLE_COMPONENTS}. + */ +public interface ConsumableExperimentSyntax extends SimpleExperimentalSyntax { + + ExperimentData EXPERIMENT_DATA = ExperimentData.createSingularData(Feature.CONSUMABLE_COMPONENTS); + + @Override + default ExperimentData getExperimentData() { + return EXPERIMENT_DATA; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableModule.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableModule.java new file mode 100644 index 00000000000..abeeeab45ca --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableModule.java @@ -0,0 +1,115 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable; + +import ch.njol.skript.Skript; +import ch.njol.skript.classes.ClassInfo; +import ch.njol.skript.classes.EnumClassInfo; +import ch.njol.skript.classes.Parser; +import ch.njol.skript.expressions.base.EventValueExpression; +import ch.njol.skript.lang.ParseContext; +import ch.njol.skript.registrations.Classes; +import ch.njol.skript.util.ItemSource; +import ch.njol.skript.util.slot.Slot; +import io.papermc.paper.datacomponent.item.Consumable; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; +import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ItemType; +import org.skriptlang.skript.addon.AddonModule; +import org.skriptlang.skript.addon.SkriptAddon; +import org.skriptlang.skript.lang.comparator.Comparators; +import org.skriptlang.skript.lang.comparator.Relation; +import org.skriptlang.skript.lang.converter.Converter; +import org.skriptlang.skript.lang.converter.Converters; + +import java.io.IOException; + +public class ConsumableModule implements AddonModule { + + @Override + public boolean canLoad(SkriptAddon addon) { + return Skript.classExists("io.papermc.paper.datacomponent.item.Consumable"); + } + + @Override + public void init(SkriptAddon addon) { + Classes.registerClass(new ClassInfo<>(ConsumableWrapper.class, "consumablecomponent") + .user("consumable ?components?") + .name("Consumable Component") + .description(""" + Represents a consumable component used for items. + NOTE: Consumable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) + .requiredPlugins("Minecraft 1.21.3+") + .since("INSERT VERSION") + .defaultExpression(new EventValueExpression<>(ConsumableWrapper.class)) + .parser(new Parser<>() { + @Override + public boolean canParse(ParseContext context) { + return false; + } + + @Override + public String toString(ConsumableWrapper wrapper, int flags) { + return "consumable component"; + } + + @Override + public String toVariableNameString(ConsumableWrapper wrapper) { + return "consumable component#" + wrapper.hashCode(); + } + }) + .after("itemstack", "itemtype", "slot") + ); + + Classes.registerClass(new ClassInfo<>(ConsumeEffect.class, "consumeeffect") + .user("consume ?effects?") + .name("Consume Effect") + .description("An effect applied to a consumable component for an item. The effect activates when the item is eaten.") + .requiredPlugins("Minecraft 1.21.3+") + .since("INSERT VERSION") + ); + + Classes.registerClass(new EnumClassInfo<>(ConsumeEffectType.class, "consumeeffecttype", "consume effect types") + .user("consume ?effect ?types?") + .name("Consume Effect Type") + .description(""" + Represents a consume effect type. + NOTE: A type is not the same as a consume effect and cannot be used to apply to a consumable component. + """) + .requiredPlugins("Minecraft 1.21.3+") + .since("INSERT VERSION") + ); + + Classes.registerClass(new EnumClassInfo<>(ItemUseAnimation.class, "itemuseanimation", "item use animations") + .user("item ?us(e|age) ?animations?") + .name("Item Use Animation") + .description("An animation for when an item is used.") + .requiredPlugins("Minecraft 1.21.3+") + .since("INSERT VERSION") + ); + + Converters.registerConverter(Consumable.class, ConsumableWrapper.class, ConsumableWrapper::new, Converter.NO_RIGHT_CHAINING); + Converters.registerConverter(ItemStack.class, ConsumableWrapper.class, ConsumableWrapper::new, Converter.NO_RIGHT_CHAINING); + Converters.registerConverter(ItemType.class, ConsumableWrapper.class, itemType -> new ConsumableWrapper(new ItemSource<>(itemType)), Converter.NO_RIGHT_CHAINING); + Converters.registerConverter(Slot.class, ConsumableWrapper.class, slot -> { + ItemSource itemSource = ItemSource.fromSlot(slot); + if (itemSource == null) + return null; + return new ConsumableWrapper(itemSource); + }, Converter.NO_RIGHT_CHAINING); + + Comparators.registerComparator(ConsumeEffect.class, ConsumeEffectType.class, (effect, type) -> + Relation.get(type.getEffectClass().isInstance(effect)) + ); + } + + @Override + public void load(SkriptAddon addon) { + try { + Skript.getAddonInstance().loadClasses("org.skriptlang.skript.bukkit.itemcomponents.consumable", "elements"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableWrapper.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableWrapper.java new file mode 100644 index 00000000000..7c1dcfdad9c --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableWrapper.java @@ -0,0 +1,87 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable; + +import ch.njol.skript.util.ItemSource; +import io.papermc.paper.datacomponent.DataComponentType.Valued; +import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.Consumable; +import io.papermc.paper.datacomponent.item.Consumable.Builder; +import org.bukkit.inventory.ItemStack; +import org.skriptlang.skript.bukkit.itemcomponents.ComponentWrapper; + +@SuppressWarnings("UnstableApiUsage") +public class ConsumableWrapper extends ComponentWrapper { + + public ConsumableWrapper(ItemStack itemStack) { + super(itemStack); + } + + public ConsumableWrapper(ItemSource itemSource) { + super(itemSource); + } + + public ConsumableWrapper(Consumable component) { + super(component); + } + + public ConsumableWrapper(Builder builder) { + super(builder); + } + + @Override + public Valued getDataComponentType() { + return DataComponentTypes.CONSUMABLE; + } + + @Override + protected Consumable getComponent(ItemStack itemStack) { + Consumable consumable = itemStack.getData(DataComponentTypes.CONSUMABLE); + if (consumable != null) + return consumable; + return Consumable.consumable().build(); + } + + @Override + protected Builder getBuilder(ItemStack itemStack) { + Consumable consumable = itemStack.getData(DataComponentTypes.CONSUMABLE); + if (consumable != null) + return consumable.toBuilder(); + return Consumable.consumable(); + } + + @Override + protected void setComponent(ItemStack itemStack, Consumable component) { + itemStack.setData(DataComponentTypes.CONSUMABLE, component); + } + + @Override + protected Builder toBuilder(Consumable component) { + return component.toBuilder(); + } + + @Override + public ConsumableWrapper clone() { + ConsumableWrapper clone = newWrapper(); + Consumable base = getComponent(); + return clone; + } + + @Override + public Consumable newComponent() { + return newBuilder().build(); + } + + @Override + public Builder newBuilder() { + return Consumable.consumable(); + } + + @Override + public ConsumableWrapper newWrapper() { + return newInstance(); + } + + public static ConsumableWrapper newInstance() { + return new ConsumableWrapper(Consumable.consumable().build()); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumeEffectType.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumeEffectType.java new file mode 100644 index 00000000000..0c2973a4e1e --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumeEffectType.java @@ -0,0 +1,35 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable; + +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect.ApplyStatusEffects; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect.ClearAllStatusEffects; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect.PlaySound; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect.RemoveStatusEffects; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect.TeleportRandomly; + +/** + * Types of {@link ConsumeEffect}s. + */ +@SuppressWarnings("UnstableApiUsage") +public enum ConsumeEffectType { + + APPLY_STATUS_EFFECTS(ApplyStatusEffects.class), + CLEAR_ALL_STATUS_EFFECTS(ClearAllStatusEffects.class), + PLAY_SOUND(PlaySound.class), + REMOVE_STATUS_EFFECTS(RemoveStatusEffects.class), + TELEPORT_RANDOMLY(TeleportRandomly.class); + + private final Class effectClass; + + ConsumeEffectType(Class effectClass) { + this.effectClass = effectClass; + } + + /** + * @return The {@link ConsumeEffect} class for this {@link ConsumeEffectType}. + */ + public Class getEffectClass() { + return effectClass; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/CondConsCompParticles.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/CondConsCompParticles.java new file mode 100644 index 00000000000..4ddd92bc0ae --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/CondConsCompParticles.java @@ -0,0 +1,39 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.doc.Description; +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 org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; + +@Name("Consumable Component - Has Particles") +@Description(""" + Whether an item has particles enabled when being consumed. + NOTE: Consumable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example(""" + if {_item} has consumption particles enabled: + disable the consume particles of {_item} + """) +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") +public class CondConsCompParticles extends PropertyCondition implements ConsumableExperimentSyntax { + + static { + register(CondConsCompParticles.class, PropertyType.HAVE, "consum(e|ption) particles [enabled]", "consumablecomponents"); + } + + @Override + public boolean check(ConsumableWrapper wrapper) { + return wrapper.getComponent().hasConsumeParticles(); + } + + @Override + protected String getPropertyName() { + return "consume particles"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/EffConsCompParticles.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/EffConsCompParticles.java new file mode 100644 index 00000000000..61316905db6 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/EffConsCompParticles.java @@ -0,0 +1,66 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +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.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; + +@Name("Consumable Component - Particles") +@Description(""" + Whether an item should have particles enabled when being consumed. + NOTE: Consumable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example(""" + if {_item} does not have consumption particles enabled: + enable the consumption particles of {_item} + """) +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") +public class EffConsCompParticles extends Effect implements ConsumableExperimentSyntax { + + static { + Skript.registerEffect(EffConsCompParticles.class, + "(enable|:disable) [the] comsum(e|ption) particle[s] [effect[s]] of %consumablecomponents%"); + } + + private Expression wrappers; + private boolean enable; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + wrappers = (Expression) exprs[0]; + enable = !parseResult.hasTag("disable"); + return false; + } + + @Override + protected void execute(Event event) { + wrappers.stream(event).forEach(wrapper -> + wrapper.editBuilder(builder -> builder.hasConsumeParticles(enable))); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug); + if (enable) { + builder.append("enable"); + } else { + builder.append("disable"); + } + builder.append("the consume particle effects of", wrappers); + return builder.toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprApplyEffect.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprApplyEffect.java new file mode 100644 index 00000000000..075cbcac013 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprApplyEffect.java @@ -0,0 +1,43 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; + +public class ExprApplyEffect extends SimpleExpression implements ConsumableExperimentSyntax { + + static { + + } + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + return false; + } + + @Override + protected ConsumeEffect @Nullable [] get(Event event) { + return new ConsumeEffect[0]; + } + + @Override + public boolean isSingle() { + return false; + } + + @Override + public Class getReturnType() { + return ConsumeEffect.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return ""; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompAnimation.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompAnimation.java new file mode 100644 index 00000000000..a071ba6f112 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompAnimation.java @@ -0,0 +1,64 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +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.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.coll.CollectionUtils; +import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; + +@Name("Consumable Component - Animation") +@Description(""" + The animation that plays when the item is being consumed. + NOTE: Consumable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example("set {_anim} to the consumption animation of {_item}") +@Example("set the consumption animation of {_item} to drink animation") +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") +@SuppressWarnings("UnstableApiUsage") +public class ExprConsCompAnimation extends SimplePropertyExpression implements ConsumableExperimentSyntax { + + static { + registerDefault(ExprConsCompAnimation.class, ItemUseAnimation.class, "consum(e|ption) animation", "consumablecomponents"); + } + + @Override + public @Nullable ItemUseAnimation convert(ConsumableWrapper wrapper) { + return wrapper.getComponent().animation(); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET) + return CollectionUtils.array(ItemUseAnimation.class); + return null; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + assert delta != null; + ItemUseAnimation animation = (ItemUseAnimation) delta[0]; + + getExpr().stream(event).forEach(wrapper -> + wrapper.editBuilder(builder -> builder.animation(animation))); + } + + @Override + public Class getReturnType() { + return ItemUseAnimation.class; + } + + @Override + protected String getPropertyName() { + return "consume animation"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompEffects.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompEffects.java new file mode 100644 index 00000000000..fa2230ffa7e --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompEffects.java @@ -0,0 +1,102 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +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.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.PropertyExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; + +import java.util.ArrayList; +import java.util.List; + +@Name("Consumable Component - Consume Effects") +@Description(""" + The consume effects that should activate when the item is consumed. + NOTE: Consumable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example("set {_effects::*} to the consumption effects of {_item}") +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") +@SuppressWarnings("UnstableApiUsage") +public class ExprConsCompEffects extends PropertyExpression implements ConsumableExperimentSyntax { + + static { + registerDefault(ExprConsCompEffects.class, ConsumeEffect.class, "consum(e|ption) effects", "consumablecomponents"); + } + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + setExpr((Expression) exprs[0]); + return true; + } + + @Override + protected ConsumeEffect[] get(Event event, ConsumableWrapper[] source) { + List effects = new ArrayList<>(); + for (ConsumableWrapper wrapper : source) { + effects.addAll(wrapper.getComponent().consumeEffects()); + } + return effects.toArray(ConsumeEffect[]::new); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + return switch (mode) { + case SET, DELETE, REMOVE, ADD -> CollectionUtils.array(ConsumeEffect[].class); + default -> null; + }; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + List provided = new ArrayList<>(); + if (delta != null) { + for (Object object : delta) { + if (object instanceof ConsumeEffect effect) + provided.add(effect); + } + } + + getExpr().stream(event).forEach(wrapper -> { + List current = new ArrayList<>(wrapper.getComponent().consumeEffects()); + switch (mode) { + case SET -> { + current.clear(); + current.addAll(provided); + } + case ADD -> current.addAll(provided); + case REMOVE -> current.removeAll(provided); + case DELETE -> current.clear(); + } + wrapper.editBuilder(builder -> builder.effects(current)); + }); + } + + @Override + public boolean isSingle() { + return false; + } + + @Override + public Class getReturnType() { + return ConsumeEffect.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "the consume effects of " + getExpr().toString(event, debug); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSeconds.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSeconds.java new file mode 100644 index 00000000000..d92260b3bf2 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSeconds.java @@ -0,0 +1,75 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +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.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.util.Timespan; +import ch.njol.skript.util.Timespan.TimePeriod; +import ch.njol.util.Math2; +import ch.njol.util.coll.CollectionUtils; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; + +import java.time.temporal.ChronoUnit; + +@Name("Consumable Component - Consume Time") +@Description(""" + The time it takes for an item to be consumed. + NOTE: Consumable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example("set the consumption time of {_item} to 5 seconds") +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") +public class ExprConsCompSeconds extends SimplePropertyExpression implements ConsumableExperimentSyntax { + + static { + registerDefault(ExprConsCompSeconds.class, Timespan.class, "consum(e|ption) time", "consumablecomponents"); + } + + @Override + public @Nullable Timespan convert(ConsumableWrapper wrapper) { + float seconds = wrapper.getComponent().consumeSeconds(); + return new Timespan(TimePeriod.SECOND, (long) seconds); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + return switch (mode) { + case SET, DELETE, REMOVE, ADD -> CollectionUtils.array(Timespan.class); + default -> null; + }; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + float seconds = delta == null ? 0f : ((Timespan) delta[0]).get(ChronoUnit.SECONDS); + float finalSeconds = Math2.fit(0, seconds, Float.MAX_VALUE); + getExpr().stream(event).forEach(wrapper -> { + float current = wrapper.getComponent().consumeSeconds(); + switch (mode) { + case SET, DELETE -> current = finalSeconds; + case ADD -> current = Math2.fit(0, current + finalSeconds, Float.MAX_VALUE); + case REMOVE -> current = Math2.fit(0, current - finalSeconds, Float.MAX_VALUE); + } + float finalCurrent = current; + wrapper.editBuilder(builder -> builder.consumeSeconds(finalCurrent)); + }); + } + + @Override + public Class getReturnType() { + return Timespan.class; + } + + @Override + protected String getPropertyName() { + return "consume time"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSound.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSound.java new file mode 100644 index 00000000000..d31c3088094 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSound.java @@ -0,0 +1,80 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +import ch.njol.skript.bukkitutil.SoundUtils; +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.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.coll.CollectionUtils; +import net.kyori.adventure.key.Key; +import org.bukkit.Registry; +import org.bukkit.Sound; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; + +@Name("Consumable Component - Consume Sound") +@Description(""" + The sound to be played when the item is being consumed. + NOTE: Consumable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example("set {_sound} to the consumption sound of {_item}") +@Example("set the consumption sound of {_item} to \"entity.sheep.ambient\"") +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") +public class ExprConsCompSound extends SimplePropertyExpression implements ConsumableExperimentSyntax { + + static { + registerDefault(ExprConsCompSound.class, String.class, "consum(e|ption) sound", "consumablecomponents"); + } + + @Override + public @Nullable String convert(ConsumableWrapper wrapper) { + return wrapper.getComponent().sound().toString(); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.DELETE) + return CollectionUtils.array(String.class); + return null; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + Sound enumSound = null; + if (delta != null) { + String string = (String) delta[0]; + enumSound = SoundUtils.getSound(string); + if (enumSound == null) { + error("Could not find a sound with the id '" + string + "'."); + return; + } + } + + Key key; + if (enumSound != null) { + key = Registry.SOUNDS.getKey(enumSound); + } else { + key = null; + } + + getExpr().stream(event).forEach(wrapper -> + wrapper.editBuilder(builder -> builder.sound(key))); + } + + @Override + public Class getReturnType() { + return String.class; + } + + @Override + protected String getPropertyName() { + return "consume sound"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumableComponent.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumableComponent.java new file mode 100644 index 00000000000..a9d828fe2a6 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumableComponent.java @@ -0,0 +1,110 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +import ch.njol.skript.aliases.ItemData; +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.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.skript.util.ItemSource; +import ch.njol.skript.util.slot.Slot; +import ch.njol.util.coll.CollectionUtils; +import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.Consumable; +import org.bukkit.event.Event; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; + +@Name("Consumable Component") +@Description(""" + The consumable component of an item. Any changes made to the consumable component will be present on the item. + NOTE: Consumable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example("clear the consumable component of {_item}") +@Example("reset the consumable component of {_item}") +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") +@SuppressWarnings("UnstableApiUsage") +public class ExprConsumableComponent extends SimplePropertyExpression implements ConsumableExperimentSyntax { + + static { + register(ExprConsumableComponent.class, ConsumableWrapper.class, "consumable component[s]", "slots/itemtypes"); + } + + @Override + public @Nullable ConsumableWrapper convert(Object object) { + ItemSource itemSource = null; + if (object instanceof ItemType itemType) { + itemSource = new ItemSource<>(itemType); + } else if (object instanceof Slot slot) { + itemSource = ItemSource.fromSlot(slot); + } + return itemSource == null ? null : new ConsumableWrapper(itemSource); + } + + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + return switch (mode) { + case SET, DELETE, RESET -> CollectionUtils.array(ConsumableWrapper.class); + default -> null; + }; + } + + @Override + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + Consumable component = null; + if (delta != null) + component = ((ConsumableWrapper) delta[0]).getComponent(); + + for (Object object : getExpr().getArray(event)) { + if (object instanceof ItemType itemType) { + changeItemType(itemType, mode, component); + } else if (object instanceof Slot slot) { + changeSlot(slot, mode, component); + } + } + } + + public void changeItemType(ItemType itemType, ChangeMode mode, Consumable component) { + for (ItemData itemData : itemType) { + ItemStack dataStack = itemData.getStack(); + if (dataStack == null) + continue; + changeItemStack(dataStack, mode, component); + } + } + + public void changeSlot(Slot slot, ChangeMode mode, Consumable component) { + ItemStack itemStack = slot.getItem(); + if (itemStack == null) + return; + itemStack = changeItemStack(itemStack, mode, component); + slot.setItem(itemStack); + } + + @SuppressWarnings("UnstableApiUsage") + public ItemStack changeItemStack(ItemStack itemStack, ChangeMode mode, Consumable component) { + switch (mode) { + case SET -> itemStack.setData(DataComponentTypes.CONSUMABLE, component); + case DELETE -> itemStack.unsetData(DataComponentTypes.CONSUMABLE); + case RESET -> itemStack.resetData(DataComponentTypes.CONSUMABLE); + } + return itemStack; + } + + @Override + public Class getReturnType() { + return ConsumableWrapper.class; + } + + @Override + protected String getPropertyName() { + return "consumable component"; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprSecBlankConsComp.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprSecBlankConsComp.java new file mode 100644 index 00000000000..211cc49208a --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprSecBlankConsComp.java @@ -0,0 +1,110 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.config.SectionNode; +import ch.njol.skript.doc.Description; +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.SectionExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.Trigger; +import ch.njol.skript.lang.TriggerItem; +import ch.njol.skript.lang.util.SectionUtils; +import ch.njol.skript.registrations.EventValues; +import ch.njol.skript.variables.Variables; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +@Name("Blank Consumable Component") +@Description(""" + Gets a blank consumable component. + NOTE: Consumable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example(""" + set {_component} to a blank consumable component + set the consumable component of {_item} to {_component} + """) +@Example(""" + set {_component} to a blank consumable component: + set the consumption time to 1 second + """) +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") +public class ExprSecBlankConsComp extends SectionExpression implements ConsumableExperimentSyntax { + + private static class BlankConsumableSectionEvent extends Event { + + private final ConsumableWrapper wrapper; + + public BlankConsumableSectionEvent(ConsumableWrapper wrapper) { + this.wrapper = wrapper; + } + + public ConsumableWrapper getWrapper() { + return wrapper; + } + + @Override + public @NotNull HandlerList getHandlers() { + throw new IllegalStateException(); + } + } + + static { + Skript.registerExpression(ExprSecBlankConsComp.class, ConsumableWrapper.class, ExpressionType.SIMPLE, + "a (blank|empty) consumable component"); + EventValues.registerEventValue(BlankConsumableSectionEvent.class, ConsumableWrapper.class, BlankConsumableSectionEvent::getWrapper); + } + + private Trigger trigger; + + @Override + public boolean init(Expression[] exprs, int pattern, Kleenean delayed, ParseResult result, @Nullable SectionNode node, @Nullable List triggerItems) { + if (node != null) { + AtomicBoolean isDelayed = new AtomicBoolean(false); + trigger = SectionUtils.loadLinkedCode("blank consumable component", (beforeLoading, afterLoading) -> + loadCode(node, "blank consumable component", beforeLoading, afterLoading, BlankConsumableSectionEvent.class) + ); + return trigger != null; + } + return true; + } + + @Override + protected ConsumableWrapper @Nullable [] get(Event event) { + ConsumableWrapper wrapper = ConsumableWrapper.newInstance(); + if (trigger != null) { + BlankConsumableSectionEvent sectionEvent = new BlankConsumableSectionEvent(wrapper); + Variables.withLocalVariables(event, sectionEvent, () -> TriggerItem.walk(trigger, sectionEvent)); + } + return new ConsumableWrapper[] {wrapper}; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return ConsumableWrapper.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "a blank consumable component"; + } + +} diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang index 9b85a110200..bec6bd6d6ee 100644 --- a/src/main/resources/lang/default.lang +++ b/src/main/resources/lang/default.lang @@ -2680,6 +2680,28 @@ damage types: wither: wither wither_skull: wither skull +# Consume Effect Types +consume effect types: + apply_status_effects: apply status effects + clear_all_status_effects: clear all status effects, clear status effects + play_sound: play sound + remove_status_effects: remove status effects + teleport_randomly: teleport randomly + +# Item Use Animations +item use animations: + block: block animation + bow: bow animation + brush: brush animation + bundle: bundle animation + crossbow: crossbow animation + drink: drink animation + eat: eat animation + none: none, no animation + spear: spear animation + spyglass: spyglass animation + toot_horn: toot horn animation + # -- Boolean -- boolean: true: @@ -2799,6 +2821,10 @@ types: damagetype: damage type¦s @a itemcomponent: item component¦s @an equippablecomponent: equippable component¦s @an + consumablecomponent: consumable component¦s @a + consumeeffect: consume effect¦s @a + consumeeffecttype: consume effect type¦s @a + itemuseanimation: item use animation¦s @an # Skript weathertype: weather type¦s @a From 6af0787fe0026ea4118ae75ec9f8f189f5134995 Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Sun, 7 Sep 2025 13:30:02 -0400 Subject: [PATCH 3/8] Consume Effects --- .../elements/ExprConsumeEffectApply.java | 82 +++++++++++++++++++ .../elements/ExprConsumeEffectRemove.java | 72 ++++++++++++++++ .../elements/ExprConsumeEffectSound.java | 79 ++++++++++++++++++ .../elements/ExprConsumeEffectTeleport.java | 81 ++++++++++++++++++ ...Effect.java => LitConsumeEffectClear.java} | 31 +++---- 5 files changed, 326 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectRemove.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectSound.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectTeleport.java rename src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/{ExprApplyEffect.java => LitConsumeEffectClear.java} (53%) diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java new file mode 100644 index 00000000000..84c6ef9c4c5 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java @@ -0,0 +1,82 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.skript.lang.simplification.SimplifiedLiteral; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import ch.njol.util.Math2; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; +import org.bukkit.event.Event; +import org.bukkit.potion.PotionEffect; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; + +import java.util.ArrayList; +import java.util.List; + +@SuppressWarnings("UnstableApiUsage") +public class ExprConsumeEffectApply extends SimpleExpression implements ConsumableExperimentSyntax { + + static { + Skript.registerExpression(ExprConsumeEffectApply.class, ConsumeEffect.class, ExpressionType.COMBINED, + "[a] consume effect to apply %potioneffects% with [a] probability of %number%"); + } + + private Expression effects; + private Expression probability; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + effects = (Expression) exprs[0]; + //noinspection unchecked + probability = (Expression) exprs[1]; + return true; + } + + @Override + protected ConsumeEffect @Nullable [] get(Event event) { + List potions = new ArrayList<>(effects.stream(event).toList()); + if (potions.isEmpty()) + return null; + + Number number = this.probability.getSingle(event); + if (number == null) + return null; + float probability = Math2.fit(0, number.floatValue(), 100) / 100; + + ConsumeEffect effect = ConsumeEffect.applyStatusEffects(potions, probability); + return new ConsumeEffect[] {effect}; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return ConsumeEffect.class; + } + + @Override + public Expression simplify() { + if (effects instanceof Literal && probability instanceof Literal) + return SimplifiedLiteral.fromExpression(this); + return this; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return new SyntaxStringBuilder(event, debug) + .append("a consume effect to apply", effects) + .append("with a probability of", probability) + .toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectRemove.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectRemove.java new file mode 100644 index 00000000000..7316b5170e4 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectRemove.java @@ -0,0 +1,72 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.skript.lang.simplification.SimplifiedLiteral; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; +import org.bukkit.event.Event; +import org.bukkit.potion.PotionEffectType; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; + +import java.util.ArrayList; +import java.util.List; + +@SuppressWarnings("UnstableApiUsage") +public class ExprConsumeEffectRemove extends SimpleExpression implements ConsumableExperimentSyntax { + + static { + Skript.registerExpression(ExprConsumeEffectRemove.class, ConsumeEffect.class, ExpressionType.PROPERTY, + "[a] consume effect to remove %potioneffecttypes%"); + } + + private Expression effectTypes; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + effectTypes = (Expression) exprs[0]; + return true; + } + + @Override + protected ConsumeEffect @Nullable [] get(Event event) { + List types = new ArrayList<>(effectTypes.stream(event).toList()); + if (types.isEmpty()) + return null; + + + return new ConsumeEffect[0] ; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return ConsumeEffect.class; + } + + @Override + public Expression simplify() { + if (effectTypes instanceof Literal) + return SimplifiedLiteral.fromExpression(this); + return this; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return new SyntaxStringBuilder(event, debug) + .append("a consume effect to remove", effectTypes) + .toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectSound.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectSound.java new file mode 100644 index 00000000000..eb5a934ce70 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectSound.java @@ -0,0 +1,79 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.bukkitutil.SoundUtils; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.skript.lang.simplification.SimplifiedLiteral; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; +import net.kyori.adventure.key.Key; +import org.bukkit.Registry; +import org.bukkit.Sound; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; + +@SuppressWarnings("UnstableApiUsage") +public class ExprConsumeEffectSound extends SimpleExpression implements ConsumableExperimentSyntax { + + static { + Skript.registerExpression(ExprConsumeEffectSound.class, ConsumeEffect.class, ExpressionType.PROPERTY, + "[a] consume effect to play [[the] sound] %string%"); + } + + private Expression string; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + string = (Expression) exprs[0]; + return true; + } + + @Override + protected ConsumeEffect @Nullable [] get(Event event) { + String string = this.string.getSingle(event); + if (string == null) + return null; + + Sound sound = SoundUtils.getSound(string); + if (sound == null) { + error("Could not find a sound with the id '" + string + "'."); + return null; + } + Key key = Registry.SOUNDS.getKey(sound); + ConsumeEffect effect = ConsumeEffect.playSoundConsumeEffect(key); + + return new ConsumeEffect[] {effect}; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return ConsumeEffect.class; + } + + @Override + public Expression simplify() { + if (string instanceof Literal) + return SimplifiedLiteral.fromExpression(this); + return this; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return new SyntaxStringBuilder(event, debug) + .append("a consume effect to play the sound", string) + .toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectTeleport.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectTeleport.java new file mode 100644 index 00000000000..e396de1dbb7 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectTeleport.java @@ -0,0 +1,81 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; +import ch.njol.skript.lang.simplification.SimplifiedLiteral; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; + +@SuppressWarnings("UnstableApiUsage") +public class ExprConsumeEffectTeleport extends SimpleExpression implements ConsumableExperimentSyntax { + + static { + Skript.registerExpression(ExprConsumeEffectTeleport.class, ConsumeEffect.class, ExpressionType.PROPERTY, + "[a] consume effect to teleport randomly in [a] (radius|:diameter) of %number%"); + } + + private Expression number; + private boolean isDiameter; + + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + number = (Expression) exprs[0]; + isDiameter = parseResult.hasTag("diameter"); + return true; + } + + @Override + protected ConsumeEffect @Nullable [] get(Event event) { + Number number = this.number.getSingle(event); + if (number == null) + return null; + + float diameter = Math.abs(number.floatValue()); + if (!isDiameter) + diameter *= 2; + + ConsumeEffect effect = ConsumeEffect.teleportRandomlyEffect(diameter); + return new ConsumeEffect[] {effect}; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return ConsumeEffect.class; + } + + @Override + public Expression simplify() { + if (number instanceof Literal) + return SimplifiedLiteral.fromExpression(this); + return this; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + SyntaxStringBuilder builder = new SyntaxStringBuilder(event, debug); + builder.append("a consume effect to teleport randomly in a"); + if (isDiameter) { + builder.append("diameter"); + } else { + builder.append("radius"); + } + builder.append("of", number); + return builder.toString(); + } + + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprApplyEffect.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java similarity index 53% rename from src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprApplyEffect.java rename to src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java index 075cbcac013..dcfb6da3151 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprApplyEffect.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java @@ -1,43 +1,36 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; +import ch.njol.skript.Skript; import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.skript.lang.util.SimpleLiteral; import ch.njol.util.Kleenean; import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; -public class ExprApplyEffect extends SimpleExpression implements ConsumableExperimentSyntax { +@SuppressWarnings("UnstableApiUsage") +public class LitConsumeEffectClear extends SimpleLiteral implements ConsumableExperimentSyntax { static { - - } - - @Override - public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - return false; + Skript.registerExpression(LitConsumeEffectClear.class, ConsumeEffect.class, ExpressionType.SIMPLE, + "[a] consume effect to clear all potion effects"); } - @Override - protected ConsumeEffect @Nullable [] get(Event event) { - return new ConsumeEffect[0]; + public LitConsumeEffectClear() { + super(ConsumeEffect.clearAllStatusEffects(), false); } @Override - public boolean isSingle() { - return false; - } - - @Override - public Class getReturnType() { - return ConsumeEffect.class; + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + return true; } @Override public String toString(@Nullable Event event, boolean debug) { - return ""; + return "a consume effect to clear all potion effects"; } } From 11473721de250ddadd8a381812736b126d504ecf Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Sun, 7 Sep 2025 13:32:22 -0400 Subject: [PATCH 4/8] # Conflicts: # src/main/java/ch/njol/skript/registrations/Feature.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentWrapper.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableModule.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableWrapper.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDamage.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDispensable.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompInteract.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompShearable.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompSwapEquipment.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDamageable.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDispensable.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompInteract.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompShearable.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompSwapEquipment.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompCameraOverlay.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEntities.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEquipSound.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompModel.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompShearSound.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompSlot.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquippableComponent.java # src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprSecBlankEquipComp.java # src/main/resources/lang/default.lang --- .../bukkit/itemcomponents/ComponentUtils.java | 47 +++++++++++++++++++ .../itemcomponents/ComponentWrapper.java | 4 +- .../equippable/EquippableModule.java | 5 +- .../equippable/EquippableWrapper.java | 12 ++--- .../elements/CondEquipCompDamage.java | 6 ++- .../elements/CondEquipCompDispensable.java | 6 ++- .../elements/CondEquipCompInteract.java | 6 ++- .../elements/CondEquipCompShearable.java | 6 ++- .../elements/CondEquipCompSwapEquipment.java | 10 ++-- .../elements/EffEquipCompDamageable.java | 6 ++- .../elements/EffEquipCompDispensable.java | 6 ++- .../elements/EffEquipCompInteract.java | 6 ++- .../elements/EffEquipCompShearable.java | 6 ++- .../elements/EffEquipCompSwapEquipment.java | 6 ++- .../elements/ExprEquipCompCameraOverlay.java | 18 +++---- .../elements/ExprEquipCompEntities.java | 8 ++-- .../elements/ExprEquipCompEquipSound.java | 6 ++- .../elements/ExprEquipCompModel.java | 16 +++---- .../elements/ExprEquipCompShearSound.java | 6 ++- .../elements/ExprEquipCompSlot.java | 6 ++- .../elements/ExprEquippableComponent.java | 6 ++- .../elements/ExprSecBlankEquipComp.java | 8 ++-- 22 files changed, 140 insertions(+), 66 deletions(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentUtils.java diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentUtils.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentUtils.java new file mode 100644 index 00000000000..008b04b851d --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentUtils.java @@ -0,0 +1,47 @@ +package org.skriptlang.skript.bukkit.itemcomponents; + +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.set.RegistryKeySet; +import io.papermc.paper.registry.set.RegistrySet; +import org.bukkit.Keyed; +import org.bukkit.Registry; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; + +/** + * Utility class for components. + */ +@SuppressWarnings("UnstableApiUsage") +public class ComponentUtils { + + /** + * Convert a {@link RegistryKeySet} to a {@link Collection}. + * @param registryKeySet The {@link RegistryKeySet} to convert. + * @param registry The {@link Registry} type of {@code registryKeySet} + * @return The converted {@link Collection}. + */ + public static Collection registryKeySetToCollection( + @Nullable RegistryKeySet registryKeySet, + Registry registry + ) { + if (registryKeySet == null || registryKeySet.isEmpty()) + return Collections.emptyList(); + return registryKeySet.resolve(registry); + } + + /** + * Convert a {@link Collection} to a {@link RegistryKeySet}. + * @param collection The {@link Collection} to convert. + * @param registryKey The {@link RegistryKey} type to convert to. + * @return The converted {@link RegistryKeySet}. + */ + public static RegistryKeySet collectionToRegistryKeySet( + Collection collection, + RegistryKey registryKey + ) { + return RegistrySet.keySetFromValues(registryKey, collection); + } + +} \ No newline at end of file diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentWrapper.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentWrapper.java index 87cbe87498b..c92ad8b261d 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentWrapper.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ComponentWrapper.java @@ -82,7 +82,7 @@ public B getBuilder() { if (itemSource != null) { return this.getBuilder(itemSource.getItemStack()); } - return toBuilder(component); + return getBuilder(component); } /** @@ -175,7 +175,7 @@ public void editBuilder(Consumer consumer) { * @param component The component. * @return The builder. */ - protected abstract B toBuilder(T component); + protected abstract B getBuilder(T component); /** * Returns a clone of this {@link ComponentWrapper}. diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableModule.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableModule.java index c1f1887295f..30de3b57433 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableModule.java @@ -30,7 +30,10 @@ public void init(SkriptAddon addon) { Classes.registerClass(new ClassInfo<>(EquippableWrapper.class, "equippablecomponent") .user("equippable ?components?") .name("Equippable Components") - .description("Represents an equippable component used for items.") + .description(""" + Represents an equippable component used for items. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) .requiredPlugins("Minecraft 1.21.2+") .since("INSERT VERSION") .defaultExpression(new EventValueExpression<>(EquippableWrapper.class)) diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableWrapper.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableWrapper.java index 82aa432fe2a..b66720fcb30 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableWrapper.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/EquippableWrapper.java @@ -8,18 +8,17 @@ import io.papermc.paper.datacomponent.item.Equippable.Builder; import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.registry.set.RegistryKeySet; -import io.papermc.paper.registry.set.RegistrySet; import net.kyori.adventure.key.Key; import org.bukkit.Registry; import org.bukkit.entity.EntityType; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.itemcomponents.ComponentUtils; import org.skriptlang.skript.bukkit.itemcomponents.ComponentWrapper; import java.lang.reflect.Method; import java.util.Collection; -import java.util.Collections; /** * A {@link ComponentWrapper} for getting and setting data on an {@link Equippable} component. @@ -92,7 +91,7 @@ protected void setComponent(ItemStack itemStack, Equippable component) { } @Override - protected Builder toBuilder(Equippable component) { + protected Builder getBuilder(Equippable component) { return component.toBuilder(); } @@ -227,10 +226,7 @@ public static Builder setModel(Builder builder, Key key) { * @return The allowed {@link EntityType}s. */ public static Collection getAllowedEntities(Equippable component) { - RegistryKeySet keys = component.allowedEntities(); - if (keys == null) - return Collections.emptyList(); - return keys.resolve(Registry.ENTITY_TYPE); + return ComponentUtils.registryKeySetToCollection(component.allowedEntities(), Registry.ENTITY_TYPE); } /** @@ -239,7 +235,7 @@ public static Collection getAllowedEntities(Equippable component) { * @return {@link RegistryKeySet} representation of {@code entityTypes}. */ public static RegistryKeySet convertAllowedEntities(Collection entityTypes) { - return RegistrySet.keySetFromValues(RegistryKey.ENTITY_TYPE, entityTypes); + return ComponentUtils.collectionToRegistryKeySet(entityTypes, RegistryKey.ENTITY_TYPE); } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDamage.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDamage.java index 03131667de2..221095fec8a 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDamage.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDamage.java @@ -14,8 +14,10 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Will Lose Durability") -@Description("Whether an item can be damaged when the wearer gets injured. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + Whether an item will be damaged when the wearer gets injured. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example(""" if {_item} will lose durability when hurt: add "Damageable on injury" to lore of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDispensable.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDispensable.java index e455a89a4b8..877c588ed5c 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDispensable.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompDispensable.java @@ -21,8 +21,10 @@ import java.util.List; @Name("Equippable Component - Can Be Dispensed") -@Description("Whether an item can be dispensed by a dispenser. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + Whether an item can be dispensed by a dispenser. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example(""" if {_item} can be dispensed: add "Dispensable" to lore of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompInteract.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompInteract.java index 545b90c52c2..1ab2ef60d07 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompInteract.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompInteract.java @@ -12,8 +12,10 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Can Equip On Entities") -@Description("Whether an entity should equip the item when right clicking on the entity with the item. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + Whether an entity should equip the item when right clicking on the entity with the item. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example("if {_item} can be equipped on entities:") @Since("INSERT VERSION") @RequiredPlugins("Minecraft 1.21.5+") diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompShearable.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompShearable.java index eddec0e829e..2e71ce77b84 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompShearable.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompShearable.java @@ -10,8 +10,10 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Can Be Sheared Off") -@Description("Whether an item can be sheared off of an entity. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + Whether an item can be sheared off of an entity. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example(""" if {_item} can be sheared off: add "Shearable" to lore of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompSwapEquipment.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompSwapEquipment.java index 961a065c227..a4304308f41 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompSwapEquipment.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/CondEquipCompSwapEquipment.java @@ -10,11 +10,11 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Can Swap Equipment") -@Description({ - "Whether an item can swap equipment by right clicking with it in your hand.", - "The item will swap places of the set 'equipment slot' of the item. If an equipment slot is not set, defaults to helmet.", - "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work aas intended." -}) +@Description(""" + Whether an item can swap equipment by right clicking with it in your hand. + The item will swap places of the set 'equipment slot' of the item. If an equipment slot is not set, defaults to helmet. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work aas intended. + """) @Example(""" if {_item} can swap equipment: add "Swappable" to lore of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDamageable.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDamageable.java index 749c0f3b5ee..92d8ea1e7e2 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDamageable.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDamageable.java @@ -13,8 +13,10 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Lose Durability") -@Description("If the item should take damage when the wearer gets injured. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + Whether the item should take damage when the wearer gets injured. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example("make {_item} lose durability when hurt") @Example(""" set {_component} to the equippable component of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDispensable.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDispensable.java index b42f288a1af..e1a12a9b4b1 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDispensable.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompDispensable.java @@ -12,8 +12,10 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Dispense") -@Description("If the item can be dispensed by a dispenser. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + Whether the item can be dispensed by a dispenser. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example("allow {_item} to be dispensed") @Example(""" set {_component} to the equippable component of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompInteract.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompInteract.java index afdc6c7f912..4a85e4d0221 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompInteract.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompInteract.java @@ -16,8 +16,10 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Equip On Entities") -@Description("If an entity should equip the item when right clicking on the entity with the item. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + Whether an entity should equip the item when right clicking on the entity with the item. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example("allow {_item} to be equipped onto entities") @Since("INSERT VERSION") @RequiredPlugins("Minecraft 1.21.5+") diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompShearable.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompShearable.java index fc982b03e4e..eb34cb961bc 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompShearable.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompShearable.java @@ -17,8 +17,10 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Shear Off") -@Description("If the item can be sheared off of entities. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + Whether the item can be sheared off of entities. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example("allow {_item} to be sheared off") @Example(""" set {_component} to the equippable component of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompSwapEquipment.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompSwapEquipment.java index 0e127791dbe..38f52b86462 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompSwapEquipment.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/EffEquipCompSwapEquipment.java @@ -12,8 +12,10 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Swap Equipment") -@Description("If the item can be swapped by right clicking with it in your hand. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + Whether the item can be swapped by right clicking with it in your hand. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example("allow {_item} to swap equipment") @Example(""" set {_component} to the equippable component of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompCameraOverlay.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompCameraOverlay.java index feef196d954..54fd919a3bf 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompCameraOverlay.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompCameraOverlay.java @@ -18,15 +18,15 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Camera Overlay") -@Description({ - "The camera overlay for the player when the item is equipped.", - "Example: The jack-o'-lantern view when having a jack-o'-lantern equipped as a helmet.", - "The camera overlay is represented as a namespaced key.", - "A namespaced key can be formatted as 'namespace:id' or 'id'. " - + "It can only contain one ':' to separate the namespace and the id. " - + "Only alphanumeric characters, periods, underscores, and dashes can be used.", - "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended." -}) +@Description(""" + The camera overlay for the player when the item is equipped. + Example: The jack-o'-lantern view when having a jack-o'-lantern equipped as a helmet. + The camera overlay is represented as a namespaced key. + A namespaced key can be formatted as 'namespace:id' or 'id'. \ + It can only contain one ':' to separate the namespace and the id. \ + Only alphanumeric characters, periods, underscores, and dashes can be used. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example("set the camera overlay of {_item} to \"custom_overlay\"") @Example(""" set {_component} to the equippable component of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEntities.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEntities.java index c85f7aef778..da6e8318bfe 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEntities.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEntities.java @@ -13,7 +13,6 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.util.Kleenean; import ch.njol.util.coll.CollectionUtils; -import io.papermc.paper.registry.set.RegistryKeySet; import org.bukkit.entity.EntityType; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @@ -25,8 +24,10 @@ import java.util.List; @Name("Equippable Component - Allowed Entities") -@Description("The entities allowed to wear the item. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + The entities allowed to wear the item. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example("set the allowed entities of {_item} to a zombie and a skeleton") @Example(""" set {_component} to the equippable component of {_item} @@ -77,7 +78,6 @@ public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { converted.add(EntityUtils.toBukkitEntityType(entityData)); } } - RegistryKeySet keys = EquippableWrapper.convertAllowedEntities(converted); getExpr().stream(event).forEach(wrapper -> { Collection allowed = wrapper.getAllowedEntities(); diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEquipSound.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEquipSound.java index e1dc83d0d6c..e4850fe3002 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEquipSound.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompEquipSound.java @@ -18,8 +18,10 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Equip Sound") -@Description("The sound to be played when the item is equipped. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + The sound to be played when the item is equipped. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example("set the equip sound of {_item} to \"entity.experience_orb.pickup\"") @Example(""" set {_component} to the equippable component of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompModel.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompModel.java index 316eb2d21ed..e73314b0249 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompModel.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompModel.java @@ -18,14 +18,14 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Model") -@Description({ - "The model of the item when equipped.", - "The model key is represented as a namespaced key.", - "A namespaced key can be formatted as 'namespace:id' or 'id'. " - + "It can only contain one ':' to separate the namespace and the id. " - + "Only alphanumeric characters, periods, underscores, and dashes can be used.", - "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended." -}) +@Description(""" + The model of the item when equipped. + The model key is represented as a namespaced key. + A namespaced key can be formatted as 'namespace:id' or 'id'. \ + It can only contain one ':' to separate the namespace and the id. \ + Only alphanumeric characters, periods, underscores, and dashes can be used. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. +""") @Example("set the equipped model key of {_item} to \"custom_model\"") @Example(""" set {_component} to the equippable component of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompShearSound.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompShearSound.java index c78edffcd80..e09a54879d3 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompShearSound.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompShearSound.java @@ -18,8 +18,10 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Shear Sound") -@Description("The sound to be played when the item is sheared off of an entity. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + The sound to be played when the item is sheared off of an entity. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example("set the shear sound of {_item} to \"entity.experience_orb.pickup\"") @Example(""" set {_component} to the equippable component of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompSlot.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompSlot.java index 14c590d23e1..4f66c48f3b9 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompSlot.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquipCompSlot.java @@ -16,8 +16,10 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component - Equipment Slot") -@Description("The equipment slot an item can be equipped to. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + The equipment slot an item can be equipped to. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example("set the equipment slot of {_item} to chest slot") @Example(""" set {_component} to the equippable component of {_item} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquippableComponent.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquippableComponent.java index a2181553983..34bc3554787 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquippableComponent.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprEquippableComponent.java @@ -21,8 +21,10 @@ import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableWrapper; @Name("Equippable Component") -@Description("The equippable component of an item. Any changes made to the equippable component will be present on the item. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended.") +@Description(""" + The equippable component of an item. Any changes made to the equippable component will be present on the item. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example(""" set {_component} to the equippable component of {_item} set the equipment slot of {_component} to helmet slot diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprSecBlankEquipComp.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprSecBlankEquipComp.java index b72a14cf06a..a7f00f1d813 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprSecBlankEquipComp.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/equippable/elements/ExprSecBlankEquipComp.java @@ -27,9 +27,11 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; -@Name("New Equippable Component") -@Description("Gets a blank equippable component. " - + "NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work aas intended.") +@Name("Blank Equippable Component") +@Description(""" + Gets a blank equippable component. + NOTE: Equippable component elements are experimental. Thus, they are subject to change and may not work as intended. + """) @Example(""" set {_component} to a blank equippable component set the equippable component of {_item} to {_component} From 3c78c6d19afdd3dbddbf1497f733ac1e14059fc6 Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Sun, 7 Sep 2025 14:00:08 -0400 Subject: [PATCH 5/8] Javadocs --- .../ch/njol/skript/registrations/Feature.java | 3 +- .../ConsumeEffectExperimentalSyntax.java | 20 +++++++++++++ .../elements/ExprConsumeEffectApply.java | 22 ++++++++++++-- .../elements/ExprConsumeEffectRemove.java | 29 ++++++++++++++++--- .../elements/ExprConsumeEffectSound.java | 21 ++++++++++++-- .../elements/ExprConsumeEffectTeleport.java | 21 ++++++++++++-- .../elements/LitConsumeEffectClear.java | 21 ++++++++++++-- 7 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumeEffectExperimentalSyntax.java diff --git a/src/main/java/ch/njol/skript/registrations/Feature.java b/src/main/java/ch/njol/skript/registrations/Feature.java index 1331ca24983..c46db34493e 100644 --- a/src/main/java/ch/njol/skript/registrations/Feature.java +++ b/src/main/java/ch/njol/skript/registrations/Feature.java @@ -19,7 +19,8 @@ public enum Feature implements Experiment { TYPE_HINTS("type hints", LifeCycle.EXPERIMENTAL, "[local variable] type hints"), DAMAGE_SOURCE("damage source", LifeCycle.EXPERIMENTAL, "damage source[s]"), EQUIPPABLE_COMPONENTS("equippable components", LifeCycle.EXPERIMENTAL, "equippable components"), - CONSUMABLE_COMPONENTS("consumable components", LifeCycle.EXPERIMENTAL, "consumable components") + CONSUMABLE_COMPONENTS("consumable components", LifeCycle.EXPERIMENTAL, "consumable components"), + CONSUME_EFFECTS("consume effects", LifeCycle.EXPERIMENTAL, "consume effects") ; private final String codeName; diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumeEffectExperimentalSyntax.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumeEffectExperimentalSyntax.java new file mode 100644 index 00000000000..a5d5a00ffc1 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumeEffectExperimentalSyntax.java @@ -0,0 +1,20 @@ +package org.skriptlang.skript.bukkit.itemcomponents.consumable; + +import ch.njol.skript.lang.SyntaxElement; +import ch.njol.skript.registrations.Feature; +import org.skriptlang.skript.lang.experiment.ExperimentData; +import org.skriptlang.skript.lang.experiment.SimpleExperimentalSyntax; + +/** + * Typed {@link SimpleExperimentalSyntax} for {@link SyntaxElement}s that require {@link Feature#CONSUME_EFFECTS}. + */ +public interface ConsumeEffectExperimentalSyntax extends SimpleExperimentalSyntax { + + ExperimentData EXPERIMENT_DATA = ExperimentData.createSingularData(Feature.CONSUME_EFFECTS); + + @Override + default ExperimentData getExperimentData() { + return EXPERIMENT_DATA; + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java index 84c6ef9c4c5..aa6e28e515d 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java @@ -1,6 +1,11 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +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.lang.Expression; import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.Literal; @@ -14,13 +19,26 @@ import org.bukkit.event.Event; import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumeEffectExperimentalSyntax; import java.util.ArrayList; import java.util.List; +@Name("Consume Effect - Apply Effects") +@Description(""" + A consume effect that applies the provided potions when the item has been consumed. + The probability is the chance the potions get applied when the item has been consumed. + Consume effects have to be added to the consumable component of an item. + NOTE: Consume Effect elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example(""" + set {_effect} to a consume effect to apply (strength of tier 3 for 1 hour) with a probability of 100 + add {_effect} to the consume effects of {_item} + """) +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") @SuppressWarnings("UnstableApiUsage") -public class ExprConsumeEffectApply extends SimpleExpression implements ConsumableExperimentSyntax { +public class ExprConsumeEffectApply extends SimpleExpression implements ConsumeEffectExperimentalSyntax { static { Skript.registerExpression(ExprConsumeEffectApply.class, ConsumeEffect.class, ExpressionType.COMBINED, diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectRemove.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectRemove.java index 7316b5170e4..c497ae70584 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectRemove.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectRemove.java @@ -1,6 +1,11 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +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.lang.Expression; import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.Literal; @@ -10,16 +15,31 @@ import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.set.RegistryKeySet; import org.bukkit.event.Event; import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.ComponentUtils; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumeEffectExperimentalSyntax; import java.util.ArrayList; import java.util.List; +@Name("Consume Effect - Remove Effects") +@Description(""" + A consume effect that removes the provided potion types when the item has been consumed. + Consume effects have to be added to the consumable component of an item. + NOTE: Consume Effect elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example(""" + set {_effect} to a consume effect to remove blindness, bad luck and slowness + add {_effect} to the consume effects of {_item} + """) +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") @SuppressWarnings("UnstableApiUsage") -public class ExprConsumeEffectRemove extends SimpleExpression implements ConsumableExperimentSyntax { +public class ExprConsumeEffectRemove extends SimpleExpression implements ConsumeEffectExperimentalSyntax { static { Skript.registerExpression(ExprConsumeEffectRemove.class, ConsumeEffect.class, ExpressionType.PROPERTY, @@ -41,8 +61,9 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye if (types.isEmpty()) return null; - - return new ConsumeEffect[0] ; + RegistryKeySet keys = ComponentUtils.collectionToRegistryKeySet(types, RegistryKey.MOB_EFFECT); + ConsumeEffect effect = ConsumeEffect.removeEffects(keys); + return new ConsumeEffect[] {effect}; } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectSound.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectSound.java index eb5a934ce70..61865bfcf03 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectSound.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectSound.java @@ -2,6 +2,11 @@ import ch.njol.skript.Skript; import ch.njol.skript.bukkitutil.SoundUtils; +import ch.njol.skript.doc.Description; +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.lang.Expression; import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.Literal; @@ -16,10 +21,22 @@ import org.bukkit.Sound; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumeEffectExperimentalSyntax; +@Name("Consume Effect - Play Sound") +@Description(""" + A consume effect that plays a sound when the item has been consumed. + Consume effects have to be added to the consumable component of an item. + NOTE: Consume Effect elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example(""" + set {_effect} to a consume effect to play the sound "ui.toast.challenge.complete" + add {_effect} to the consume effects of {_item} + """) +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") @SuppressWarnings("UnstableApiUsage") -public class ExprConsumeEffectSound extends SimpleExpression implements ConsumableExperimentSyntax { +public class ExprConsumeEffectSound extends SimpleExpression implements ConsumeEffectExperimentalSyntax { static { Skript.registerExpression(ExprConsumeEffectSound.class, ConsumeEffect.class, ExpressionType.PROPERTY, diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectTeleport.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectTeleport.java index e396de1dbb7..6f893c4326f 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectTeleport.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectTeleport.java @@ -1,6 +1,11 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +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.lang.Expression; import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.Literal; @@ -12,10 +17,22 @@ import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumeEffectExperimentalSyntax; +@Name("Consume Effect - Teleport Randomly") +@Description(""" + A consume effect that teleports randomly in the provided radius or diameter when the item has been consumed. + Consume effects have to be added to the consumable component of an item. + NOTE: Consume Effect elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example(""" + set {_effect} to a consume effect to teleport randomly in a radius of 5 + add {_effect} to the consume effects of {_item} + """) +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") @SuppressWarnings("UnstableApiUsage") -public class ExprConsumeEffectTeleport extends SimpleExpression implements ConsumableExperimentSyntax { +public class ExprConsumeEffectTeleport extends SimpleExpression implements ConsumeEffectExperimentalSyntax { static { Skript.registerExpression(ExprConsumeEffectTeleport.class, ConsumeEffect.class, ExpressionType.PROPERTY, diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java index dcfb6da3151..cd779353b28 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java @@ -1,6 +1,11 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +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.lang.Expression; import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.SkriptParser.ParseResult; @@ -9,10 +14,22 @@ import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumeEffectExperimentalSyntax; +@Name("Consume Effect - Clear Effects") +@Description(""" + A consume effect that clears all potions when the item has been consumed. + Consume effects have to be added to the consumable component of an item. + NOTE: Consume Effect elements are experimental. Thus, they are subject to change and may not work as intended. + """) +@Example(""" + set {_effect} to a consume effect to clear all potion effects + add {_effect} to the consume effects of {_item} + """) +@RequiredPlugins("Minecraft 1.21.3+") +@Since("INSERT VERSION") @SuppressWarnings("UnstableApiUsage") -public class LitConsumeEffectClear extends SimpleLiteral implements ConsumableExperimentSyntax { +public class LitConsumeEffectClear extends SimpleLiteral implements ConsumeEffectExperimentalSyntax { static { Skript.registerExpression(LitConsumeEffectClear.class, ConsumeEffect.class, ExpressionType.SIMPLE, From 543ab56d0abcfbef32a93cc7c9a231e529c6b181 Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Mon, 8 Sep 2025 12:06:16 -0400 Subject: [PATCH 6/8] Update --- .../itemcomponents/ItemComponentModule.java | 6 +- .../consumable/ConsumableModule.java | 4 +- .../consumable/ConsumableWrapper.java | 101 ++++++++++++-- .../elements/CondConsCompParticles.java | 19 ++- .../elements/EffConsCompParticles.java | 4 +- .../elements/ExprConsCompEffects.java | 4 + .../elements/ExprConsCompSound.java | 2 +- .../elements/ExprConsumeEffectApply.java | 2 +- .../elements/LitConsumeEffectClear.java | 2 +- src/main/resources/lang/default.lang | 10 +- .../tests/general/ConsumableComponents.sk | 129 ++++++++++++++++++ .../skript/tests/general/ConsumeEffects.sk | 18 +++ 12 files changed, 275 insertions(+), 26 deletions(-) create mode 100644 src/test/skript/tests/general/ConsumableComponents.sk create mode 100644 src/test/skript/tests/general/ConsumeEffects.sk diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ItemComponentModule.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ItemComponentModule.java index 1e2183a969a..a3749557845 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ItemComponentModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/ItemComponentModule.java @@ -7,6 +7,7 @@ import ch.njol.skript.registrations.Classes; import org.skriptlang.skript.addon.AddonModule; import org.skriptlang.skript.addon.SkriptAddon; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableModule; import org.skriptlang.skript.bukkit.itemcomponents.equippable.EquippableModule; import java.io.IOException; @@ -48,7 +49,10 @@ public String toVariableNameString(ComponentWrapper wrapper) { @Override public void load(SkriptAddon addon) { - addon.loadModules(new EquippableModule()); + addon.loadModules( + new EquippableModule(), + new ConsumableModule() + ); try { Skript.getAddonInstance().loadClasses("org.skriptlang.skript.bukkit.itemcomponents", "generic"); diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableModule.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableModule.java index abeeeab45ca..09d4ef7d3e4 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableModule.java @@ -1,6 +1,7 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable; import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; import ch.njol.skript.classes.ClassInfo; import ch.njol.skript.classes.EnumClassInfo; import ch.njol.skript.classes.Parser; @@ -13,7 +14,6 @@ import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.ItemType; import org.skriptlang.skript.addon.AddonModule; import org.skriptlang.skript.addon.SkriptAddon; import org.skriptlang.skript.lang.comparator.Comparators; @@ -64,7 +64,7 @@ public String toVariableNameString(ConsumableWrapper wrapper) { Classes.registerClass(new ClassInfo<>(ConsumeEffect.class, "consumeeffect") .user("consume ?effects?") .name("Consume Effect") - .description("An effect applied to a consumable component for an item. The effect activates when the item is eaten.") + .description("An effect applied to an item. The effect activates when the item is consumed.") .requiredPlugins("Minecraft 1.21.3+") .since("INSERT VERSION") ); diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableWrapper.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableWrapper.java index 7c1dcfdad9c..c57eadd4888 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableWrapper.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableWrapper.java @@ -1,15 +1,24 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable; import ch.njol.skript.util.ItemSource; +import io.papermc.paper.datacomponent.DataComponentBuilder; import io.papermc.paper.datacomponent.DataComponentType.Valued; import io.papermc.paper.datacomponent.DataComponentTypes; import io.papermc.paper.datacomponent.item.Consumable; -import io.papermc.paper.datacomponent.item.Consumable.Builder; +import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect; +import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; +import net.kyori.adventure.key.Key; +import org.bukkit.Registry; +import org.bukkit.Sound; import org.bukkit.inventory.ItemStack; import org.skriptlang.skript.bukkit.itemcomponents.ComponentWrapper; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper.ConsumableBuilder; + +import java.util.ArrayList; +import java.util.List; @SuppressWarnings("UnstableApiUsage") -public class ConsumableWrapper extends ComponentWrapper { +public class ConsumableWrapper extends ComponentWrapper { public ConsumableWrapper(ItemStack itemStack) { super(itemStack); @@ -23,7 +32,7 @@ public ConsumableWrapper(Consumable component) { super(component); } - public ConsumableWrapper(Builder builder) { + public ConsumableWrapper(ConsumableBuilder builder) { super(builder); } @@ -41,11 +50,11 @@ protected Consumable getComponent(ItemStack itemStack) { } @Override - protected Builder getBuilder(ItemStack itemStack) { + protected ConsumableBuilder getBuilder(ItemStack itemStack) { Consumable consumable = itemStack.getData(DataComponentTypes.CONSUMABLE); if (consumable != null) - return consumable.toBuilder(); - return Consumable.consumable(); + return new ConsumableBuilder(consumable); + return new ConsumableBuilder(); } @Override @@ -54,8 +63,8 @@ protected void setComponent(ItemStack itemStack, Consumable component) { } @Override - protected Builder toBuilder(Consumable component) { - return component.toBuilder(); + protected ConsumableBuilder getBuilder(Consumable component) { + return new ConsumableBuilder(component); } @Override @@ -71,8 +80,8 @@ public Consumable newComponent() { } @Override - public Builder newBuilder() { - return Consumable.consumable(); + public ConsumableBuilder newBuilder() { + return new ConsumableBuilder(); } @Override @@ -84,4 +93,76 @@ public static ConsumableWrapper newInstance() { return new ConsumableWrapper(Consumable.consumable().build()); } + /** + * Custom builder class for {@link Consumable} that mimics {@link Consumable.Builder} allowing methods not + * shared across all versions to be used. + */ + @SuppressWarnings("NonExtendableApiUsage") + public static class ConsumableBuilder implements DataComponentBuilder { + + private ItemUseAnimation animation = ItemUseAnimation.EAT; + private List consumeEffects = new ArrayList<>(); + private boolean consumeParticles = true; + private float consumeSeconds = 5; + private Key sound = Registry.SOUNDS.getKey(Sound.ENTITY_GENERIC_EAT); + + public ConsumableBuilder() {} + + public ConsumableBuilder(Consumable consumable) { + this.animation = consumable.animation(); + this.consumeEffects.addAll(consumable.consumeEffects()); + this.consumeParticles = consumable.hasConsumeParticles(); + this.consumeSeconds = consumable.consumeSeconds(); + this.sound = consumable.sound(); + } + + public ConsumableBuilder animation(ItemUseAnimation animation) { + this.animation = animation; + return this; + } + + public ConsumableBuilder addEffect(ConsumeEffect effect) { + consumeEffects.add(effect); + return this; + } + + public ConsumableBuilder addEffects(List effects) { + this.consumeEffects.addAll(effects); + return this; + } + + public ConsumableBuilder effects(List effects) { + this.consumeEffects.clear(); + this.consumeEffects.addAll(effects); + return this; + } + + public ConsumableBuilder hasConsumeParticles(boolean consumeParticles) { + this.consumeParticles = consumeParticles; + return this; + } + + public ConsumableBuilder consumeSeconds(float seconds) { + this.consumeSeconds = seconds; + return this; + } + + public ConsumableBuilder sound(Key sound) { + this.sound = sound; + return this; + } + + @Override + public Consumable build() { + return Consumable.consumable() + .animation(animation) + .addEffects(consumeEffects) + .hasConsumeParticles(consumeParticles) + .consumeSeconds(consumeSeconds) + .sound(sound) + .build(); + } + + } + } diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/CondConsCompParticles.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/CondConsCompParticles.java index 4ddd92bc0ae..9a0a49f8308 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/CondConsCompParticles.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/CondConsCompParticles.java @@ -6,6 +6,9 @@ import ch.njol.skript.doc.Name; import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; @@ -23,17 +26,27 @@ public class CondConsCompParticles extends PropertyCondition implements ConsumableExperimentSyntax { static { - register(CondConsCompParticles.class, PropertyType.HAVE, "consum(e|ption) particles [enabled]", "consumablecomponents"); + register(CondConsCompParticles.class, PropertyType.HAVE, "consum(e|ption) particles [enabled|:disabled]", "consumablecomponents"); + } + + private boolean checkEnabled; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + checkEnabled = !parseResult.hasTag("disabled"); + return super.init(expressions, matchedPattern, isDelayed, parseResult); } @Override public boolean check(ConsumableWrapper wrapper) { - return wrapper.getComponent().hasConsumeParticles(); + return wrapper.getComponent().hasConsumeParticles() == checkEnabled; } @Override protected String getPropertyName() { - return "consume particles"; + if (checkEnabled) + return "consume particles enabled"; + return "consume particles disabled"; } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/EffConsCompParticles.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/EffConsCompParticles.java index 61316905db6..0cc13d56d70 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/EffConsCompParticles.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/EffConsCompParticles.java @@ -31,7 +31,7 @@ public class EffConsCompParticles extends Effect implements ConsumableExperiment static { Skript.registerEffect(EffConsCompParticles.class, - "(enable|:disable) [the] comsum(e|ption) particle[s] [effect[s]] of %consumablecomponents%"); + "(enable|:disable) [the] consum(e|ption) particle[s] [effect[s]] (of|for) %consumablecomponents%"); } private Expression wrappers; @@ -42,7 +42,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye //noinspection unchecked wrappers = (Expression) exprs[0]; enable = !parseResult.hasTag("disable"); - return false; + return true; } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompEffects.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompEffects.java index fa2230ffa7e..cc4d1295ae9 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompEffects.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompEffects.java @@ -26,6 +26,10 @@ NOTE: Consumable component elements are experimental. Thus, they are subject to change and may not work as intended. """) @Example("set {_effects::*} to the consumption effects of {_item}") +@Example(""" + set {_effect} to a consume effect to clear all potion effects + add {_effect} to the consume effects of {_item} + """) @RequiredPlugins("Minecraft 1.21.3+") @Since("INSERT VERSION") @SuppressWarnings("UnstableApiUsage") diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSound.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSound.java index d31c3088094..50a22f835a3 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSound.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSound.java @@ -23,7 +23,7 @@ NOTE: Consumable component elements are experimental. Thus, they are subject to change and may not work as intended. """) @Example("set {_sound} to the consumption sound of {_item}") -@Example("set the consumption sound of {_item} to \"entity.sheep.ambient\"") +@Example("set the consumption sound of {_item} to \"minecraft:entity.sheep.ambient\"") @RequiredPlugins("Minecraft 1.21.3+") @Since("INSERT VERSION") public class ExprConsCompSound extends SimplePropertyExpression implements ConsumableExperimentSyntax { diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java index aa6e28e515d..9fc6ea39bfb 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java @@ -32,7 +32,7 @@ NOTE: Consume Effect elements are experimental. Thus, they are subject to change and may not work as intended. """) @Example(""" - set {_effect} to a consume effect to apply (strength of tier 3 for 1 hour) with a probability of 100 + set {_effect} to a consume effect to apply (a new potion effect of strength of tier 3 for 1 hour) with a probability of 100 add {_effect} to the consume effects of {_item} """) @RequiredPlugins("Minecraft 1.21.3+") diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java index cd779353b28..8f1a8cf40b8 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java @@ -33,7 +33,7 @@ public class LitConsumeEffectClear extends SimpleLiteral implemen static { Skript.registerExpression(LitConsumeEffectClear.class, ConsumeEffect.class, ExpressionType.SIMPLE, - "[a] consume effect to clear all potion effects"); + "[a] consume effect to clear all (potion|status) effects"); } public LitConsumeEffectClear() { diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang index bec6bd6d6ee..0e786a9ba8a 100644 --- a/src/main/resources/lang/default.lang +++ b/src/main/resources/lang/default.lang @@ -2682,11 +2682,11 @@ damage types: # Consume Effect Types consume effect types: - apply_status_effects: apply status effects - clear_all_status_effects: clear all status effects, clear status effects - play_sound: play sound - remove_status_effects: remove status effects - teleport_randomly: teleport randomly + apply_status_effects: status apply + clear_all_status_effects: status clear + play_sound: play sound, sound + remove_status_effects: status remove + teleport_randomly: teleport randomly, teleport # Item Use Animations item use animations: diff --git a/src/test/skript/tests/general/ConsumableComponents.sk b/src/test/skript/tests/general/ConsumableComponents.sk new file mode 100644 index 00000000000..27b897d2126 --- /dev/null +++ b/src/test/skript/tests/general/ConsumableComponents.sk @@ -0,0 +1,129 @@ +options: + animation: drink animation + time: 1 hour + sound: "minecraft:ui.toast.challenge_complete" + effect: a consume effect to clear all potion effects + +using consumable components +using consume effects + +test "consumable components - new" when running minecraft "1.21.3": + set {_component} to a blank consumable component + set the consumption animation of {_component} to {@animation} + assert the consumption animation of {_component} is {@animation} with "Consume animation of component was not set" + set the consumption time of {_component} to {@time} + assert the consumption time of {_component} is {@time} with "Consume time of component was not set" + set the consumption sound of {_component} to {@sound} + assert the consumption sound of {_component} is {@sound} with "Consume sound of component was not set" + + add {@effect} to the consume effects of {_component} + assert the consume effects of {_component} contains {@effect} with "Consume effect was not added to component" + clear the consume effects of {_component} + assert the consume effects of {_component} is not set with "Consume effects of component was not cleared" + + enable the consumption particles of {_component} + assert {_component} has consumption particles enabled with "Consume particles of component were not enabled" + disable the consumption particles of {_component} + assert {_component} does not have consumption particles enabled with "Consume particles of component were not disabled" + +test "consumable components - itemtype" when running minecraft "1.21.3": + set {_item} to a leather helmet (item type) + set the consumption animation of {_item} to {@animation} + assert the consumption animation of {_item} is {@animation} with "Consume animation of itemtype was not set" + set the consumption time of {_item} to {@time} + assert the consumption time of {_item} is {@time} with "Consume time of itemtype was not set" + set the consumption sound of {_item} to {@sound} + assert the consumption sound of {_item} is {@sound} with "Consume sound of itemtype was not set" + + add {@effect} to the consume effects of {_item} + assert the consume effects of {_item} contains {@effect} with "Consume effect was not added to itemtype" + clear the consume effects of {_item} + assert the consume effects of {_item} is not set with "Consume effects of itemtype was not cleared" + + enable the consumption particles of {_item} + assert {_item} has consumption particles enabled with "Consume particles of itemtype were not enabled" + disable the consumption particles of {_item} + assert {_item} does not have consumption particles enabled with "Consume particles of itemtype were not disabled" + +test "consumable components - itemstack" when running minecraft "1.21.3": + set {_item} to an iron helmet (item stack) + set the consumption animation of {_item} to {@animation} + assert the consumption animation of {_item} is {@animation} with "Consume animation of itemstack was not set" + set the consumption time of {_item} to {@time} + assert the consumption time of {_item} is {@time} with "Consume time of itemstack was not set" + set the consumption sound of {_item} to {@sound} + assert the consumption sound of {_item} is {@sound} with "Consume sound of itemstack was not set" + + add {@effect} to the consume effects of {_item} + assert the consume effects of {_item} contains {@effect} with "Consume effect was not added to itemstack" + clear the consume effects of {_item} + assert the consume effects of {_item} is not set with "Consume effects of itemstack was not cleared" + + enable the consumption particles of {_item} + assert {_item} has consumption particles enabled with "Consume particles of itemstack were not enabled" + disable the consumption particles of {_item} + assert {_item} does not have consumption particles enabled with "Consume particles of itemstack were not disabled" + +test "consumable components - copy" when running minecraft "1.21.3": + set {_component} to a blank consumable component + set the consumption animation of {_component} to {@animation} + assert the consumption animation of {_component} is {@animation} with "Consume animation of component was not set" + set the consumption time of {_component} to {@time} + assert the consumption time of {_component} is {@time} with "Consume time of component was not set" + set the consumption sound of {_component} to {@sound} + assert the consumption sound of {_component} is {@sound} with "Consume sound of component was not set" + + add {@effect} to the consume effects of {_component} + assert the consume effects of {_component} contains {@effect} with "Consume effect was not added to component" + clear the consume effects of {_component} + assert the consume effects of {_component} is not set with "Consume effects of component was not cleared" + + enable the consumption particles of {_component} + assert {_component} has consumption particles enabled with "Consume particles of component were not enabled" + disable the consumption particles of {_component} + assert {_component} does not have consumption particles enabled with "Consume particles of component were not disabled" + + set {_original} to {_component} + set {_copy} to a item component copy of {_original} + set the consumption animation of {_copy} to eat animation + assert the consumption animation of {_copy} is eat animation with "Consume animation of copy was not set" + assert the consumption animation of {_original} is {@animation} with "Consume animation of original should not have changed" + set the consumption time of {_copy} to 30 minutes + assert the consumption time of {_copy} is 30 minutes with "Consume time of copy was not set" + assert the consumption time of {_original} is {@time} with "Consume time of original should not have changed" + set the consumption sound of {_copy} to "minecraft:ui.toast.in" + assert the consumption sound of {_copy} is "minecraft:ui.toast.in" with "Consume sound of copy was not set" + assert the consumption sound of {_original} is {@sound} with "Consume sound of original should not have changed" + + add {@effect} to the consume effects of {_copy} + assert the consume effects of {_copy} contains {@effect} with "Consume effect was not added to copy" + assert the consume effects of {_original} is not set with "Consume effects of original should not have changed" + clear the consume effects of {_copy} + assert the consume effects of {_copy} is not set with "Consume effects of copy was not cleared" + + enable the consumption particles of {_copy} + assert {_copy} has consumption particles enabled with "Consume particles of copy were not enabled" + assert {_original} does not have consumption particles enabled with "Consume particles of original should not have changed" + disable the consumption particles of {_copy} + assert {_copy} does not have consumption particles enabled with "Consume particles of copy were not disabled" + +test "consumable components - slot" when running minecraft "1.21.3": + set {_gui} to a chest inventory with 1 row + set slot 1 of {_gui} to a diamond helmet + + set the consumption animation of (slot 1 of {_gui}) to {@animation} + assert the consumption animation of (slot 1 of {_gui}) is {@animation} with "Consume animation of slot was not set" + set the consumption time of (slot 1 of {_gui}) to {@time} + assert the consumption time of (slot 1 of {_gui}) is {@time} with "Consume time of slot was not set" + set the consumption sound of (slot 1 of {_gui}) to {@sound} + assert the consumption sound of (slot 1 of {_gui}) is {@sound} with "Consume sound of slot was not set" + + add {@effect} to the consume effects of (slot 1 of {_gui}) + assert the consume effects of (slot 1 of {_gui}) contains {@effect} with "Consume effect was not added to slot" + clear the consume effects of (slot 1 of {_gui}) + assert the consume effects of (slot 1 of {_gui}) is not set with "Consume effects of slot was not cleared" + + enable the consumption particles of (slot 1 of {_gui}) + assert (slot 1 of {_gui}) has consumption particles enabled with "Consume particles of slot were not enabled" + disable the consumption particles of (slot 1 of {_gui}) + assert (slot 1 of {_gui}) does not have consumption particles enabled with "Consume particles of slot were not disabled" diff --git a/src/test/skript/tests/general/ConsumeEffects.sk b/src/test/skript/tests/general/ConsumeEffects.sk new file mode 100644 index 00000000000..75f335ac540 --- /dev/null +++ b/src/test/skript/tests/general/ConsumeEffects.sk @@ -0,0 +1,18 @@ + +using consume effects + +test "consume effect type comparison" when running minecraft "1.21.3": + set {_apply} to a consume effect to apply (a new potion effect of strength of tier 3 for 1 hour) with a probability of 100 + assert {_apply} is (status apply) with "Consume effect apply did not match" + + set {_remove} to a consume effect to remove blindness, bad luck and slowness + assert {_remove} is (status remove) with "Consume effect remove did not match" + + set {_clear} to a consume effect to clear all potion effects + assert {_clear} is (status clear) with "Consume effect clear did not match" + + set {_sound} to a consume effect to play the sound "minecraft:ui.toast.challenge_complete" + assert {_sound} is (sound) with "Consume effect sound did not match" + + set {_teleport} to a consume effect to teleport randomly in a radius of 5 + assert (a consume effect to teleport randomly in a radius of 5) is (teleport (consume effect type)) with "Consume effect teleport did not match" From 1ceb0cee2e5b5fa3ffcd5fd49cd36cf4176c1af2 Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Tue, 9 Sep 2025 16:05:36 -0400 Subject: [PATCH 7/8] Update ExprSecBlankConsComp.java --- .../consumable/elements/ExprSecBlankConsComp.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprSecBlankConsComp.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprSecBlankConsComp.java index 211cc49208a..25387cc5eb6 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprSecBlankConsComp.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprSecBlankConsComp.java @@ -32,13 +32,14 @@ Gets a blank consumable component. NOTE: Consumable component elements are experimental. Thus, they are subject to change and may not work as intended. """) -@Example(""" - set {_component} to a blank consumable component - set the consumable component of {_item} to {_component} - """) @Example(""" set {_component} to a blank consumable component: - set the consumption time to 1 second + set the consumption animation to drink animation + add (a consume effect to clear all potion effects) to the consume effects + set the consumption time to 5 seconds + set the consumption sound to "ui.toast.out" + enable the consumption particles for event-consumable component + set the consumable component of {_item} to {_component} """) @RequiredPlugins("Minecraft 1.21.3+") @Since("INSERT VERSION") From 09fa9405b3f6db9eaefd69005211376dbb7d460d Mon Sep 17 00:00:00 2001 From: SirSmurfy2 Date: Tue, 30 Sep 2025 20:45:54 -0400 Subject: [PATCH 8/8] Update --- .../consumable/ConsumableModule.java | 34 +++++++++++++++---- .../elements/CondConsCompParticles.java | 10 ++++-- .../elements/EffConsCompParticles.java | 14 +++++--- .../elements/ExprConsCompAnimation.java | 10 ++++-- .../elements/ExprConsCompEffects.java | 10 ++++-- .../elements/ExprConsCompSound.java | 10 ++++-- ...CompSeconds.java => ExprConsCompTime.java} | 12 +++++-- .../elements/ExprConsumableComponent.java | 10 ++++++ .../elements/ExprConsumeEffectApply.java | 15 +++++--- .../elements/ExprConsumeEffectRemove.java | 15 +++++--- .../elements/ExprConsumeEffectSound.java | 15 +++++--- .../elements/ExprConsumeEffectTeleport.java | 15 +++++--- .../elements/ExprSecBlankConsComp.java | 15 +++++--- .../elements/LitConsumeEffectClear.java | 15 +++++--- 14 files changed, 149 insertions(+), 51 deletions(-) rename src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/{ExprConsCompSeconds.java => ExprConsCompTime.java} (84%) diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableModule.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableModule.java index 09d4ef7d3e4..7547a0b7c28 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/ConsumableModule.java @@ -16,12 +16,15 @@ import org.bukkit.inventory.ItemStack; import org.skriptlang.skript.addon.AddonModule; import org.skriptlang.skript.addon.SkriptAddon; +import org.skriptlang.skript.bukkit.itemcomponents.consumable.elements.*; import org.skriptlang.skript.lang.comparator.Comparators; import org.skriptlang.skript.lang.comparator.Relation; import org.skriptlang.skript.lang.converter.Converter; import org.skriptlang.skript.lang.converter.Converters; +import org.skriptlang.skript.registration.SyntaxRegistry; -import java.io.IOException; +import java.util.Arrays; +import java.util.function.Consumer; public class ConsumableModule implements AddonModule { @@ -105,11 +108,30 @@ public String toVariableNameString(ConsumableWrapper wrapper) { @Override public void load(SkriptAddon addon) { - try { - Skript.getAddonInstance().loadClasses("org.skriptlang.skript.bukkit.itemcomponents.consumable", "elements"); - } catch (IOException e) { - throw new RuntimeException(e); - } + register(addon.syntaxRegistry(), + + CondConsCompParticles::register, + + EffConsCompParticles::register, + + ExprConsCompAnimation::register, + ExprConsCompEffects::register, + ExprConsCompSound::register, + ExprConsCompTime::register, + ExprConsumableComponent::register, + ExprConsumeEffectApply::register, + ExprConsumeEffectRemove::register, + ExprConsumeEffectSound::register, + ExprConsumeEffectTeleport::register, + + ExprSecBlankConsComp::register, + + LitConsumeEffectClear::register + ); + } + + private void register(SyntaxRegistry registry, Consumer... consumers) { + Arrays.stream(consumers).forEach(consumer -> consumer.accept(registry)); } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/CondConsCompParticles.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/CondConsCompParticles.java index 9a0a49f8308..687372676e7 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/CondConsCompParticles.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/CondConsCompParticles.java @@ -11,6 +11,7 @@ import ch.njol.util.Kleenean; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; +import org.skriptlang.skript.registration.SyntaxRegistry; @Name("Consumable Component - Has Particles") @Description(""" @@ -25,8 +26,13 @@ @Since("INSERT VERSION") public class CondConsCompParticles extends PropertyCondition implements ConsumableExperimentSyntax { - static { - register(CondConsCompParticles.class, PropertyType.HAVE, "consum(e|ption) particles [enabled|:disabled]", "consumablecomponents"); + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.CONDITION, + infoBuilder(CondConsCompParticles.class, PropertyType.HAVE, "consum(e|ption) particles [enabled|:disabled]", "consumablecomponents") + .supplier(CondConsCompParticles::new) + .build() + ); } private boolean checkEnabled; diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/EffConsCompParticles.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/EffConsCompParticles.java index 0cc13d56d70..7846add9cd9 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/EffConsCompParticles.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/EffConsCompParticles.java @@ -1,6 +1,5 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; -import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Example; import ch.njol.skript.doc.Name; @@ -15,6 +14,8 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; +import org.skriptlang.skript.registration.SyntaxInfo; +import org.skriptlang.skript.registration.SyntaxRegistry; @Name("Consumable Component - Particles") @Description(""" @@ -29,9 +30,14 @@ @Since("INSERT VERSION") public class EffConsCompParticles extends Effect implements ConsumableExperimentSyntax { - static { - Skript.registerEffect(EffConsCompParticles.class, - "(enable|:disable) [the] consum(e|ption) particle[s] [effect[s]] (of|for) %consumablecomponents%"); + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EFFECT, + SyntaxInfo.builder(EffConsCompParticles.class) + .addPatterns("(enable|:disable) [the] consum(e|ption) particle[s] [effect[s]] (of|for) %consumablecomponents%") + .supplier(EffConsCompParticles::new) + .build() + ); } private Expression wrappers; diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompAnimation.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompAnimation.java index a071ba6f112..a030b9ce5bb 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompAnimation.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompAnimation.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; +import org.skriptlang.skript.registration.SyntaxRegistry; @Name("Consumable Component - Animation") @Description(""" @@ -26,8 +27,13 @@ @SuppressWarnings("UnstableApiUsage") public class ExprConsCompAnimation extends SimplePropertyExpression implements ConsumableExperimentSyntax { - static { - registerDefault(ExprConsCompAnimation.class, ItemUseAnimation.class, "consum(e|ption) animation", "consumablecomponents"); + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + infoBuilder(ExprConsCompAnimation.class, ItemUseAnimation.class, "consum(e|ption) animation", "consumablecomponents", true) + .supplier(ExprConsCompAnimation::new) + .build() + ); } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompEffects.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompEffects.java index cc4d1295ae9..a9515928f62 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompEffects.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompEffects.java @@ -16,6 +16,7 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; +import org.skriptlang.skript.registration.SyntaxRegistry; import java.util.ArrayList; import java.util.List; @@ -35,8 +36,13 @@ @SuppressWarnings("UnstableApiUsage") public class ExprConsCompEffects extends PropertyExpression implements ConsumableExperimentSyntax { - static { - registerDefault(ExprConsCompEffects.class, ConsumeEffect.class, "consum(e|ption) effects", "consumablecomponents"); + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + infoBuilder(ExprConsCompEffects.class, ConsumeEffect.class, "consum(e|ption) effects", "consumablecomponents", true) + .supplier(ExprConsCompEffects::new) + .build() + ); } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSound.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSound.java index 50a22f835a3..736ee969ef9 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSound.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSound.java @@ -16,6 +16,7 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; +import org.skriptlang.skript.registration.SyntaxRegistry; @Name("Consumable Component - Consume Sound") @Description(""" @@ -28,8 +29,13 @@ @Since("INSERT VERSION") public class ExprConsCompSound extends SimplePropertyExpression implements ConsumableExperimentSyntax { - static { - registerDefault(ExprConsCompSound.class, String.class, "consum(e|ption) sound", "consumablecomponents"); + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + infoBuilder(ExprConsCompSound.class, String.class, "consum(e|ption) sound", "consumablecomponents", true) + .supplier(ExprConsCompSound::new) + .build() + ); } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSeconds.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompTime.java similarity index 84% rename from src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSeconds.java rename to src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompTime.java index d92260b3bf2..540f8047b95 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompSeconds.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsCompTime.java @@ -15,6 +15,7 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; +import org.skriptlang.skript.registration.SyntaxRegistry; import java.time.temporal.ChronoUnit; @@ -26,10 +27,15 @@ @Example("set the consumption time of {_item} to 5 seconds") @RequiredPlugins("Minecraft 1.21.3+") @Since("INSERT VERSION") -public class ExprConsCompSeconds extends SimplePropertyExpression implements ConsumableExperimentSyntax { +public class ExprConsCompTime extends SimplePropertyExpression implements ConsumableExperimentSyntax { - static { - registerDefault(ExprConsCompSeconds.class, Timespan.class, "consum(e|ption) time", "consumablecomponents"); + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + infoBuilder(ExprConsCompTime.class, Timespan.class, "consum(e|ption) time", "consumablecomponents", true) + .supplier(ExprConsCompTime::new) + .build() + ); } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumableComponent.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumableComponent.java index a9d828fe2a6..c1613c00c37 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumableComponent.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumableComponent.java @@ -19,6 +19,7 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; +import org.skriptlang.skript.registration.SyntaxRegistry; @Name("Consumable Component") @Description(""" @@ -36,6 +37,15 @@ public class ExprConsumableComponent extends SimplePropertyExpression itemSource = null; diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java index 9fc6ea39bfb..e47eda3256e 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectApply.java @@ -1,13 +1,11 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; -import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; 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.lang.Expression; -import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.SyntaxStringBuilder; @@ -20,6 +18,8 @@ import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumeEffectExperimentalSyntax; +import org.skriptlang.skript.registration.SyntaxInfo; +import org.skriptlang.skript.registration.SyntaxRegistry; import java.util.ArrayList; import java.util.List; @@ -40,9 +40,14 @@ @SuppressWarnings("UnstableApiUsage") public class ExprConsumeEffectApply extends SimpleExpression implements ConsumeEffectExperimentalSyntax { - static { - Skript.registerExpression(ExprConsumeEffectApply.class, ConsumeEffect.class, ExpressionType.COMBINED, - "[a] consume effect to apply %potioneffects% with [a] probability of %number%"); + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + SyntaxInfo.Expression.builder(ExprConsumeEffectApply.class, ConsumeEffect.class) + .addPatterns("[a] consume effect to apply %potioneffects% with [a] probability of %number%") + .supplier(ExprConsumeEffectApply::new) + .build() + ); } private Expression effects; diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectRemove.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectRemove.java index c497ae70584..ffb96a80fec 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectRemove.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectRemove.java @@ -1,13 +1,11 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; -import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; 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.lang.Expression; -import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.SyntaxStringBuilder; @@ -22,6 +20,8 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.ComponentUtils; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumeEffectExperimentalSyntax; +import org.skriptlang.skript.registration.SyntaxInfo; +import org.skriptlang.skript.registration.SyntaxRegistry; import java.util.ArrayList; import java.util.List; @@ -41,9 +41,14 @@ @SuppressWarnings("UnstableApiUsage") public class ExprConsumeEffectRemove extends SimpleExpression implements ConsumeEffectExperimentalSyntax { - static { - Skript.registerExpression(ExprConsumeEffectRemove.class, ConsumeEffect.class, ExpressionType.PROPERTY, - "[a] consume effect to remove %potioneffecttypes%"); + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + SyntaxInfo.Expression.builder(ExprConsumeEffectRemove.class, ConsumeEffect.class) + .addPatterns("[a] consume effect to remove %potioneffecttypes%") + .supplier(ExprConsumeEffectRemove::new) + .build() + ); } private Expression effectTypes; diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectSound.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectSound.java index 61865bfcf03..ad239e422db 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectSound.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectSound.java @@ -1,6 +1,5 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; -import ch.njol.skript.Skript; import ch.njol.skript.bukkitutil.SoundUtils; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Example; @@ -8,7 +7,6 @@ import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.SyntaxStringBuilder; @@ -22,6 +20,8 @@ import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumeEffectExperimentalSyntax; +import org.skriptlang.skript.registration.SyntaxInfo; +import org.skriptlang.skript.registration.SyntaxRegistry; @Name("Consume Effect - Play Sound") @Description(""" @@ -38,9 +38,14 @@ @SuppressWarnings("UnstableApiUsage") public class ExprConsumeEffectSound extends SimpleExpression implements ConsumeEffectExperimentalSyntax { - static { - Skript.registerExpression(ExprConsumeEffectSound.class, ConsumeEffect.class, ExpressionType.PROPERTY, - "[a] consume effect to play [[the] sound] %string%"); + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + SyntaxInfo.Expression.builder(ExprConsumeEffectSound.class, ConsumeEffect.class) + .addPatterns("[a] consume effect to play [[the] sound] %string%") + .supplier(ExprConsumeEffectSound::new) + .build() + ); } private Expression string; diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectTeleport.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectTeleport.java index 6f893c4326f..9656443e83b 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectTeleport.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprConsumeEffectTeleport.java @@ -1,13 +1,11 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; -import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; 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.lang.Expression; -import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.SyntaxStringBuilder; @@ -18,6 +16,8 @@ import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumeEffectExperimentalSyntax; +import org.skriptlang.skript.registration.SyntaxInfo; +import org.skriptlang.skript.registration.SyntaxRegistry; @Name("Consume Effect - Teleport Randomly") @Description(""" @@ -34,9 +34,14 @@ @SuppressWarnings("UnstableApiUsage") public class ExprConsumeEffectTeleport extends SimpleExpression implements ConsumeEffectExperimentalSyntax { - static { - Skript.registerExpression(ExprConsumeEffectTeleport.class, ConsumeEffect.class, ExpressionType.PROPERTY, - "[a] consume effect to teleport randomly in [a] (radius|:diameter) of %number%"); + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + SyntaxInfo.Expression.builder(ExprConsumeEffectTeleport.class, ConsumeEffect.class) + .addPatterns("[a] consume effect to teleport randomly in [a] (radius|:diameter) of %number%") + .supplier(ExprConsumeEffectTeleport::new) + .build() + ); } private Expression number; diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprSecBlankConsComp.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprSecBlankConsComp.java index 25387cc5eb6..56bcf10cd8b 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprSecBlankConsComp.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/ExprSecBlankConsComp.java @@ -1,6 +1,5 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; -import ch.njol.skript.Skript; import ch.njol.skript.config.SectionNode; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Example; @@ -9,7 +8,6 @@ import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SectionExpression; import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.Trigger; import ch.njol.skript.lang.TriggerItem; @@ -23,6 +21,8 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableExperimentSyntax; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumableWrapper; +import org.skriptlang.skript.registration.SyntaxInfo; +import org.skriptlang.skript.registration.SyntaxRegistry; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -63,9 +63,14 @@ public ConsumableWrapper getWrapper() { } } - static { - Skript.registerExpression(ExprSecBlankConsComp.class, ConsumableWrapper.class, ExpressionType.SIMPLE, - "a (blank|empty) consumable component"); + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + SyntaxInfo.Expression.builder(ExprSecBlankConsComp.class, ConsumableWrapper.class) + .addPatterns("a (blank|empty) consumable component") + .supplier(ExprSecBlankConsComp::new) + .build() + ); EventValues.registerEventValue(BlankConsumableSectionEvent.class, ConsumableWrapper.class, BlankConsumableSectionEvent::getWrapper); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java index 8f1a8cf40b8..04d0f337774 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java +++ b/src/main/java/org/skriptlang/skript/bukkit/itemcomponents/consumable/elements/LitConsumeEffectClear.java @@ -1,13 +1,11 @@ package org.skriptlang.skript.bukkit.itemcomponents.consumable.elements; -import ch.njol.skript.Skript; import ch.njol.skript.doc.Description; 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.lang.Expression; -import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.util.SimpleLiteral; import ch.njol.util.Kleenean; @@ -15,6 +13,8 @@ import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.itemcomponents.consumable.ConsumeEffectExperimentalSyntax; +import org.skriptlang.skript.registration.SyntaxInfo; +import org.skriptlang.skript.registration.SyntaxRegistry; @Name("Consume Effect - Clear Effects") @Description(""" @@ -31,9 +31,14 @@ @SuppressWarnings("UnstableApiUsage") public class LitConsumeEffectClear extends SimpleLiteral implements ConsumeEffectExperimentalSyntax { - static { - Skript.registerExpression(LitConsumeEffectClear.class, ConsumeEffect.class, ExpressionType.SIMPLE, - "[a] consume effect to clear all (potion|status) effects"); + public static void register(SyntaxRegistry registry) { + registry.register( + SyntaxRegistry.EXPRESSION, + SyntaxInfo.Expression.builder(LitConsumeEffectClear.class, ConsumeEffect.class) + .addPatterns("[a] consume effect to clear all (potion|status) effects") + .supplier(LitConsumeEffectClear::new) + .build() + ); } public LitConsumeEffectClear() {