From befa81f902ddf5cb22bcb2c7bcf7dd9bcf2a4896 Mon Sep 17 00:00:00 2001 From: Shane Bee Date: Mon, 1 Jul 2024 13:04:49 -0700 Subject: [PATCH 1/6] RegistryParser - strip out minecraft namespaces from docs (#6844) * RegistryParser - strip out minecraft namespaces from docs * RegistryParser - Stream#toList() not available on older java versions --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> --- .../java/ch/njol/skript/classes/data/BukkitClasses.java | 9 ++++++--- .../ch/njol/skript/classes/registry/RegistryParser.java | 6 ++---- 2 files changed, 8 insertions(+), 7 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 7ff72f27e69..b48c69149d7 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitClasses.java @@ -990,7 +990,8 @@ public String toVariableNameString(final ItemStack i) { Classes.registerClass(biomeClassInfo .user("biomes?") .name("Biome") - .description("All possible biomes Minecraft uses to generate a world.") + .description("All possible biomes Minecraft uses to generate a world.", + "NOTE: Minecraft namespaces are supported, ex: 'minecraft:basalt_deltas'.") .examples("biome at the player is desert") .since("1.4.4") .after("damagecause")); @@ -1465,7 +1466,8 @@ public String toVariableNameString(FireworkEffect effect) { Classes.registerClass(catTypeClassInfo .user("cat ?(type|race)s?") .name("Cat Type") - .description("Represents the race/type of a cat entity.") + .description("Represents the race/type of a cat entity.", + "NOTE: Minecraft namespaces are supported, ex: 'minecraft:british_shorthair'.") .since("2.4") .requiredPlugins("Minecraft 1.14 or newer") .documentationId("CatType")); @@ -1533,7 +1535,8 @@ public String toVariableNameString(EnchantmentOffer eo) { .user("attribute ?types?") .name("Attribute Type") .description("Represents the type of an attribute. Note that this type does not contain any numerical values." - + "See attribute types for more info.") + + "See attribute types for more info.", + "NOTE: Minecraft namespaces are supported, ex: 'minecraft:generic.attack_damage'.") .since("2.5")); Classes.registerClass(new EnumClassInfo<>(Environment.class, "environment", "environments") diff --git a/src/main/java/ch/njol/skript/classes/registry/RegistryParser.java b/src/main/java/ch/njol/skript/classes/registry/RegistryParser.java index 51cb4637434..dc9bf9f00b7 100644 --- a/src/main/java/ch/njol/skript/classes/registry/RegistryParser.java +++ b/src/main/java/ch/njol/skript/classes/registry/RegistryParser.java @@ -30,12 +30,11 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.stream.Collectors; /** * A parser based on a {@link Registry} used to parse data from a string or turn data into a string. @@ -147,8 +146,7 @@ private void refresh() { * Note that some entries may represent the same registry object. */ public String getAllNames() { - List strings = new ArrayList<>(parseMap.keySet()); - Collections.sort(strings); + List strings = parseMap.keySet().stream().filter(s -> !s.startsWith("minecraft:")).sorted().collect(Collectors.toList()); return StringUtils.join(strings, ", "); } From 3c0119f4351dae51b02936d37e02625769451d0c Mon Sep 17 00:00:00 2001 From: cheeezburga <47320303+cheeezburga@users.noreply.github.com> Date: Tue, 2 Jul 2024 06:24:03 +1000 Subject: [PATCH 2/6] Adds tooltip syntax (#6712) * Adds effect, condition, and tests for tooltip-related syntax * Removed star imports * Apply suggestions from code review Co-authored-by: Patrick Miller Co-authored-by: Fusezion * Suggestions from Pickle and Lyric - Changed the parse marks/tags in the effect and patterns for the condition - Added some info to the condition's description * Apply suggestions from code review Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> * Some more suggestions - Changed the condition to use setNegated and isNegated, and use Sovde's pattern changes - Changed the effect description and fixed to work with Sovde's pattern changes * Small fix * Apply suggestions from code review Co-authored-by: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com> * Update src/main/java/ch/njol/skript/conditions/CondTooltip.java Co-authored-by: Patrick Miller * Adds "reveal" as option in syntax --------- Co-authored-by: Patrick Miller Co-authored-by: Fusezion Co-authored-by: Moderocky Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> Co-authored-by: LimeGlass <16087552+TheLimeGlass@users.noreply.github.com> --- .../njol/skript/conditions/CondTooltip.java | 87 +++++++++++++++++ .../ch/njol/skript/effects/EffTooltip.java | 95 +++++++++++++++++++ .../tests/syntaxes/conditions/CondTooltip.sk | 15 +++ 3 files changed, 197 insertions(+) create mode 100644 src/main/java/ch/njol/skript/conditions/CondTooltip.java create mode 100644 src/main/java/ch/njol/skript/effects/EffTooltip.java create mode 100644 src/test/skript/tests/syntaxes/conditions/CondTooltip.sk diff --git a/src/main/java/ch/njol/skript/conditions/CondTooltip.java b/src/main/java/ch/njol/skript/conditions/CondTooltip.java new file mode 100644 index 00000000000..dc7c795ca76 --- /dev/null +++ b/src/main/java/ch/njol/skript/conditions/CondTooltip.java @@ -0,0 +1,87 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package ch.njol.skript.conditions; + +import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Condition; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.meta.ItemMeta; +import org.eclipse.jdt.annotation.Nullable; + +@Name("Has Item Tooltips") +@Description({ + "Whether the entire or additional tooltip of an item is shown or hidden.", + "The 'entire tooltip' is what shows to the player when they hover an item (i.e. name, lore, etc.).", + "The 'additional tooltip' hides certain information from certain items (potions, maps, books, fireworks, and banners)." +}) +@Examples({ + "send true if entire tooltip of player's tool is shown", + "if additional tooltip of {_item} is hidden:" +}) +@RequiredPlugins("Spigot 1.20.5+") +@Since("INSERT VERSION") +public class CondTooltip extends Condition { + + static { + if (Skript.methodExists(ItemMeta.class, "isHideTooltip")) {// this method was added in the same version as the additional tooltip item flag + Skript.registerCondition(CondTooltip.class, + "[the] [entire|:additional] tool[ ]tip[s] of %itemtypes% (is|are) (:shown|hidden)", + "[the] [entire|:additional] tool[ ]tip[s] of %itemtypes% (isn't|is not|aren't|are not) (:shown|hidden)", + "%itemtypes%'[s] [entire|:additional] tool[ ]tip[s] (is|are) (:shown|hidden)", + "%itemtypes%'[s] [entire|:additional] tool[ ]tip[s] (isn't|is not|aren't|are not) (:shown|hidden)" + ); + } + } + + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression items; + private boolean entire; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + items = (Expression) exprs[0]; + entire = !parseResult.hasTag("additional"); + setNegated(parseResult.hasTag("shown") ^ (matchedPattern == 1 || matchedPattern == 3)); + return true; + } + + @Override + public boolean check(Event event) { + if (entire) + return items.check(event, item -> item.getItemMeta().isHideTooltip(), isNegated()); + return items.check(event, item -> item.getItemMeta().hasItemFlag(ItemFlag.HIDE_ADDITIONAL_TOOLTIP), isNegated()); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "the " + (entire ? "entire" : "additional") + " tooltip of " + items.toString(event, debug) + " is " + (isNegated() ? "hidden" : "shown"); + } + +} diff --git a/src/main/java/ch/njol/skript/effects/EffTooltip.java b/src/main/java/ch/njol/skript/effects/EffTooltip.java new file mode 100644 index 00000000000..26272c4b716 --- /dev/null +++ b/src/main/java/ch/njol/skript/effects/EffTooltip.java @@ -0,0 +1,95 @@ +/** + * This file is part of Skript. + * + * Skript is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Skript is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ +package ch.njol.skript.effects; + +import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.event.Event; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.meta.ItemMeta; +import org.eclipse.jdt.annotation.Nullable; + +@Name("Item Tooltips") +@Description({ + "Show or hide the tooltip of an item.", + "If changing the 'entire' tooltip of an item, nothing will show up when a player hovers over it.", + "If changing the 'additional' tooltip, only specific parts (which change per item) will be hidden." +}) +@Examples({ + "hide the entire tooltip of player's tool", + "hide {_item}'s additional tool tip" +}) +@RequiredPlugins("Spigot 1.20.5+") +@Since("INSERT VERSION") +public class EffTooltip extends Effect { + + static { + if (Skript.methodExists(ItemMeta.class, "setHideTooltip", boolean.class)) { // this method was added in the same version as the additional tooltip item flag + Skript.registerEffect(EffTooltip.class, + "(show|reveal|:hide) %itemtypes%'[s] [entire|:additional] tool[ ]tip", + "(show|reveal|:hide) [the] [entire|:additional] tool[ ]tip of %itemtypes%" + ); + } + } + + @SuppressWarnings("NotNullFieldNotInitialized") + private Expression items; + private boolean hide, entire; + + @Override + @SuppressWarnings("unchecked") + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + items = (Expression) exprs[0]; + hide = parseResult.hasTag("hide"); + entire = !parseResult.hasTag("additional"); + return true; + } + + @Override + protected void execute(Event event) { + for (ItemType item : items.getArray(event)) { + ItemMeta meta = item.getItemMeta(); + if (entire) { + meta.setHideTooltip(hide); + } else { + if (hide) { + meta.addItemFlags(ItemFlag.HIDE_ADDITIONAL_TOOLTIP); + } else { + meta.removeItemFlags(ItemFlag.HIDE_ADDITIONAL_TOOLTIP); + } + } + item.setItemMeta(meta); + } + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return (hide ? "hide" : "show") + " the " + (entire ? "entire" : "additional") + " tooltip of " + items.toString(event, debug); + } + +} diff --git a/src/test/skript/tests/syntaxes/conditions/CondTooltip.sk b/src/test/skript/tests/syntaxes/conditions/CondTooltip.sk new file mode 100644 index 00000000000..117a2b5bbb1 --- /dev/null +++ b/src/test/skript/tests/syntaxes/conditions/CondTooltip.sk @@ -0,0 +1,15 @@ +test "tooltip" when running minecraft "1.20.5": + + set {_item} to a diamond + assert entire tooltip of {_item} is shown with "item unexpectedly doesn't have entire tooltip" + assert additional tooltip of {_item} is shown with "item unexpectedly doesn't have additional tooltip" + + hide entire tooltip of {_item} + assert entire tooltip of {_item} is hidden with "item unexpectedly has entire tooltip" + hide additional tooltip of {_item} + assert additional tooltip of {_item} is hidden with "item unexpectedly has additional tooltip" + + show entire tooltip of {_item} + assert entire tooltip of {_item} is shown with "item unexpectedly doesn't have entire tooltip" + show additional tooltip of {_item} + assert additional tooltip of {_item} is shown with "item unexpectedly doesn't have additional tooltip" From d4ccff74c90614375b4bc41c032bfa19c6bb2ae5 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Mon, 1 Jul 2024 22:38:24 +0200 Subject: [PATCH 3/6] Exposes 'load default aliases' config option and removes hardcoded alias dependencies (#6834) * Removes dependencies on hardcoded aliases (javaItemType) and exposes 'load deafult aliases' config option * Update ItemUtils.java * Apply suggestions from code review Co-authored-by: Patrick Miller * requested changes * requested * Update src/main/java/ch/njol/skript/expressions/ExprSpawnerType.java Co-authored-by: Patrick Miller --------- Co-authored-by: Patrick Miller --- .../java/ch/njol/skript/aliases/Aliases.java | 11 ++- .../java/ch/njol/skript/aliases/ItemType.java | 13 +++ .../ch/njol/skript/bukkitutil/ItemUtils.java | 59 +++++++++++- .../bukkitutil/block/NewBlockCompat.java | 90 ++++++++++--------- .../classes/data/BukkitEventValues.java | 6 +- .../classes/data/DefaultComparators.java | 3 +- .../java/ch/njol/skript/effects/EffEquip.java | 61 +++++++++++-- .../ch/njol/skript/effects/EffOpenBook.java | 5 +- .../ch/njol/skript/entity/BoatChestData.java | 29 ++---- .../java/ch/njol/skript/entity/BoatData.java | 24 ++--- .../njol/skript/entity/ThrownPotionData.java | 19 ++-- .../java/ch/njol/skript/events/EvtMoveOn.java | 14 ++- .../njol/skript/events/EvtPressurePlate.java | 31 +++++-- .../skript/expressions/ExprBurnCookTime.java | 15 ++-- .../ch/njol/skript/expressions/ExprName.java | 4 +- .../njol/skript/expressions/ExprSignText.java | 22 ++--- .../ch/njol/skript/expressions/ExprSkull.java | 5 +- .../skript/expressions/ExprSpawnerType.java | 19 ++-- src/main/resources/config.sk | 10 +++ 19 files changed, 290 insertions(+), 150 deletions(-) diff --git a/src/main/java/ch/njol/skript/aliases/Aliases.java b/src/main/java/ch/njol/skript/aliases/Aliases.java index 56bffc24f9a..fe1a3a624c4 100644 --- a/src/main/java/ch/njol/skript/aliases/Aliases.java +++ b/src/main/java/ch/njol/skript/aliases/Aliases.java @@ -25,6 +25,7 @@ import ch.njol.skript.config.Node; import ch.njol.skript.config.SectionNode; import ch.njol.skript.entity.EntityData; +import org.bukkit.entity.EntityType; import org.skriptlang.skript.lang.script.Script; import ch.njol.skript.lang.parser.ParserInstance; import ch.njol.skript.localization.ArgsMessage; @@ -431,7 +432,6 @@ private static void loadInternal() throws IOException { Path aliasesPath = zipFs.getPath("/", "aliases-english"); assert aliasesPath != null; loadDirectory(aliasesPath); - loadMissingAliases(); } } catch (URISyntaxException e) { assert false; @@ -445,6 +445,9 @@ private static void loadInternal() throws IOException { assert aliasesFolder != null; loadDirectory(aliasesFolder); } + + // generate aliases from item names for any missing items + loadMissingAliases(); // Update tracked item types for (Map.Entry entry : trackedTypes.entrySet()) { @@ -554,10 +557,16 @@ public static EntityData getRelatedEntity(ItemData data) { *

Item types provided by this method are updated when aliases are * reloaded. However, this also means they are tracked by aliases system * and NOT necessarily garbage-collected. + * + *

Relying on this method to create item types is not safe, + * as users can change aliases at any point. ItemTypes should instead be created + * via {@link Material}s, {@link org.bukkit.Tag}s, or any other manual method. + * * @param name Name of item to search from aliases. * @return An item. * @throws IllegalArgumentException When item is not found. */ + @Deprecated(forRemoval = true, since = "2.9.0") public static ItemType javaItemType(String name) { ItemType type = parseItemType(name); if (type == null) { diff --git a/src/main/java/ch/njol/skript/aliases/ItemType.java b/src/main/java/ch/njol/skript/aliases/ItemType.java index 0b47617ef5c..efaa59249f2 100644 --- a/src/main/java/ch/njol/skript/aliases/ItemType.java +++ b/src/main/java/ch/njol/skript/aliases/ItemType.java @@ -40,6 +40,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.OfflinePlayer; +import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Skull; @@ -173,6 +174,18 @@ public ItemType(Material id) { add_(new ItemData(id)); } + public ItemType(Material... ids) { + for (Material id : ids) { + add_(new ItemData(id)); + } + } + + public ItemType(Tag tag) { + for (Material id : tag.getValues()) { + add_(new ItemData(id)); + } + } + public ItemType(Material id, String tags) { add_(new ItemData(id, tags)); } diff --git a/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java b/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java index 216be44b918..611aba0d1d7 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java +++ b/src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java @@ -21,7 +21,13 @@ import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.TreeType; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.type.Fence; +import org.bukkit.block.data.type.Gate; +import org.bukkit.block.data.type.Wall; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; @@ -234,5 +240,56 @@ public static boolean isAir(Material type) { public static Material getTreeSapling(TreeType treeType) { return TREE_TO_SAPLING_MAP.get(treeType); } - + + + private static final boolean HAS_FENCE_TAGS = !Skript.isRunningMinecraft(1, 14); + + /** + * Whether the block is a fence or a wall. + * @param block the block to check. + * @return whether the block is a fence/wall. + */ + public static boolean isFence(Block block) { + // TODO: 1.13 only, so remove in 2.10 + if (!HAS_FENCE_TAGS) { + BlockData data = block.getBlockData(); + return data instanceof Fence + || data instanceof Wall + || data instanceof Gate; + } + + Material type = block.getType(); + return Tag.FENCES.isTagged(type) + || Tag.FENCE_GATES.isTagged(type) + || Tag.WALLS.isTagged(type); + } + + /** + * @param material The material to check + * @return whether the material is a full glass block + */ + public static boolean isGlass(Material material) { + switch (material) { + case GLASS: + case RED_STAINED_GLASS: + case ORANGE_STAINED_GLASS: + case YELLOW_STAINED_GLASS: + case LIGHT_BLUE_STAINED_GLASS: + case BLUE_STAINED_GLASS: + case CYAN_STAINED_GLASS: + case LIME_STAINED_GLASS: + case GREEN_STAINED_GLASS: + case MAGENTA_STAINED_GLASS: + case PURPLE_STAINED_GLASS: + case PINK_STAINED_GLASS: + case WHITE_STAINED_GLASS: + case LIGHT_GRAY_STAINED_GLASS: + case GRAY_STAINED_GLASS: + case BLACK_STAINED_GLASS: + case BROWN_STAINED_GLASS: + return true; + default: + return false; + } + } } 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 e5cf9c0567b..e72a947996f 100644 --- a/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java +++ b/src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java @@ -22,6 +22,7 @@ import ch.njol.skript.aliases.Aliases; import ch.njol.skript.aliases.ItemType; import ch.njol.skript.aliases.MatchQuality; +import ch.njol.skript.bukkitutil.ItemUtils; import ch.njol.skript.variables.Variables; import ch.njol.yggdrasil.Fields; import org.bukkit.Bukkit; @@ -31,10 +32,12 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; +import org.bukkit.block.BlockSupport; import org.bukkit.block.data.Bisected; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Directional; import org.bukkit.block.data.type.Bed; +import org.bukkit.block.data.type.Snow; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -141,15 +144,6 @@ public void deserialize(@NonNull Fields fields) throws StreamCorruptedException } private static class NewBlockSetter implements BlockSetter { - - private ItemType floorTorch; - private ItemType wallTorch; - - private ItemType specialTorchSides; - private ItemType specialTorchFloors; - - private boolean typesLoaded = false; - private static final BlockFace[] CARDINAL_FACES = new BlockFace[] {BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST}; @@ -158,14 +152,11 @@ public NewBlockSetter() {} @Override public void setBlock(Block block, Material type, @Nullable BlockValues values, int flags) { - if (!typesLoaded) - loadTypes(); - - boolean rotate = (flags | ROTATE) != 0; - boolean rotateForce = (flags | ROTATE_FORCE) != 0; - boolean rotateFixType = (flags | ROTATE_FIX_TYPE) != 0; - boolean multipart = (flags | MULTIPART) != 0; - boolean applyPhysics = (flags | APPLY_PHYSICS) != 0; + boolean rotate = (flags & ROTATE) != 0; + boolean rotateForce = (flags & ROTATE_FORCE) != 0; + boolean rotateFixType = (flags & ROTATE_FIX_TYPE) != 0; + boolean multipart = (flags & MULTIPART) != 0; + boolean applyPhysics = (flags & APPLY_PHYSICS) != 0; NewBlockValues ourValues = null; if (values != null) ourValues = (NewBlockValues) values; @@ -178,31 +169,23 @@ public void setBlock(Block block, Material type, @Nullable BlockValues values, i */ boolean placed = false; if (rotate) { - if (floorTorch.isOfType(type) || (rotateFixType && wallTorch.isOfType(type))) { + if (type == Material.TORCH || (rotateFixType && type == Material.WALL_TORCH)) { // If floor torch cannot be placed, try a wall torch Block under = block.getRelative(0, -1, 0); - boolean canPlace = true; - if (!under.getType().isOccluding()) { // Usually cannot be placed, but there are exceptions - // TODO check for stairs and slabs, currently complicated since there is no 'any' alias - if (specialTorchFloors.isOfType(under)) { - canPlace = true; - } else { - canPlace = false; - } - } + boolean canPlace = canSupportFloorTorch(under); // Can't really place a floor torch, try wall one instead if (!canPlace) { BlockFace face = findWallTorchSide(block); if (face != null) { // Found better torch spot - block.setType(wallTorch.getMaterial()); + block.setType(Material.WALL_TORCH); Directional data = (Directional) block.getBlockData(); data.setFacing(face); block.setBlockData(data, applyPhysics); placed = true; } } - } else if (wallTorch.isOfType(type)) { + } else if (type == Material.WALL_TORCH) { Directional data; if (ourValues != null) data = (Directional) ourValues.data; @@ -210,7 +193,7 @@ public void setBlock(Block block, Material type, @Nullable BlockValues values, i data = (Directional) Bukkit.createBlockData(type); Block relative = block.getRelative(data.getFacing()); - if ((!relative.getType().isOccluding() && !specialTorchSides.isOfType(relative)) || rotateForce) { + if ((!canSupportWallTorch(relative, data.getFacing().getOppositeFace())) || rotateForce) { // Attempt to figure out a better rotation BlockFace face = findWallTorchSide(block); if (face != null) { // Found better torch spot @@ -294,22 +277,49 @@ public void setBlock(Block block, Material type, @Nullable BlockValues values, i block.setBlockData(ourValues.data, applyPhysics); } } - - private void loadTypes() { - floorTorch = Aliases.javaItemType("floor torch"); - wallTorch = Aliases.javaItemType("wall torch"); - - specialTorchSides = Aliases.javaItemType("special torch sides"); - specialTorchFloors = Aliases.javaItemType("special torch floors"); - - typesLoaded = true; + + // 1.19+ + // TODO: remove in 2.10 + private static final boolean HAS_BLOCK_SUPPORT = Skript.classExists("org.bukkit.block.BlockSupport"); + + /** + * Returns whether this block can support a floor torch. + * @param block The block the torch will be placed on + * @return whether the block can support the torch. + */ + private static boolean canSupportFloorTorch(Block block) { + if (HAS_BLOCK_SUPPORT) + return block.getBlockData().isFaceSturdy(BlockFace.UP, BlockSupport.CENTER); + + Material material = block.getType(); + return (material.isOccluding() + || canSupportWallTorch(block, null) + || ItemUtils.isFence(block) + || ItemUtils.isGlass(material) + || material == Material.HOPPER + || (material == Material.SNOW && (((Snow) block.getBlockData()).getLayers() == 8)) + ); + } + + /** + * Returns whether this block can support a wall torch. In 1.19+, a face can be specified. + * @param block The block the torch will be placed on + * @param face The face the torch will be placed on (only considered in 1.19+) + * @return whether the block face can support the torch. + */ + private static boolean canSupportWallTorch(Block block, @Nullable BlockFace face) { + if (HAS_BLOCK_SUPPORT && face != null) + return block.getBlockData().isFaceSturdy(face, BlockSupport.FULL); + + Material material = block.getType(); + return material.isOccluding() || material == Material.SOUL_SAND || material == Material.SPAWNER; } @Nullable private BlockFace findWallTorchSide(Block block) { for (BlockFace face : CARDINAL_FACES) { Block relative = block.getRelative(face); - if (relative.getType().isOccluding() || specialTorchSides.isOfType(relative)) + if (relative.getType().isOccluding() || canSupportWallTorch(relative, face.getOppositeFace())) return face.getOppositeFace(); // Torch can be rotated towards from this face } 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 6a49566c827..34792550178 100644 --- a/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java +++ b/src/main/java/ch/njol/skript/classes/data/BukkitEventValues.java @@ -392,12 +392,11 @@ public Block get(final BlockBreakEvent e) { return new DelayedChangeBlock(e.getBlock()); } }, 0); - ItemType stationaryWater = Aliases.javaItemType("stationary water"); EventValues.registerEventValue(BlockBreakEvent.class, Block.class, new Getter() { @Override public Block get(final BlockBreakEvent e) { final BlockState s = e.getBlock().getState(); - s.setType(s.getType() == Material.ICE ? stationaryWater.getMaterial() : Material.AIR); + s.setType(s.getType() == Material.ICE ? Material.WATER : Material.AIR); s.setRawData((byte) 0); return new BlockStateBlock(s, true); } @@ -760,12 +759,11 @@ public Block get(final PlayerBucketEmptyEvent e) { return e.getBlockClicked().getRelative(e.getBlockFace()); } }, -1); - ItemType stationaryLava = Aliases.javaItemType("stationary lava"); EventValues.registerEventValue(PlayerBucketEmptyEvent.class, Block.class, new Getter() { @Override public Block get(final PlayerBucketEmptyEvent e) { final BlockState s = e.getBlockClicked().getRelative(e.getBlockFace()).getState(); - s.setType(e.getBucket() == Material.WATER_BUCKET ? stationaryWater.getMaterial() : stationaryLava.getMaterial()); + s.setType(e.getBucket() == Material.WATER_BUCKET ? Material.WATER : Material.LAVA); s.setRawData((byte) 0); return new BlockStateBlock(s, true); } diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultComparators.java b/src/main/java/ch/njol/skript/classes/data/DefaultComparators.java index 87fa10b1089..e5e42bf1423 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultComparators.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultComparators.java @@ -496,7 +496,6 @@ public boolean supportsOrdering() { }); // DamageCause - ItemType - ItemType lava = Aliases.javaItemType("lava"); Comparators.registerComparator(DamageCause.class, ItemType.class, new Comparator() { @Override public Relation compare(DamageCause dc, ItemType t) { @@ -504,7 +503,7 @@ public Relation compare(DamageCause dc, ItemType t) { case FIRE: return Relation.get(t.isOfType(Material.FIRE)); case LAVA: - return Relation.get(t.equals(lava)); + return Relation.get(t.getMaterial() == Material.LAVA); case MAGIC: return Relation.get(t.isOfType(Material.POTION)); case HOT_FLOOR: diff --git a/src/main/java/ch/njol/skript/effects/EffEquip.java b/src/main/java/ch/njol/skript/effects/EffEquip.java index c66a5a1d2fd..baa7334b160 100644 --- a/src/main/java/ch/njol/skript/effects/EffEquip.java +++ b/src/main/java/ch/njol/skript/effects/EffEquip.java @@ -18,7 +18,9 @@ */ package ch.njol.skript.effects; +import ch.njol.skript.aliases.ItemData; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.entity.AbstractHorse; import org.bukkit.entity.ChestedHorse; import org.bukkit.entity.LivingEntity; @@ -93,13 +95,58 @@ public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelaye private static final boolean SUPPORTS_STEERABLE = Skript.classExists("org.bukkit.entity.Steerable"); - private static final ItemType CHESTPLATE = Aliases.javaItemType("chestplate"); - private static final ItemType LEGGINGS = Aliases.javaItemType("leggings"); - private static final ItemType BOOTS = Aliases.javaItemType("boots"); - private static final ItemType HORSE_ARMOR = Aliases.javaItemType("horse armor"); - private static final ItemType SADDLE = Aliases.javaItemType("saddle"); - private static final ItemType CHEST = Aliases.javaItemType("chest"); - private static final ItemType CARPET = Aliases.javaItemType("carpet"); + private static ItemType CHESTPLATE; + private static ItemType LEGGINGS; + private static ItemType BOOTS; + private static ItemType CARPET; + private static final ItemType HORSE_ARMOR = new ItemType(Material.IRON_HORSE_ARMOR, Material.GOLDEN_HORSE_ARMOR, Material.DIAMOND_HORSE_ARMOR); + private static final ItemType SADDLE = new ItemType(Material.SADDLE); + private static final ItemType CHEST = new ItemType(Material.CHEST); + + static { + boolean usesWoolCarpetTag = Skript.fieldExists(Tag.class, "WOOL_CARPET"); + CARPET = new ItemType(usesWoolCarpetTag ? Tag.WOOL_CARPETS : Tag.CARPETS); + // added in 1.20.6 + if (Skript.fieldExists(Tag.class, "ITEM_CHEST_ARMOR")) { + CHESTPLATE = new ItemType(Tag.ITEMS_CHEST_ARMOR); + LEGGINGS = new ItemType(Tag.ITEMS_LEG_ARMOR); + BOOTS = new ItemType(Tag.ITEMS_FOOT_ARMOR); + } else { + CHESTPLATE = new ItemType( + Material.LEATHER_CHESTPLATE, + Material.CHAINMAIL_CHESTPLATE, + Material.GOLDEN_CHESTPLATE, + Material.IRON_CHESTPLATE, + Material.DIAMOND_CHESTPLATE, + Material.ELYTRA + ); + + LEGGINGS = new ItemType( + Material.LEATHER_LEGGINGS, + Material.CHAINMAIL_LEGGINGS, + Material.GOLDEN_LEGGINGS, + Material.IRON_LEGGINGS, + Material.DIAMOND_LEGGINGS + ); + + BOOTS = new ItemType( + Material.LEATHER_BOOTS, + Material.CHAINMAIL_BOOTS, + Material.GOLDEN_BOOTS, + Material.IRON_BOOTS, + Material.DIAMOND_BOOTS + ); + + // netherite + if (Skript.isRunningMinecraft(1,16)) { + CHESTPLATE.add(new ItemData(Material.NETHERITE_CHESTPLATE)); + LEGGINGS.add(new ItemData(Material.NETHERITE_LEGGINGS)); + BOOTS.add(new ItemData(Material.NETHERITE_BOOTS)); + } + } + } + + private static final ItemType[] ALL_EQUIPMENT = new ItemType[] {CHESTPLATE, LEGGINGS, BOOTS, HORSE_ARMOR, SADDLE, CHEST, CARPET}; diff --git a/src/main/java/ch/njol/skript/effects/EffOpenBook.java b/src/main/java/ch/njol/skript/effects/EffOpenBook.java index 5b96114818b..f49df089abe 100644 --- a/src/main/java/ch/njol/skript/effects/EffOpenBook.java +++ b/src/main/java/ch/njol/skript/effects/EffOpenBook.java @@ -18,6 +18,7 @@ */ package ch.njol.skript.effects; +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.inventory.ItemStack; @@ -49,8 +50,6 @@ public class EffOpenBook extends Effect { } } - private static final ItemType bookItemType = Aliases.javaItemType("written book"); - @SuppressWarnings("null") private Expression book; @SuppressWarnings("null") @@ -69,7 +68,7 @@ protected void execute(final Event e) { ItemType itemType = book.getSingle(e); if (itemType != null) { ItemStack itemStack = itemType.getRandom(); - if (itemStack != null && bookItemType.isOfType(itemStack)) { + if (itemStack.getType() == Material.WRITTEN_BOOK) { for (Player player : players.getArray(e)) { player.openBook(itemStack); } diff --git a/src/main/java/ch/njol/skript/entity/BoatChestData.java b/src/main/java/ch/njol/skript/entity/BoatChestData.java index bb8d8506e23..bb29004028d 100644 --- a/src/main/java/ch/njol/skript/entity/BoatChestData.java +++ b/src/main/java/ch/njol/skript/entity/BoatChestData.java @@ -23,6 +23,7 @@ import ch.njol.skript.aliases.ItemType; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptParser; +import org.bukkit.Material; import org.bukkit.TreeSpecies; import org.bukkit.entity.ChestBoat; import org.bukkit.inventory.ItemStack; @@ -32,21 +33,8 @@ public class BoatChestData extends EntityData { - private static ItemType oakBoat = null; - private static ItemType spruceBoat = null; - private static ItemType birchBoat = null; - private static ItemType jungleBoat = null; - private static ItemType acaciaBoat = null; - private static ItemType darkOakBoat = null; - static { if (Skript.classExists("org.bukkit.entity.ChestBoat")) { - oakBoat = Aliases.javaItemType("oak chest boat"); - spruceBoat = Aliases.javaItemType("spruce chest boat"); - birchBoat = Aliases.javaItemType("birch chest boat"); - jungleBoat = Aliases.javaItemType("jungle chest boat"); - acaciaBoat = Aliases.javaItemType("acacia chest boat"); - darkOakBoat = Aliases.javaItemType("dark oak chest boat"); EntityData.register(BoatChestData.class, "chest boat", ChestBoat.class, 0, "chest boat", "any chest boat", "oak chest boat", "spruce chest boat", "birch chest boat", "jungle chest boat", "acacia chest boat", "dark oak chest boat"); @@ -120,22 +108,21 @@ public boolean isSupertypeOf(EntityData e) { } public boolean isOfItemType(ItemType itemType) { - if (itemType.getRandom() == null) - return false; int ordinal = -1; ItemStack stack = itemType.getRandom(); - if (oakBoat.isOfType(stack)) + Material type = stack.getType(); + if (type == Material.OAK_CHEST_BOAT) ordinal = 0; - else if (spruceBoat.isOfType(stack)) + else if (type == Material.SPRUCE_CHEST_BOAT) ordinal = TreeSpecies.REDWOOD.ordinal(); - else if (birchBoat.isOfType(stack)) + else if (type == Material.BIRCH_CHEST_BOAT) ordinal = TreeSpecies.BIRCH.ordinal(); - else if (jungleBoat.isOfType(stack)) + else if (type == Material.JUNGLE_CHEST_BOAT) ordinal = TreeSpecies.JUNGLE.ordinal(); - else if (acaciaBoat.isOfType(stack)) + else if (type == Material.ACACIA_CHEST_BOAT) ordinal = TreeSpecies.ACACIA.ordinal(); - else if (darkOakBoat.isOfType(stack)) + else if (type == Material.DARK_OAK_CHEST_BOAT) ordinal = TreeSpecies.DARK_OAK.ordinal(); return hashCode_i() == ordinal + 2 || (matchedPattern + ordinal == 0) || ordinal == 0; } diff --git a/src/main/java/ch/njol/skript/entity/BoatData.java b/src/main/java/ch/njol/skript/entity/BoatData.java index dfeb1f22890..b273f2ca370 100644 --- a/src/main/java/ch/njol/skript/entity/BoatData.java +++ b/src/main/java/ch/njol/skript/entity/BoatData.java @@ -18,8 +18,10 @@ */ package ch.njol.skript.entity; +import java.lang.reflect.Method; import java.util.Random; +import org.bukkit.Material; import org.bukkit.TreeSpecies; import org.bukkit.entity.Boat; import org.bukkit.inventory.ItemStack; @@ -108,30 +110,22 @@ public boolean isSupertypeOf(EntityData e) { return false; } - private static final ItemType oakBoat = Aliases.javaItemType("oak boat"); - private static final ItemType spruceBoat = Aliases.javaItemType("spruce boat"); - private static final ItemType birchBoat = Aliases.javaItemType("birch boat"); - private static final ItemType jungleBoat = Aliases.javaItemType("jungle boat"); - private static final ItemType acaciaBoat = Aliases.javaItemType("acacia boat"); - private static final ItemType darkOakBoat = Aliases.javaItemType("dark oak boat"); - public boolean isOfItemType(ItemType i){ - if (i.getRandom() == null) - return false; int ordinal = -1; ItemStack stack = i.getRandom(); - if (oakBoat.isOfType(stack)) + Material type = stack.getType(); + if (type == Material.OAK_BOAT) ordinal = 0; - else if (spruceBoat.isOfType(stack)) + else if (type == Material.SPRUCE_BOAT) ordinal = TreeSpecies.REDWOOD.ordinal(); - else if (birchBoat.isOfType(stack)) + else if (type == Material.BIRCH_BOAT) ordinal = TreeSpecies.BIRCH.ordinal(); - else if (jungleBoat.isOfType(stack)) + else if (type == Material.JUNGLE_BOAT) ordinal = TreeSpecies.JUNGLE.ordinal(); - else if (acaciaBoat.isOfType(stack)) + else if (type == Material.ACACIA_BOAT) ordinal = TreeSpecies.ACACIA.ordinal(); - else if (darkOakBoat.isOfType(stack)) + else if (type == Material.DARK_OAK_BOAT) ordinal = TreeSpecies.DARK_OAK.ordinal(); return hashCode_i() == ordinal + 2 || (matchedPattern + ordinal == 0) || ordinal == 0; diff --git a/src/main/java/ch/njol/skript/entity/ThrownPotionData.java b/src/main/java/ch/njol/skript/entity/ThrownPotionData.java index 407460d56c5..12d03199fbe 100644 --- a/src/main/java/ch/njol/skript/entity/ThrownPotionData.java +++ b/src/main/java/ch/njol/skript/entity/ThrownPotionData.java @@ -22,6 +22,7 @@ import java.util.function.Consumer; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.entity.LingeringPotion; import org.bukkit.entity.ThrownPotion; import org.bukkit.inventory.ItemStack; @@ -51,9 +52,9 @@ public class ThrownPotionData extends EntityData { @SuppressWarnings("removal") private static final Class LINGERING_POTION_ENTITY_CLASS = LINGERING_POTION_ENTITY_USED ? LingeringPotion.class : ThrownPotion.class; - private static final ItemType POTION = Aliases.javaItemType("potion"); - private static final ItemType SPLASH_POTION = Aliases.javaItemType("splash potion"); - private static final ItemType LINGER_POTION = Aliases.javaItemType("lingering potion"); + private static final Material POTION = Material.POTION; + private static final Material SPLASH_POTION = Material.SPLASH_POTION; + private static final Material LINGER_POTION = Material.LINGERING_POTION; @Nullable private ItemType[] types; @@ -63,18 +64,18 @@ protected boolean init(Literal[] exprs, int matchedPattern, ParseResult parse if (exprs.length > 0 && exprs[0] != null) { return (types = Converters.convert((ItemType[]) exprs[0].getAll(), ItemType.class, t -> { // If the itemtype is a potion, lets make it a splash potion (required by Bukkit) - if (t.isSupertypeOf(POTION)) { + if (t.getMaterial() == POTION) { ItemMeta meta = t.getItemMeta(); - ItemType itemType = SPLASH_POTION.clone(); + ItemType itemType = new ItemType(SPLASH_POTION); itemType.setItemMeta(meta); return itemType; - } else if (!t.isSupertypeOf(SPLASH_POTION ) && !t.isSupertypeOf(LINGER_POTION)) { + } else if (t.getMaterial() != SPLASH_POTION && t.getMaterial() != LINGER_POTION) { return null; } return t; })).length != 0; // no error message - other things can be thrown as well } else { - types = new ItemType[]{SPLASH_POTION.clone()}; + types = new ItemType[]{new ItemType(SPLASH_POTION)}; } return true; } @@ -109,7 +110,7 @@ protected boolean match(ThrownPotion entity) { if (i == null) return null; - Class thrownPotionClass = (Class) (LINGER_POTION.isOfType(i) ? LINGERING_POTION_ENTITY_CLASS : ThrownPotion.class); + Class thrownPotionClass = (Class) (i.getType() == LINGER_POTION ? LINGERING_POTION_ENTITY_CLASS : ThrownPotion.class); ThrownPotion potion; if (consumer != null) { potion = EntityData.spawn(location, thrownPotionClass, consumer); @@ -131,7 +132,7 @@ public void set(ThrownPotion entity) { ItemStack i = t.getRandom(); if (i == null) return; // Missing item, can't make thrown potion of it - if (LINGERING_POTION_ENTITY_USED && (LINGERING_POTION_ENTITY_CLASS.isInstance(entity) != LINGER_POTION.isOfType(i))) + if (LINGERING_POTION_ENTITY_USED && (LINGERING_POTION_ENTITY_CLASS.isInstance(entity) != (LINGER_POTION == i.getType()))) return; entity.setItem(i); } diff --git a/src/main/java/ch/njol/skript/events/EvtMoveOn.java b/src/main/java/ch/njol/skript/events/EvtMoveOn.java index 52b552b0040..c5677e5783c 100644 --- a/src/main/java/ch/njol/skript/events/EvtMoveOn.java +++ b/src/main/java/ch/njol/skript/events/EvtMoveOn.java @@ -33,6 +33,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.event.Event; import org.bukkit.event.Listener; @@ -66,9 +67,6 @@ public class EvtMoveOn extends SkriptEvent { ).since("2.0"); } - // Fence blocks and fence gates - private static final ItemType FENCE_PART = Aliases.javaItemType("fence part"); - private static final Map> ITEM_TYPE_TRIGGERS = new ConcurrentHashMap<>(); private static final AtomicBoolean REGISTERED_EXECUTOR = new AtomicBoolean(); @@ -87,10 +85,10 @@ public class EvtMoveOn extends SkriptEvent { if (triggers == null) return; - int y = getBlockY(to.getY(), id); + int y = getBlockY(to.getY(), block); if (to.getWorld().equals(from.getWorld()) && to.getBlockX() == from.getBlockX() && to.getBlockZ() == from.getBlockZ()) { Block fromOnBlock = getOnBlock(from); - if (fromOnBlock != null && y == getBlockY(from.getY(), fromOnBlock.getType()) && fromOnBlock.getType() == id) + if (fromOnBlock != null && y == getBlockY(from.getY(), fromOnBlock) && fromOnBlock.getType() == id) return; } @@ -114,14 +112,14 @@ private static Block getOnBlock(Location location) { Block block = location.getWorld().getBlockAt(location.getBlockX(), (int) (Math.ceil(location.getY()) - 1), location.getBlockZ()); if (block.getType() == Material.AIR && Math.abs((location.getY() - location.getBlockY()) - 0.5) < Skript.EPSILON) { // Fences block = location.getWorld().getBlockAt(location.getBlockX(), location.getBlockY() - 1, location.getBlockZ()); - if (!FENCE_PART.isOfType(block)) + if (!ItemUtils.isFence(block)) return null; } return block; } - private static int getBlockY(double y, Material id) { - if (FENCE_PART.isOfType(id) && Math.abs((y - Math.floor(y)) - 0.5) < Skript.EPSILON) + private static int getBlockY(double y, Block block) { + if (ItemUtils.isFence(block) && Math.abs((y - Math.floor(y)) - 0.5) < Skript.EPSILON) return (int) Math.floor(y) - 1; return (int) Math.ceil(y) - 1; } diff --git a/src/main/java/ch/njol/skript/events/EvtPressurePlate.java b/src/main/java/ch/njol/skript/events/EvtPressurePlate.java index de320c57f26..4d3f876a3b5 100644 --- a/src/main/java/ch/njol/skript/events/EvtPressurePlate.java +++ b/src/main/java/ch/njol/skript/events/EvtPressurePlate.java @@ -19,6 +19,7 @@ package ch.njol.skript.events; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.event.Event; import org.bukkit.event.block.Action; @@ -36,6 +37,9 @@ * @author Peter Güttinger */ public class EvtPressurePlate extends SkriptEvent { + + private static final boolean HAS_PRESSURE_PLATE_TAG = Skript.fieldExists(Tag.class, "PRESSURE_PLATES"); + static { // TODO is EntityInteractEvent similar for entities? Skript.registerEvent("Pressure Plate / Trip", EvtPressurePlate.class, PlayerInteractEvent.class, @@ -46,8 +50,6 @@ public class EvtPressurePlate extends SkriptEvent { .since("1.0 (pressure plate), 1.4.4 (tripwire)"); } - private static final ItemType plate = Aliases.javaItemType("pressure plate"); - private boolean tripwire; @Override @@ -55,14 +57,25 @@ public boolean init(final Literal[] args, final int matchedPattern, final Par tripwire = matchedPattern == 1; return true; } - + @Override - public boolean check(final Event e) { - final Block b = ((PlayerInteractEvent) e).getClickedBlock(); - final Material type = b == null ? null : b.getType(); - return type != null && ((PlayerInteractEvent) e).getAction() == Action.PHYSICAL && - (tripwire ? (type == Material.TRIPWIRE || type == Material.TRIPWIRE_HOOK) - : plate.isOfType(type)); + public boolean check(Event event) { + Block clickedBlock = ((PlayerInteractEvent) event).getClickedBlock(); + Material type = clickedBlock == null ? null : clickedBlock.getType(); + if (type == null || ((PlayerInteractEvent) event).getAction() != Action.PHYSICAL ) + return false; + + if (tripwire) + return(type == Material.TRIPWIRE || type == Material.TRIPWIRE_HOOK); + + // TODO: 1.16+, remove check in 2.10 + if (HAS_PRESSURE_PLATE_TAG) + return Tag.PRESSURE_PLATES.isTagged(type); + + return Tag.WOODEN_PRESSURE_PLATES.isTagged(type) + || type == Material.HEAVY_WEIGHTED_PRESSURE_PLATE + || type == Material.LIGHT_WEIGHTED_PRESSURE_PLATE + || type == Material.STONE_PRESSURE_PLATE; } @Override diff --git a/src/main/java/ch/njol/skript/expressions/ExprBurnCookTime.java b/src/main/java/ch/njol/skript/expressions/ExprBurnCookTime.java index 3763d242dc1..0d98c551925 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprBurnCookTime.java +++ b/src/main/java/ch/njol/skript/expressions/ExprBurnCookTime.java @@ -23,6 +23,7 @@ import ch.njol.skript.classes.Changer.ChangeMode; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; import org.bukkit.block.Furnace; import org.bukkit.event.Event; import org.bukkit.event.inventory.FurnaceBurnEvent; @@ -65,8 +66,6 @@ public class ExprBurnCookTime extends PropertyExpression { "[the] (burn|1:cook)[ing] time of %blocks%", "%blocks%'[s] (burn|1:cook)[ing] time"); } - - static final ItemType anyFurnace = Aliases.javaItemType("any furnace"); private boolean cookTime; private boolean isEvent; @@ -92,10 +91,11 @@ protected Timespan[] get(Event event, Block[] source) { return CollectionUtils.array(Timespan.fromTicks(((FurnaceBurnEvent) event).getBurnTime())); } else { return Arrays.stream(source) - .filter(anyFurnace::isOfType) - .map(furnace -> { - Furnace state = (Furnace) furnace.getState(); - return Timespan.fromTicks(cookTime ? state.getCookTime() : state.getBurnTime()); + .map(Block::getState) + .filter(blockState -> blockState instanceof Furnace) + .map(state -> { + Furnace furnace = (Furnace) state; + return Timespan.fromTicks(cookTime ? furnace.getCookTime() : furnace.getBurnTime()); }) .toArray(Timespan[]::new); } @@ -141,7 +141,8 @@ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { } for (Block block : getExpr().getArray(event)) { - if (!anyFurnace.isOfType(block)) + BlockState state = block.getState(); + if (!(state instanceof Furnace)) continue; Furnace furnace = (Furnace) block.getState(); long time = value.apply(Timespan.fromTicks(cookTime ? furnace.getCookTime() : furnace.getBurnTime())).getTicks(); diff --git a/src/main/java/ch/njol/skript/expressions/ExprName.java b/src/main/java/ch/njol/skript/expressions/ExprName.java index b6f873e0b89..666a39092a1 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprName.java +++ b/src/main/java/ch/njol/skript/expressions/ExprName.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.List; +import ch.njol.skript.bukkitutil.ItemUtils; import org.bukkit.Bukkit; import org.bukkit.GameRule; import org.bukkit.Nameable; @@ -139,7 +140,6 @@ public class ExprName extends SimplePropertyExpression { * 3 = "tablist name" */ private int mark; - private static final ItemType AIR = Aliases.javaItemType("air"); @Override public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { @@ -282,7 +282,7 @@ public void change(Event event, @Nullable Object[] delta, ChangeMode mode) { } else if (object instanceof Slot) { Slot s = (Slot) object; ItemStack is = s.getItem(); - if (is != null && !AIR.isOfType(is)) { + if (is != null && !ItemUtils.isAir(is.getType())) { ItemMeta m = is.hasItemMeta() ? is.getItemMeta() : Bukkit.getItemFactory().getItemMeta(is.getType()); m.setDisplayName(name); is.setItemMeta(m); diff --git a/src/main/java/ch/njol/skript/expressions/ExprSignText.java b/src/main/java/ch/njol/skript/expressions/ExprSignText.java index 592420ed647..0b549483b17 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprSignText.java +++ b/src/main/java/ch/njol/skript/expressions/ExprSignText.java @@ -18,7 +18,10 @@ */ package ch.njol.skript.expressions; +import ch.njol.skript.bukkitutil.ItemUtils; +import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.event.Event; import org.bukkit.event.block.SignChangeEvent; @@ -56,8 +59,6 @@ public class ExprSignText extends SimpleExpression { "[the] line %number% [of %block%]", "[the] (1¦1st|1¦first|2¦2nd|2¦second|3¦3rd|3¦third|4¦4th|4¦fourth) line [of %block%]"); } - private static final ItemType sign = Aliases.javaItemType("sign"); - @SuppressWarnings("null") private Expression line; @SuppressWarnings("null") @@ -99,7 +100,7 @@ protected String[] get(final Event e) { final Block b = block.getSingle(e); if (b == null) return new String[0]; - if (!sign.isOfType(b)) + if (!(b.getState() instanceof Sign)) return new String[0]; return new String[] {((Sign) b.getState()).getLine(line)}; } @@ -143,27 +144,28 @@ public void change(final Event e, final @Nullable Object[] delta, final ChangeMo break; } } else { - if (!sign.isOfType(b)) + BlockState state = b.getState(); + if (!(state instanceof Sign)) return; - final Sign s = (Sign) b.getState(); + Sign sign = (Sign) b.getState(); switch (mode) { case DELETE: - s.setLine(line, ""); + sign.setLine(line, ""); break; case SET: assert delta != null; - s.setLine(line, (String) delta[0]); + sign.setLine(line, (String) delta[0]); break; } if (hasUpdateBooleanBoolean) { try { - s.update(false, false); + sign.update(false, false); } catch (final NoSuchMethodError err) { hasUpdateBooleanBoolean = false; - s.update(); + sign.update(); } } else { - s.update(); + sign.update(); } } } diff --git a/src/main/java/ch/njol/skript/expressions/ExprSkull.java b/src/main/java/ch/njol/skript/expressions/ExprSkull.java index e3a0fa2767d..4e133a79bfd 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprSkull.java +++ b/src/main/java/ch/njol/skript/expressions/ExprSkull.java @@ -18,6 +18,7 @@ */ package ch.njol.skript.expressions; +import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.inventory.meta.SkullMeta; import org.eclipse.jdt.annotation.Nullable; @@ -48,8 +49,6 @@ public class ExprSkull extends SimplePropertyExpression { register(ExprSkull.class, ItemType.class, "(head|skull)", "offlineplayers"); } - private static final ItemType playerSkull = Aliases.javaItemType("player skull"); - /** * In 2017, SkullMeta finally got a method that takes OfflinePlayer. */ @@ -64,7 +63,7 @@ public boolean init(final Expression[] exprs, final int matchedPattern, final @Override @Nullable public ItemType convert(final Object o) { - ItemType skull = playerSkull.clone(); + ItemType skull = new ItemType(Material.PLAYER_HEAD); SkullMeta meta = (SkullMeta) skull.getItemMeta(); if (newSkullOwner) meta.setOwningPlayer((OfflinePlayer) o); diff --git a/src/main/java/ch/njol/skript/expressions/ExprSpawnerType.java b/src/main/java/ch/njol/skript/expressions/ExprSpawnerType.java index d9d31b824cc..24b59ae9dd3 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprSpawnerType.java +++ b/src/main/java/ch/njol/skript/expressions/ExprSpawnerType.java @@ -22,6 +22,7 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.CreatureSpawner; +import org.bukkit.entity.EntityType; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; @@ -44,18 +45,19 @@ @Since("2.4") public class ExprSpawnerType extends SimplePropertyExpression { - private static final Material MATERIAL_SPAWNER = Aliases.javaItemType("spawner").getMaterial(); - static { register(ExprSpawnerType.class, EntityData.class, "(spawner|entity|creature) type[s]", "blocks"); } @Override @Nullable - public EntityData convert(final Block b) { - if (b.getType() != MATERIAL_SPAWNER) + public EntityData convert(Block block) { + if (!(block.getState() instanceof CreatureSpawner)) + return null; + EntityType type = ((CreatureSpawner) block.getState()).getSpawnedType(); + if (type == null) return null; - return EntityUtils.toSkriptEntityData(((CreatureSpawner) b.getState()).getSpawnedType()); + return EntityUtils.toSkriptEntityData(type); } @Nullable @@ -68,13 +70,14 @@ public Class[] acceptChange(Changer.ChangeMode mode) { @SuppressWarnings("null") @Override - public void change(final Event e, final @Nullable Object[] delta, final ChangeMode mode) { - for (Block b : getExpr().getArray(e)) { - if (b.getType() != MATERIAL_SPAWNER) + public void change(Event event, Object @Nullable [] delta, ChangeMode mode) { + for (Block b : getExpr().getArray(event)) { + if (!(b.getState() instanceof CreatureSpawner)) continue; CreatureSpawner s = (CreatureSpawner) b.getState(); switch (mode) { case SET: + assert delta != null; s.setSpawnedType(EntityUtils.toBukkitEntityType((EntityData) delta[0])); break; case RESET: diff --git a/src/main/resources/config.sk b/src/main/resources/config.sk index 4ba081e7c33..ff5e1e9e40a 100644 --- a/src/main/resources/config.sk +++ b/src/main/resources/config.sk @@ -80,6 +80,16 @@ log effect commands: false # Whether Skript should log the usage of effect commands. # They will be logged as [INFORMATION] in this format: ' issued effect command: ' + +load default aliases: true +# Whether Skript should use the default, Skript-provided aliases for items. +# Disabling this will cause all aliases to be automatically generated. Some items, like potions, +# will likely not have aliases in this case. +# +# You can provide your own aliases by making an 'aliases' folder in the Skript directory and putting the alias files there. +# The default aliases folder is available with Skript releases on GitHub. + + player variable fix: true # Whether to enable the player variable fix if a player has rejoined and was reciding inside a variable. # Player objects inside a variable(list or normal) are not updated to the new player object From b48f66d83760be7ebdfcc1dfcc833d3760709ba2 Mon Sep 17 00:00:00 2001 From: Patrick Miller Date: Mon, 1 Jul 2024 17:19:22 -0400 Subject: [PATCH 4/6] Fix current section update issues (#6845) --- src/main/java/ch/njol/skript/lang/Section.java | 12 +++++++++--- .../java/ch/njol/skript/lang/TriggerSection.java | 12 +++++++++--- .../6843-current section reference issue.sk | 9 +++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 src/test/skript/tests/regressions/6843-current section reference issue.sk diff --git a/src/main/java/ch/njol/skript/lang/Section.java b/src/main/java/ch/njol/skript/lang/Section.java index c511e88b2a2..5a665165eff 100644 --- a/src/main/java/ch/njol/skript/lang/Section.java +++ b/src/main/java/ch/njol/skript/lang/Section.java @@ -27,6 +27,7 @@ import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.function.Supplier; @@ -81,12 +82,17 @@ public abstract boolean init(Expression[] expressions, * (although the loaded code may change it), the calling code must deal with this. */ protected void loadCode(SectionNode sectionNode) { - List currentSections = getParser().getCurrentSections(); - currentSections.add(this); + ParserInstance parser = getParser(); + List previousSections = parser.getCurrentSections(); + + List sections = new ArrayList<>(previousSections); + sections.add(this); + parser.setCurrentSections(sections); + try { setTriggerItems(ScriptLoader.loadItems(sectionNode)); } finally { - currentSections.remove(currentSections.size() - 1); + parser.setCurrentSections(previousSections); } } diff --git a/src/main/java/ch/njol/skript/lang/TriggerSection.java b/src/main/java/ch/njol/skript/lang/TriggerSection.java index d1343d43605..e7945784752 100644 --- a/src/main/java/ch/njol/skript/lang/TriggerSection.java +++ b/src/main/java/ch/njol/skript/lang/TriggerSection.java @@ -24,6 +24,7 @@ import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; +import java.util.ArrayList; import java.util.List; /** @@ -42,12 +43,17 @@ protected TriggerSection(List items) { } protected TriggerSection(SectionNode node) { - List currentSections = ParserInstance.get().getCurrentSections(); - currentSections.add(this); + ParserInstance parser = ParserInstance.get(); + List previousSections = parser.getCurrentSections(); + + List sections = new ArrayList<>(previousSections); + sections.add(this); + parser.setCurrentSections(sections); + try { setTriggerItems(ScriptLoader.loadItems(node)); } finally { - currentSections.remove(currentSections.size() - 1); + parser.setCurrentSections(previousSections); } } diff --git a/src/test/skript/tests/regressions/6843-current section reference issue.sk b/src/test/skript/tests/regressions/6843-current section reference issue.sk new file mode 100644 index 00000000000..20e8beb20ef --- /dev/null +++ b/src/test/skript/tests/regressions/6843-current section reference issue.sk @@ -0,0 +1,9 @@ +test "outdated current section references": + parse: + loop {_list::*}: + spawn a sheep at {_loc}: + set {_e} to event-entity + loop {_list::*}: + set {_var} to loop-value + set {_var} to loop-value-1 + assert last parse logs is not set with "loop-value and loop-value-1 should've worked" From e65fe2f7934259468d6bd3d46a88c232f073dfaa Mon Sep 17 00:00:00 2001 From: EquipableMC <66171067+EquipableMC@users.noreply.github.com> Date: Mon, 1 Jul 2024 18:21:27 -0400 Subject: [PATCH 5/6] Support for LogLevel in EffLog (#6659) * Improved EffLog Added wats to declare severity when logging * Update EffLog.java * Update EffLog.java Updated `@Since` to include when severity to logs was added * Update EffLog.java * Update EffLog.java * Update EffLog.java * Update EffLog.java * Update EffLog.java * Update EffLog.java * Update EffLog.java * Update EffLog.java Adds the `[Skript]` prefix to `Level.INFO` * Update EffLog.java * Update EffLog.java * Update EffLog.java * Update EffLog.java * Update EffLog.java * Update EffLog.java Fixes a spacing issue * Update EffLog.java * Update EffLog.java * Update EffLog.java * Update EffLog.java * Update EffLog.java * Update EffLog.java * Update EffLog.java changes to use .toString instead of String.valueOf * Update EffLog.java * Update EffLog.java * Update EffLog.java --------- Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> Co-authored-by: Moderocky --- .../java/ch/njol/skript/effects/EffLog.java | 84 +++++++++++-------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/src/main/java/ch/njol/skript/effects/EffLog.java b/src/main/java/ch/njol/skript/effects/EffLog.java index bce9d3bae76..a3b7cc23f44 100644 --- a/src/main/java/ch/njol/skript/effects/EffLog.java +++ b/src/main/java/ch/njol/skript/effects/EffLog.java @@ -46,28 +46,31 @@ import ch.njol.util.Closeable; import ch.njol.util.Kleenean; -/** - * @author Peter Güttinger - */ @Name("Log") @Description({"Writes text into a .log file. Skript will write these files to /plugins/Skript/logs.", "NB: Using 'server.log' as the log file will write to the default server log. Omitting the log file altogether will log the message as '[Skript] [<script>.sk] <message>' in the server log."}) -@Examples({"on place of TNT:", - " log \"%player% placed TNT in %world% at %location of block%\" to \"tnt/placement.log\""}) -@Since("2.0") +@Examples({ + "on join:", + "\tlog \"%player% has just joined the server!\"", + "on world change:", + "\tlog \"Someone just went to %event-world%!\" to file \"worldlog/worlds.log\"", + "on command:", + "\tlog \"%player% just executed %full command%!\" to file \"server/commands.log\" with a severity of warning" +}) +@Since("2.0, INSERT VERSION (severities)") public class EffLog extends Effect { static { - Skript.registerEffect(EffLog.class, "log %strings% [(to|in) [file[s]] %-strings%]"); + Skript.registerEffect(EffLog.class, "log %strings% [(to|in) [file[s]] %-strings%] [with [the|a] severity [of] (1:warning|2:severe)]"); } - private final static File logsFolder = new File(Skript.getInstance().getDataFolder(), "logs"); + private static final File logsFolder = new File(Skript.getInstance().getDataFolder(), "logs"); final static HashMap writers = new HashMap<>(); static { Skript.closeOnDisable(new Closeable() { @Override public void close() { - for (final PrintWriter pw : writers.values()) + for (PrintWriter pw : writers.values()) pw.close(); } }); @@ -77,42 +80,55 @@ public void close() { private Expression messages; @Nullable private Expression files; - + + private Level logLevel = Level.INFO; + private static String getLogPrefix(Level logLevel) { + String timestamp = SkriptConfig.formatDate(System.currentTimeMillis()); + if (logLevel == Level.INFO) + return "[" + timestamp + "]"; + return "[" + timestamp + " " + logLevel + "]"; + } + @SuppressWarnings({"unchecked", "null"}) @Override - public boolean init(final Expression[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parser) { + public boolean init(Expression[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parser) { messages = (Expression) exprs[0]; files = (Expression) exprs[1]; + if (parser.mark == 1) { + logLevel = Level.WARNING; + } else if (parser.mark == 2) { + logLevel = Level.SEVERE; + } return true; } @SuppressWarnings("resource") @Override - protected void execute(final Event e) { - for (final String message : messages.getArray(e)) { + protected void execute(Event event) { + for (String message : messages.getArray(event)) { if (files != null) { - for (String s : files.getArray(e)) { - s = s.toLowerCase(Locale.ENGLISH); - if (!s.endsWith(".log")) - s += ".log"; - if (s.equals("server.log")) { - SkriptLogger.LOGGER.log(Level.INFO, message); + for (String logFile : files.getArray(event)) { + logFile = logFile.toLowerCase(Locale.ENGLISH); + if (!logFile.endsWith(".log")) + logFile += ".log"; + if (logFile.equals("server.log")) { + SkriptLogger.LOGGER.log(logLevel, message); continue; } - PrintWriter w = writers.get(s); - if (w == null) { - final File f = new File(logsFolder, s); // REMIND what if s contains '..'? + PrintWriter logWriter = writers.get(logFile); + if (logWriter == null) { + File logFolder = new File(logsFolder, logFile); // REMIND what if logFile contains '..'? try { - f.getParentFile().mkdirs(); - w = new PrintWriter(new BufferedWriter(new FileWriter(f, true))); - writers.put(s, w); - } catch (final IOException ex) { - Skript.error("Cannot write to log file '" + s + "' (" + f.getPath() + "): " + ExceptionUtils.toString(ex)); + logFolder.getParentFile().mkdirs(); + logWriter = new PrintWriter(new BufferedWriter(new FileWriter(logFolder, true))); + writers.put(logFile, logWriter); + } catch (IOException ex) { + Skript.error("Cannot write to log file '" + logFile + "' (" + logFolder.getPath() + "): " + ExceptionUtils.toString(ex)); return; } } - w.println("[" + SkriptConfig.formatDate(System.currentTimeMillis()) + "] " + message); - w.flush(); + logWriter.println(getLogPrefix(logLevel) + " " + message); + logWriter.flush(); } } else { Trigger t = getTrigger(); @@ -122,13 +138,15 @@ protected void execute(final Event e) { if (script != null) scriptName = script.getConfig().getFileName(); } - Skript.info("[" + scriptName + "] " + message); + SkriptLogger.LOGGER.log(logLevel, "[" + scriptName + "] " + message); } } } - + @Override - public String toString(final @Nullable Event e, final boolean debug) { - return "log " + messages.toString(e, debug) + (files != null ? " to " + files.toString(e, debug) : ""); + public String toString(@Nullable Event event, boolean debug) { + return "log " + messages.toString(event, debug) + + (files != null ? " to " + files.toString(event, debug) : "") + + (logLevel != Level.INFO ? "with severity " + logLevel.toString().toLowerCase(Locale.ENGLISH) : ""); } } From f1e0dd63b86f1e04f3bbf52e243d03faf693d287 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Tue, 2 Jul 2024 00:33:18 +0200 Subject: [PATCH 6/6] add allowLookups option to offlineplayer function (#6831) * add allowLookups option to offlineplayer function * typo * less ambiguous wording in description --- .../skript/classes/data/DefaultFunctions.java | 66 ++++++++++++++----- .../tests/syntaxes/functions/offlinePlayer.sk | 7 ++ 2 files changed, 57 insertions(+), 16 deletions(-) create mode 100644 src/test/skript/tests/syntaxes/functions/offlinePlayer.sk diff --git a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java index afc46cba346..525e639fbc3 100644 --- a/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java +++ b/src/main/java/ch/njol/skript/classes/data/DefaultFunctions.java @@ -18,6 +18,7 @@ */ package ch.njol.skript.classes.data; +import ch.njol.skript.Skript; import ch.njol.skript.expressions.base.EventValueExpression; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.function.FunctionEvent; @@ -45,7 +46,9 @@ import java.math.BigDecimal; import java.math.RoundingMode; +import java.util.ArrayList; import java.util.Calendar; +import java.util.List; import java.util.UUID; public class DefaultFunctions { @@ -556,23 +559,54 @@ public Player[] executeSimple(Object[][] params) { .examples("set {_p} to player(\"Notch\") # will return an online player whose name is or starts with 'Notch'", "set {_p} to player(\"Notch\", true) # will return the only online player whose name is 'Notch'", "set {_p} to player(\"069a79f4-44e9-4726-a5be-fca90e38aaf5\") # if player is offline") .since("2.8.0"); - Functions.registerFunction(new SimpleJavaFunction("offlineplayer", new Parameter[] { - new Parameter<>("nameOrUUID", DefaultClasses.STRING, true, null) - }, DefaultClasses.OFFLINE_PLAYER, true) { - @Override - public OfflinePlayer[] executeSimple(Object[][] params) { - String name = (String) params[0][0]; - UUID uuid = null; - if (name.length() > 16 || name.contains("-")) { // shortcut - try { - uuid = UUID.fromString(name); - } catch (IllegalArgumentException ignored) {} + { // offline player function + boolean hasIfCached = Skript.methodExists(Bukkit.class, "getOfflinePlayerIfCached", String.class); + + List> params = new ArrayList<>(); + params.add(new Parameter<>("nameOrUUID", DefaultClasses.STRING, true, null)); + if (hasIfCached) + params.add(new Parameter<>("allowLookups", DefaultClasses.BOOLEAN, true, new SimpleLiteral<>(true, true))); + + Functions.registerFunction(new SimpleJavaFunction("offlineplayer", params.toArray(new Parameter[0]), + DefaultClasses.OFFLINE_PLAYER, true) { + @Override + public OfflinePlayer[] executeSimple(Object[][] params) { + String name = (String) params[0][0]; + UUID uuid = null; + if (name.length() > 16 || name.contains("-")) { // shortcut + try { + uuid = UUID.fromString(name); + } catch (IllegalArgumentException ignored) { + } + } + OfflinePlayer result; + + if (uuid != null) { + result = Bukkit.getOfflinePlayer(uuid); // doesn't do lookups + } else if (hasIfCached && !((Boolean) params[1][0])) { + result = Bukkit.getOfflinePlayerIfCached(name); + if (result == null) + return new OfflinePlayer[0]; + } else { + result = Bukkit.getOfflinePlayer(name); + } + + return CollectionUtils.array(result); } - return CollectionUtils.array(uuid != null ? Bukkit.getOfflinePlayer(uuid) : Bukkit.getOfflinePlayer(name)); - } - }).description("Returns a offline player from their name or UUID. This function will still return the player if they're online.") - .examples("set {_p} to offlineplayer(\"Notch\")", "set {_p} to offlineplayer(\"069a79f4-44e9-4726-a5be-fca90e38aaf5\")") - .since("2.8.0"); + + }).description( + "Returns a offline player from their name or UUID. This function will still return the player if they're online. " + + "If Paper 1.16.5+ is used, the 'allowLookup' parameter can be set to false to prevent this function from doing a " + + "web lookup for players who have not joined before. Lookups can cause lag spikes of up to multiple seconds, so " + + "use offline players with caution." + ) + .examples( + "set {_p} to offlineplayer(\"Notch\")", + "set {_p} to offlineplayer(\"069a79f4-44e9-4726-a5be-fca90e38aaf5\")", + "set {_p} to offlineplayer(\"Notch\", false)" + ) + .since("2.8.0, INSERT VERSION (prevent lookups)"); + } // end offline player function Functions.registerFunction(new SimpleJavaFunction("isNaN", numberParam, DefaultClasses.BOOLEAN, true) { @Override diff --git a/src/test/skript/tests/syntaxes/functions/offlinePlayer.sk b/src/test/skript/tests/syntaxes/functions/offlinePlayer.sk new file mode 100644 index 00000000000..b96d67a7487 --- /dev/null +++ b/src/test/skript/tests/syntaxes/functions/offlinePlayer.sk @@ -0,0 +1,7 @@ +test "offline player function": + set {_lookup} to offlineplayer("Notch") + assert {_lookup} is set with "Failed to look up offline player" + +test "offline player function no lookup" when running minecraft "1.16": + set {_non-lookup} to offlineplayer("Dinnerbone", false) + assert {_non-lookup} is not set with "Looked up offline player when told not to"