From 8a5ceaecb196e38c130091306f7933e6e99a0b8b Mon Sep 17 00:00:00 2001 From: Shane Bee Date: Wed, 10 Jul 2024 08:33:23 -0700 Subject: [PATCH 01/16] RegistrySerializer - fix serialization issues (#6865) --- .../classes/registry/RegistrySerializer.java | 32 +++++++++---------- src/test/skript/tests/misc/registry.sk | 8 +++++ 2 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 src/test/skript/tests/misc/registry.sk diff --git a/src/main/java/ch/njol/skript/classes/registry/RegistrySerializer.java b/src/main/java/ch/njol/skript/classes/registry/RegistrySerializer.java index 2c0796e4218..33f6645fe52 100644 --- a/src/main/java/ch/njol/skript/classes/registry/RegistrySerializer.java +++ b/src/main/java/ch/njol/skript/classes/registry/RegistrySerializer.java @@ -43,27 +43,27 @@ public RegistrySerializer(Registry registry) { @Override public @NotNull Fields serialize(R o) { Fields fields = new Fields(); - fields.putPrimitive("name", o.getKey().toString()); + fields.putObject("name", o.getKey().toString()); return fields; } @Override - protected R deserialize(Fields fields) { - try { - String name = fields.getAndRemovePrimitive("name", String.class); - NamespacedKey namespacedKey; - if (!name.contains(":")) { - // Old variables - namespacedKey = NamespacedKey.minecraft(name); - } else { - namespacedKey = NamespacedKey.fromString(name); - } - if (namespacedKey == null) - return null; - return registry.get(namespacedKey); - } catch (StreamCorruptedException e) { - return null; + protected R deserialize(Fields fields) throws StreamCorruptedException { + String name = fields.getAndRemoveObject("name", String.class); + assert name != null; + NamespacedKey namespacedKey; + if (!name.contains(":")) { + // Old variables + namespacedKey = NamespacedKey.minecraft(name); + } else { + namespacedKey = NamespacedKey.fromString(name); } + if (namespacedKey == null) + throw new StreamCorruptedException("Invalid namespacedkey: " + name); + R object = registry.get(namespacedKey); + if (object == null) + throw new StreamCorruptedException("Invalid object from registry: " + namespacedKey); + return object; } @Override diff --git a/src/test/skript/tests/misc/registry.sk b/src/test/skript/tests/misc/registry.sk new file mode 100644 index 00000000000..2294472fbae --- /dev/null +++ b/src/test/skript/tests/misc/registry.sk @@ -0,0 +1,8 @@ +test "registry" when minecraft version is "1.14": + + # Test namespaced keys + assert curse of vanishing = minecraft:vanishing_curse with "'curse of vanishing' enchant should match namespace key" + + # Test serialization + set {test::enchantment} to minecraft:sharpness + assert {test::enchantment} = sharpness with "variable should have been set to sharpness enchantment" From c7826522dfbf264067d164882255b5bb18fa2455 Mon Sep 17 00:00:00 2001 From: Shane Bee Date: Wed, 10 Jul 2024 09:00:45 -0700 Subject: [PATCH 02/16] ItemUtils - fix error when setting damage lower than 0 (#6870) --- src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java | 2 +- .../skript/tests/syntaxes/expressions/ExprDurability.sk | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java b/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java index 9ccd2aa370c..b216f645127 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java +++ b/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java @@ -105,7 +105,7 @@ public static void setMaxDamage(ItemStack itemStack, int maxDamage) { public static void setDamage(ItemStack itemStack, int damage) { ItemMeta meta = itemStack.getItemMeta(); if (meta instanceof Damageable) { - ((Damageable) meta).setDamage(damage); + ((Damageable) meta).setDamage(Math.max(0, damage)); itemStack.setItemMeta(meta); } } diff --git a/src/test/skript/tests/syntaxes/expressions/ExprDurability.sk b/src/test/skript/tests/syntaxes/expressions/ExprDurability.sk index a35190f0a80..3935ad883b6 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprDurability.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprDurability.sk @@ -13,6 +13,15 @@ test "durability": assert damage of {_i} is {_max} with "max item damage failed" assert durability of {_i} is 0 with "zero item durability failed" + # Test out of bound values + set durability of {_i} to 500 + assert damage of {_i} is 0 with "damage of item should be 0 when setting durability higher than max" + assert durability of {_i} is {_max} with "durability of item should be max when setting higher than max" + + set damage of {_i} to -1 + assert damage of {_i} is 0 with "damage of item should be 0 when setting damage less than 0" + assert durability of {_i} is {_max} with "durability of item should be max when setting damage below 0" + test "durability - custom" when running minecraft "1.20.5": set {_i} to 1 of iron sword set max durability of {_i} to 1000 From 7fc1033230f93b533e43becf31aa1f00c03460b6 Mon Sep 17 00:00:00 2001 From: Shane Bee Date: Wed, 10 Jul 2024 10:05:53 -0700 Subject: [PATCH 03/16] EnchantmentType - fix toString showing namespacedkeys (#6871) --- .../ch/njol/skript/util/EnchantmentType.java | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main/java/ch/njol/skript/util/EnchantmentType.java b/src/main/java/ch/njol/skript/util/EnchantmentType.java index 97f4b8d22d0..dd8ab383128 100644 --- a/src/main/java/ch/njol/skript/util/EnchantmentType.java +++ b/src/main/java/ch/njol/skript/util/EnchantmentType.java @@ -19,7 +19,6 @@ package ch.njol.skript.util; import ch.njol.skript.aliases.ItemType; -import ch.njol.skript.bukkitutil.EnchantmentUtils; import ch.njol.skript.classes.ClassInfo; import ch.njol.skript.classes.Parser; import ch.njol.skript.lang.ParseContext; @@ -92,7 +91,7 @@ public boolean has(final ItemType item) { @Override public String toString() { - return EnchantmentUtils.toString(type) + (level == -1 ? "" : " " + level); + return getEnchantmentParser().toString(type, 0) + (level == -1 ? "" : " " + level); } @SuppressWarnings("null") @@ -107,27 +106,18 @@ public String toString() { */ @Nullable public static EnchantmentType parse(final String s) { - if (ENCHANTMENT_PARSER == null) { - ClassInfo classInfo = Classes.getExactClassInfo(Enchantment.class); - if (classInfo == null) { - throw new IllegalStateException("Enchantment ClassInfo not found"); - } - ENCHANTMENT_PARSER = (Parser) classInfo.getParser(); - if (ENCHANTMENT_PARSER == null) { - throw new IllegalStateException("Enchantment parser not found"); - } - } + Parser enchantmentParser = getEnchantmentParser(); if (pattern.matcher(s).matches()) { String name = s.substring(0, s.lastIndexOf(' ')); assert name != null; - final Enchantment ench = ENCHANTMENT_PARSER.parse(name, ParseContext.DEFAULT); + final Enchantment ench = enchantmentParser.parse(name, ParseContext.DEFAULT); if (ench == null) return null; String level = s.substring(s.lastIndexOf(' ') + 1); assert level != null; return new EnchantmentType(ench, Utils.parseInt(level)); } - final Enchantment ench = ENCHANTMENT_PARSER.parse(s, ParseContext.DEFAULT); + final Enchantment ench = enchantmentParser.parse(s, ParseContext.DEFAULT); if (ench == null) return null; return new EnchantmentType(ench, -1); @@ -156,4 +146,19 @@ public boolean equals(final @Nullable Object obj) { return type.equals(other.type); } + @SuppressWarnings("unchecked") + private static Parser getEnchantmentParser() { + if (ENCHANTMENT_PARSER == null) { + ClassInfo classInfo = Classes.getExactClassInfo(Enchantment.class); + if (classInfo == null) { + throw new IllegalStateException("Enchantment ClassInfo not found"); + } + ENCHANTMENT_PARSER = (Parser) classInfo.getParser(); + if (ENCHANTMENT_PARSER == null) { + throw new IllegalStateException("Enchantment parser not found"); + } + } + return ENCHANTMENT_PARSER; + } + } From b0f48b9fd82602855406e6d0ad1948ebfa6e26fd Mon Sep 17 00:00:00 2001 From: Patrick Miller Date: Wed, 10 Jul 2024 13:34:31 -0400 Subject: [PATCH 04/16] Fix Incorrect BlockValues#isDefault (#6876) --- .../java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java b/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java index e72a947996f..a1413a8ad35 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java +++ b/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java @@ -349,7 +349,7 @@ public BlockValues getBlockValues(BlockState blockState) { @Override public @Nullable BlockValues getBlockValues(Material material) { if (material.isBlock()) - return new NewBlockValues(material, Bukkit.createBlockData(material), false); + return new NewBlockValues(material, Bukkit.createBlockData(material), true); return null; } From 312b83953136732b45d6eaba1c247edf8072320a Mon Sep 17 00:00:00 2001 From: Pikachu920 <28607612+Pikachu920@users.noreply.github.com> Date: Wed, 10 Jul 2024 12:43:33 -0500 Subject: [PATCH 05/16] Fix archive docs requiring release-docs job (#6848) --- .github/workflows/archive-docs.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/archive-docs.yml b/.github/workflows/archive-docs.yml index e183f748d78..c31092b63b0 100644 --- a/.github/workflows/archive-docs.yml +++ b/.github/workflows/archive-docs.yml @@ -8,7 +8,6 @@ on: jobs: archive-docs: if: "! contains(toJSON(github.event.commits.*.message), '[ci skip]')" - needs: release-docs runs-on: ubuntu-latest steps: - name: Configure workflow From 94aa3e5e26674c9bdad9f51141077ae10c0e29ef Mon Sep 17 00:00:00 2001 From: Patrick Miller Date: Wed, 10 Jul 2024 15:36:12 -0400 Subject: [PATCH 06/16] Fix ExprName InventoryView IncompatibleClassChangeError (#6874) --- .../skript/bukkitutil/InventoryUtils.java | 111 ++++++++++++++++++ .../classes/data/BukkitEventValues.java | 13 +- .../ch/njol/skript/expressions/ExprName.java | 8 +- .../expressions/ExprOpenedInventory.java | 10 +- 4 files changed, 128 insertions(+), 14 deletions(-) create mode 100644 src/main/java/ch/njol/skript/bukkitutil/InventoryUtils.java diff --git a/src/main/java/ch/njol/skript/bukkitutil/InventoryUtils.java b/src/main/java/ch/njol/skript/bukkitutil/InventoryUtils.java new file mode 100644 index 00000000000..e04228edc3a --- /dev/null +++ b/src/main/java/ch/njol/skript/bukkitutil/InventoryUtils.java @@ -0,0 +1,111 @@ +package ch.njol.skript.bukkitutil; + +import ch.njol.skript.Skript; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; +import org.eclipse.jdt.annotation.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +/** + * Utilities for inventories. + * In newer versions (1.21+), InventoryView is an interface instead of an abstract class + * Directing calling InventoryView#getTitle on 1.20.6 and below results in an IncompatibleClassChangeError + * as an interface, not an abstract class, is expected. + */ +public class InventoryUtils { + + private static final @Nullable MethodHandle GET_TITLE; + private static final @Nullable MethodHandle GET_INVENTORY; + private static final @Nullable MethodHandle CONVERT_SLOT; + private static final @Nullable MethodHandle GET_TOP_INVENTORY; + private static final @Nullable MethodHandle GET_BOTTOM_INVENTORY; + + static { + MethodHandle getTitle = null; + MethodHandle getInventory = null; + MethodHandle convertSlot = null; + MethodHandle getTopInventory = null; + MethodHandle getBottomInventory = null; + if (!InventoryView.class.isInterface()) { // initialize legacy support as it's likely an abstract class + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + getTitle = lookup.findVirtual(InventoryView.class, "getTitle", MethodType.methodType(String.class)); + getInventory = lookup.findVirtual(InventoryView.class, "getInventory", MethodType.methodType(Inventory.class, int.class)); + convertSlot = lookup.findVirtual(InventoryView.class, "convertSlot", MethodType.methodType(int.class, int.class)); + getTopInventory = lookup.findVirtual(InventoryView.class, "getTopInventory", MethodType.methodType(Inventory.class)); + getBottomInventory = lookup.findVirtual(InventoryView.class, "getBottomInventory", MethodType.methodType(Inventory.class)); + } catch (NoSuchMethodException | IllegalAccessException e) { + Skript.exception(e, "Failed to load old inventory view support."); + } + } + GET_TITLE = getTitle; + GET_INVENTORY = getInventory; + CONVERT_SLOT = convertSlot; + GET_TOP_INVENTORY = getTopInventory; + GET_BOTTOM_INVENTORY = getBottomInventory; + } + + /** + * @see InventoryView#getTitle() + */ + public static @Nullable String getTitle(InventoryView inventoryView) { + if (GET_TITLE == null) + return inventoryView.getTitle(); + try { + return (String) GET_TITLE.invoke(inventoryView); + } catch (Throwable ignored) { } + return null; + } + + /** + * @see InventoryView#getInventory(int) + */ + public static @Nullable Inventory getInventory(InventoryView inventoryView, int rawSlot) { + if (GET_INVENTORY == null) + return inventoryView.getInventory(rawSlot); + try { + return (Inventory) GET_INVENTORY.invoke(inventoryView, rawSlot); + } catch (Throwable ignored) { } + return null; + } + + /** + * @see InventoryView#convertSlot(int) + */ + public static @Nullable Integer convertSlot(InventoryView inventoryView, int rawSlot) { + if (CONVERT_SLOT == null) + return inventoryView.convertSlot(rawSlot); + try { + return (Integer) CONVERT_SLOT.invoke(inventoryView, rawSlot); + } catch (Throwable ignored) { } + return null; + } + + /** + * @see InventoryView#getTopInventory() + */ + public static @Nullable Inventory getTopInventory(InventoryView inventoryView) { + if (GET_TOP_INVENTORY == null) + return inventoryView.getTopInventory(); + try { + return (Inventory) GET_TOP_INVENTORY.invoke(inventoryView); + } catch (Throwable ignored) { } + return null; + } + + /** + * @see InventoryView#getBottomInventory() + */ + public static @Nullable Inventory getBottomInventory(InventoryView inventoryView) { + if (GET_BOTTOM_INVENTORY == null) + return inventoryView.getBottomInventory(); + try { + return (Inventory) GET_BOTTOM_INVENTORY.invoke(inventoryView); + } catch (Throwable ignored) { } + return null; + } + +} diff --git a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java index f38476203d6..e430dd472f6 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java @@ -26,6 +26,7 @@ import ch.njol.skript.Skript; import ch.njol.skript.aliases.Aliases; import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.bukkitutil.InventoryUtils; import ch.njol.skript.command.CommandEvent; import ch.njol.skript.events.bukkit.ScriptEvent; import ch.njol.skript.events.bukkit.SkriptStartEvent; @@ -1252,15 +1253,15 @@ public Slot[] get(InventoryDragEvent event) { List slots = new ArrayList<>(event.getRawSlots().size()); InventoryView view = event.getView(); for (Integer rawSlot : event.getRawSlots()) { - Inventory inventory = view.getInventory(rawSlot); - int slot = view.convertSlot(rawSlot); - if (inventory == null) + Inventory inventory = InventoryUtils.getInventory(view, rawSlot); + Integer slot = InventoryUtils.convertSlot(view, rawSlot); + if (inventory == null || slot == null) continue; // Not all indices point to inventory slots. Equipment, for example if (inventory instanceof PlayerInventory && slot >= 36) { slots.add(new ch.njol.skript.util.slot.EquipmentSlot(((PlayerInventory) view.getBottomInventory()).getHolder(), slot)); } else { - slots.add(new InventorySlot(inventory, view.convertSlot(rawSlot))); + slots.add(new InventorySlot(inventory, slot)); } } return slots.toArray(new Slot[0]); @@ -1280,7 +1281,9 @@ public Inventory[] get(InventoryDragEvent event) { Set inventories = new HashSet<>(); InventoryView view = event.getView(); for (Integer rawSlot : event.getRawSlots()) { - inventories.add(view.getInventory(rawSlot)); + Inventory inventory = InventoryUtils.getInventory(view, rawSlot); + if (inventory != null) + inventories.add(inventory); } return inventories.toArray(new Inventory[0]); } diff --git a/src/main/java/ch/njol/skript/expressions/ExprName.java b/src/main/java/ch/njol/skript/expressions/ExprName.java index 666a39092a1..1d5dd354e0c 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprName.java +++ b/src/main/java/ch/njol/skript/expressions/ExprName.java @@ -18,12 +18,10 @@ */ package ch.njol.skript.expressions; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.List; +import ch.njol.skript.bukkitutil.InventoryUtils; import ch.njol.skript.bukkitutil.ItemUtils; import org.bukkit.Bukkit; import org.bukkit.GameRule; @@ -45,7 +43,6 @@ import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.Skript; -import ch.njol.skript.aliases.Aliases; import ch.njol.skript.aliases.ItemType; import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.doc.Description; @@ -61,7 +58,6 @@ import ch.njol.util.Kleenean; import ch.njol.util.coll.CollectionUtils; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; @@ -182,7 +178,7 @@ public String convert(Object object) { Inventory inventory = (Inventory) object; if (inventory.getViewers().isEmpty()) return null; - return inventory.getViewers().get(0).getOpenInventory().getTitle(); + return InventoryUtils.getTitle(inventory.getViewers().get(0).getOpenInventory()); } else if (object instanceof Slot) { ItemStack is = ((Slot) object).getItem(); if (is != null && is.hasItemMeta()) { diff --git a/src/main/java/ch/njol/skript/expressions/ExprOpenedInventory.java b/src/main/java/ch/njol/skript/expressions/ExprOpenedInventory.java index d6f09b7d9d4..b8390e160d3 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprOpenedInventory.java +++ b/src/main/java/ch/njol/skript/expressions/ExprOpenedInventory.java @@ -18,9 +18,11 @@ */ package ch.njol.skript.expressions; +import ch.njol.skript.bukkitutil.InventoryUtils; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.Skript; @@ -61,10 +63,12 @@ public boolean init(final Expression[] exprs, final int matchedPattern, final @Override protected Inventory[] get(Event event, Player[] source) { return get(source, new Getter() { - @SuppressWarnings("null") @Override - public Inventory get(final Player player) { - return player.getOpenInventory() != null ? player.getOpenInventory().getTopInventory() : null; + public @Nullable Inventory get(final Player player) { + InventoryView openInventory = player.getOpenInventory(); + if (openInventory == null) + return null; + return InventoryUtils.getTopInventory(openInventory); } }); } From d48a26107c1c3152842da60a4d5193080ecfd1a7 Mon Sep 17 00:00:00 2001 From: Patrick Miller Date: Fri, 12 Jul 2024 11:52:40 -0400 Subject: [PATCH 07/16] ItemType Random Safety Improvements (#6886) --- .../java/ch/njol/skript/aliases/ItemType.java | 23 +++++++++++++++---- .../skript/classes/data/BukkitClasses.java | 5 +++- .../conditions/CondIsPreferredTool.java | 13 ++++++----- .../ch/njol/skript/effects/EffOpenBook.java | 2 +- .../ch/njol/skript/effects/EffReplace.java | 7 +++--- .../ch/njol/skript/entity/BoatChestData.java | 3 +-- .../java/ch/njol/skript/entity/BoatData.java | 5 ++-- .../njol/skript/entity/DroppedItemData.java | 11 ++++++++- .../njol/skript/expressions/ExprMaxStack.java | 9 ++++++-- .../ch/njol/skript/expressions/ExprPlain.java | 3 ++- .../skript/util/visual/VisualEffects.java | 7 ++++-- .../tests/regression/ExprPlainAliasTest.java | 2 +- 12 files changed, 63 insertions(+), 27 deletions(-) diff --git a/src/main/java/ch/njol/skript/aliases/ItemType.java b/src/main/java/ch/njol/skript/aliases/ItemType.java index efaa59249f2..d2a6fc85421 100644 --- a/src/main/java/ch/njol/skript/aliases/ItemType.java +++ b/src/main/java/ch/njol/skript/aliases/ItemType.java @@ -612,15 +612,27 @@ public ItemType clone() { .collect(Collectors.toList()); if (datas.isEmpty()) return null; - int numItems = datas.size(); - int index = random.nextInt(numItems); - ItemStack is = datas.get(index).getStack(); + ItemStack is = datas.get(random.nextInt(datas.size())).getStack(); assert is != null; // verified above is = is.clone(); is.setAmount(getAmount()); return is; } + /** + * @return One random ItemStack or Material that this ItemType represents. + * A Material may only be returned for ItemStacks containing a Material where {@link Material#isItem()} is false. + */ + public Object getRandomStackOrMaterial() { + ItemData randomData = types.get(random.nextInt(types.size())); + ItemStack stack = randomData.getStack(); + if (stack == null) + return randomData.getType(); + stack = stack.clone(); + stack.setAmount(getAmount()); + return stack; + } + /** * Test whether this ItemType can be put into the given inventory completely. *

@@ -1396,8 +1408,11 @@ public void clearItemMeta() { globalMeta = null; } + /** + * @return A random Material this ItemType represents. + */ public Material getMaterial() { - ItemData data = types.get(0); + ItemData data = types.get(random.nextInt(types.size())); if (data == null) throw new IllegalStateException("material not found"); return data.getType(); diff --git a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java index 231d5ef9986..6da8522d035 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java @@ -949,7 +949,10 @@ public ItemStack parse(final String s, final ParseContext context) { } final ItemStack i = t.getRandom(); - assert i != null; + if (i == null) { + Skript.error("'" + s + "' cannot represent an item"); + return null; + } return i; } diff --git a/src/main/java/ch/njol/skript/conditions/CondIsPreferredTool.java b/src/main/java/ch/njol/skript/conditions/CondIsPreferredTool.java index 195e8240d93..f69a183adfd 100644 --- a/src/main/java/ch/njol/skript/conditions/CondIsPreferredTool.java +++ b/src/main/java/ch/njol/skript/conditions/CondIsPreferredTool.java @@ -80,13 +80,14 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye public boolean check(Event event) { return blocks.check(event, block -> items.check(event, item -> { - if (block instanceof Block) { - return ((Block) block).isPreferredTool(item.getRandom()); - } else if (block instanceof BlockData) { - return ((BlockData) block).isPreferredTool(item.getRandom()); - } else { - return false; + ItemStack stack = item.getRandom(); + if (stack != null) { + if (block instanceof Block) + return ((Block) block).isPreferredTool(stack); + if (block instanceof BlockData) + return ((BlockData) block).isPreferredTool(stack); } + return false; }), isNegated()); } diff --git a/src/main/java/ch/njol/skript/effects/EffOpenBook.java b/src/main/java/ch/njol/skript/effects/EffOpenBook.java index f49df089abe..95d82caf27e 100644 --- a/src/main/java/ch/njol/skript/effects/EffOpenBook.java +++ b/src/main/java/ch/njol/skript/effects/EffOpenBook.java @@ -68,7 +68,7 @@ protected void execute(final Event e) { ItemType itemType = book.getSingle(e); if (itemType != null) { ItemStack itemStack = itemType.getRandom(); - if (itemStack.getType() == Material.WRITTEN_BOOK) { + if (itemStack != null && itemStack.getType() == Material.WRITTEN_BOOK) { for (Player player : players.getArray(e)) { player.openBook(itemStack); } diff --git a/src/main/java/ch/njol/skript/effects/EffReplace.java b/src/main/java/ch/njol/skript/effects/EffReplace.java index f6a1fd5bad8..bf163106851 100644 --- a/src/main/java/ch/njol/skript/effects/EffReplace.java +++ b/src/main/java/ch/njol/skript/effects/EffReplace.java @@ -129,9 +129,10 @@ private void replace(Event event, Object[] needles, Expression haystackExpr) if (new ItemType(itemStack).isSimilar(needle)) { ItemStack newItemStack = ((ItemType) replacement).getRandom(); - newItemStack.setAmount(itemStack.getAmount()); - - inv.setItem(slot, newItemStack); + if (newItemStack != null) { + newItemStack.setAmount(itemStack.getAmount()); + inv.setItem(slot, newItemStack); + } } } } diff --git a/src/main/java/ch/njol/skript/entity/BoatChestData.java b/src/main/java/ch/njol/skript/entity/BoatChestData.java index bb29004028d..499a7ed3e44 100644 --- a/src/main/java/ch/njol/skript/entity/BoatChestData.java +++ b/src/main/java/ch/njol/skript/entity/BoatChestData.java @@ -110,8 +110,7 @@ public boolean isSupertypeOf(EntityData e) { public boolean isOfItemType(ItemType itemType) { int ordinal = -1; - ItemStack stack = itemType.getRandom(); - Material type = stack.getType(); + Material type = itemType.getMaterial(); if (type == Material.OAK_CHEST_BOAT) ordinal = 0; else if (type == Material.SPRUCE_CHEST_BOAT) diff --git a/src/main/java/ch/njol/skript/entity/BoatData.java b/src/main/java/ch/njol/skript/entity/BoatData.java index b273f2ca370..36bc23691d7 100644 --- a/src/main/java/ch/njol/skript/entity/BoatData.java +++ b/src/main/java/ch/njol/skript/entity/BoatData.java @@ -112,9 +112,8 @@ public boolean isSupertypeOf(EntityData e) { public boolean isOfItemType(ItemType i){ int ordinal = -1; - - ItemStack stack = i.getRandom(); - Material type = stack.getType(); + + Material type = i.getMaterial(); if (type == Material.OAK_BOAT) ordinal = 0; else if (type == Material.SPRUCE_BOAT) diff --git a/src/main/java/ch/njol/skript/entity/DroppedItemData.java b/src/main/java/ch/njol/skript/entity/DroppedItemData.java index e9b136407c1..aa7b4a6b8a4 100644 --- a/src/main/java/ch/njol/skript/entity/DroppedItemData.java +++ b/src/main/java/ch/njol/skript/entity/DroppedItemData.java @@ -64,8 +64,15 @@ public DroppedItemData(ItemType @Nullable [] types) { @Override protected boolean init(Literal[] expressions, int matchedPattern, ParseResult parseResult) { - if (expressions.length > 0 && expressions[0] != null) + if (expressions.length > 0 && expressions[0] != null) { types = (ItemType[]) expressions[0].getAll(); + for (ItemType type : types) { + if (!type.getMaterial().isItem()) { + Skript.error("'" + type + "' cannot represent a dropped item"); + return false; + } + } + } return true; } @@ -97,6 +104,7 @@ public void set(final Item entity) { final ItemType t = CollectionUtils.getRandom(types); assert t != null; ItemStack stack = t.getItem().getRandom(); + assert stack != null; // should be true by init checks entity.setItemStack(stack); } @@ -159,6 +167,7 @@ public boolean canSpawn(@Nullable World world) { final ItemType itemType = CollectionUtils.getRandom(types); assert itemType != null; ItemStack stack = itemType.getItem().getRandom(); + assert stack != null; // should be true by init checks Item item; if (consumer == null) { diff --git a/src/main/java/ch/njol/skript/expressions/ExprMaxStack.java b/src/main/java/ch/njol/skript/expressions/ExprMaxStack.java index 71abeb61b7d..77b65fa5191 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprMaxStack.java +++ b/src/main/java/ch/njol/skript/expressions/ExprMaxStack.java @@ -24,6 +24,8 @@ import ch.njol.skript.doc.Name; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; /** * @author joeuguce99 @@ -40,8 +42,11 @@ public class ExprMaxStack extends SimplePropertyExpression { @SuppressWarnings("null") @Override - public Long convert(final ItemType i) { - return (long) i.getRandom().getMaxStackSize(); + public Long convert(ItemType itemType) { + Object random = itemType.getRandomStackOrMaterial(); + if (random instanceof Material) + return (long) ((Material) random).getMaxStackSize(); + return (long) ((ItemStack) random).getMaxStackSize(); } @Override diff --git a/src/main/java/ch/njol/skript/expressions/ExprPlain.java b/src/main/java/ch/njol/skript/expressions/ExprPlain.java index ca73ba22820..67fb7ca3086 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprPlain.java +++ b/src/main/java/ch/njol/skript/expressions/ExprPlain.java @@ -32,6 +32,7 @@ import ch.njol.util.Kleenean; import org.bukkit.event.Event; +import org.bukkit.inventory.ItemStack; import org.eclipse.jdt.annotation.Nullable; @Name("Plain Item") @@ -61,7 +62,7 @@ protected ItemType[] get(Event e) { ItemType itemType = item.getSingle(e); if (itemType == null) return new ItemType[0]; - ItemData data = new ItemData(itemType.getRandom().getType()); + ItemData data = new ItemData(itemType.getMaterial()); data.setPlain(true); ItemType plain = new ItemType(data); return new ItemType[]{plain}; diff --git a/src/main/java/ch/njol/skript/util/visual/VisualEffects.java b/src/main/java/ch/njol/skript/util/visual/VisualEffects.java index dd9d31456c9..e8f4beb7333 100644 --- a/src/main/java/ch/njol/skript/util/visual/VisualEffects.java +++ b/src/main/java/ch/njol/skript/util/visual/VisualEffects.java @@ -151,8 +151,11 @@ private static void registerDataSupplier(String id, BiFunction Date: Fri, 12 Jul 2024 13:54:52 -0400 Subject: [PATCH 08/16] Fix index of player's tool (#6846) --- .../njol/skript/util/slot/EquipmentSlot.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/ch/njol/skript/util/slot/EquipmentSlot.java b/src/main/java/ch/njol/skript/util/slot/EquipmentSlot.java index 5ab854e68c8..47f229bda23 100644 --- a/src/main/java/ch/njol/skript/util/slot/EquipmentSlot.java +++ b/src/main/java/ch/njol/skript/util/slot/EquipmentSlot.java @@ -20,6 +20,7 @@ import java.util.Locale; +import org.bukkit.entity.Entity; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.Event; @@ -132,10 +133,18 @@ public void set(final EntityEquipment e, final @Nullable ItemStack item) { private final EntityEquipment e; private final EquipSlot slot; + private final int slotIndex; private final boolean slotToString; public EquipmentSlot(final EntityEquipment e, final EquipSlot slot, final boolean slotToString) { this.e = e; + int slotIndex = -1; + if (slot == EquipSlot.TOOL) { + Entity holder = e.getHolder(); + if (holder instanceof Player) + slotIndex = ((Player) holder).getInventory().getHeldItemSlot(); + } + this.slotIndex = slotIndex; this.slot = slot; this.slotToString = slotToString; } @@ -146,10 +155,12 @@ public EquipmentSlot(final EntityEquipment e, final EquipSlot slot) { @SuppressWarnings("null") public EquipmentSlot(HumanEntity holder, int index) { - this.e = holder.getEquipment(); - this.slot = values[41 - index]; // 6 entries in EquipSlot, indices descending - // So this math trick gets us the EquipSlot from inventory slot index - this.slotToString = true; // Referring to numeric slot id, right? + /* + * slot: 6 entries in EquipSlot, indices descending + * So this math trick gets us the EquipSlot from inventory slot index + * slotToString: Referring to numeric slot id, right? + */ + this(holder.getEquipment(), values[41 - index], true); } @Override @@ -189,7 +200,8 @@ public EquipSlot getEquipSlot() { @Override public int getIndex() { - return slot.slotNumber; + // use specific slotIndex if available + return slotIndex != -1 ? slotIndex : slot.slotNumber; } @Override From accb30d96126c42945fed998178955c09474c2c8 Mon Sep 17 00:00:00 2001 From: Patrick Miller Date: Fri, 12 Jul 2024 14:17:49 -0400 Subject: [PATCH 09/16] Fix ItemData#equals check (#6888) --- src/main/java/ch/njol/skript/aliases/ItemData.java | 2 +- src/test/skript/tests/syntaxes/effects/EffEquip.sk | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 src/test/skript/tests/syntaxes/effects/EffEquip.sk diff --git a/src/main/java/ch/njol/skript/aliases/ItemData.java b/src/main/java/ch/njol/skript/aliases/ItemData.java index 0f68279f43a..f18812aabb8 100644 --- a/src/main/java/ch/njol/skript/aliases/ItemData.java +++ b/src/main/java/ch/njol/skript/aliases/ItemData.java @@ -278,7 +278,7 @@ public boolean equals(final @Nullable Object obj) { return false; ItemData other = (ItemData) obj; - if (isAlias) { // This is alias, other item might not be + if (isAlias()) { // This is alias, other item might not be return other.matchAlias(this).isAtLeast(MatchQuality.SAME_ITEM); } else { // This is not alias, but other might be return matchAlias(other).isAtLeast(MatchQuality.SAME_ITEM); diff --git a/src/test/skript/tests/syntaxes/effects/EffEquip.sk b/src/test/skript/tests/syntaxes/effects/EffEquip.sk new file mode 100644 index 00000000000..a4a88a94f28 --- /dev/null +++ b/src/test/skript/tests/syntaxes/effects/EffEquip.sk @@ -0,0 +1,12 @@ +test "equip effect": + spawn a zombie at spawn of "world": + set {_entity} to event-entity + + equip {_entity} with a diamond chestplate + assert chestplate of {_entity} is a diamond chestplate with "entity was not wearing a diamond chestplate" + set chestplate of {_entity} to air + + equip {_entity} with a diamond chestplate named "Test" + assert chestplate of {_entity} is a diamond chestplate named "Test" with "entity was not wearing a named diamond chestplate" + + delete the entity within {_entity} From c8e5457e946bb546ad2545817faa59d2504ebd45 Mon Sep 17 00:00:00 2001 From: APickledWalrus Date: Fri, 12 Jul 2024 14:26:47 -0400 Subject: [PATCH 10/16] Prepare For Release (2.9.0-pre2) --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 7538ea20a76..8b633bdc344 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ org.gradle.parallel=true groupid=ch.njol name=skript -version=2.9.0-pre1 +version=2.9.0-pre2 jarName=Skript.jar testEnv=java21/paper-1.21.0 testEnvJavaVersion=21 From ad3d5dbca598d670659fb746fe166015748c53b0 Mon Sep 17 00:00:00 2001 From: Patrick Miller Date: Mon, 15 Jul 2024 13:22:16 -0400 Subject: [PATCH 11/16] Add Missing 1.21 Lang Entries (#6895) --- src/main/resources/lang/default.lang | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang index 7ba10ec99f7..3e4bc87b7a4 100644 --- a/src/main/resources/lang/default.lang +++ b/src/main/resources/lang/default.lang @@ -1328,6 +1328,8 @@ damage causes: sonic_boom: sonic boom kill: kill, killed world_border: world border + # 1.21 + campfire: campfire # -- Teleport Causes -- teleport causes: @@ -2111,6 +2113,9 @@ spawn reasons: trap: trap village_defense: village defense, golem defense, iron golem defense village_invasion: village invasion, village invading + # 1.21 + trial_spawner: trial spawner, trial mob spawner, trial creature spawner + enchantment: enchantment # -- Difficulties -- difficulties: From db337a63285bfee737a950514b5c9ceda7d1691f Mon Sep 17 00:00:00 2001 From: _tud <98935832+UnderscoreTud@users.noreply.github.com> Date: Mon, 15 Jul 2024 20:28:55 +0300 Subject: [PATCH 12/16] Improve ReturnHandler#returnValues method (#6894) --- .../java/ch/njol/skript/effects/EffReturn.java | 3 +-- .../java/ch/njol/skript/lang/ReturnHandler.java | 6 ++++-- .../ch/njol/skript/lang/ReturnableTrigger.java | 5 +++-- .../njol/skript/lang/function/ScriptFunction.java | 14 ++++++++------ .../ch/njol/skript/test/runner/SecReturnable.java | 6 +++--- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/main/java/ch/njol/skript/effects/EffReturn.java b/src/main/java/ch/njol/skript/effects/EffReturn.java index 21ce3d4d475..7c4025b5d7a 100644 --- a/src/main/java/ch/njol/skript/effects/EffReturn.java +++ b/src/main/java/ch/njol/skript/effects/EffReturn.java @@ -19,7 +19,6 @@ package ch.njol.skript.effects; import ch.njol.skript.Skript; -import ch.njol.skript.classes.ClassInfo; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Name; @@ -110,7 +109,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye protected TriggerItem walk(Event event) { debug(event, false); //noinspection rawtypes,unchecked - ((ReturnHandler) handler).returnValues(value.getArray(event)); + ((ReturnHandler) handler).returnValues(event, value); TriggerSection parent = getParent(); while (parent != null && parent != handler) { diff --git a/src/main/java/ch/njol/skript/lang/ReturnHandler.java b/src/main/java/ch/njol/skript/lang/ReturnHandler.java index f908fc68c51..d905599dc4b 100644 --- a/src/main/java/ch/njol/skript/lang/ReturnHandler.java +++ b/src/main/java/ch/njol/skript/lang/ReturnHandler.java @@ -130,9 +130,11 @@ default ReturnableTrigger loadReturnableTrigger(SectionNode node, String name } /** - * @param values the values to return + * Called when {@link ch.njol.skript.effects.EffReturn} is executed + * @param event the event providing context + * @param value an expression representing the value(s) to return */ - void returnValues(T @Nullable [] values); + void returnValues(Event event, Expression value); /** * @return whether this return handler may accept multiple return values diff --git a/src/main/java/ch/njol/skript/lang/ReturnableTrigger.java b/src/main/java/ch/njol/skript/lang/ReturnableTrigger.java index 51c025ef70c..4b8b601d990 100644 --- a/src/main/java/ch/njol/skript/lang/ReturnableTrigger.java +++ b/src/main/java/ch/njol/skript/lang/ReturnableTrigger.java @@ -18,6 +18,7 @@ */ package ch.njol.skript.lang; +import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; import org.skriptlang.skript.lang.script.Script; @@ -36,8 +37,8 @@ public ReturnableTrigger(ReturnHandler handler, @Nullable Script script, Stri } @Override - public void returnValues(T @Nullable [] values) { - handler.returnValues(values); + public void returnValues(Event event, Expression value) { + handler.returnValues(event, value); } @Override diff --git a/src/main/java/ch/njol/skript/lang/function/ScriptFunction.java b/src/main/java/ch/njol/skript/lang/function/ScriptFunction.java index d3a1e85117c..c34f26fd448 100644 --- a/src/main/java/ch/njol/skript/lang/function/ScriptFunction.java +++ b/src/main/java/ch/njol/skript/lang/function/ScriptFunction.java @@ -19,13 +19,14 @@ package ch.njol.skript.lang.function; import ch.njol.skript.classes.ClassInfo; +import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ReturnHandler; +import org.bukkit.event.Event; import org.jetbrains.annotations.ApiStatus; import org.skriptlang.skript.lang.script.Script; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.config.SectionNode; -import ch.njol.skript.effects.EffReturn; import ch.njol.skript.lang.Trigger; import ch.njol.skript.lang.util.SimpleEvent; import ch.njol.skript.variables.Variables; @@ -80,13 +81,14 @@ public ScriptFunction(Signature sign, SectionNode node) { } /** - * Should only be called by {@link EffReturn}. - * @deprecated Use {@link ScriptFunction#returnValues(Object[])} + * @deprecated Use {@link ScriptFunction#returnValues(Event, Expression)} */ @Deprecated @ApiStatus.Internal public final void setReturnValue(@Nullable T[] values) { - returnValues(values); + assert !returnValueSet; + returnValueSet = true; + this.returnValues = values; } @Override @@ -97,10 +99,10 @@ public boolean resetReturnValue() { } @Override - public final void returnValues(T @Nullable [] values) { + public final void returnValues(Event event, Expression value) { assert !returnValueSet; returnValueSet = true; - this.returnValues = values; + this.returnValues = value.getArray(event); } @Override diff --git a/src/main/java/ch/njol/skript/test/runner/SecReturnable.java b/src/main/java/ch/njol/skript/test/runner/SecReturnable.java index 436b6d282fb..03833d7132d 100644 --- a/src/main/java/ch/njol/skript/test/runner/SecReturnable.java +++ b/src/main/java/ch/njol/skript/test/runner/SecReturnable.java @@ -56,8 +56,8 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is } @Override - public void returnValues(Object @Nullable [] values) { - returnedValues = values; + public void returnValues(Event event, Expression value) { + returnedValues = value.getArray(event); } @Override @@ -110,5 +110,5 @@ public String toString(@Nullable Event event, boolean debug) { } } - + } From 0e10975d55b87b742a38ed9f4b01e9cfead1269d Mon Sep 17 00:00:00 2001 From: Patrick Miller Date: Mon, 15 Jul 2024 15:12:15 -0400 Subject: [PATCH 13/16] Prepare For Release (2.9.0) (#6903) --- gradle.properties | 2 +- src/main/java/ch/njol/skript/effects/EffBroadcast.java | 2 +- src/main/java/ch/njol/skript/expressions/ExprInput.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 8b633bdc344..80e986f1ef1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ org.gradle.parallel=true groupid=ch.njol name=skript -version=2.9.0-pre2 +version=2.9.0 jarName=Skript.jar testEnv=java21/paper-1.21.0 testEnvJavaVersion=21 diff --git a/src/main/java/ch/njol/skript/effects/EffBroadcast.java b/src/main/java/ch/njol/skript/effects/EffBroadcast.java index fd6ef3ff245..373565bfe6d 100644 --- a/src/main/java/ch/njol/skript/effects/EffBroadcast.java +++ b/src/main/java/ch/njol/skript/effects/EffBroadcast.java @@ -86,7 +86,7 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye } /** - * This effect will call {@link BroadcastMessageEvent} as of INSERT_VERSION. + * This effect will call {@link BroadcastMessageEvent} as of 2.9.0. */ @Override @SuppressWarnings("deprecation") diff --git a/src/main/java/ch/njol/skript/expressions/ExprInput.java b/src/main/java/ch/njol/skript/expressions/ExprInput.java index 334fc79cd93..c04df548244 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprInput.java +++ b/src/main/java/ch/njol/skript/expressions/ExprInput.java @@ -53,7 +53,7 @@ "send \"congrats on being staff!\" to all players where [input has permission \"staff\"]", "sort {_list::*} based on length of input index" }) -@Since("2.2-dev36, INSERT_VERSION (input index)") +@Since("2.2-dev36, 2.9.0 (input index)") public class ExprInput extends SimpleExpression { static { From ce932630c6a117af25adb7277bffcac6fefd5d67 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Wed, 17 Jul 2024 23:03:38 -0700 Subject: [PATCH 14/16] Fix bugs with Timespan#getAs (#6909) * Remove rounding from getAs (it should truncate anyway) to avoid limiting as int max value. Fix bug where millis was multiplied instead of divided. * the ol' switcheroo * Update javadocs for Eclipse users --- .../java/ch/njol/skript/util/Timespan.java | 27 +++++++++---------- .../regressions/6908-timespan too big.sk | 6 +++++ 2 files changed, 19 insertions(+), 14 deletions(-) create mode 100644 src/test/skript/tests/regressions/6908-timespan too big.sk diff --git a/src/main/java/ch/njol/skript/util/Timespan.java b/src/main/java/ch/njol/skript/util/Timespan.java index ff70f8b365f..3b192a34dff 100644 --- a/src/main/java/ch/njol/skript/util/Timespan.java +++ b/src/main/java/ch/njol/skript/util/Timespan.java @@ -18,18 +18,6 @@ */ package ch.njol.skript.util; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.Locale; - -import org.eclipse.jdt.annotation.Nullable; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.ApiStatus.ScheduledForRemoval; - import ch.njol.skript.Skript; import ch.njol.skript.localization.GeneralWords; import ch.njol.skript.localization.Language; @@ -38,6 +26,17 @@ import ch.njol.util.NonNullPair; import ch.njol.util.coll.CollectionUtils; import ch.njol.yggdrasil.YggdrasilSerializable; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.ApiStatus.ScheduledForRemoval; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class Timespan implements YggdrasilSerializable, Comparable { // REMIND unit @@ -211,7 +210,7 @@ public Timespan(TimePeriod timePeriod, long time) { /** * Builds a Timespan from the given long parameter. * - * @deprecated Use {@link Timespan#Timespan(TimePeriod, long)} + * @deprecated Use {@link #Timespan(TimePeriod, long)} * * @param ticks The amount of Minecraft ticks to convert to a timespan. * @return Timespan based on the provided long. @@ -257,7 +256,7 @@ public long getTicks() { * @return the amount of TimePeriod this timespan represents. */ public long getAs(TimePeriod timePeriod) { - return Math.round(millis * timePeriod.getTime()); + return millis / timePeriod.getTime(); } /** diff --git a/src/test/skript/tests/regressions/6908-timespan too big.sk b/src/test/skript/tests/regressions/6908-timespan too big.sk new file mode 100644 index 00000000000..82277775d68 --- /dev/null +++ b/src/test/skript/tests/regressions/6908-timespan too big.sk @@ -0,0 +1,6 @@ +test "large timespans truncated to ints": + set {_now} to now + set {_a} to unix timestamp of {_now} * 1 seconds + set {_b} to unix timestamp of 10 minutes from {_now} * 1 second + assert {_b} - {_a} is 10 minutes with "large timespan was truncated" + From 7b2dcd964e6f312a6bac05ff502fcbdce4b89fd1 Mon Sep 17 00:00:00 2001 From: Patrick Miller Date: Fri, 19 Jul 2024 10:55:48 -0400 Subject: [PATCH 15/16] Fix compilation/runtime errors due to Bukkit enum changes (#6926) --- .../skript/classes/data/BukkitClasses.java | 3 +- .../java/ch/njol/skript/entity/CatData.java | 17 ++++++-- .../java/ch/njol/skript/entity/FrogData.java | 25 +++++++++-- .../ch/njol/skript/entity/VillagerData.java | 38 +++++++++++----- .../skript/entity/ZombieVillagerData.java | 43 +++++++++++++------ 5 files changed, 94 insertions(+), 32 deletions(-) diff --git a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java index 6da8522d035..ba0a66a1f41 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java @@ -1412,7 +1412,8 @@ public String toVariableNameString(FireworkEffect effect) { if (BukkitUtils.registryExists("CAT_VARIANT")) { catTypeClassInfo = new RegistryClassInfo<>(Cat.Type.class, Registry.CAT_VARIANT, "cattype", "cat types"); } else { - catTypeClassInfo = new EnumClassInfo<>(Cat.Type.class, "cattype", "cat types"); + //noinspection unchecked, rawtypes - it is an enum on other versions + catTypeClassInfo = new EnumClassInfo<>((Class) Cat.Type.class, "cattype", "cat types"); } Classes.registerClass(catTypeClassInfo .user("cat ?(type|race)s?") diff --git a/src/main/java/ch/njol/skript/entity/CatData.java b/src/main/java/ch/njol/skript/entity/CatData.java index 20d338e39df..1c435133c8e 100644 --- a/src/main/java/ch/njol/skript/entity/CatData.java +++ b/src/main/java/ch/njol/skript/entity/CatData.java @@ -18,6 +18,8 @@ */ package ch.njol.skript.entity; +import ch.njol.skript.registrations.Classes; +import com.google.common.collect.Iterators; import org.bukkit.entity.Cat; import org.eclipse.jdt.annotation.Nullable; @@ -26,12 +28,19 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.util.coll.CollectionUtils; +import java.util.Objects; + public class CatData extends EntityData { static { - if (Skript.classExists("org.bukkit.entity.Cat")) + if (Skript.classExists("org.bukkit.entity.Cat")) { EntityData.register(CatData.class, "cat", Cat.class, "cat"); + types = Iterators.toArray(Classes.getExactClassInfo(Cat.Type.class).getSupplier().get(), Cat.Type.class); + } } + + @SuppressWarnings("NotNullFieldNotInitialized") + private static Cat.Type[] types; private Cat.@Nullable Type race = null; @@ -42,7 +51,7 @@ protected boolean init(Literal[] exprs, int matchedPattern, ParseResult parse race = ((Literal) exprs[0]).getSingle(); return true; } - + @Override protected boolean init(@Nullable Class c, @Nullable Cat cat) { race = (cat == null) ? Cat.Type.TABBY : cat.getCatType(); @@ -51,7 +60,7 @@ protected boolean init(@Nullable Class c, @Nullable Cat cat) { @Override public void set(Cat entity) { - Cat.Type type = race != null ? race : CollectionUtils.getRandom(Cat.Type.values()); + Cat.Type type = race != null ? race : CollectionUtils.getRandom(types); assert type != null; entity.setCatType(type); } @@ -73,7 +82,7 @@ public EntityData getSuperType() { @Override protected int hashCode_i() { - return race != null ? race.hashCode() : 0; + return Objects.hashCode(race); } @Override diff --git a/src/main/java/ch/njol/skript/entity/FrogData.java b/src/main/java/ch/njol/skript/entity/FrogData.java index 116c781b326..8ce2d24f712 100644 --- a/src/main/java/ch/njol/skript/entity/FrogData.java +++ b/src/main/java/ch/njol/skript/entity/FrogData.java @@ -25,6 +25,8 @@ import org.bukkit.entity.Frog.Variant; import org.eclipse.jdt.annotation.Nullable; +import java.util.Objects; + public class FrogData extends EntityData { static { @@ -42,13 +44,28 @@ public FrogData() { public FrogData(@Nullable Variant variant) { this.variant = variant; - matchedPattern = variant != null ? variant.ordinal() + 1 : 0; + matchedPattern = 0; + if (variant == Variant.TEMPERATE) + matchedPattern = 1; + if (variant == Variant.WARM) + matchedPattern = 2; + if (variant == Variant.COLD) + matchedPattern = 3; } @Override protected boolean init(Literal[] exprs, int matchedPattern, SkriptParser.ParseResult parseResult) { - if (matchedPattern > 0) - variant = Variant.values()[matchedPattern - 1]; + switch (matchedPattern) { + case 1: + variant = Variant.TEMPERATE; + break; + case 2: + variant = Variant.WARM; + break; + case 3: + variant = Variant.COLD; + break; + } return true; } @@ -82,7 +99,7 @@ public EntityData getSuperType() { @Override protected int hashCode_i() { - return variant != null ? variant.hashCode() : 0; + return Objects.hashCode(variant); } @Override diff --git a/src/main/java/ch/njol/skript/entity/VillagerData.java b/src/main/java/ch/njol/skript/entity/VillagerData.java index 2a686ca6784..dfceb63f867 100644 --- a/src/main/java/ch/njol/skript/entity/VillagerData.java +++ b/src/main/java/ch/njol/skript/entity/VillagerData.java @@ -18,10 +18,13 @@ */ package ch.njol.skript.entity; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; import org.bukkit.entity.Villager; import org.bukkit.entity.Villager.Profession; @@ -37,7 +40,7 @@ * @author Peter Güttinger */ public class VillagerData extends EntityData { - + /** * Professions can be for zombies also. These are the ones which are only * for villagers. @@ -49,25 +52,37 @@ public class VillagerData extends EntityData { // NORMAL(-1), FARMER(0), LIBRARIAN(1), PRIEST(2), BLACKSMITH(3), BUTCHER(4), NITWIT(5); Variables.yggdrasil.registerSingleClass(Profession.class, "Villager.Profession"); - + + professions = new ArrayList<>(); if (Skript.isRunningMinecraft(1, 14)) { EntityData.register(VillagerData.class, "villager", Villager.class, 0, "villager", "normal", "armorer", "butcher", "cartographer", "cleric", "farmer", "fisherman", "fletcher", "leatherworker", "librarian", "mason", "nitwit", "shepherd", "toolsmith", "weaponsmith"); - professions = Arrays.asList(Profession.values()); + // TODO obtain from the registry in the future + // This is not currently done as the ordering of the professions is important + // There is no ordering guarantee from the registry + professions = Arrays.asList(Profession.NONE, Profession.ARMORER, Profession.BUTCHER, Profession.CARTOGRAPHER, + Profession.CLERIC, Profession.FARMER, Profession.FISHERMAN, Profession.FLETCHER, Profession.LEATHERWORKER, + Profession.LIBRARIAN, Profession.MASON, Profession.NITWIT, Profession.SHEPHERD, Profession.TOOLSMITH, + Profession.WEAPONSMITH); } else { // Post 1.10: Not all professions go for villagers EntityData.register(VillagerData.class, "villager", Villager.class, 0, "normal", "villager", "farmer", "librarian", "priest", "blacksmith", "butcher", "nitwit"); // Normal is for zombie villagers, but needs to be here, since someone thought changing first element in enum was good idea :( - professions = new ArrayList<>(); - for (Profession prof : Profession.values()) { - // We're better off doing stringfying the constants since these don't exist in 1.14 - if (!prof.toString().equals("NORMAL") && !prof.toString().equals("HUSK")) - professions.add(prof); + try { + for (Profession prof : (Profession[]) MethodHandles.lookup().findStatic(Profession.class, "values", MethodType.methodType(Profession[].class)).invoke()) { + // We're better off doing stringfying the constants since these don't exist in 1.14 + // Using String#valueOf to prevent IncompatibleClassChangeError due to Enum->Interface change + String profString = String.valueOf(prof); + if (!profString.equals("NORMAL") && !profString.equals("HUSK")) + professions.add(prof); + } + } catch (Throwable e) { + throw new RuntimeException("Failed to load legacy villager profession support", e); } } } @@ -116,7 +131,7 @@ public Class getType() { @Override protected int hashCode_i() { - return profession != null ? profession.hashCode() : 0; + return Objects.hashCode(profession); } @Override @@ -133,7 +148,8 @@ protected boolean deserialize(final String s) { if (s.isEmpty()) return true; try { - profession = Profession.valueOf(s); + //noinspection unchecked, rawtypes - prevent IncompatibleClassChangeError due to Enum->Interface change + profession = (Profession) Enum.valueOf((Class) Profession.class, s); return true; } catch (final IllegalArgumentException e) { return false; @@ -143,7 +159,7 @@ protected boolean deserialize(final String s) { @Override public boolean isSupertypeOf(final EntityData e) { if (e instanceof VillagerData) - return profession == null || ((VillagerData) e).profession == profession; + return profession == null || Objects.equals(((VillagerData) e).profession, profession); return false; } diff --git a/src/main/java/ch/njol/skript/entity/ZombieVillagerData.java b/src/main/java/ch/njol/skript/entity/ZombieVillagerData.java index 3ac61bced2d..24b4080ec1f 100644 --- a/src/main/java/ch/njol/skript/entity/ZombieVillagerData.java +++ b/src/main/java/ch/njol/skript/entity/ZombieVillagerData.java @@ -28,34 +28,53 @@ import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptParser.ParseResult; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + public class ZombieVillagerData extends EntityData { - private final static boolean PROFESSION_UPDATE = Skript.isRunningMinecraft(1, 14); - private final static Villager.Profession[] professions = Villager.Profession.values(); + private static final boolean PROFESSION_UPDATE = Skript.isRunningMinecraft(1, 14); + private static final List professions; static { - if (PROFESSION_UPDATE) + if (PROFESSION_UPDATE) { EntityData.register(ZombieVillagerData.class, "zombie villager", ZombieVillager.class, 0, "zombie villager", "zombie armorer", "zombie butcher", "zombie cartographer", "zombie cleric", "zombie farmer", "zombie fisherman", "zombie fletcher", "zombie leatherworker", "zombie librarian", "zombie mason", "zombie nitwit", "zombie shepherd", "zombie toolsmith", "zombie weaponsmith"); - else + professions = Arrays.asList(Profession.NONE, Profession.ARMORER, Profession.BUTCHER, Profession.CARTOGRAPHER, + Profession.CLERIC, Profession.FARMER, Profession.FISHERMAN, Profession.FLETCHER, Profession.LEATHERWORKER, + Profession.LIBRARIAN, Profession.MASON, Profession.NITWIT, Profession.SHEPHERD, Profession.TOOLSMITH, + Profession.WEAPONSMITH); + } else { EntityData.register(ZombieVillagerData.class, "zombie villager", ZombieVillager.class, 0, "zombie villager", "zombie farmer", "zombie librarian", "zombie priest", "zombie blacksmith", "zombie butcher", "zombie nitwit"); + try { + professions = Arrays.asList((Profession[]) MethodHandles.lookup().findStatic(Profession.class, "values", MethodType.methodType(Profession[].class)).invoke()); + } catch (Throwable e) { + throw new RuntimeException("Failed to load legacy villager profession support", e); + } + } } - - private Villager.Profession profession = PROFESSION_UPDATE ? Profession.NONE : Profession.valueOf("NORMAL"); + + // prevent IncompatibleClassChangeError due to Enum->Interface change + @SuppressWarnings({"unchecked", "rawtypes"}) + private Villager.Profession profession = PROFESSION_UPDATE ? Profession.NONE + : (Profession) Enum.valueOf((Class) Profession.class, "NORMAL"); public ZombieVillagerData() {} public ZombieVillagerData(Profession prof) { profession = prof; - super.matchedPattern = prof.ordinal(); + super.matchedPattern = professions.indexOf(prof); } @SuppressWarnings("null") @Override protected boolean init(final Literal[] exprs, final int matchedPattern, final ParseResult parseResult) { - profession = professions[matchedPattern]; + profession = professions.get(matchedPattern); return true; } @@ -73,8 +92,8 @@ protected boolean init(final @Nullable Class c, final @Override protected boolean deserialize(final String s) { try { - profession = professions[Integer.parseInt(s)]; - } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) { + profession = professions.get(Integer.parseInt(s)); + } catch (NumberFormatException | IndexOutOfBoundsException e) { throw new SkriptAPIException("Cannot parse zombie villager type " + s); } @@ -106,13 +125,13 @@ protected boolean equals_i(final EntityData obj) { @Override protected int hashCode_i() { - return profession.hashCode(); + return Objects.hashCode(profession); } @Override public boolean isSupertypeOf(final EntityData e) { if (e instanceof ZombieVillagerData) - return ((ZombieVillagerData) e).profession.equals(profession); + return Objects.equals(((ZombieVillagerData) e).profession, profession); return false; } From 22a2bfb421655a9f48ba5da683d7bcc33bac2bbf Mon Sep 17 00:00:00 2001 From: potaro Date: Sat, 27 Jul 2024 16:03:01 -0400 Subject: [PATCH 16/16] Fix sorting indices of a list with children (#6897) --- .../ch/njol/skript/expressions/ExprIndices.java | 9 ++++++++- .../6881-sorted indices with children.sk | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/test/skript/tests/regressions/6881-sorted indices with children.sk diff --git a/src/main/java/ch/njol/skript/expressions/ExprIndices.java b/src/main/java/ch/njol/skript/expressions/ExprIndices.java index c09bfe81964..87dffe51ae5 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprIndices.java +++ b/src/main/java/ch/njol/skript/expressions/ExprIndices.java @@ -30,6 +30,7 @@ import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.skript.util.LiteralUtils; import ch.njol.util.Kleenean; +import ch.njol.util.Pair; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; @@ -101,8 +102,14 @@ protected String[] get(Event e) { if (sort) { int direction = descending ? -1 : 1; return variable.entrySet().stream() + .map((entry) -> new Pair<>( + entry.getKey(), + entry.getValue() instanceof Map + ? ((Map) entry.getValue()).get(null) + : entry.getValue() + )) .sorted((a, b) -> ExprSortedList.compare(a.getValue(), b.getValue()) * direction) - .map(Entry::getKey) + .map(Pair::getKey) .toArray(String[]::new); } diff --git a/src/test/skript/tests/regressions/6881-sorted indices with children.sk b/src/test/skript/tests/regressions/6881-sorted indices with children.sk new file mode 100644 index 00000000000..3b7826e90d5 --- /dev/null +++ b/src/test/skript/tests/regressions/6881-sorted indices with children.sk @@ -0,0 +1,15 @@ +test "sorted indices with children": + set {_test::1} to 111 + set {_test::2} to 555 + set {_test::3} to 444 + set {_test::1::a} to 2 + set {_test::2::b} to 3 + set {_test::3::c} to 6 + set {_test::3::a::foo} to "i" + set {_test::3::b::bar} to "love" + set {_test::3::c::baz} to "skript" + set {_indices::*} to (sorted indices of {_test::*} in ascending order) + + assert {_indices::*} is ("1", "3", "2") with "sorted indices on list with children threw or was incorrect" + assert {_test::*} is (111, 555, 444) with "modified children wrongly" + assert {_test::3::*} is 6 with "modified children wrongly"