diff --git a/build.gradle b/build.gradle index 4f0851f5e..58731f751 100644 --- a/build.gradle +++ b/build.gradle @@ -46,7 +46,7 @@ dependencies { compileOnly("org.apache.commons:commons-text:1.10.0") // NBT-API - implementation("de.tr7zw:item-nbt-api:2.13.1") { + implementation("de.tr7zw:item-nbt-api:2.13.2") { transitive = false } @@ -100,7 +100,7 @@ shadowJar { tasks.register('server', Copy) { from shadowJar // Change this to wherever you want your jar to build - into '/Users/ShaneBee/Desktop/Server/Skript/1-21/plugins' + into '/Users/ShaneBee/Desktop/Server/Skript/1-21-1/plugins' } publishing { diff --git a/src/main/java/com/shanebeestudios/skbee/AddonLoader.java b/src/main/java/com/shanebeestudios/skbee/AddonLoader.java index 5e4f73884..35bb3d33c 100644 --- a/src/main/java/com/shanebeestudios/skbee/AddonLoader.java +++ b/src/main/java/com/shanebeestudios/skbee/AddonLoader.java @@ -2,6 +2,7 @@ import ch.njol.skript.Skript; import ch.njol.skript.SkriptAddon; +import ch.njol.skript.localization.Noun; import ch.njol.skript.registrations.Classes; import ch.njol.skript.test.runner.TestMode; import ch.njol.skript.util.Version; @@ -141,6 +142,16 @@ private void loadSkriptElements() { for (int i = 0; i < finish.length; i++) { Util.log(" - %s %s%s", finish[i], elementNames[i], finish[i] == 1 ? "" : "s"); } + + if (this.config.SETTINGS_DEBUG) { + // Print names of ClassInfos with missing lang entry + Bukkit.getScheduler().runTaskLater(this.plugin, () -> Classes.getClassInfos().forEach(classInfo -> { + Noun name = classInfo.getName(); + if (name.toString().contains("types.")) { + Util.log("ClassInfo missing lang entry for: &c%s", name); + } + }), 1); + } } private void loadNBTElements() { diff --git a/src/main/java/com/shanebeestudios/skbee/SkBee.java b/src/main/java/com/shanebeestudios/skbee/SkBee.java index 2e049e4dd..0892e543a 100644 --- a/src/main/java/com/shanebeestudios/skbee/SkBee.java +++ b/src/main/java/com/shanebeestudios/skbee/SkBee.java @@ -6,6 +6,7 @@ import com.shanebeestudios.skbee.api.structure.StructureManager; import com.shanebeestudios.skbee.api.util.UpdateChecker; import com.shanebeestudios.skbee.api.util.Util; +import com.shanebeestudios.skbee.api.wrapper.LazyLocation; import com.shanebeestudios.skbee.config.BoundConfig; import com.shanebeestudios.skbee.config.Config; import com.shanebeestudios.skbee.elements.other.sections.SecRunTaskLater; @@ -25,6 +26,7 @@ public class SkBee extends JavaPlugin { static { ConfigurationSerialization.registerClass(Bound.class, "Bound"); + ConfigurationSerialization.registerClass(LazyLocation.class, "LazyLocation"); } // Earliest MC Version that SkBee will support diff --git a/src/main/java/com/shanebeestudios/skbee/api/bound/Bound.java b/src/main/java/com/shanebeestudios/skbee/api/bound/Bound.java index c89baed93..7807479b2 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/bound/Bound.java +++ b/src/main/java/com/shanebeestudios/skbee/api/bound/Bound.java @@ -2,6 +2,7 @@ import com.google.common.base.Preconditions; import com.shanebeestudios.skbee.api.util.WorldUtils; +import com.shanebeestudios.skbee.api.wrapper.LazyLocation; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; @@ -12,6 +13,7 @@ import org.bukkit.util.BoundingBox; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -139,11 +141,11 @@ public boolean overlaps(Location l1, Location l2) { * @param type Type of entity to get * @return List of loaded entities in bound */ - public List getEntities(Class type) { + public @Nullable List getEntities(Class type) { World world = getWorld(); if (world == null) return null; Collection nearbyEntities = world.getNearbyEntities(this.boundingBox, entity -> - type.isAssignableFrom(entity.getClass())); + type.isAssignableFrom(entity.getClass())); return new ArrayList<>(nearbyEntities); } @@ -152,7 +154,7 @@ public List getEntities(Class type) { * * @return List of blocks within bound */ - public List getBlocks() { + public @Nullable List getBlocks() { World w = getWorld(); if (w == null) return null; List array = new ArrayList<>(); @@ -457,7 +459,11 @@ public void removeMember(UUID member) { * @param value Value to set */ public void setValue(String key, Object value) { - this.values.put(key, value); + if (value instanceof Location location) { + this.values.put(key, new LazyLocation(location)); + } else { + this.values.put(key, value); + } } /** @@ -483,7 +489,9 @@ public void clearValues() { * @return Value from bound */ public Object getValue(String key) { - return this.values.get(key); + Object o = this.values.get(key); + if (o instanceof LazyLocation lazyLocation) return lazyLocation.getLocation(); + return o; } /** diff --git a/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTCustomItemStack.java b/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTCustomItemStack.java index 4e818e84d..17a80cfec 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTCustomItemStack.java +++ b/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTCustomItemStack.java @@ -14,20 +14,32 @@ public class NBTCustomItemStack extends NBTContainer { private final ItemStack originalItemStack; - private final boolean useComponents; + private final boolean isCustomData; - public NBTCustomItemStack(ItemStack itemStack, boolean useComponents) { - super(getContainer(NBTItem.convertItemtoNBT(itemStack), useComponents).toString()); + public NBTCustomItemStack(ItemStack itemStack, boolean isCustomData, boolean isVanilla, boolean isFull) { + super(getInitialContainer(itemStack, isCustomData, isVanilla, isFull).toString()); this.originalItemStack = itemStack; - this.useComponents = useComponents; + this.isCustomData = isCustomData; } - private static NBTCompound getContainer(NBTContainer itemContainer, boolean useComponents) { - NBTCompound componentsContainer = itemContainer.getOrCreateCompound(NBTApi.TAG_NAME); - if (useComponents) { - return componentsContainer; + private static NBTCompound getInitialContainer(ItemStack itemStack, boolean isCustomData, boolean isVanilla, boolean isFull) { + NBTCompound nbtContainer; + if (isVanilla) { + nbtContainer = NBTReflection.getVanillaNBT(itemStack); } else { + nbtContainer = NBTItem.convertItemtoNBT(itemStack); + } + if (nbtContainer == null) nbtContainer = new NBTContainer(); + return getContainer(nbtContainer, isCustomData, isFull); + } + + private static NBTCompound getContainer(NBTCompound itemContainer, boolean isCustomData, boolean isFull) { + if (isFull) return itemContainer; + NBTCompound componentsContainer = itemContainer.getOrCreateCompound(NBTApi.TAG_NAME); + if (isCustomData) { return componentsContainer.getOrCreateCompound("minecraft:custom_data"); + } else { + return componentsContainer; } } @@ -35,7 +47,7 @@ private static NBTCompound getContainer(NBTContainer itemContainer, boolean useC protected void saveCompound() { super.saveCompound(); NBTContainer originalItemContainer = NBTItem.convertItemtoNBT(this.originalItemStack.clone()); - NBTCompound components = getContainer(originalItemContainer, this.useComponents); + NBTCompound components = getContainer(originalItemContainer, this.isCustomData, false); components.clearNBT(); components.mergeCompound(this); ItemStack itemStack = NBTItem.convertNBTtoItem(originalItemContainer); diff --git a/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTCustomItemType.java b/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTCustomItemType.java index 59f520be5..a14789175 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTCustomItemType.java +++ b/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTCustomItemType.java @@ -10,8 +10,8 @@ public class NBTCustomItemType extends NBTCustomItemStack { private final ItemType itemType; - public NBTCustomItemType(ItemType itemType, boolean useComponents) { - super(itemType.getRandom(), useComponents); + public NBTCustomItemType(ItemType itemType, boolean isCustomData, boolean isVanilla, boolean isFull) { + super(itemType.getRandom(), isCustomData, isVanilla, isFull); this.itemType = itemType; } diff --git a/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTCustomSlot.java b/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTCustomSlot.java index 083f46fb1..8c8ea8844 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTCustomSlot.java +++ b/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTCustomSlot.java @@ -12,8 +12,8 @@ public class NBTCustomSlot extends NBTCustomItemStack { private final Slot slot; - public NBTCustomSlot(Slot slot, boolean useComponents) { - super(Objects.requireNonNull(slot.getItem()), useComponents); + public NBTCustomSlot(Slot slot, boolean isCustomData, boolean isVanilla, boolean isFull) { + super(Objects.requireNonNull(slot.getItem()), isCustomData, isVanilla, isFull); this.slot = slot; } diff --git a/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTReflection.java b/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTReflection.java new file mode 100644 index 000000000..8a4acca10 --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/api/nbt/NBTReflection.java @@ -0,0 +1,98 @@ +package com.shanebeestudios.skbee.api.nbt; + +import com.shanebeestudios.skbee.SkBee; +import com.shanebeestudios.skbee.api.reflection.ReflectionUtils; +import de.tr7zw.changeme.nbtapi.NBTCompound; +import de.tr7zw.changeme.nbtapi.NBTContainer; +import de.tr7zw.changeme.nbtapi.NBTItem; +import org.bukkit.Bukkit; +import org.bukkit.inventory.ItemStack; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +@SuppressWarnings({"SequencedCollectionMethodCanBeUsed", "CallToPrintStackTrace", "DataFlowIssue"}) +public class NBTReflection { + + private static final boolean DEBUG = SkBee.getPlugin().getPluginConfig().SETTINGS_DEBUG; + + // Classes + private static Class CRAFT_ITEM_STACK_CLASS; + + // Fields/Objects + private static Object CODEC; + private static Object REGISTERY_ACCESS; + private static Object NBT_OPS_INSTANCE; + + // Methods + private static Method GET_COMPONENTS_METHOD; + private static Method ENCODE_METHOD; + private static Method GET_OR_ELSE; + private static Method CREATE_SERIALIZER_METHOD; + + // Constructors + private static Constructor NBT_COMPOUND_CONSTRUCTOR; + + static { + try { + // Classes + CRAFT_ITEM_STACK_CLASS = ReflectionUtils.getOBCClass("inventory.CraftItemStack"); + Class compoundTag = ReflectionUtils.getNMSClass("net.minecraft.nbt.CompoundTag"); + Class craftWorld = ReflectionUtils.getOBCClass("CraftWorld"); + Class dataComponentMap = ReflectionUtils.getNMSClass("net.minecraft.core.component.DataComponentMap"); + Class dataResult = ReflectionUtils.getNMSClass("com.mojang.serialization.DataResult"); + Class dynamicOps = ReflectionUtils.getNMSClass("com.mojang.serialization.DynamicOps"); + Class encoder = ReflectionUtils.getNMSClass("com.mojang.serialization.Encoder"); + Class holderLookup = ReflectionUtils.getNMSClass("net.minecraft.core.HolderLookup$Provider"); + Class itemStack = ReflectionUtils.getNMSClass("net.minecraft.world.item.ItemStack"); + Class level = ReflectionUtils.getNMSClass("net.minecraft.world.level.Level"); + Class nbtOps = ReflectionUtils.getNMSClass("net.minecraft.nbt.NbtOps"); + + // Fields/Objects + CODEC = ReflectionUtils.getField("CODEC", dataComponentMap, null); + Object nmsWorld = craftWorld.getDeclaredMethod("getHandle").invoke(Bukkit.getWorlds().get(0)); + REGISTERY_ACCESS = level.getDeclaredMethod("registryAccess").invoke(nmsWorld); + NBT_OPS_INSTANCE = ReflectionUtils.getField("INSTANCE", nbtOps, null); + + // Methods + GET_COMPONENTS_METHOD = itemStack.getDeclaredMethod("getComponents"); + ENCODE_METHOD = encoder.getMethod("encode", Object.class, dynamicOps, Object.class); + GET_OR_ELSE = dataResult.getDeclaredMethod("getOrThrow"); + CREATE_SERIALIZER_METHOD = holderLookup.getDeclaredMethod("createSerializationContext", dynamicOps); + + // Constructors + NBT_COMPOUND_CONSTRUCTOR = compoundTag.getDeclaredConstructor(); + + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + if (DEBUG) e.printStackTrace(); + } + } + + /** + * Get the vanilla version of NBT of an item + *
This will show components which don't normally show in NBT + * + * @param itemStack Item to grab NBT from + * @return Vanilla NBT of item + */ + @SuppressWarnings({"deprecation"}) + public static NBTCompound getVanillaNBT(ItemStack itemStack) { + try { + Object nmsItem = ReflectionUtils.getField("handle", CRAFT_ITEM_STACK_CLASS, itemStack); + Object components = GET_COMPONENTS_METHOD.invoke(nmsItem); + Object serial = CREATE_SERIALIZER_METHOD.invoke(REGISTERY_ACCESS, NBT_OPS_INSTANCE); + Object newNBTCompound = NBT_COMPOUND_CONSTRUCTOR.newInstance(); + + Object encoded = ENCODE_METHOD.invoke(CODEC, components, serial, newNBTCompound); + Object nmsNbt = GET_OR_ELSE.invoke(encoded); + NBTCompound itemNbt = NBTItem.convertItemtoNBT(itemStack); + itemNbt.getOrCreateCompound("components").mergeCompound(new NBTContainer(nmsNbt)); + return itemNbt; + } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + if (DEBUG) e.printStackTrace(); + return new NBTContainer(); + } + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/api/util/ItemUtils.java b/src/main/java/com/shanebeestudios/skbee/api/util/ItemUtils.java index ad39d29d1..4b1a3c6ec 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/util/ItemUtils.java +++ b/src/main/java/com/shanebeestudios/skbee/api/util/ItemUtils.java @@ -1,12 +1,16 @@ package com.shanebeestudios.skbee.api.util; import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; import ch.njol.skript.registrations.Classes; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; +import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; public class ItemUtils { @@ -67,4 +71,46 @@ public static String attributeModifierToString(AttributeModifier attributeModifi return builder.toString(); } + /** + * Add ItemTypes to a list of ItemStacks + *
This will split up oversized stacks as well + * + * @param itemTypes List of ItemTypes to add + * @param itemStacks Option list of ItemStacks to modify + * @return List of ItemStacks split up correctly + */ + public static List addItemTypesToList(List itemTypes, List itemStacks) { + List originalList = itemStacks != null ? new ArrayList<>(itemStacks) : new ArrayList<>(); + ItemStack[] buffer = originalList.toArray(new ItemStack[1000]); + for (ItemType itemType : itemTypes) { + // Split up oversized stacks + itemType.addTo(buffer); + } + List newList = new ArrayList<>(); + for (ItemStack itemStack : buffer) { + if (itemStack != null && !itemStack.isEmpty()) newList.add(itemStack); + } + return newList; + } + + /** + * Remove list of ItemTypes from a list of ItemStacks + *
This will split up oversized stacks as well + * + * @param itemStacks List of ItemStacks to have ItemTypes removed from + * @param itemTypes List of ItemTypes to remove + * @return Updated list of ItemStacks + */ + public static List removeItemTypesFromList(List itemStacks, List itemTypes) { + List copyList = new ArrayList<>(itemStacks); + for (ItemType itemType : itemTypes) { + itemType.removeFrom(copyList); + } + List newItems = new ArrayList<>(); + for (ItemStack itemStack : copyList) { + if (itemStack != null && !itemStack.isEmpty()) newItems.add(itemStack); + } + return newItems; + } + } diff --git a/src/main/java/com/shanebeestudios/skbee/api/wrapper/ComponentWrapper.java b/src/main/java/com/shanebeestudios/skbee/api/wrapper/ComponentWrapper.java index a5f3e2e8a..16ae6e535 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/wrapper/ComponentWrapper.java +++ b/src/main/java/com/shanebeestudios/skbee/api/wrapper/ComponentWrapper.java @@ -56,6 +56,10 @@ public class ComponentWrapper { // STATIC private static final boolean HAS_SIDES = Skript.classExists("org.bukkit.block.sign.SignSide"); + /** + * Check if ItemMeta supports 'itemName' ('item_name' component + */ + public static final boolean HAS_ITEM_NAME = Skript.methodExists(ItemMeta.class, "itemName"); /** * Create an empty component @@ -521,17 +525,6 @@ public void setEntityName(Entity entity, boolean alwaysVisible) { } } - /** - * Set the name of an item - * - * @param itemType Item to change name - */ - public void setItemName(ItemType itemType) { - ItemMeta itemMeta = itemType.getItemMeta(); - itemMeta.displayName(this.component); - itemType.setItemMeta(itemMeta); - } - /** * Set the name of the inventory *

NOTE: This is not permanent, this will just rename the open inventory view

diff --git a/src/main/java/com/shanebeestudios/skbee/api/wrapper/LazyLocation.java b/src/main/java/com/shanebeestudios/skbee/api/wrapper/LazyLocation.java new file mode 100644 index 000000000..161b16f8b --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/api/wrapper/LazyLocation.java @@ -0,0 +1,80 @@ +package com.shanebeestudios.skbee.api.wrapper; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.util.NumberConversions; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +/** + * Represents a lazy version of {@link Location} + *
These are used in {@link com.shanebeestudios.skbee.api.bound.Bound Bounds} + * when a world might not have been loaded yet + */ +public class LazyLocation extends Location { + + private String worldName; + + public LazyLocation(World world, double x, double y, double z, float yaw, float pitch) { + super(world, x, y, z, yaw, pitch); + this.worldName = world.getName(); + } + + public LazyLocation(String worldName, double x, double y, double z, float yaw, float pitch) { + super(null, x, y, z, yaw, pitch); + this.worldName = worldName; + } + + public LazyLocation(Location location) { + super(location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + /** + * Get the {@link Location} this LazyLocation holds + *
Will attempt to check/update the world + * + * @return Location with hopefully updated world + */ + public Location getLocation() { + if (super.getWorld() == null) { + World world = Bukkit.getWorld(this.worldName); + if (world != null) this.setWorld(world); + } + return this; + } + + /** + * hidden + * Copied from {@link Location Bukkit Location} + */ + @Override + public @NotNull Map serialize() { + Map data = super.serialize(); + + if (!data.containsKey("world")) { + data.put("world", this.worldName); + } + + return data; + } + + /** + * hidden + * Copied from {@link Location Bukkit Location} + */ + @NotNull + public static Location deserialize(@NotNull Map args) { + World world = null; + if (args.containsKey("world")) { + String name = (String) args.get("world"); + world = Bukkit.getWorld(name); + if (world == null) { + return new LazyLocation(name, NumberConversions.toDouble(args.get("x")), NumberConversions.toDouble(args.get("y")), NumberConversions.toDouble(args.get("z")), NumberConversions.toFloat(args.get("yaw")), NumberConversions.toFloat(args.get("pitch"))); + } + } + return new LazyLocation(world, NumberConversions.toDouble(args.get("x")), NumberConversions.toDouble(args.get("y")), NumberConversions.toDouble(args.get("z")), NumberConversions.toFloat(args.get("yaw")), NumberConversions.toFloat(args.get("pitch"))); + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/elements/gameevent/type/Types.java b/src/main/java/com/shanebeestudios/skbee/elements/gameevent/type/Types.java index 066776404..f9d603cef 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/gameevent/type/Types.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/gameevent/type/Types.java @@ -1,69 +1,23 @@ package com.shanebeestudios.skbee.elements.gameevent.type; -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 ch.njol.util.StringUtils; +import com.shanebeestudios.skbee.api.wrapper.RegistryClassInfo; import org.bukkit.GameEvent; -import org.bukkit.NamespacedKey; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.bukkit.Registry; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@SuppressWarnings("deprecation") // GameEvent.values() <-- paper did this I'm assuming public class Types { - private static final Map GAME_EVENT_MAP = new HashMap<>(); - static { - List names = new ArrayList<>(); - for (GameEvent gameEvent : GameEvent.values()) { - NamespacedKey key = gameEvent.getKey(); - GAME_EVENT_MAP.put(key.toString(), gameEvent); - GAME_EVENT_MAP.put(key.getKey(), gameEvent); - names.add(key.getKey()); - } - Collections.sort(names); - String namesString = StringUtils.join(names, ", "); - Classes.registerClass(new ClassInfo<>(GameEvent.class, "gameevent") + Classes.registerClass(RegistryClassInfo.create(Registry.GAME_EVENT, GameEvent.class, "gameevent") .name("Game Event") .user("game ?events?") .description("Represents a Minecraft 'GameEvent', mainly used by Skulk Sensors. Requires MC 1.17+.", - "See [**GameEvents**](https://minecraft.wiki/w/Sculk_Sensor#Vibration_amplitudes) on McWiki for more details.", + "See [**GameEvents**](https://minecraft.wiki/w/Sculk_Sensor#Vibration_frequencies) on McWiki for more details.", "NOTE: These are auto-generated and may differ between server versions.") - .usage(namesString) .after("itemtype") .examples("") - .since("1.14.0") - .parser(new Parser<>() { - - @SuppressWarnings("NullableProblems") - @Nullable - @Override - public GameEvent parse(String string, ParseContext context) { - if (string.contains(" ")) - string = string.replace(" ", "_"); - if (GAME_EVENT_MAP.containsKey(string)) return GAME_EVENT_MAP.get(string); - return null; - } - - @Override - public @NotNull String toString(GameEvent gameEvent, int flags) { - return gameEvent.getKey().getKey(); - } - - @Override - public @NotNull String toVariableNameString(GameEvent gameEvent) { - return "gameevent:" + gameEvent.getKey().getKey(); - } - })); + .since("1.14.0")); } } diff --git a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/effects/EffApplyPotion.java b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/effects/EffApplyPotion.java index 0dfdcf721..dde707f89 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/effects/EffApplyPotion.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/effects/EffApplyPotion.java @@ -17,7 +17,7 @@ @Name("ItemComponent - Food Component Apply Potion Effect") @Description({"Apply a potion effect to a food component. This works in the `effects` section of a food component section.", - "Probability is an optional value between 0 and 100. This is the chance the player will get this effect when eaten."}) + "`probability` is an optional value between 0 and 1. This is the chance the player will get this effect when eaten."}) @Examples({"apply food component to player's tool:", "\tnutrition: 5", "\tsaturation: 3", @@ -25,7 +25,7 @@ "\tcan always eat: true", "\teffects:", "\t\tapply potion effect of nausea without particles for 10 seconds", - "\t\tapply potion effect of poison without particles for 5 seconds with probability 50"}) + "\t\tapply potion effect of poison without particles for 5 seconds with probability 0.5"}) @Since("3.5.8") public class EffApplyPotion extends Effect { @@ -56,7 +56,7 @@ protected void execute(Event event) { if (effect == null) return; Number probNum = this.probability != null ? this.probability.getSingle(event) : null; - float probability = probNum != null ? MathUtil.clamp((probNum.floatValue() / 100), 0.0F, 1.0F) : 1; + float probability = probNum != null ? MathUtil.clamp(probNum.floatValue(), 0.0F, 1.0F) : 1; applyEvent.getComponent().addEffect(effect, probability); } diff --git a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/expressions/ExprBundleContents.java b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/expressions/ExprBundleContents.java new file mode 100644 index 000000000..3703db744 --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/expressions/ExprBundleContents.java @@ -0,0 +1,121 @@ +package com.shanebeestudios.skbee.elements.itemcomponent.expressions; + +import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +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.SimpleExpression; +import ch.njol.util.Kleenean; +import ch.njol.util.coll.CollectionUtils; +import com.shanebeestudios.skbee.api.util.ItemUtils; +import org.bukkit.event.Event; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BundleMeta; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +@Name("ItemComponent - Bundle Contents") +@Description("Represents the contents of a bundle item.") +@Examples({"add 100 diamonds to bundle contents of player's tool", + "remove all diamonds from bundle contents of player's tool", + "delete bundle contents of player's tool"}) +@Since("INSERT VERSION") +public class ExprBundleContents extends SimpleExpression { + + static { + Skript.registerExpression(ExprBundleContents.class, ItemType.class, ExpressionType.COMBINED, + "bundle contents of %itemtypes%", + "%itemtypes%'[s] bundle contents"); + } + + private Expression itemTypes; + + @SuppressWarnings({"unchecked", "NullableProblems"}) + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + this.itemTypes = (Expression) exprs[0]; + return true; + } + + @SuppressWarnings("NullableProblems") + @Override + protected @Nullable ItemType[] get(Event event) { + List itemTypes = new ArrayList<>(); + for (ItemType itemType : this.itemTypes.getArray(event)) { + ItemMeta itemMeta = itemType.getItemMeta(); + if (itemMeta instanceof BundleMeta bundleMeta) { + bundleMeta.getItems().forEach(itemStack -> itemTypes.add(new ItemType(itemStack))); + } + } + return itemTypes.toArray(new ItemType[0]); + } + + @SuppressWarnings("NullableProblems") + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.ADD || mode == ChangeMode.REMOVE) + return CollectionUtils.array(ItemType[].class); + else if (mode == ChangeMode.DELETE) + return CollectionUtils.array(); + return null; + } + + @SuppressWarnings({"NullableProblems", "ConstantValue"}) + @Override + public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { + List itemStacks = null; + List changedTypes = new ArrayList<>(); + if (delta != null) { + for (Object object : delta) { + if (object instanceof ItemType itemType) { + changedTypes.add(itemType); + } + } + itemStacks = ItemUtils.addItemTypesToList(changedTypes, null); + } + for (ItemType itemType : this.itemTypes.getArray(event)) { + ItemMeta itemMeta = itemType.getItemMeta(); + if (!(itemMeta instanceof BundleMeta bundleMeta)) continue; + + if (mode == ChangeMode.SET) { + bundleMeta.setItems(itemStacks); + } else if (mode == ChangeMode.ADD) { + List contents = ItemUtils.addItemTypesToList(changedTypes, bundleMeta.getItems()); + bundleMeta.setItems(contents); + } else if (mode == ChangeMode.REMOVE) { + List i = ItemUtils.removeItemTypesFromList(bundleMeta.getItems(), changedTypes); + bundleMeta.setItems(i); + } else if (mode == ChangeMode.DELETE) { + bundleMeta.setItems(itemStacks); + } + + itemType.setItemMeta(itemMeta); + } + } + + @Override + public @NotNull Class getReturnType() { + return ItemType.class; + } + + @Override + public boolean isSingle() { + return false; + } + + @Override + public @NotNull String toString(Event e, boolean d) { + return "bundle contents of " + this.itemTypes.toString(e, d); + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/expressions/ExprEnchantmentGlintOverride.java b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/expressions/ExprEnchantmentGlintOverride.java new file mode 100644 index 000000000..2864ec4de --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/expressions/ExprEnchantmentGlintOverride.java @@ -0,0 +1,72 @@ +package com.shanebeestudios.skbee.elements.itemcomponent.expressions; + +import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.coll.CollectionUtils; +import org.bukkit.event.Event; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@Name("ItemComponent - Enchantment Glint Override") +@Description({"Represents the enchantment glint override of an item (Requires Minecraft 1.20.5+).", + "Overrides the enchantment glint effect on an item. When `true`, the item will display a glint, even without enchantments.", + "When `false`, the item will not display a glint, even with enchantments.", + "**Note**: If no override is applied, will return null.", + "**Changers**:", + "- `set` = Allows you to override the glint.", + "- `reset` = Reset back to default state."}) +@Examples({"set glint override of player's tool to true", + "set glint override of player's tool to false"}) +@Since("INSERT VERSION") +public class ExprEnchantmentGlintOverride extends SimplePropertyExpression { + + static { + if (Skript.methodExists(ItemMeta.class, "getEnchantmentGlintOverride")) { + register(ExprEnchantmentGlintOverride.class, Boolean.class, "[enchantment] glint [override]", "itemtypes"); + } + } + + @Override + public @Nullable Boolean convert(ItemType itemType) { + ItemMeta itemMeta = itemType.getItemMeta(); + if (!itemMeta.hasEnchantmentGlintOverride()) return null; + return itemMeta.getEnchantmentGlintOverride(); + } + + @SuppressWarnings("NullableProblems") + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET) return CollectionUtils.array(Boolean.class); + else if (mode == ChangeMode.RESET) return CollectionUtils.array(); + return null; + } + + @SuppressWarnings({"NullableProblems", "ConstantValue"}) + @Override + public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { + Boolean glint = delta != null && delta[0] instanceof Boolean bool ? bool : null; + for (ItemType itemType : getExpr().getArray(event)) { + ItemMeta itemMeta = itemType.getItemMeta(); + itemMeta.setEnchantmentGlintOverride(glint); + itemType.setItemMeta(itemMeta); + } + } + + @Override + protected @NotNull String getPropertyName() { + return "enchantment glint override"; + } + + @Override + public @NotNull Class getReturnType() { + return Boolean.class; + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/expressions/ExprMaxStackSizeComponent.java b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/expressions/ExprMaxStackSizeComponent.java new file mode 100644 index 000000000..9598001a6 --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/expressions/ExprMaxStackSizeComponent.java @@ -0,0 +1,70 @@ +package com.shanebeestudios.skbee.elements.itemcomponent.expressions; + +import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.coll.CollectionUtils; +import com.shanebeestudios.skbee.api.util.MathUtil; +import org.bukkit.event.Event; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@Name("ItemComponent - Max Stack Size") +@Description({"Represents the max stack size of an item (Requires Minecraft 1.20.5+).", + "**Changers**:", + "- `set` = Set the max stack size, must be an integer between 1 and 99.", + "- `reset` = Resets back to default stack size."}) +@Examples({"set max stack size component of player's tool to 1", + "reset max stack size component of player's tool"}) +@Since("INSERT VERSION") +public class ExprMaxStackSizeComponent extends SimplePropertyExpression { + + static { + if (Skript.methodExists(ItemMeta.class, "setMaxStackSize", Integer.class)) { + register(ExprMaxStackSizeComponent.class, Number.class, "max stack size component", "itemtypes"); + } + } + + @Override + public @Nullable Number convert(ItemType itemType) { + ItemMeta itemMeta = itemType.getItemMeta(); + if (!itemMeta.hasMaxStackSize()) return itemType.getMaterial().getMaxStackSize(); + return itemMeta.getMaxStackSize(); + } + + @SuppressWarnings("NullableProblems") + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.RESET) return CollectionUtils.array(); + else if (mode == ChangeMode.SET) return CollectionUtils.array(Number.class); + return null; + } + + @SuppressWarnings({"NullableProblems", "ConstantValue"}) + @Override + public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { + Integer maxStackSize = delta != null && delta[0] instanceof Number num ? MathUtil.clamp(num.intValue(), 1, 99) : null; + for (ItemType itemType : getExpr().getArray(event)) { + ItemMeta itemMeta = itemType.getItemMeta(); + itemMeta.setMaxStackSize(maxStackSize); + itemType.setItemMeta(itemMeta); + } + } + + @Override + protected @NotNull String getPropertyName() { + return "max stack size component"; + } + + @Override + public @NotNull Class getReturnType() { + return Number.class; + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/expressions/ExprRepairCost.java b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/expressions/ExprRepairCost.java new file mode 100644 index 000000000..d873a20d0 --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/expressions/ExprRepairCost.java @@ -0,0 +1,77 @@ +package com.shanebeestudios.skbee.elements.itemcomponent.expressions; + +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.coll.CollectionUtils; +import org.bukkit.event.Event; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.Repairable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@Name("ItemComponent - Repair Cost") +@Description({"The number of experience levels to add to the base level cost when repairing, combining, or renaming this item with an anvil.", + "Must be a non-negative integer, defaults to 0."}) +@Examples({"set repair cost of player's tool to 3", + "add 2 to repair cost of player's tool", + "subtract 1 from repair cost of player's tool", + "reset repair cost of player's tool", + "if repair cost of player's tool > 0:"}) +@Since("INSERT VERSION") +public class ExprRepairCost extends SimplePropertyExpression { + + static { + register(ExprRepairCost.class, Number.class, "repair cost", "itemtypes"); + } + + @Override + public @Nullable Number convert(ItemType itemType) { + ItemMeta itemMeta = itemType.getItemMeta(); + if (itemMeta instanceof Repairable repairable) { + return repairable.getRepairCost(); + } + return null; + } + + @SuppressWarnings("NullableProblems") + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET || mode == ChangeMode.REMOVE || mode == ChangeMode.ADD) return CollectionUtils.array(Number.class); + else if (mode == ChangeMode.RESET || mode == ChangeMode.DELETE) return CollectionUtils.array(); + return null; + } + + @SuppressWarnings({"NullableProblems", "ConstantValue"}) + @Override + public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { + int cost = delta != null && delta[0] instanceof Number num ? num.intValue() : 0; + for (ItemType itemType : getExpr().getArray(event)) { + ItemMeta itemMeta = itemType.getItemMeta(); + if (itemMeta instanceof Repairable repairable) { + int newCost = switch (mode) { + case ADD -> repairable.getRepairCost() + cost; + case REMOVE -> repairable.getRepairCost() - cost; + default-> cost; + }; + repairable.setRepairCost(Math.max(newCost, 0)); + itemType.setItemMeta(itemMeta); + } + } + } + + @Override + protected @NotNull String getPropertyName() { + return "repair cost"; + } + + @Override + public @NotNull Class getReturnType() { + return Number.class; + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecFoodComponent.java b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecFoodComponent.java index 0dcce6657..59355925d 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecFoodComponent.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecFoodComponent.java @@ -77,11 +77,12 @@ public FoodComponent getComponent() { } } - private static final boolean HAS_CONVERT = Skript.methodExists(FoodComponent.class, "setUsingConvertsTo", ItemStack.class); + private static boolean HAS_CONVERT = false; private static final EntryValidator.EntryValidatorBuilder VALIDATIOR = EntryValidator.builder(); static { if (Skript.classExists("org.bukkit.inventory.meta.components.FoodComponent")) { + HAS_CONVERT = Skript.methodExists(FoodComponent.class, "setUsingConvertsTo", ItemStack.class); VALIDATIOR.addEntryData(new ExpressionEntryData<>("nutrition", null, false, Number.class)); VALIDATIOR.addEntryData(new ExpressionEntryData<>("saturation", null, false, Number.class)); VALIDATIOR.addEntryData(new ExpressionEntryData<>("can always eat", null, true, Boolean.class)); @@ -112,6 +113,10 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye this.canAlwaysEat = (Expression) container.getOptional("can always eat", false); this.eatTime = (Expression) container.getOptional("eat time", false); this.usingConverts = (Expression) container.getOptional("using converts to", false); + if (this.usingConverts != null && !HAS_CONVERT) { + Skript.error("'using converts to' requires Minecraft 1.21+"); + return false; + } SectionNode potionEffects = container.getOptional("effects", SectionNode.class, false); if (potionEffects != null) { this.potionEffectSection = loadCode(potionEffects, "potion effects", FoodComponentApplyEvent.class); diff --git a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecToolComponent.java b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecToolComponent.java index 00f185ae7..e3f9058c5 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecToolComponent.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecToolComponent.java @@ -33,7 +33,7 @@ "", "**Entries/Sections**:", "- `default mining speed` = The default mining speed of this tool, used if no rules override it. Defaults to 1.0. [Optional]", - "- `damage per block` = The amount of durability to remove each time a block is broken with this tool. Must be a non-negative integer.", + "- `damage per block` = The amount of durability to remove each time a block is broken with this tool. Must be a non-negative integer. [Optional]", "- `rules:` = A list of rules for the blocks that this tool has a special behavior with."}) @Examples({"set {_i} to a stick", "apply tool component to {_i}:", @@ -74,7 +74,7 @@ public ToolComponent getComponent() { static { if (Skript.classExists("org.bukkit.inventory.meta.components.ToolComponent")) { - VALIDATIOR.addEntryData(new ExpressionEntryData<>("default mining speed", null, false, Number.class)); + VALIDATIOR.addEntryData(new ExpressionEntryData<>("default mining speed", null, true, Number.class)); VALIDATIOR.addEntryData(new ExpressionEntryData<>("damage per block", null, true, Number.class)); VALIDATIOR.addSection("rules", true); Skript.registerSection(SecToolComponent.class, "apply tool component to %itemtypes%"); @@ -108,20 +108,20 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye protected @Nullable TriggerItem walk(Event event) { Object localVars = Variables.copyLocalVariables(event); - Number miningSpeedNum = this.defaultMiningSpeed.getSingle(event); - Number damagePerNum = this.damagePerBlock.getSingle(event); - if (damagePerNum == null) return super.walk(event, false); - - int damagePerBlock = damagePerNum.intValue(); + Number defaultMiningSpeed = this.defaultMiningSpeed != null ? this.defaultMiningSpeed.getSingle(event) : null; + Number damagePerBlock = this.damagePerBlock != null ? this.damagePerBlock.getSingle(event) : null; for (ItemType itemType : this.items.getArray(event)) { ItemMeta itemMeta = itemType.getItemMeta(); ToolComponent tool = itemMeta.getTool(); - if (miningSpeedNum != null) { - tool.setDefaultMiningSpeed(miningSpeedNum.floatValue()); + if (defaultMiningSpeed != null) { + tool.setDefaultMiningSpeed(defaultMiningSpeed.floatValue()); + } + if (damagePerBlock != null) { + int dpb = damagePerBlock.intValue(); + if (dpb >= 0) tool.setDamagePerBlock(dpb); } - tool.setDamagePerBlock(damagePerBlock); if (this.rulesSection != null) { ToolComponentApplyRulesEvent toolEvent = new ToolComponentApplyRulesEvent(tool); diff --git a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecToolRule.java b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecToolRule.java index 3dcb1ac5d..b98780f52 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecToolRule.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecToolRule.java @@ -35,7 +35,7 @@ "NOTE: One of either `block types` or `block tag` MUST be used.", "`block types` = The blocks to match for this rule to apply.", "`block tag` = A Minecraft Tag to match for this rule to apply.", - "`speed` = If the blocks match, overrides the default mining speed. [Optional]", + "`speed` = If the blocks match, overrides the default mining speed (Must be a positive number). [Optional]", "`correct for drops` = If the blocks match, overrides whether or not this tool is " + "considered correct to mine at its most efficient speed, and to drop items if the block's loot table requires it. [Optional]"}) @Examples({"set {_i} to a stick", @@ -102,6 +102,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye Number speedNum = this.speed != null ? this.speed.getSingle(event) : null; Float speed = speedNum != null ? speedNum.floatValue() : null; + if (speed != null && speed <= 0) speed = null; Boolean correctForDrops = this.correctForDrops != null ? this.correctForDrops.getSingle(event) : null; if (this.blockTypes != null) { diff --git a/src/main/java/com/shanebeestudios/skbee/elements/nbt/expressions/ExprNbtCompound.java b/src/main/java/com/shanebeestudios/skbee/elements/nbt/expressions/ExprNbtCompound.java index abefeb758..7fd971cb1 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/nbt/expressions/ExprNbtCompound.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/nbt/expressions/ExprNbtCompound.java @@ -24,7 +24,6 @@ import de.tr7zw.changeme.nbtapi.NBTChunk; import de.tr7zw.changeme.nbtapi.NBTCompound; import de.tr7zw.changeme.nbtapi.NBTContainer; -import de.tr7zw.changeme.nbtapi.NBTItem; import org.bukkit.Chunk; import org.bukkit.Material; import org.bukkit.OfflinePlayer; @@ -36,28 +35,28 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -@SuppressWarnings("deprecation") @Name("NBT - Compound of Object") @Description({"Get the NBT compound of a block/entity/item/file/chunk.", "", "SPECIAL CASES:", - "`full nbt of %item%` = Returns a copy of the FULL NBT of an item (this includes id, count and 'tag/components' compound).", + "- `full nbt of %item%` = Returns a copy of the FULL NBT of an item (this includes id, count and 'tag/components' compound).", "Modifying this will have no effect on the original item. This is useful for serializing items.", - "`nbt of %item%` = Returns the original. Modifying this will modify the original item.", - "\\- (1.20.4-) This will return the 'tag' portion of an items full NBT.", - "\\- (1.20.5+) This will return the 'minecraft:custom_data' component container of an item's NBT.", - "`components nbt of %item%` = Returns the components container of an item's NBT. Modifying this will modify the original item. (This is an MC 1.20.5+ feature).", + "- `nbt of %item%` = Returns the original. Modifying this will modify the original item.", + "\\- (MC 1.20.4-) This will return the 'tag' portion of an items full NBT.", + "\\- (MC 1.20.5+) This will return the 'components' portion of an item's full NBT.", + "- `custom nbt of %item%` = Returns the 'minecraft:custom_data' component of an item's NBT. Modifying this will modify the original item. (This is an MC 1.20.5+ feature).", "Please see [**Data Component Format**](https://minecraft.wiki/w/Data_component_format) on McWiki for more information on item NBT components.", - "`nbt copy of %objects%` = Returns a copy of the original NBT compound. This way you can modify it without", + "- `[full] vanilla nbt of %item%` = Will return the same as above except it will include vanilla components which don't normally show in NBT.", + "- `nbt copy of %objects%` = Returns a copy of the original NBT compound. This way you can modify it without", "actually modifying the original NBT compound, for example when grabbing the compound from an entity, modifying it and applying to other entities.", "", "NBT from a file will need to be saved manually using", - "the 'NBT - Save File effect'. If the file does not yet exist, a new file will be created.", + "the 'NBT - Save File' effect. If the file does not yet exist, a new file will be created.", "", "CHANGERS:", - "\t`add` = Adding a compound to another compound will merge them (This is controlled by Minecraft, results may vary).", - "\t`delete` = Will delete NBT files, or clear the NBT compound (This can break entities/players, be careful!).", - "\t`reset` = Will clear the NBT compound (This can break entities/players, be careful!)"}) + "- `add` = Adding a compound to another compound will merge them (This is controlled by Minecraft, results may vary).", + "- `delete` = Will delete NBT files, or clear the NBT compound (This can break entities/players, be careful!).", + "- `reset` = Will clear the NBT compound (This can break entities/players, be careful!)"}) @Examples({"set {_n} to nbt of player's tool", "set {_n} to full nbt of player's tool", "set {_nbt} to nbt of target entity", @@ -79,13 +78,14 @@ public class ExprNbtCompound extends PropertyExpression { static { Skript.registerExpression(ExprNbtCompound.class, NBTCompound.class, ExpressionType.PROPERTY, - "[(:full|:component[s])] nbt [compound] [:copy] (of|from) %objects%", + "[:full] [:vanilla] [:custom] nbt [compound] [:copy] (of|from) %objects%", "nbt [compound] [:copy] (of|from) file[s] %strings%" ); } private boolean isFullItem; - private boolean isComponents; + private boolean isVanilla; + private boolean isCustom; private boolean isCopy; private boolean isFile; @@ -94,7 +94,8 @@ public boolean init(Expression @NotNull [] exprs, int matchedPattern, @NotNul Expression expr = LiteralUtils.defendExpression(exprs[0]); setExpr(expr); this.isFullItem = parseResult.hasTag("full"); - this.isComponents = parseResult.hasTag("component") || !NBTApi.HAS_ITEM_COMPONENTS; + this.isVanilla = parseResult.hasTag("vanilla") && NBTApi.HAS_ITEM_COMPONENTS; + this.isCustom = parseResult.hasTag("custom") && NBTApi.HAS_ITEM_COMPONENTS; this.isCopy = parseResult.hasTag("copy"); this.isFile = matchedPattern == 1; return LiteralUtils.canInitSafely(expr); @@ -122,27 +123,14 @@ public boolean init(Expression @NotNull [] exprs, int matchedPattern, @NotNul compound = new NBTCustomEntity(entity); } else if (object instanceof ItemType itemType) { if (itemType.getMaterial() == Material.AIR) return null; - if (this.isFullItem) { - compound = NBTItem.convertItemtoNBT(itemType.getRandom()); - } else { - compound = new NBTCustomItemType(itemType, this.isComponents); - } + compound = new NBTCustomItemType(itemType, this.isCustom, this.isVanilla, this.isFullItem); } else if (object instanceof ItemStack itemStack) { if (itemStack.getType() == Material.AIR) return null; - if (this.isFullItem) { - return NBTItem.convertItemtoNBT(itemStack); - } else { - compound = new NBTCustomItemStack(itemStack, this.isComponents); - } + compound = new NBTCustomItemStack(itemStack, this.isCustom, this.isVanilla, this.isFullItem); } else if (object instanceof Slot slot) { ItemStack stack = slot.getItem(); if (stack == null || stack.getType() == Material.AIR) return null; - - if (this.isFullItem) { - compound = NBTItem.convertItemtoNBT(stack); - } else { - compound = new NBTCustomSlot(slot, this.isComponents); - } + compound = new NBTCustomSlot(slot, this.isCustom, this.isVanilla, this.isFullItem); } else if (object instanceof String nbtString) { if (this.isFile) { compound = NBTApi.getNBTFile(nbtString); @@ -176,7 +164,7 @@ public boolean init(Expression @NotNull [] exprs, int matchedPattern, @NotNul @Override public @NotNull String toString(Event e, boolean d) { - String full = this.isFullItem ? "full " : (this.isComponents && NBTApi.HAS_ITEM_COMPONENTS) ? "components " : ""; + String full = this.isFullItem ? "full " : this.isCustom ? "custom " : ""; String copy = this.isCopy ? "copy " : ""; return full + "nbt " + copy + "from " + getExpr().toString(e, d); } diff --git a/src/main/java/com/shanebeestudios/skbee/elements/nbt/expressions/ExprTagOfNBT.java b/src/main/java/com/shanebeestudios/skbee/elements/nbt/expressions/ExprTagOfNBT.java index 0690c3966..aea4acfdb 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/nbt/expressions/ExprTagOfNBT.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/nbt/expressions/ExprTagOfNBT.java @@ -25,18 +25,21 @@ @Name("NBT - Tag") @Description({"Get/set/delete the value of the specified tag of an NBT compound. Also supports getting nested tags using a semi colon as a delimiter.", "If the return value is a list, you can use it as a list, as it will automatically split it for ya.", - "\nNOTE: `uuid tag` will set an int array tag (This is how MC stores uuids). On return it'll convert back to a uuid.", - "\nNOTE: Entities/blocks can not natively hold custom NBT tags. SkBee allows you to put custom nbt", + "**NOTES**:", + "- `uuid tag` will set an int array tag (This is how MC stores uuids). On return it'll convert back to a uuid.", + "- Entities/blocks can not natively hold custom NBT tags. SkBee allows you to put custom nbt", "data in the \"custom\" compound tag of a block/entity's NBT compound. Due to Minecraft not supporting this, I had to use some hacky methods to make this happen.", "That said, this system is a tad convoluted, see the SkBee WIKI for more details.", - "\nNOTE 1.20.5+: All custom data on items must be stored in the \"minecraft:custom_data\" compound " + + "- 1.20.5+: All custom data on items must be stored in the \"minecraft:custom_data\" compound " + "(see examples and [**McWiki**](https://minecraft.wiki/w/Data_component_format#custom_data)).", - "For more info regarding 1.20.5+ components please see [**Data Component Format**](https://minecraft.wiki/w/Data_component_format) on McWiki.", - "\nADD: You can add numbers to number type tags, you can also add numbers/strings/compounds to lists type tags.", - "\nREMOVE: You can remove numbers from number type tags, you can also remove numbers/strings from lists type tags.", - "(You can NOT remove compounds from lists type tags)", - "\nGET FROM LIST BY POSITION: You can get the element of a list by adding `[%number%]` to the end of a tag", - "(This only works for getters, not set/add/remove/delete) see examples."}) + "- For more info regarding 1.20.5+ components please see [**Data Component Format**](https://minecraft.wiki/w/Data_component_format) on McWiki.", + "- GET FROM LIST BY POSITION: You can get the element of a list by adding `[%number%]` to the end of a tag", + "(This only works for getters, not set/add/remove/delete) see examples.", + "", + "**CHANGERS**:", + "- ADD: You can add numbers to number type tags, you can also add numbers/strings/compounds to lists type tags.", + "- REMOVE: You can remove numbers from number type tags, you can also remove numbers/strings from lists type tags." + + "(You can NOT remove compounds from lists type tags)"}) @Examples({"# Getting the value of a simple tag", "set {_damage} to int tag \"minecraft:damage\" of nbt of player's tool", "set {_sheared} to byte tag \"Sheared\" of nbt of target entity", @@ -83,18 +86,19 @@ "set {_b} to byte tag \"someBytes[10]\" of {_nbt}", "", "# Minecraft 1.20.5+ item component stuff", - "set int tag \"minecraft:max_damage\" of component nbt of player's tool to 500", - "set int tag \"minecraft:max_stack_size\" of component nbt of player's tool to 25", - "set byte tag \"minecraft:enchantment_glint_override\" of component nbt of player's tool to 1", - "set compound tag \"minecraft:fire_resistant\" of component nbt of player's tool to nbt from \"{}\"", - "set string tag \"minecraft:rarity\" of component nbt of player's tool to \"epic\"", + "set int tag \"minecraft:max_damage\" of nbt of player's tool to 500", + "set int tag \"minecraft:max_stack_size\" of nbt of player's tool to 25", + "set byte tag \"minecraft:enchantment_glint_override\" of nbt of player's tool to 1", + "set compound tag \"minecraft:fire_resistant\" of nbt of player's tool to nbt from \"{}\"", + "set string tag \"minecraft:rarity\" of nbt of player's tool to \"epic\"", "", "# All custom data must be within the \"minecraft:custom_data\" compound", "# See NBT Compound expression for futher details on the `component nbt` expression", - "set byte tag \"Points\" of nbt of player's tool to 10", - "set int tag \"MyBloop\" of nbt of player's tool to 152", - "set byte tag \"minecraft:custom_data;Points\" of component nbt of player's tool to 10", - "set int tag \"minecraft:custom_data;MyBloop\" of component nbt of player's tool to 152"}) + "set byte tag \"Points\" of custom nbt of player's tool to 10", + "set int tag \"MyBloop\" of custom nbt of player's tool to 152", + "# These examples will do the same as above", + "set byte tag \"minecraft:custom_data;Points\" of nbt of player's tool to 10", + "set int tag \"minecraft:custom_data;MyBloop\" of nbt of player's tool to 152"}) @Since("1.0.0") public class ExprTagOfNBT extends SimpleExpression { diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffGiveOrDrop.java b/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffGiveOrDrop.java index 4f2ee0c57..11e95ebe2 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffGiveOrDrop.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffGiveOrDrop.java @@ -10,22 +10,22 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.util.Kleenean; +import com.shanebeestudios.skbee.api.util.ItemUtils; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; @Name("Give or Drop Item") @Description("Attempts to give an item to a player and if they dont have room it will drop instead.") @Examples({"give or drop a diamond to player", - "give or drop {_items::*} to all players"}) + "give or drop {_items::*} to all players"}) @Since("2.14.0") public class EffGiveOrDrop extends Effect { @@ -47,11 +47,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye @SuppressWarnings("NullableProblems") @Override protected void execute(Event event) { - List itemStacks = new ArrayList<>(); - for (ItemType itemData : this.itemTypes.getArray(event)) { - itemStacks.add(itemData.getRandom()); - } - + List itemStacks = ItemUtils.addItemTypesToList(Arrays.asList(this.itemTypes.getArray(event)), null); ItemStack[] itemStacksArray = itemStacks.toArray(itemStacks.toArray(new ItemStack[0])); for (Player player : this.players.getArray(event)) { @@ -65,7 +61,7 @@ protected void execute(Event event) { } @Override - public @NotNull String toString(@Nullable Event e, boolean d) { + public @NotNull String toString(Event e, boolean d) { return "give or drop " + this.itemTypes.toString(e, d) + " to " + this.players.toString(e, d); } diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffOpenRealInventory.java b/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffOpenRealInventory.java new file mode 100644 index 000000000..43b2e95dd --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffOpenRealInventory.java @@ -0,0 +1,110 @@ +package com.shanebeestudios.skbee.elements.other.effects; + +import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +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.Location; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.inventory.InventoryView; +import org.jetbrains.annotations.NotNull; + +@Name("Open Real Inventory") +@Description({"Open real inventories to players.", + "This will open a real inventory object instead of a custom inventory object to players.", + "Most of these (except enchanting and workbench) require a PaperMC server.", + "`at %location%` is used to open an inventory at an actual block (Optional, will default to player's location).", + "Some inventories require a location of a block for extra functionality," + + "such as an enchanting table uses nearby bookshelves to determine enchantment level."}) +@Examples({"open real anvil inventory to player", + "open real anvil named \"Mr Anvil\" to player", + "open real anvil at location(1,1,1) named \"Senor Anvil\" to player"}) +@Since("INSERT VERSION") +public class EffOpenRealInventory extends Effect { + + private static final boolean HAS_PAPER = Skript.methodExists(HumanEntity.class, "openAnvil", Location.class, boolean.class); + + enum InventoryViewType { + ANVIL("anvil", true), + CARTOGRAPHY("cartography [table]", true), + ENCHANTING("enchanting [table]", false), + GRINDSTONE("grindstone", true), + LOOM("loom", true), + SMITHING("smithing [table]", true), + STONECUTTER("stonecutter", true), + WORKBENCH("workbench", false); + + private final String name; + private final boolean canUse; + + InventoryViewType(String name, boolean requiresPaper) { + this.name = name; + this.canUse = !requiresPaper || HAS_PAPER; + } + } + + static { + InventoryViewType[] viewTypes = InventoryViewType.values(); + int size = viewTypes.length; + String[] patterns = new String[size]; + for (int i = 0; i < size; i++) { + patterns[i] = "open real " + viewTypes[i].name + " [inventory] [at %-location%] [named %-string%] to %players%"; + } + Skript.registerEffect(EffOpenRealInventory.class, patterns); + } + + private InventoryViewType viewType; + private Expression location; + private Expression name; + private Expression players; + + @SuppressWarnings({"NullableProblems", "unchecked"}) + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + this.viewType = InventoryViewType.values()[matchedPattern]; + if (!this.viewType.canUse) { + Skript.error("'open real " + this.viewType.name + "' requires PaperMC."); + return false; + } + this.location = (Expression) exprs[0]; + this.name = (Expression) exprs[1]; + this.players = (Expression) exprs[2]; + return true; + } + + @SuppressWarnings("NullableProblems") + @Override + protected void execute(Event event) { + Location location = this.location != null ? this.location.getSingle(event) : null; + String name = this.name != null ? this.name.getSingle(event) : null; + + for (Player player : this.players.getArray(event)) { + InventoryView inventoryView = switch (this.viewType) { + case ANVIL -> player.openAnvil(location, true); + case CARTOGRAPHY -> player.openCartographyTable(location, true); + case ENCHANTING -> player.openEnchanting(location, true); + case GRINDSTONE -> player.openGrindstone(location, true); + case LOOM -> player.openLoom(location, true); + case SMITHING -> player.openSmithingTable(location, true); + case STONECUTTER -> player.openStonecutter(location, true); + case WORKBENCH -> player.openWorkbench(location, true); + }; + if (inventoryView != null && name != null) inventoryView.setTitle(name); + } + } + + @Override + public @NotNull String toString(Event e, boolean d) { + String loc = this.location != null ? ("at " + this.location.toString(e, d)) : ""; + String name = this.name != null ? ("named " + this.name.toString(e, d)) : ""; + return "open real " + this.viewType.name + " inventory " + loc + name + "to " + this.players.toString(e, d); + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprBiomeKeyLocation.java b/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprBiomeKeyLocation.java new file mode 100644 index 000000000..ca19610c0 --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprBiomeKeyLocation.java @@ -0,0 +1,86 @@ +package com.shanebeestudios.skbee.elements.other.expressions; + +import ch.njol.skript.Skript; +import ch.njol.skript.classes.Changer.ChangeMode; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import ch.njol.util.coll.CollectionUtils; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.RegionAccessor; +import org.bukkit.UnsafeValues; +import org.bukkit.World; +import org.bukkit.event.Event; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@SuppressWarnings("deprecation") +@Name("Biome Key of Location") +@Description({"Get/set the biome of a block/location using a NamespacedKey. Requires Paper 1.19+.", + "**NOTES**:", + "- This will support custom biomes.", + "- When setting this will not immediately visually update the biome to players, you will need to use the `refresh %chunk%` effect."}) +@Examples({"set biome key of block at player to mc key \"minecraft:plains\"", + "set biome key of blocks in chunk at player to mc key \"wythers:ancient_taiga\"", + "refresh chunk at player # forces biomes to be re-sent to the player.", + "set {_key} to biome key of block at player", + "set {_keys::*} to biome keys of blocks in chunk at player"}) +@Since("INSERT VERSION") +public class ExprBiomeKeyLocation extends SimplePropertyExpression { + + private static final UnsafeValues UNSAFE = Bukkit.getUnsafe(); + + static { + if (Skript.methodExists(UnsafeValues.class, "getBiomeKey", RegionAccessor.class, int.class, int.class, int.class)) { + register(ExprBiomeKeyLocation.class, NamespacedKey.class, "biome key[s]", "locations"); + } + } + + @Override + public @Nullable NamespacedKey convert(Location from) { + World world = from.getWorld(); + if (world != null) { + return UNSAFE.getBiomeKey(world, from.getBlockX(), from.getBlockY(), from.getBlockZ()); + } + return null; + } + + @SuppressWarnings("NullableProblems") + @Override + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET) return CollectionUtils.array(NamespacedKey.class); + return null; + } + + @SuppressWarnings({"NullableProblems", "ConstantValue"}) + @Override + public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { + if (delta != null && delta[0] instanceof NamespacedKey key) { + for (Location loc : getExpr().getArray(event)) { + World world = loc.getWorld(); + if (world != null) { + try { + UNSAFE.setBiomeKey(world, loc.blockX(), loc.blockY(), loc.blockZ(), key); + } catch (IllegalStateException ignore) { + + } + } + } + } + } + + @Override + protected @NotNull String getPropertyName() { + return "biome key"; + } + + @Override + public @NotNull Class getReturnType() { + return NamespacedKey.class; + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprGiveOrReturn.java b/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprGiveOrReturn.java index c608db6df..e3363d6df 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprGiveOrReturn.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprGiveOrReturn.java @@ -1,6 +1,7 @@ package com.shanebeestudios.skbee.elements.other.expressions; import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; @@ -10,6 +11,7 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; +import com.shanebeestudios.skbee.api.util.ItemUtils; import org.bukkit.event.Event; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -17,65 +19,67 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; @Name("Give or Return Items") @Description({"Attempts to add items to an inventory and will return a list of items that did not fit in the inventory."}) @Examples({"set {_i} to give or return diamond to player", - "if {_i} is set:", - "\tdrop {_i} at player", - "", - "set {_i::*} to add or return (a diamond and an emerald) to inventory of target block", - "if {_i::*} is set:", - "\tdrop {_i::*} above target block without velocity"}) + "if {_i} is set:", + "\tdrop {_i} at player", + "", + "set {_i::*} to add or return (a diamond and an emerald) to inventory of target block", + "if {_i::*} is set:", + "\tdrop {_i::*} above target block without velocity"}) @Since("3.0.0") -public class ExprGiveOrReturn extends SimpleExpression { +public class ExprGiveOrReturn extends SimpleExpression { static { - Skript.registerExpression(ExprGiveOrReturn.class, ItemStack.class, ExpressionType.COMBINED, - "(give|add) or return %itemstacks% to %inventories%"); + Skript.registerExpression(ExprGiveOrReturn.class, ItemType.class, ExpressionType.COMBINED, + "(give|add) or return %itemtypes% to %inventories%"); } - private Expression itemStacks; + private Expression itemTypes; private Expression inventories; @SuppressWarnings({"unchecked", "NullableProblems"}) @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - this.itemStacks = (Expression) exprs[0]; + this.itemTypes = (Expression) exprs[0]; this.inventories = (Expression) exprs[1]; return true; } @SuppressWarnings("NullableProblems") @Override - protected @Nullable ItemStack[] get(Event event) { - ItemStack[] itemStacks = this.itemStacks.getArray(event); + protected @Nullable ItemType[] get(Event event) { + List itemStacks = ItemUtils.addItemTypesToList(Arrays.asList(this.itemTypes.getArray(event)), null); + ItemStack[] itemStacksArray = itemStacks.toArray(itemStacks.toArray(new ItemStack[0])); - List returns = new ArrayList<>(); + List returns = new ArrayList<>(); for (Inventory inventory : this.inventories.getArray(event)) { - HashMap leftOvers = inventory.addItem(itemStacks); + HashMap leftOvers = inventory.addItem(itemStacksArray); if (!leftOvers.isEmpty()) { - returns.addAll(leftOvers.values()); + leftOvers.values().forEach(itemStack -> returns.add(new ItemType(itemStack))); } } - return returns.toArray(new ItemStack[0]); + return returns.toArray(new ItemType[0]); } @Override public boolean isSingle() { - return this.itemStacks.isSingle() && this.inventories.isSingle(); + return this.itemTypes.isSingle() && this.inventories.isSingle(); } @Override - public @NotNull Class getReturnType() { - return ItemStack.class; + public @NotNull Class getReturnType() { + return ItemType.class; } @Override - public @NotNull String toString(@Nullable Event e, boolean d) { - return "give or return " + this.itemStacks.toString(e, d) + " to " + this.inventories.toString(e, d); + public @NotNull String toString(Event e, boolean d) { + return "give or return " + this.itemTypes.toString(e, d) + " to " + this.inventories.toString(e, d); } } diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprTabCompletion.java b/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprTabCompletion.java index 92894f32d..a8bdf1bb0 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprTabCompletion.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprTabCompletion.java @@ -95,7 +95,7 @@ public void change(@NotNull Event event, @Nullable Object[] objects, @NotNull Ch switch (mode) { case SET, ADD -> { String arg; - if (position == buffers.length) { + if (position == buffers.length || position == -1) { arg = ""; } else { arg = buffers[position]; diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/type/Types.java b/src/main/java/com/shanebeestudios/skbee/elements/other/type/Types.java index 475d62c6d..a6065ba23 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/type/Types.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/type/Types.java @@ -78,7 +78,8 @@ public class Types { Classes.registerClass(SPELL_ENUM.getClassInfo("spell") .user("spells?") .name("Spellcaster Spell") - .description("Represents the different spells of a spellcaster.") + .description("Represents the different spells of a spellcaster.", + "NOTE: These are auto-generated and may differ between server versions.") .since("1.17.0")); } else { Util.logLoading("It looks like another addon registered 'spell' already."); @@ -92,7 +93,8 @@ public class Types { Classes.registerClass(POTION_EFFECT_EVENT_CAUSE.getClassInfo("potioneffectcause") .user("potion ?effect ?causes?") .name("Potion Effect Cause") - .description("Represents the different causes of an entity potion effect event.") + .description("Represents the different causes of an entity potion effect event.", + "NOTE: These are auto-generated and may differ between server versions.") .since("1.17.0")); } else { Util.logLoading("It looks like another addon registered 'potioneffectcause' already."); @@ -107,6 +109,7 @@ public class Types { "which can identify built-in and user-defined objects without potential ambiguity or conflicts.", "For more information see [**Resource Location**](https://minecraft.wiki/w/Resource_location) on McWiki.") .since("2.6.0") + .parser(SkriptUtils.getDefaultParser()) .serializer(new Serializer<>() { @Override public @NotNull Fields serialize(NamespacedKey namespacedKey) { @@ -147,7 +150,8 @@ protected boolean canBeInstantiated() { Classes.registerClass(BLOCK_FACE_ENUM.getClassInfo("blockface") .user("blockfaces?") .name("BlockFace") - .description("Represents the face of a block.") + .description("Represents the face of a block.", + "NOTE: These are auto-generated and may differ between server versions.") .since("2.6.0") .defaultExpression(new SimpleLiteral<>(BlockFace.NORTH, true))); } @@ -157,7 +161,8 @@ protected boolean canBeInstantiated() { Classes.registerClass(RESPAWN_REASON_ENUM.getClassInfo("respawnreason") .user("respawn ?reasons?") .name("Respawn Reason") - .description("Represents the reason the respawn event was called. Requires MC 1.19.4+") + .description("Represents the reason the respawn event was called. Requires MC 1.19.4+", + "NOTE: These are auto-generated and may differ between server versions.") .examples("on respawn:", "\tif respawn reason = death respawn:", "\t\tgive player 10 diamonds") @@ -242,11 +247,12 @@ public boolean canParse(@NotNull ParseContext context) { .user("chunk ?load ?levels?") .name("Chunk Load Level") .description("Represents the types of load levels of a chunk.", - "\n`border_level` = Most game logic is not processed, including entities and redstone.", - "\n`entity_ticking_level` = All game logic is processed.", - "\n`inaccessible_level` = No game logic is processed, world generation may still occur.", - "\n`ticking_level` = All game logic except entities is processed.", - "\n`unloaded_level` = This chunk is not loaded.") + "- `border_level` = Most game logic is not processed, including entities and redstone.", + "- `entity_ticking_level` = All game logic is processed.", + "- `inaccessible_level` = No game logic is processed, world generation may still occur.", + "- `ticking_level` = All game logic except entities is processed.", + "- `unloaded_level` = This chunk is not loaded.", + "NOTE: These are auto-generated and may differ between server versions.") .since("2.17.0")); } @@ -255,7 +261,8 @@ public boolean canParse(@NotNull ParseContext context) { Classes.registerClass(ENTITY_EFFECT_ENUM.getClassInfo("entityeffect") .user("entit(y|ies) ?effects?") .name("Entity Effect") - .description("Represents an effect that can be played on an entity.") + .description("Represents an effect that can be played on an entity.", + "NOTE: These are auto-generated and may differ between server versions.") .since("3.0.0")); } else { Util.logLoading("It looks like another addon registered 'EntityEffect' already."); @@ -273,7 +280,8 @@ public boolean canParse(@NotNull ParseContext context) { Classes.registerClass(SLOT_ENUM.getClassInfo("equipmentslot") .user("equipment ?slots?") .name("Equipment Slot") - .description("") + .description("Represents different slots of an entity.", + "NOTE: These are auto-generated and may differ between server versions.") .since("3.4.0")); } @@ -282,7 +290,8 @@ public boolean canParse(@NotNull ParseContext context) { Classes.registerClass(ACTION_ENUM.getClassInfo("blockaction") .user("block ?actions?") .name("Block Action") - .description("") + .description("Represents different wants to interact.", + "NOTE: These are auto-generated and may differ between server versions.") .since("3.4.0")); } @@ -317,7 +326,8 @@ public boolean canParse(@NotNull ParseContext context) { Classes.registerClass(CAUSE_ENUM.getClassInfo("entityremovecause") .user("entity ?remove ?causes?") .name("Entity Remove Cause") - .description("Represents the reasons an entity was removed from the world.") + .description("Represents the reasons an entity was removed from the world.", + "NOTE: These are auto-generated and may differ between server versions.") .after("damagecause", "damagetype") .since("3.4.0")); } @@ -327,7 +337,8 @@ public boolean canParse(@NotNull ParseContext context) { Classes.registerClass(CAUSE_ENUM.getClassInfo("playerspawnchangereason") .user("player ?spawn ?change ?reasons?") .name("Player Spawn Change Reason") - .description("Represents the reasons why a player changed their spawn location.") + .description("Represents the reasons why a player changed their spawn location.", + "NOTE: These are auto-generated and may differ between server versions.") .after("damagecause", "damagetype", "itemtype") .since("3.4.0")); } diff --git a/src/main/java/com/shanebeestudios/skbee/elements/team/effects/EffTeamRegister.java b/src/main/java/com/shanebeestudios/skbee/elements/team/effects/EffTeamRegister.java deleted file mode 100644 index cace42f3a..000000000 --- a/src/main/java/com/shanebeestudios/skbee/elements/team/effects/EffTeamRegister.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.shanebeestudios.skbee.elements.team.effects; - -import ch.njol.skript.Skript; -import ch.njol.skript.doc.Description; -import ch.njol.skript.doc.Examples; -import ch.njol.skript.doc.Name; -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 com.shanebeestudios.skbee.elements.team.type.TeamManager; -import org.bukkit.event.Event; -import org.jetbrains.annotations.Nullable; - -@Name("Team - Register") -@Description({"Register a new team or unregister an existing team.", - "\nTHIS IS NOW DEPRECATED and will be removed in the future!", - "\nYou can use the `team named %string%` expression to get/register or delete a team."}) -@Examples({"on load:", - "\tregister new team \"a-team\""}) -@Since("1.16.0, DEPRECATED!") -public class EffTeamRegister extends Effect { - - static { - // TODO DEPRECATED in 2.11.0 - Skript.registerEffect(EffTeamRegister.class, "[1:un]register [new] team %string%"); - } - - private Expression name; - private boolean register; - - @SuppressWarnings({"unchecked", "NullableProblems"}) - @Override - public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - this.name = (Expression) exprs[0]; - this.register = parseResult.mark == 0; - String prefix = "DEPRECATED - Will be removed in the future! "; - if (this.register) { - Skript.warning(prefix + "Please use 'set {_} to team named \"name_here\"'"); - } else { - Skript.warning(prefix + "Please use 'delete team named \"name_here\"'"); - } - return true; - } - - @SuppressWarnings("NullableProblems") - @Override - protected void execute(Event event) { - String name = this.name.getSingle(event); - if (name == null) return; - - if (register) { - TeamManager.getTeam(name); - } else { - TeamManager.unregisterTeam(name); - } - } - - @SuppressWarnings("NullableProblems") - @Override - public String toString(@Nullable Event e, boolean d) { - String reg = register ? "" : "un"; - return reg + "register team " + this.name.toString(e, d); - } - -} diff --git a/src/main/java/com/shanebeestudios/skbee/elements/text/expressions/ExprItemName.java b/src/main/java/com/shanebeestudios/skbee/elements/text/expressions/ExprItemName.java index e98bfb650..3421f8058 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/text/expressions/ExprItemName.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/text/expressions/ExprItemName.java @@ -1,5 +1,6 @@ package com.shanebeestudios.skbee.elements.text.expressions; +import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.doc.Description; @@ -7,46 +8,78 @@ import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; +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 com.shanebeestudios.skbee.api.wrapper.ComponentWrapper; +import net.kyori.adventure.text.Component; import org.bukkit.event.Event; -import org.jetbrains.annotations.Nullable; +import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -@Name("TextComponent - ItemType Name") -@Description("Get/set the component name of an ItemType.") -@Examples("set component item name of player's tool to translate component of \"item.minecraft.diamond_sword\"") +@Name("TextComponent - Item Name") +@Description({"Get/set the component name of an Item.", + "`(custom|display) name` = Get/set the `custom_name` component of an item just like you would with Skript's name expression.", + "`item name` = Get/set the `item_name` component of an item (Requires Minecraft 1.20.5+).", + "Unlike setting the custom/display name of an item, this name cannot be changed through an anvil,", + "and does not show in some labels, such as banner markers and item frames.", + "See [**McWiki**](https://minecraft.wiki/w/Data_component_format#item_name) for more details."}) +@Examples({"set component custom name of player's tool to translate component of \"item.minecraft.diamond_sword\"", + "delete component custom name of player's tool", + "set component item name of player's tool to mini message from \"Stickaxe\"", + "delete component item name of player's tool"}) @Since("2.4.0") public class ExprItemName extends SimplePropertyExpression { static { register(ExprItemName.class, ComponentWrapper.class, - "component item[[ ]type] name", "itemtypes"); + "component (:item|(custom|display)) name", "itemtypes"); + } + + private boolean itemName; + + @SuppressWarnings("NullableProblems") + @Override + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + this.itemName = parseResult.hasTag("item"); + if (this.itemName && !ComponentWrapper.HAS_ITEM_NAME) { + Skript.error("'custom item name' requires Minecraft 1.20.5+"); + return false; + } + return super.init(exprs, matchedPattern, isDelayed, parseResult); } @Override public @Nullable ComponentWrapper convert(ItemType itemType) { - return ComponentWrapper.fromComponent(itemType.getItemMeta().displayName()); + Component nameComponent; + if (this.itemName) { + nameComponent = itemType.getItemMeta().itemName(); + } else { + nameComponent = itemType.getItemMeta().displayName(); + } + return ComponentWrapper.fromComponent(nameComponent); } @SuppressWarnings("NullableProblems") @Override - public @Nullable Class[] acceptChange(ChangeMode mode) { - if (mode == ChangeMode.SET) { - return CollectionUtils.array(ComponentWrapper.class); - } + public Class @Nullable [] acceptChange(ChangeMode mode) { + if (mode == ChangeMode.SET) return CollectionUtils.array(ComponentWrapper.class); + else if (mode == ChangeMode.RESET || mode == ChangeMode.DELETE) return CollectionUtils.array(); return null; } - @SuppressWarnings("NullableProblems") + @SuppressWarnings({"NullableProblems", "ConstantValue"}) @Override public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { - if (mode == ChangeMode.SET) { - if (delta[0] instanceof ComponentWrapper component) { - for (ItemType itemType : getExpr().getArray(event)) { - component.setItemName(itemType); - } - } + Component component = delta != null && delta[0] instanceof ComponentWrapper comp ? comp.getComponent() : null; + + for (ItemType itemType : getExpr().getArray(event)) { + ItemMeta itemMeta = itemType.getItemMeta(); + if (this.itemName) itemMeta.itemName(component); + else itemMeta.displayName(component); + itemType.setItemMeta(itemMeta); } } @@ -57,7 +90,8 @@ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { @Override protected @NotNull String getPropertyName() { - return "component itemtype name"; + String type = this.itemName ? "item" : "custom"; + return "component" + type + " name"; } } diff --git a/src/main/java/com/shanebeestudios/skbee/elements/text/expressions/ExprMiniMessage.java b/src/main/java/com/shanebeestudios/skbee/elements/text/expressions/ExprMiniMessage.java index cf19a3f33..f38a63147 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/text/expressions/ExprMiniMessage.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/text/expressions/ExprMiniMessage.java @@ -20,28 +20,29 @@ @Name("TextComponent - MiniMessage") @Description({"Get a mini message from a string.", - "These messages are still components, which you can still apply hover/click events to.", - "You can also add optional tag resolvers. Essential you create a resolver to replace `` ", - "in mini message with something else (See examples for more details).", - "For more info check out the [**Mini Message Format**](https://docs.adventure.kyori.net/minimessage/format.html) page."}) + "These messages are still components, which you can still apply hover/click events to.", + "You can also add optional tag resolvers. Essential you create a resolver to replace `` ", + "in mini message with something else (See examples for more details).", + "For more info check out the [**Mini Message Format**](https://docs.adventure.kyori.net/minimessage/format.html) page."}) @Examples({"set {_m} to mini message from \"this is a rainbow message\"", - "set {_m} to mini message from \"PRETTY MESSAGE FROM RED TO BLUE\"", - "set {_m} to mini message from \"This is a test!\"", - "send component mini message from \"This is a test!\" to all players", - "", - "# Create a component", - "set {_i} to translate component of player's tool", - "# Use this comonent in the resolver to replace \"\" in the mini message", - "set {_r::1} to resolver(\"item\", {_i})", - "# setup the mini message with the replacement placeholder", - "set {_m} to mini message from \" Hey guys check out my aint she a beaut?\" with {_r::*}", - "send component {_m}"}) + "set {_m} to mini message from \"PRETTY MESSAGE FROM RED TO BLUE\"", + "set {_m} to mini message from \"This is a test!\"", + "send component mini message from \"This is a test!\" to all players", + "", + "# Create a component", + "set {_t} to translate component of player's tool", + "add hover event showing player's tool to {_t}", + "# Use this component in the resolver to replace \"\" in the mini message", + "set {_r} to resolver(\"item\", {_t})", + "# Setup the mini message with the replacement placeholder", + "set {_m} to mini message from \" Hey guys check out my aint she a beaut?\" with {_r}", + "send component {_m}"}) @Since("2.4.0") public class ExprMiniMessage extends SimpleExpression { static { Skript.registerExpression(ExprMiniMessage.class, ComponentWrapper.class, ExpressionType.SIMPLE, - "mini[ ]message from %string% [with [resolver[s]] %-tagresolvers%]"); + "mini[ ]message from %string% [with [resolver[s]] %-tagresolvers%]"); } private Expression string; diff --git a/src/main/java/com/shanebeestudios/skbee/elements/text/type/Types.java b/src/main/java/com/shanebeestudios/skbee/elements/text/type/Types.java index 22dcd99db..86cae048c 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/text/type/Types.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/text/type/Types.java @@ -119,12 +119,14 @@ public void change(SignedMessage[] what, @Nullable Object[] delta, ChangeMode mo .user("tag ?resolvers?") .description("Represents an object to replace text in a mini message.") .examples("# Create a component", - "set {_i} to translate component of player's tool", - "# Use this comonent in the resolver to replace \"\" in the mini message", - "set {_r::1} to resolver(\"item\", {_i})", + "set {_t} to translate component of player's tool", + "add hover event showing player's tool to {_t}", + "# Use this component in the resolver to replace \"\" in the mini message", + "set {_r} to resolver(\"item\", {_t})", "# setup the mini message with the replacement placeholder", - "set {_m} to mini message from \" Hey guys check out my aint she a beaut?\" with {_r::*}", + "set {_m} to mini message from \" Hey guys check out my aint she a beaut?\" with {_r}", "send component {_m}") + .parser(SkriptUtils.getDefaultParser()) .since("3.5.0")); // Functions @@ -158,11 +160,12 @@ public void change(SignedMessage[] what, @Nullable Object[] delta, ChangeMode mo "In the mini message itself this part needs to be surrounded by <>. See examples!", "`replacement` = A string/text component that will replace the first string.") .examples("# Create a component", - "set {_i} to translate component of player's tool", - "# Use this comonent in the resolver to replace \"\" in the mini message", - "set {_r::1} to resolver(\"item\", {_i})", + "set {_t} to translate component of player's tool", + "add hover event showing player's tool to {_t}", + "# Use this component in the resolver to replace \"\" in the mini message", + "set {_r} to resolver(\"item\", {_t})", "# setup the mini message with the replacement placeholder", - "set {_m} to mini message from \" Hey guys check out my aint she a beaut?\" with {_r::*}", + "set {_m} to mini message from \" Hey guys check out my aint she a beaut?\" with {_r}", "send component {_m}") .since("3.5.0")); } diff --git a/src/main/resources/lang/english.lang b/src/main/resources/lang/english.lang index 5f2245d1b..2ff002d0d 100644 --- a/src/main/resources/lang/english.lang +++ b/src/main/resources/lang/english.lang @@ -1,85 +1,83 @@ version: @version@ types: - worldcreator: world creator - environment: environment type¦s @an - worldtype: world type¦s @- - bound: bound - nbtcompound: nbt compound¦s @an - nbttype: nbt type¦s @an - textcomponent: text component¦s @- - particle: particle¦s @- - dustoption: dust option¦s @- - dusttransition: dust transition¦s @- - vibration: vibration¦s @- - recipechoice: recipe choice¦s - minecrafttag: minecraft tag¦s - structure: structure¦s - mirror: mirror¦s - structurerotation: structure rotation¦s - blockstate: blockstate¦s - gameevent: game event¦s - team: team¦s - teamoption: team options¦s - teamoptionstatus: team option status¦es - equipmentslot: equipment slot¦s - attributeoperation: attribute operation¦s - attributepair: attribute pair¦s - attributemodifier: attribute modifier¦s - fishingstate: fishing state¦s - fishhookstate: fish hook state¦s - bossbar: boss bars¦s - bossbarcolor: boss bar color¦s - bossbarstyle: boss bar style¦s - bossbarflag: boss bar flags¦s - statistic: statistic¦s - profession: profession¦s - villagertype: villager type¦s - potioneffectcause: potion effect cause¦s - merchant: merchant¦s - merchantrecipe: merchant recipe¦s - merchantinventory: merchant inventor¦y¦ies - advancement: advancement¦s - advancementpro: advancement progress¦es - worldborder: world border¦s - spell: spell¦s - itemflag: item flag¦s - transformreason: transform reason¦s - quitreason: quit reason¦s - recipetype: recipe type¦s - objective: objective¦s - criteria: criteria¦s - rendertype: render type¦s - displayslot: display slot¦s - namespacedkey: namespacedkey¦s - blockface: blockface¦s - raytraceresult: raytraceresult¦s - displaybrightness: display brightness¦es - displaybillboard: display billboard¦s - textalignment: text alignment¦s - itemdisplaytransform: item display transform¦s - bukkitcolor: bukkit col(or|our)¦s - quaternion: quaternion¦s - transformation: transformation¦s - respawnreason: respawn reason¦s - armortrim: armor trim¦s - trimpattern: trim pattern¦s - trimmaterial: trim material¦s - machine: machine¦s - machineproperty: machine propert¦y¦ies - damagesource: damage source¦s - damagetype: damage type¦s - memory: memor¦y¦ies - loottable: loot table¦s - entityremovecause: entity remove cause¦s - playerspawnchangereason: player spawn change reason¦s - signedmessage: signed message¦s - tagresolver: tag resolver¦s - minecraftentitytype: minecraft entity type¦s - chunkloadlevel: chunk load level¦s - entityeffect: entity effect¦s - blockaction: block action¦s - bukkittreetype: bukkit tree type¦s - pose: pose¦s - equipmentslotgroup: equipment slot group¦s - attributeoperation: attribute operation¦s + advancement: advancement¦s + advancementpro: advancement progress¦es + armortrim: armor trim¦s + attributemodifier: attribute modifier¦s + attributeoperation: attribute operation¦s + blockaction: block action¦s + blockface: blockface¦s + blockstate: blockstate¦s + bossbar: boss bars¦s + bossbarcolor: boss bar color¦s + bossbarflag: boss bar flags¦s + bossbarstyle: boss bar style¦s + bound: bound + bukkitcolor: bukkit col(or|our)¦s + bukkittreetype: bukkit tree type¦s + chunkloadlevel: chunk load level¦s + criteria: criteria¦s + damagesource: damage source¦s + damagetype: damage type¦s + displaybillboard: display billboard¦s + displaybrightness: display brightness¦es + displayslot: display slot¦s + dustoption: dust option¦s @- + dusttransition: dust transition¦s @- + entityeffect: entity effect¦s + entityremovecause: entity remove cause¦s + environment: environment type¦s @an + equipmentslot: equipment slot¦s + equipmentslotgroup: equipment slot group¦s + fishingstate: fishing state¦s + fishhookstate: fish hook state¦s + gameevent: game event¦s + itemdisplaytransform: item display transform¦s + itemflag: item flag¦s + loottable: loot table¦s + machine: machine¦s + machineproperty: machine propert¦y¦ies + memory: memor¦y¦ies + merchant: merchant¦s + merchantinventory: merchant inventor¦y¦ies + merchantrecipe: merchant recipe¦s + minecraftentitytype: minecraft entity type¦s + minecrafttag: minecraft tag¦s + mirror: mirror¦s + namespacedkey: namespacedkey¦s + nbtcompound: nbt compound¦s @an + nbttype: nbt type¦s @an + objective: objective¦s + particle: particle¦s @- + playerspawnchangereason: player spawn change reason¦s + pose: pose¦s + potioneffectcause: potion effect cause¦s + profession: profession¦s + quaternion: quaternion¦s + quitreason: quit reason¦s + raytraceresult: raytraceresult¦s + recipechoice: recipe choice¦s + recipetype: recipe type¦s + rendertype: render type¦s + respawnreason: respawn reason¦s + spell: spell¦s + signedmessage: signed message¦s + statistic: statistic¦s + structure: structure¦s + structurerotation: structure rotation¦s + tagresolver: tag resolver¦s + team: team¦s + teamoption: team options¦s + teamoptionstatus: team option status¦es + textalignment: text alignment¦s + textcomponent: text component¦s @- + transformation: transformation¦s + transformreason: transform reason¦s + trimmaterial: trim material¦s + trimpattern: trim pattern¦s + vibration: vibration¦s @- + villagertype: villager type¦s + worldborder: world border¦s + worldcreator: world creator + worldtype: world type¦s @- diff --git a/src/test/scripts/general/nbt-test.sk b/src/test/scripts/general/nbt-test.sk index e4493b80e..6c2b8521d 100644 --- a/src/test/scripts/general/nbt-test.sk +++ b/src/test/scripts/general/nbt-test.sk @@ -23,7 +23,7 @@ test "SkBee - simple nbt compound": delete {_n} set {_i} to diamond sword with custom model data 1 - set {_n} to component nbt of {_i} + set {_n} to nbt of {_i} # Test that tag of item nbt is set assert int tag "minecraft:custom_model_data" of {_n} is set with "tag ""minecraft:custom_model_data"" of an item should be set"