From 74212a170181699b380fc875c5fe8aa8ed636cc9 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:59:39 -0400 Subject: [PATCH 01/21] minecraft tags part 1 --- src/main/java/ch/njol/skript/Skript.java | 2 + src/main/java/ch/njol/util/Pair.java | 72 ++++-------- .../skript/bukkit/tags/CondIsTagged.java | 90 +++++++++++++++ .../skript/bukkit/tags/ExprTag.java | 106 ++++++++++++++++++ .../skript/bukkit/tags/ExprTagContents.java | 70 ++++++++++++ .../skript/bukkit/tags/TagModule.java | 45 ++++++++ src/main/resources/lang/default.lang | 1 + .../tests/syntaxes/conditions/CondIsTagged.sk | 16 +++ 8 files changed, 354 insertions(+), 48 deletions(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/CondIsTagged.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/ExprTag.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagContents.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java create mode 100644 src/test/skript/tests/syntaxes/conditions/CondIsTagged.sk diff --git a/src/main/java/ch/njol/skript/Skript.java b/src/main/java/ch/njol/skript/Skript.java index c51112be9ac..deceb765d55 100644 --- a/src/main/java/ch/njol/skript/Skript.java +++ b/src/main/java/ch/njol/skript/Skript.java @@ -97,6 +97,7 @@ import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.skriptlang.skript.bukkit.SkriptMetrics; +import org.skriptlang.skript.bukkit.tags.TagModule; import org.skriptlang.skript.lang.comparator.Comparator; import org.skriptlang.skript.lang.comparator.Comparators; import org.skriptlang.skript.lang.converter.Converter; @@ -541,6 +542,7 @@ public void onEnable() { try { getAddonInstance().loadClasses("ch.njol.skript", "conditions", "effects", "events", "expressions", "entity", "sections", "structures"); + TagModule.load(); } catch (final Exception e) { exception(e, "Could not load required .class files: " + e.getLocalizedMessage()); setEnabled(false); diff --git a/src/main/java/ch/njol/util/Pair.java b/src/main/java/ch/njol/util/Pair.java index c17887f9778..d3b79975861 100644 --- a/src/main/java/ch/njol/util/Pair.java +++ b/src/main/java/ch/njol/util/Pair.java @@ -1,39 +1,20 @@ -/** - * 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.util; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnknownNullability; + +import java.io.Serial; import java.io.Serializable; import java.util.Map.Entry; import java.util.Objects; -import org.jetbrains.annotations.Nullable; - -/** - * @author Peter Güttinger - */ public class Pair implements Entry, Cloneable, Serializable { + @Serial private static final long serialVersionUID = 8296563685697678334L; - - @Nullable - protected T1 first; - @Nullable - protected T2 second; + + protected @UnknownNullability T1 first; + protected @UnknownNullability T2 second; public Pair() { first = null; @@ -45,22 +26,20 @@ public Pair(final @Nullable T1 first, final @Nullable T2 second) { this.second = second; } - public Pair(final Entry e) { + public Pair(final @NotNull Entry e) { this.first = e.getKey(); this.second = e.getValue(); } - - @Nullable - public T1 getFirst() { + + public @UnknownNullability T1 getFirst() { return first; } public void setFirst(final @Nullable T1 first) { this.first = first; } - - @Nullable - public T2 getSecond() { + + public @UnknownNullability T2 getSecond() { return second; } @@ -73,23 +52,22 @@ public void setSecond(final @Nullable T2 second) { */ @Override public String toString() { - return "" + first + "," + second; + return first + "," + second; } /** * Checks for equality with Entries to match {@link #hashCode()} */ @Override - public final boolean equals(final @Nullable Object obj) { + public final boolean equals(@Nullable Object obj) { if (obj == this) return true; - if (!(obj instanceof Entry)) + if (!(obj instanceof Entry entry)) return false; - final Entry other = (Entry) obj; final T1 first = this.first; final T2 second = this.second; - return (first == null ? other.getKey() == null : first.equals(other.getKey())) && - (second == null ? other.getValue() == null : second.equals(other.getValue())); + return (first == null ? entry.getKey() == null : first.equals(entry.getKey())) && + (second == null ? entry.getValue() == null : second.equals(entry.getValue())); } /** @@ -101,21 +79,19 @@ public final int hashCode() { } @Override - @Nullable - public T1 getKey() { + public @UnknownNullability T1 getKey() { return first; } @Override - @Nullable - public T2 getValue() { + public @UnknownNullability T2 getValue() { return second; } @Override - @Nullable - public T2 setValue(final @Nullable T2 value) { - final T2 old = second; + + public @UnknownNullability T2 setValue(@Nullable T2 value) { + T2 old = second; second = value; return old; } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/CondIsTagged.java b/src/main/java/org/skriptlang/skript/bukkit/tags/CondIsTagged.java new file mode 100644 index 00000000000..227f25d21d8 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/CondIsTagged.java @@ -0,0 +1,90 @@ +package org.skriptlang.skript.bukkit.tags; + +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.bukkitutil.EntityUtils; +import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.entity.EntityData; +import ch.njol.skript.lang.Condition; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.util.slot.Slot; +import ch.njol.util.Kleenean; +import org.bukkit.Keyed; +import org.bukkit.Tag; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; +import org.bukkit.event.Event; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; + +public class CondIsTagged extends Condition { + + static { + PropertyCondition.register(CondIsTagged.class, PropertyCondition.PropertyType.BE, + "tagged (as|with) %minecrafttags%", + "itemtypes/entities/entitydatas"); + } + + private Expression> tags; + private Expression elements; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + this.elements = expressions[0]; + //noinspection unchecked + this.tags = (Expression>) expressions[1]; + setNegated(matchedPattern == 1); + return true; + } + + @Override + public boolean check(Event event) { + Tag[] tags = this.tags.getArray(event); + if (tags.length == 0) + return isNegated(); + boolean and = this.tags.getAnd(); + return elements.check(event, element -> { + Keyed value = null; + if (element instanceof Entity entity) { + value = entity.getType(); + } if (element instanceof EntityData data) { + value = EntityUtils.toBukkitEntityType(data); + } else if (element instanceof ItemType itemType) { + value = itemType.getMaterial(); + } else if (element instanceof ItemStack itemStack) { + value = itemStack.getType(); + } else if (element instanceof Slot slot) { + ItemStack stack = slot.getItem(); + if (stack == null) + return false; + value = stack.getType(); + } else if (element instanceof Block block) { + value = block.getType(); + } else if (element instanceof BlockData data) { + value = data.getMaterial(); + } + + if (value == null) + return false; + + for (Tag tag : tags) { + if (tag.isTagged(value)) { + if (!and) + return true; + } else if (and) { + return false; + } + } + return and; + }, isNegated()); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + String plural = elements.isSingle() ? "is" : "are"; + String negated = isNegated() ? " not" : ""; + return elements.toString(event, debug) + " " + plural + negated + " tagged as " + tags.toString(event, debug); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTag.java new file mode 100644 index 00000000000..07547c3b0f8 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTag.java @@ -0,0 +1,106 @@ +package org.skriptlang.skript.bukkit.tags; + +import ch.njol.skript.Skript; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import org.bukkit.Bukkit; +import org.bukkit.Keyed; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; +import org.bukkit.entity.EntityType; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ExprTag extends SimpleExpression { + + private record RegistryInfo(String registry, String pattern, Class type) {} + + // Fluid and GameEvent registries also exist, but are not useful at this time. + // Any new types added here must be handled in CondIsTagged + private static final List REGISTRIES = new ArrayList<>(List.of( + new RegistryInfo(Tag.REGISTRY_ITEMS, "item", Material.class), + new RegistryInfo(Tag.REGISTRY_BLOCKS, "block", Material.class), + new RegistryInfo(Tag.REGISTRY_ENTITY_TYPES, "entity [type]", EntityType.class) + )); + + static { + // build pattern + StringBuilder registriesPattern = new StringBuilder("["); + int numRegistries = REGISTRIES.size(); + for (int i = 0; i < numRegistries; i++) { + registriesPattern.append(i + 1).append(":").append(REGISTRIES.get(i).pattern()); + if (i + 1 != numRegistries) + registriesPattern.append("|"); + } + registriesPattern.append("]"); + + Skript.registerExpression(ExprTag.class, Tag.class, ExpressionType.COMBINED, "[minecraft] " + registriesPattern + " tag %string%"); + } + + Expression name; + int type; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + //noinspection unchecked + name = (Expression) expressions[0]; + type = parseResult.mark - 1; + return true; + } + + @Override + protected Tag @Nullable [] get(Event event) { + String name = this.name.getSingle(event); + if (name == null) + return null; + + NamespacedKey key = NamespacedKey.fromString(name); + if (key == null) + return null; + + + List registries; + if (type == -1) { + registries = REGISTRIES; + } else if (type < REGISTRIES.size()) { + registries = Collections.singletonList(REGISTRIES.get(type)); + } else { + return null; + } + + Tag tag; + for (RegistryInfo registry : registries) { + tag = Bukkit.getTag(registry.registry(), key, registry.type()); + if (tag != null) + return new Tag[]{tag}; + } + + return null; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return Tag.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + String registry = type == -1 ? "" : REGISTRIES.get(type).pattern(); + return "minecraft " + registry + "tag " + name.toString(event, debug); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagContents.java b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagContents.java new file mode 100644 index 00000000000..84e20aee099 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagContents.java @@ -0,0 +1,70 @@ +package org.skriptlang.skript.bukkit.tags; + +import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.bukkitutil.EntityUtils; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import org.bukkit.Material; +import org.bukkit.Tag; +import org.bukkit.entity.EntityType; +import org.bukkit.event.Event; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public class ExprTagContents extends SimpleExpression { + + static { + Skript.registerExpression(ExprTagContents.class, Object.class, ExpressionType.PROPERTY, + "tag (contents|values) of %minecrafttags%", + "%minecrafttags%'[s] tag (contents|values)"); + } + + private Expression> tag; + + @Override + public boolean init(Expression @NotNull [] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + tag = (Expression>) expressions[0]; + return true; + } + + @Override + protected Object @Nullable [] get(Event event) { + Tag tag = this.tag.getSingle(event); + if (tag == null) + return null; + return tag.getValues().stream() + .map(value -> { + if (value instanceof Material material) { + return new ItemType(material); + } else if (value instanceof EntityType entityType) { + return EntityUtils.toSkriptEntityData(entityType); + } + return null; + }) + .filter(Objects::nonNull) + .toArray(); + } + + @Override + public boolean isSingle() { + return false; + } + + @Override + public Class getReturnType() { + return Object.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "tag contents of " + tag.toString(event, debug); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java new file mode 100644 index 00000000000..9cc31d2fa89 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java @@ -0,0 +1,45 @@ +package org.skriptlang.skript.bukkit.tags; + +import ch.njol.skript.Skript; +import ch.njol.skript.classes.ClassInfo; +import ch.njol.skript.classes.Parser; +import ch.njol.skript.lang.ParseContext; +import ch.njol.skript.registrations.Classes; +import org.bukkit.Tag; + +import java.io.IOException; + +public class TagModule { + public static void load() throws IOException { + // abort if no class exists + if (!Skript.classExists("org.bukkit.Tag")) + return; + + // load classes (todo: replace with registering methods after regitration api + Skript.getAddonInstance().loadClasses("org.skriptlang.skript.bukkit", "tags"); + + // Classes + Classes.registerClass(new ClassInfo<>(Tag.class, "minecrafttag") + .user("minecraft ?tags?") + .name("Minecraft Tag") + .description("A tag that classifies a material, or entity.") + .since("INSERT VERSION") + .parser(new Parser>() { + @Override + public boolean canParse(ParseContext context) { + return false; + } + + @Override + public String toString(Tag tag, int flags) { + return "minecraft tag \"" + tag.getKey() + "\""; + } + + @Override + public String toVariableNameString(Tag tag) { + return "minecraft tag: " + tag.getKey(); + } + })); + } + +} diff --git a/src/main/resources/lang/default.lang b/src/main/resources/lang/default.lang index d95bf8b9907..146a1a118eb 100644 --- a/src/main/resources/lang/default.lang +++ b/src/main/resources/lang/default.lang @@ -2383,6 +2383,7 @@ types: quitreason: quit reason¦s @a inventoryclosereason: inventory close reason¦s @an transformreason: transform reason¦s @a + minecrafttag: minecraft tag¦s @a # Skript weathertype: weather type¦s @a diff --git a/src/test/skript/tests/syntaxes/conditions/CondIsTagged.sk b/src/test/skript/tests/syntaxes/conditions/CondIsTagged.sk new file mode 100644 index 00000000000..7b6ec7b5638 --- /dev/null +++ b/src/test/skript/tests/syntaxes/conditions/CondIsTagged.sk @@ -0,0 +1,16 @@ +test "CondIsTagged": + assert oak slab is tagged as item tag "slabs" with "oak slab is not a slab" + assert oak slab is not tagged as item tag "stairs" with "oak slab is somehow a stair" + assert a skeleton is tagged as entity tag "minecraft:skeletons" with "skeleton is not a skeleton" + assert a cow is not tagged as tag "unknown" with "a cow is somehow tagged as unknown" + + assert a skeleton and a stray are tagged as tag "skeletons" with "skeleton and stray are not skeletons" + assert a skeleton or a zombie is tagged as tag "skeletons" with "skeleton or zombie are not skeletons" + + set block at location(0,20,0) to oak slab + assert block at location(0,20,0) is tagged as block tag "slabs" with "oak slab is not a slab" + set block at location(0,20,0) to air + + spawn a skeleton at spawn of world "world": + assert entity is tagged as entity tag "minecraft:skeletons" with "skeleton is not a skeleton" + delete entity From cc91087bf206e239368760f8f3a67b81398f1fd6 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 3 Oct 2024 00:35:40 -0400 Subject: [PATCH 02/21] tags part 2 paper's material/entity tags, get all tags of something --- .../skript/bukkit/tags/CondIsTagged.java | 29 +---- .../skript/bukkit/tags/ExprTag.java | 49 +++---- .../skript/bukkit/tags/ExprTagContents.java | 4 +- .../skript/bukkit/tags/ExprTagsOf.java | 120 ++++++++++++++++++ .../skript/bukkit/tags/TagModule.java | 103 ++++++++++++++- 5 files changed, 251 insertions(+), 54 deletions(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOf.java diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/CondIsTagged.java b/src/main/java/org/skriptlang/skript/bukkit/tags/CondIsTagged.java index 227f25d21d8..691197e3334 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/CondIsTagged.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/CondIsTagged.java @@ -1,21 +1,13 @@ package org.skriptlang.skript.bukkit.tags; -import ch.njol.skript.aliases.ItemType; -import ch.njol.skript.bukkitutil.EntityUtils; import ch.njol.skript.conditions.base.PropertyCondition; -import ch.njol.skript.entity.EntityData; import ch.njol.skript.lang.Condition; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.skript.util.slot.Slot; import ch.njol.util.Kleenean; import org.bukkit.Keyed; import org.bukkit.Tag; -import org.bukkit.block.Block; -import org.bukkit.block.data.BlockData; -import org.bukkit.entity.Entity; import org.bukkit.event.Event; -import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; public class CondIsTagged extends Condition { @@ -45,26 +37,7 @@ public boolean check(Event event) { return isNegated(); boolean and = this.tags.getAnd(); return elements.check(event, element -> { - Keyed value = null; - if (element instanceof Entity entity) { - value = entity.getType(); - } if (element instanceof EntityData data) { - value = EntityUtils.toBukkitEntityType(data); - } else if (element instanceof ItemType itemType) { - value = itemType.getMaterial(); - } else if (element instanceof ItemStack itemStack) { - value = itemStack.getType(); - } else if (element instanceof Slot slot) { - ItemStack stack = slot.getItem(); - if (stack == null) - return false; - value = stack.getType(); - } else if (element instanceof Block block) { - value = block.getType(); - } else if (element instanceof BlockData data) { - value = data.getMaterial(); - } - + Keyed value = TagModule.getKeyed(element); if (value == null) return false; diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTag.java index 07547c3b0f8..39b48600b0b 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTag.java @@ -6,8 +6,8 @@ import ch.njol.skript.lang.SkriptParser; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; +import org.skriptlang.skript.bukkit.tags.TagModule.RegistryInfo; import org.bukkit.Bukkit; -import org.bukkit.Keyed; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Tag; @@ -15,34 +15,16 @@ import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class ExprTag extends SimpleExpression { +import static org.skriptlang.skript.bukkit.tags.TagModule.REGISTRIES; - private record RegistryInfo(String registry, String pattern, Class type) {} +public class ExprTag extends SimpleExpression { - // Fluid and GameEvent registries also exist, but are not useful at this time. - // Any new types added here must be handled in CondIsTagged - private static final List REGISTRIES = new ArrayList<>(List.of( - new RegistryInfo(Tag.REGISTRY_ITEMS, "item", Material.class), - new RegistryInfo(Tag.REGISTRY_BLOCKS, "block", Material.class), - new RegistryInfo(Tag.REGISTRY_ENTITY_TYPES, "entity [type]", EntityType.class) - )); static { - // build pattern - StringBuilder registriesPattern = new StringBuilder("["); - int numRegistries = REGISTRIES.size(); - for (int i = 0; i < numRegistries; i++) { - registriesPattern.append(i + 1).append(":").append(REGISTRIES.get(i).pattern()); - if (i + 1 != numRegistries) - registriesPattern.append("|"); - } - registriesPattern.append("]"); - - Skript.registerExpression(ExprTag.class, Tag.class, ExpressionType.COMBINED, "[minecraft] " + registriesPattern + " tag %string%"); + Skript.registerExpression(ExprTag.class, Tag.class, ExpressionType.COMBINED, "[minecraft] " + TagModule.REGISTRIES_PATTERN + " tag %string%"); } Expression name; @@ -83,6 +65,29 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is return new Tag[]{tag}; } + // try paper keys if they exist + if (!TagModule.PAPER_TAGS_EXIST) + return null; + + + key = new NamespacedKey("paper", key.value() + "_settag"); + + // fallback to paper material tags + if (type == -1 || REGISTRIES.get(type).type() == Material.class) { + for (Tag paperMaterialTag : TagModule.PAPER_MATERIAL_TAGS) { + if (paperMaterialTag.getKey().equals(key)) + return new Tag[]{paperMaterialTag}; + } + } + + // fallback to paper entity tags + if (type == -1 || REGISTRIES.get(type).type() == EntityType.class) { + for (Tag paperEntityTag : TagModule.PAPER_ENTITY_TAGS) { + if (paperEntityTag.getKey().equals(key)) + return new Tag[]{paperEntityTag}; + } + } + return null; } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagContents.java b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagContents.java index 84e20aee099..9ac05bb2efe 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagContents.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagContents.java @@ -21,8 +21,8 @@ public class ExprTagContents extends SimpleExpression { static { Skript.registerExpression(ExprTagContents.class, Object.class, ExpressionType.PROPERTY, - "tag (contents|values) of %minecrafttags%", - "%minecrafttags%'[s] tag (contents|values)"); + "tag (contents|values) of %minecrafttag%", + "%minecrafttag%'[s] tag (contents|values)"); } private Expression> tag; diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOf.java b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOf.java new file mode 100644 index 00000000000..6a00f92f52e --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOf.java @@ -0,0 +1,120 @@ +package org.skriptlang.skript.bukkit.tags; + +import ch.njol.skript.Skript; +import ch.njol.skript.expressions.base.PropertyExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.Bukkit; +import org.bukkit.Keyed; +import org.bukkit.Material; +import org.bukkit.Tag; +import org.bukkit.entity.EntityType; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.tags.TagModule.RegistryInfo; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import static org.skriptlang.skript.bukkit.tags.TagModule.REGISTRIES; + +public class ExprTagsOf extends PropertyExpression { + + static { + Skript.registerExpression(ExprTagsOf.class, Tag.class, ExpressionType.PROPERTY, + "[all [[of] the]] [minecraft] " + TagModule.REGISTRIES_PATTERN + " tags of %itemtype/entity/entitydata%", + "%itemtype/entity/entitydata%'[s] [minecraft] tags"); + } + + int type; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + this.setExpr(expressions[0]); + type = parseResult.mark - 1; + return true; + } + + @Override + protected Tag @Nullable [] get(Event event, Object[] source) { + //noinspection DataFlowIssue + Object object = getExpr().getSingle(event); + Keyed value = TagModule.getKeyed(object); + if (value == null) + return null; + + Set> tags = new TreeSet<>(Comparator.comparing(Keyed::key)); + List registries; + if (type == -1) { + registries = REGISTRIES; + } else { + registries = Collections.singletonList(REGISTRIES.get(type)); + } + for (RegistryInfo registry : registries) { + if (value.getClass() == registry.type()) + tags.addAll(getTags(value, registry.registry())); + } + + // try paper keys if they exist + if (!TagModule.PAPER_TAGS_EXIST) + return tags.toArray(new Tag[0]); + + // fallback to paper material tags + if (value.getClass() == Material.class && (type == -1 || REGISTRIES.get(type).type() == Material.class)) { + for (Tag paperMaterialTag : TagModule.PAPER_MATERIAL_TAGS) { + if (paperMaterialTag.isTagged((Material) value)) + tags.add(paperMaterialTag); + } + } + + // fallback to paper entity tags + if (value.getClass() == EntityType.class && (type == -1 || REGISTRIES.get(type).type() == EntityType.class)) { + for (Tag paperEntityTag : TagModule.PAPER_ENTITY_TAGS) { + if (paperEntityTag.isTagged((EntityType) value)) + tags.add(paperEntityTag); + } + } + + return tags.toArray(new Tag[0]); + } + + public static List> getTags(Keyed value, String registry) { + List> tags = new ArrayList<>(); + + // Capture the class type of the value + //noinspection unchecked + Class clazz = (Class) value.getClass(); + + // Fetch and process tags + for (Tag tag : Bukkit.getTags(registry, clazz)) { + //noinspection unchecked + if (tag.isTagged((T) value)) { + tags.add(tag); + } + } + + return tags; + } + + @Override + public boolean isSingle() { + return false; + } + + @Override + public Class getReturnType() { + return Tag.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + //noinspection DataFlowIssue + return "minecraft tags of " + getExpr().toString(event, debug); + } +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java index 9cc31d2fa89..9110893e0eb 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java @@ -1,15 +1,92 @@ package org.skriptlang.skript.bukkit.tags; import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.bukkitutil.EntityUtils; import ch.njol.skript.classes.ClassInfo; import ch.njol.skript.classes.Parser; +import ch.njol.skript.entity.EntityData; import ch.njol.skript.lang.ParseContext; import ch.njol.skript.registrations.Classes; +import ch.njol.skript.util.slot.Slot; +import com.destroystokyo.paper.MaterialSetTag; +import com.destroystokyo.paper.MaterialTags; +import io.papermc.paper.tag.EntityTags; +import org.bukkit.Keyed; +import org.bukkit.Material; import org.bukkit.Tag; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; import java.io.IOException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; public class TagModule { + + // paper tags + public static final List> PAPER_MATERIAL_TAGS = new ArrayList<>(); + public static final List> PAPER_ENTITY_TAGS = new ArrayList<>(); + public static final boolean PAPER_TAGS_EXIST = Skript.classExists("com.destroystokyo.paper.MaterialTags"); + + // bukkit tags + public record RegistryInfo(String registry, String pattern, Class type) {} + + // Fluid and GameEvent registries also exist, but are not useful at this time. + // Any new types added here must be handled in CondIsTagged and ExprTagsOf. + public static final List REGISTRIES = new ArrayList<>(List.of( + new RegistryInfo(Tag.REGISTRY_ITEMS, "item", Material.class), + new RegistryInfo(Tag.REGISTRY_BLOCKS, "block", Material.class), + new RegistryInfo(Tag.REGISTRY_ENTITY_TYPES, "entity [type]", EntityType.class) + )); + + public static final String REGISTRIES_PATTERN; + + static { + + StringBuilder registriesPattern = new StringBuilder("["); + int numRegistries = REGISTRIES.size(); + for (int i = 0; i < numRegistries; i++) { + registriesPattern.append(i + 1).append(":").append(REGISTRIES.get(i).pattern()); + if (i + 1 != numRegistries) + registriesPattern.append("|"); + } + registriesPattern.append("]"); + REGISTRIES_PATTERN = registriesPattern.toString(); + } + + @Contract(value = "null -> null", pure = true) + public static @Nullable Keyed getKeyed(Object input) { + Keyed value = null; + if (input == null) + return null; + if (input instanceof Entity entity) { + value = entity.getType(); + } if (input instanceof EntityData data) { + value = EntityUtils.toBukkitEntityType(data); + } else if (input instanceof ItemType itemType) { + value = itemType.getMaterial(); + } else if (input instanceof ItemStack itemStack) { + value = itemStack.getType(); + } else if (input instanceof Slot slot) { + ItemStack stack = slot.getItem(); + if (stack == null) + return null; + value = stack.getType(); + } else if (input instanceof Block block) { + value = block.getType(); + } else if (input instanceof BlockData data) { + value = data.getMaterial(); + } + return value; + } + public static void load() throws IOException { // abort if no class exists if (!Skript.classExists("org.bukkit.Tag")) @@ -32,14 +109,36 @@ public boolean canParse(ParseContext context) { @Override public String toString(Tag tag, int flags) { - return "minecraft tag \"" + tag.getKey() + "\""; + String key = tag.getKey().toString(); + if (TagModule.PAPER_TAGS_EXIST && tag instanceof MaterialSetTag) + key = key.replace("_settag", ""); + return "minecraft tag \"" + key + "\""; } @Override public String toVariableNameString(Tag tag) { - return "minecraft tag: " + tag.getKey(); + String key = tag.getKey().toString(); + if (TagModule.PAPER_TAGS_EXIST && tag instanceof MaterialSetTag) + key = key.replace("_settag", ""); + return "minecraft tag: " + key; } })); + + + if (PAPER_TAGS_EXIST) { + try { + for (Field field : MaterialTags.class.getDeclaredFields()) { + if (field.canAccess(null)) + //noinspection unchecked + PAPER_MATERIAL_TAGS.add((Tag) field.get(null)); + } + for (Field field : EntityTags.class.getDeclaredFields()) { + if (field.canAccess(null)) + //noinspection unchecked + PAPER_ENTITY_TAGS.add((Tag) field.get(null)); + } + } catch (IllegalAccessException ignored) {} + } } } From 85d3a43f0e3a360e1b3d0de3f1725cd41687a5ee Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 3 Oct 2024 00:40:20 -0400 Subject: [PATCH 03/21] forgot to remove _settag for entity tags too --- .../java/org/skriptlang/skript/bukkit/tags/TagModule.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java index 9110893e0eb..efbd085e7ec 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java @@ -11,6 +11,7 @@ import ch.njol.skript.util.slot.Slot; import com.destroystokyo.paper.MaterialSetTag; import com.destroystokyo.paper.MaterialTags; +import io.papermc.paper.tag.EntitySetTag; import io.papermc.paper.tag.EntityTags; import org.bukkit.Keyed; import org.bukkit.Material; @@ -110,7 +111,7 @@ public boolean canParse(ParseContext context) { @Override public String toString(Tag tag, int flags) { String key = tag.getKey().toString(); - if (TagModule.PAPER_TAGS_EXIST && tag instanceof MaterialSetTag) + if (TagModule.PAPER_TAGS_EXIST && (tag instanceof MaterialSetTag || tag instanceof EntitySetTag)) key = key.replace("_settag", ""); return "minecraft tag \"" + key + "\""; } @@ -118,7 +119,7 @@ public String toString(Tag tag, int flags) { @Override public String toVariableNameString(Tag tag) { String key = tag.getKey().toString(); - if (TagModule.PAPER_TAGS_EXIST && tag instanceof MaterialSetTag) + if (TagModule.PAPER_TAGS_EXIST && (tag instanceof MaterialSetTag || tag instanceof EntitySetTag)) key = key.replace("_settag", ""); return "minecraft tag: " + key; } From 6d2f935e6962b2f955400e5331064d9ab269d967 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 3 Oct 2024 01:09:24 -0400 Subject: [PATCH 04/21] all tags of type --- .../skript/bukkit/tags/ExprTagsOf.java | 9 +- .../skript/bukkit/tags/ExprTagsOfType.java | 84 +++++++++++++++++++ 2 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOfType.java diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOf.java b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOf.java index 6a00f92f52e..f8577377b14 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOf.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOf.java @@ -43,9 +43,9 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is @Override protected Tag @Nullable [] get(Event event, Object[] source) { - //noinspection DataFlowIssue - Object object = getExpr().getSingle(event); - Keyed value = TagModule.getKeyed(object); + if (source.length == 0) + return null; + Keyed value = TagModule.getKeyed(source[0]); if (value == null) return null; @@ -114,7 +114,8 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { + String registry = type == -1 ? "" : REGISTRIES.get(type).pattern() + " "; //noinspection DataFlowIssue - return "minecraft tags of " + getExpr().toString(event, debug); + return "minecraft " + registry + "tags of " + getExpr().toString(event, debug); } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOfType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOfType.java new file mode 100644 index 00000000000..a77a467d90b --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOfType.java @@ -0,0 +1,84 @@ +package org.skriptlang.skript.bukkit.tags; + +import ch.njol.skript.Skript; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import org.bukkit.Bukkit; +import org.bukkit.Keyed; +import org.bukkit.Material; +import org.bukkit.Tag; +import org.bukkit.entity.EntityType; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import static org.skriptlang.skript.bukkit.tags.TagModule.REGISTRIES; + +public class ExprTagsOfType extends SimpleExpression { + + static { + Skript.registerExpression(ExprTagsOfType.class, Tag.class, ExpressionType.SIMPLE, + "[all [[of] the]] [minecraft] " + TagModule.REGISTRIES_PATTERN + " tags"); + } + int type; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + type = parseResult.mark - 1; + return true; + } + + @Override + protected Tag @Nullable [] get(Event event) { + + Set> tags = new TreeSet<>(Comparator.comparing(Keyed::key)); + List registries; + if (type == -1) { + registries = REGISTRIES; + } else { + registries = Collections.singletonList(REGISTRIES.get(type)); + } + for (TagModule.RegistryInfo registry : registries) { + tags.addAll((java.util.Collection>) Bukkit.getTags(registry.registry(), registry.type())); + } + + // try paper keys if they exist + if (!TagModule.PAPER_TAGS_EXIST) + return tags.toArray(new Tag[0]); + + // fallback to paper material tags + if (type == -1 || REGISTRIES.get(type).type() == Material.class) { + tags.addAll(TagModule.PAPER_MATERIAL_TAGS); + } + + // fallback to paper entity tags + if (type == -1 || REGISTRIES.get(type).type() == EntityType.class) { + tags.addAll(TagModule.PAPER_ENTITY_TAGS); + } + return tags.toArray(new Tag[0]); + } + + @Override + public boolean isSingle() { + return false; + } + + @Override + public Class getReturnType() { + return Tag.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + String registry = type == -1 ? "" : REGISTRIES.get(type).pattern() + " "; + return "all of the minecraft " + registry + "tags"; + } +} From 4ccf6913a9db1fc5ccf54a9c1b70a0bec5146f76 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:47:21 -0400 Subject: [PATCH 05/21] major refactor --- .../java/ch/njol/skript/aliases/ItemType.java | 12 ++ .../skript/bukkit/tags/ExprTag.java | 111 ------------ .../skript/bukkit/tags/ExprTagsOf.java | 121 ------------- .../skript/bukkit/tags/TagModule.java | 105 ++++-------- .../skript/bukkit/tags/TagType.java | 58 +++++++ .../skriptlang/skript/bukkit/tags/Tags.java | 160 ++++++++++++++++++ .../tags/{ => elements}/CondIsTagged.java | 24 ++- .../skript/bukkit/tags/elements/ExprTag.java | 72 ++++++++ .../tags/{ => elements}/ExprTagContents.java | 2 +- .../bukkit/tags/elements/ExprTagsOf.java | 92 ++++++++++ .../tags/{ => elements}/ExprTagsOfType.java | 43 ++--- .../bukkit/tags/sources/BukkitTagSource.java | 29 ++++ .../bukkit/tags/sources/CustomTagSource.java | 37 ++++ .../bukkit/tags/sources/PaperTagSource.java | 58 +++++++ .../skript/bukkit/tags/sources/TagSource.java | 52 ++++++ 15 files changed, 633 insertions(+), 343 deletions(-) delete mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/ExprTag.java delete mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOf.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java rename src/main/java/org/skriptlang/skript/bukkit/tags/{ => elements}/CondIsTagged.java (71%) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java rename src/main/java/org/skriptlang/skript/bukkit/tags/{ => elements}/ExprTagContents.java (97%) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java rename src/main/java/org/skriptlang/skript/bukkit/tags/{ => elements}/ExprTagsOfType.java (51%) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagSource.java diff --git a/src/main/java/ch/njol/skript/aliases/ItemType.java b/src/main/java/ch/njol/skript/aliases/ItemType.java index aa772d2b646..a7fbb5d59ae 100644 --- a/src/main/java/ch/njol/skript/aliases/ItemType.java +++ b/src/main/java/ch/njol/skript/aliases/ItemType.java @@ -44,6 +44,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -1414,6 +1415,17 @@ public Material getMaterial() { return data.getType(); } + /** + * @return All Materials this ItemType represents. + */ + public Material[] getMaterials() { + Set materials = new HashSet<>(); + for (ItemData data : types) { + materials.add(data.getType()); + } + return materials.toArray(new Material[0]); + } + /** * Returns a base item type of this. Essentially, this calls * {@link ItemData#aliasCopy()} on all datas and creates a new type diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTag.java deleted file mode 100644 index 39b48600b0b..00000000000 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTag.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.skriptlang.skript.bukkit.tags; - -import ch.njol.skript.Skript; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.SkriptParser; -import ch.njol.skript.lang.util.SimpleExpression; -import ch.njol.util.Kleenean; -import org.skriptlang.skript.bukkit.tags.TagModule.RegistryInfo; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Tag; -import org.bukkit.entity.EntityType; -import org.bukkit.event.Event; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.List; - -import static org.skriptlang.skript.bukkit.tags.TagModule.REGISTRIES; - -public class ExprTag extends SimpleExpression { - - - static { - Skript.registerExpression(ExprTag.class, Tag.class, ExpressionType.COMBINED, "[minecraft] " + TagModule.REGISTRIES_PATTERN + " tag %string%"); - } - - Expression name; - int type; - - @Override - public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { - //noinspection unchecked - name = (Expression) expressions[0]; - type = parseResult.mark - 1; - return true; - } - - @Override - protected Tag @Nullable [] get(Event event) { - String name = this.name.getSingle(event); - if (name == null) - return null; - - NamespacedKey key = NamespacedKey.fromString(name); - if (key == null) - return null; - - - List registries; - if (type == -1) { - registries = REGISTRIES; - } else if (type < REGISTRIES.size()) { - registries = Collections.singletonList(REGISTRIES.get(type)); - } else { - return null; - } - - Tag tag; - for (RegistryInfo registry : registries) { - tag = Bukkit.getTag(registry.registry(), key, registry.type()); - if (tag != null) - return new Tag[]{tag}; - } - - // try paper keys if they exist - if (!TagModule.PAPER_TAGS_EXIST) - return null; - - - key = new NamespacedKey("paper", key.value() + "_settag"); - - // fallback to paper material tags - if (type == -1 || REGISTRIES.get(type).type() == Material.class) { - for (Tag paperMaterialTag : TagModule.PAPER_MATERIAL_TAGS) { - if (paperMaterialTag.getKey().equals(key)) - return new Tag[]{paperMaterialTag}; - } - } - - // fallback to paper entity tags - if (type == -1 || REGISTRIES.get(type).type() == EntityType.class) { - for (Tag paperEntityTag : TagModule.PAPER_ENTITY_TAGS) { - if (paperEntityTag.getKey().equals(key)) - return new Tag[]{paperEntityTag}; - } - } - - return null; - } - - @Override - public boolean isSingle() { - return true; - } - - @Override - @SuppressWarnings("rawtypes") - public Class getReturnType() { - return Tag.class; - } - - @Override - public String toString(@Nullable Event event, boolean debug) { - String registry = type == -1 ? "" : REGISTRIES.get(type).pattern(); - return "minecraft " + registry + "tag " + name.toString(event, debug); - } - -} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOf.java b/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOf.java deleted file mode 100644 index f8577377b14..00000000000 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOf.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.skriptlang.skript.bukkit.tags; - -import ch.njol.skript.Skript; -import ch.njol.skript.expressions.base.PropertyExpression; -import ch.njol.skript.lang.Expression; -import ch.njol.skript.lang.ExpressionType; -import ch.njol.skript.lang.SkriptParser.ParseResult; -import ch.njol.util.Kleenean; -import org.bukkit.Bukkit; -import org.bukkit.Keyed; -import org.bukkit.Material; -import org.bukkit.Tag; -import org.bukkit.entity.EntityType; -import org.bukkit.event.Event; -import org.jetbrains.annotations.Nullable; -import org.skriptlang.skript.bukkit.tags.TagModule.RegistryInfo; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; - -import static org.skriptlang.skript.bukkit.tags.TagModule.REGISTRIES; - -public class ExprTagsOf extends PropertyExpression { - - static { - Skript.registerExpression(ExprTagsOf.class, Tag.class, ExpressionType.PROPERTY, - "[all [[of] the]] [minecraft] " + TagModule.REGISTRIES_PATTERN + " tags of %itemtype/entity/entitydata%", - "%itemtype/entity/entitydata%'[s] [minecraft] tags"); - } - - int type; - - @Override - public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - this.setExpr(expressions[0]); - type = parseResult.mark - 1; - return true; - } - - @Override - protected Tag @Nullable [] get(Event event, Object[] source) { - if (source.length == 0) - return null; - Keyed value = TagModule.getKeyed(source[0]); - if (value == null) - return null; - - Set> tags = new TreeSet<>(Comparator.comparing(Keyed::key)); - List registries; - if (type == -1) { - registries = REGISTRIES; - } else { - registries = Collections.singletonList(REGISTRIES.get(type)); - } - for (RegistryInfo registry : registries) { - if (value.getClass() == registry.type()) - tags.addAll(getTags(value, registry.registry())); - } - - // try paper keys if they exist - if (!TagModule.PAPER_TAGS_EXIST) - return tags.toArray(new Tag[0]); - - // fallback to paper material tags - if (value.getClass() == Material.class && (type == -1 || REGISTRIES.get(type).type() == Material.class)) { - for (Tag paperMaterialTag : TagModule.PAPER_MATERIAL_TAGS) { - if (paperMaterialTag.isTagged((Material) value)) - tags.add(paperMaterialTag); - } - } - - // fallback to paper entity tags - if (value.getClass() == EntityType.class && (type == -1 || REGISTRIES.get(type).type() == EntityType.class)) { - for (Tag paperEntityTag : TagModule.PAPER_ENTITY_TAGS) { - if (paperEntityTag.isTagged((EntityType) value)) - tags.add(paperEntityTag); - } - } - - return tags.toArray(new Tag[0]); - } - - public static List> getTags(Keyed value, String registry) { - List> tags = new ArrayList<>(); - - // Capture the class type of the value - //noinspection unchecked - Class clazz = (Class) value.getClass(); - - // Fetch and process tags - for (Tag tag : Bukkit.getTags(registry, clazz)) { - //noinspection unchecked - if (tag.isTagged((T) value)) { - tags.add(tag); - } - } - - return tags; - } - - @Override - public boolean isSingle() { - return false; - } - - @Override - public Class getReturnType() { - return Tag.class; - } - - @Override - public String toString(@Nullable Event event, boolean debug) { - String registry = type == -1 ? "" : REGISTRIES.get(type).pattern() + " "; - //noinspection DataFlowIssue - return "minecraft " + registry + "tags of " + getExpr().toString(event, debug); - } -} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java index efbd085e7ec..b5d0d1ed1c9 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java @@ -10,83 +10,25 @@ import ch.njol.skript.registrations.Classes; import ch.njol.skript.util.slot.Slot; import com.destroystokyo.paper.MaterialSetTag; -import com.destroystokyo.paper.MaterialTags; import io.papermc.paper.tag.EntitySetTag; -import io.papermc.paper.tag.EntityTags; import org.bukkit.Keyed; -import org.bukkit.Material; import org.bukkit.Tag; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; public class TagModule { // paper tags - public static final List> PAPER_MATERIAL_TAGS = new ArrayList<>(); - public static final List> PAPER_ENTITY_TAGS = new ArrayList<>(); public static final boolean PAPER_TAGS_EXIST = Skript.classExists("com.destroystokyo.paper.MaterialTags"); - // bukkit tags - public record RegistryInfo(String registry, String pattern, Class type) {} - - // Fluid and GameEvent registries also exist, but are not useful at this time. - // Any new types added here must be handled in CondIsTagged and ExprTagsOf. - public static final List REGISTRIES = new ArrayList<>(List.of( - new RegistryInfo(Tag.REGISTRY_ITEMS, "item", Material.class), - new RegistryInfo(Tag.REGISTRY_BLOCKS, "block", Material.class), - new RegistryInfo(Tag.REGISTRY_ENTITY_TYPES, "entity [type]", EntityType.class) - )); - - public static final String REGISTRIES_PATTERN; - - static { - - StringBuilder registriesPattern = new StringBuilder("["); - int numRegistries = REGISTRIES.size(); - for (int i = 0; i < numRegistries; i++) { - registriesPattern.append(i + 1).append(":").append(REGISTRIES.get(i).pattern()); - if (i + 1 != numRegistries) - registriesPattern.append("|"); - } - registriesPattern.append("]"); - REGISTRIES_PATTERN = registriesPattern.toString(); - } - - @Contract(value = "null -> null", pure = true) - public static @Nullable Keyed getKeyed(Object input) { - Keyed value = null; - if (input == null) - return null; - if (input instanceof Entity entity) { - value = entity.getType(); - } if (input instanceof EntityData data) { - value = EntityUtils.toBukkitEntityType(data); - } else if (input instanceof ItemType itemType) { - value = itemType.getMaterial(); - } else if (input instanceof ItemStack itemStack) { - value = itemStack.getType(); - } else if (input instanceof Slot slot) { - ItemStack stack = slot.getItem(); - if (stack == null) - return null; - value = stack.getType(); - } else if (input instanceof Block block) { - value = block.getType(); - } else if (input instanceof BlockData data) { - value = data.getMaterial(); - } - return value; - } + // tag object + public static Tags TAGS; public static void load() throws IOException { // abort if no class exists @@ -125,21 +67,38 @@ public String toVariableNameString(Tag tag) { } })); + // init tags + TAGS = new Tags(); + } - if (PAPER_TAGS_EXIST) { - try { - for (Field field : MaterialTags.class.getDeclaredFields()) { - if (field.canAccess(null)) - //noinspection unchecked - PAPER_MATERIAL_TAGS.add((Tag) field.get(null)); - } - for (Field field : EntityTags.class.getDeclaredFields()) { - if (field.canAccess(null)) - //noinspection unchecked - PAPER_ENTITY_TAGS.add((Tag) field.get(null)); - } - } catch (IllegalAccessException ignored) {} + + @Contract(value = "null -> null", pure = true) + public static @Nullable Keyed[] getKeyed(Object input) { + Keyed value = null; + Keyed[] values = null; + if (input == null) + return null; + if (input instanceof Entity entity) { + value = entity.getType(); + } if (input instanceof EntityData data) { + value = EntityUtils.toBukkitEntityType(data); + } else if (input instanceof ItemType itemType) { + values = itemType.getMaterials(); + } else if (input instanceof ItemStack itemStack) { + value = itemStack.getType(); + } else if (input instanceof Slot slot) { + ItemStack stack = slot.getItem(); + if (stack == null) + return null; + value = stack.getType(); + } else if (input instanceof Block block) { + value = block.getType(); + } else if (input instanceof BlockData data) { + value = data.getMaterial(); } + if (value == null) + return values; + return new Keyed[]{value}; } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java new file mode 100644 index 00000000000..afecd31354b --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java @@ -0,0 +1,58 @@ +package org.skriptlang.skript.bukkit.tags; + +import org.bukkit.Keyed; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.UnmodifiableView; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public record TagType(String pattern, Class type) { + + private static final List> REGISTERED_TAG_TYPES = new ArrayList<>(); + + public static final TagType ITEMS = new TagType<>("item", Material.class); + public static final TagType BLOCKS = new TagType<>("block", Material.class); + public static final TagType ENTITIES = new TagType<>("entity [type]", EntityType.class); + + static { + TagType.addType(ITEMS, BLOCKS, ENTITIES); + } + + + public static void addType(TagType... type) { + REGISTERED_TAG_TYPES.addAll(List.of(type)); + } + + public static void addType(String pattern, Class type) { + REGISTERED_TAG_TYPES.add(new TagType<>(pattern, type)); + } + + @Contract(pure = true) + public static @NotNull @UnmodifiableView List> getTypes() { + return Collections.unmodifiableList(REGISTERED_TAG_TYPES); + } + + public static TagType @NotNull [] getType(int i) { + if (i < 0) + return REGISTERED_TAG_TYPES.toArray(new TagType[0]); + return new TagType[]{REGISTERED_TAG_TYPES.get(i)}; + } + + public static @NotNull String getFullPattern() { + StringBuilder fullPattern = new StringBuilder("["); + int numRegistries = REGISTERED_TAG_TYPES.size(); + for (int i = 0; i < numRegistries; i++) { + fullPattern.append(i + 1).append(":").append(REGISTERED_TAG_TYPES.get(i).pattern()); + if (i + 1 != numRegistries) + fullPattern.append("|"); + } + fullPattern.append("]"); + return fullPattern.toString(); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java b/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java new file mode 100644 index 00000000000..3e9bb478021 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java @@ -0,0 +1,160 @@ +package org.skriptlang.skript.bukkit.tags; + +import ch.njol.util.coll.iterator.CheckedIterator; +import com.destroystokyo.paper.MaterialTags; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Iterators; +import io.papermc.paper.tag.EntityTags; +import org.bukkit.Keyed; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; +import org.bukkit.entity.EntityType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.tags.sources.BukkitTagSource; +import org.skriptlang.skript.bukkit.tags.sources.PaperTagSource; +import org.skriptlang.skript.bukkit.tags.sources.TagSource; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.function.Predicate; + +public class Tags { + + private final TagSourceMap tagSourceMap = new TagSourceMap(); + + public Tags() { + tagSourceMap.put(TagType.ITEMS, new BukkitTagSource<>("items", TagType.ITEMS)); + tagSourceMap.put(TagType.BLOCKS, new BukkitTagSource<>("blocks", TagType.BLOCKS)); + tagSourceMap.put(TagType.ENTITIES, new BukkitTagSource<>("entity_types", TagType.ENTITIES)); + + if (TagModule.PAPER_TAGS_EXIST) { + try { + List> materialTags = new ArrayList<>(); + for (Field field : MaterialTags.class.getDeclaredFields()) { + if (field.canAccess(null)) + //noinspection unchecked + materialTags.add((Tag) field.get(null)); + } + PaperTagSource paperMaterialTags = new PaperTagSource<>(materialTags, TagType.BLOCKS, TagType.ITEMS); + tagSourceMap.put(TagType.BLOCKS, paperMaterialTags); + tagSourceMap.put(TagType.ITEMS, paperMaterialTags); + + List> entityTags = new ArrayList<>(); + for (Field field : EntityTags.class.getDeclaredFields()) { + if (field.canAccess(null)) + //noinspection unchecked + entityTags.add((Tag) field.get(null)); + } + PaperTagSource paperEntityTags = new PaperTagSource<>(entityTags, TagType.ENTITIES); + tagSourceMap.put(TagType.ENTITIES, paperEntityTags); + } catch (IllegalAccessException ignored) {} + } + } + + public Iterable> getTags(Class typeClass) { + List>> tagIterators = new ArrayList<>(); + for (TagType type : tagSourceMap.map.keys()) { + if (type.type() == typeClass) + //noinspection unchecked + tagIterators.add(getTags((TagType) type).iterator()); + } + return new Iterable<>() { + @Override + public @NotNull Iterator> iterator() { + return Iterators.concat(tagIterators.iterator()); + } + }; + } + + public Iterable> getTags(TagType type) { + if (!tagSourceMap.containsKey(type)) + return null; + Iterator> tagSources = tagSourceMap.get(type).iterator(); + if (!tagSources.hasNext()) + return null; + return new Iterable<>() { + @Override + public @NotNull Iterator> iterator() { + return new Iterator<>() { + // + private Iterator> currentTagIter = tagSources.next().getAllTags().iterator(); + private Iterator> nextTagIter; + + @Override + public boolean hasNext() { + // does the current source have more tags + if (currentTagIter.hasNext()) + return true; + // is there another source in the pipeline? if so, check it. + if (nextTagIter != null) + return nextTagIter.hasNext(); + // if there's no known next source, check if have one. + // if we do, mark it as the next source. + if (tagSources.hasNext()) { + nextTagIter = tagSources.next().getAllTags().iterator(); + return nextTagIter.hasNext(); + } + return false; + } + + @Override + public Tag next() { + // if current source has more, get more. + if (currentTagIter.hasNext()) + return currentTagIter.next(); + // if current source is dry, switch to using the next source + if (nextTagIter != null && nextTagIter.hasNext()) { + currentTagIter = nextTagIter; + nextTagIter = null; + return currentTagIter.next(); + } + throw new IllegalStateException("Called next without calling hasNext to set the next tag iterator."); + } + // + }; + } + }; + } + + public Iterable> getTagsMatching(TagType type, Predicate> predicate) { + Iterator> tagIterator = getTags(type).iterator(); + return new Iterable<>() { + @Override + public @NotNull Iterator> iterator() { + return new CheckedIterator<>(tagIterator, predicate::test); + } + }; + } + + public @Nullable Tag getTag(TagType type, NamespacedKey key) { + Tag tag; + for (TagSource source : tagSourceMap.get(type)) { + tag = source.getTag(key); + if (tag != null) + return tag; + } + return null; + } + + private static class TagSourceMap { + private final ArrayListMultimap, TagSource> map = ArrayListMultimap.create(); + + public void put(TagType key, TagSource value) { + map.put(key, value); + } + + public @NotNull List> get(TagType key) { + //noinspection unchecked + return (List>) (List>) map.get(key); + } + + public boolean containsKey(TagType type) { + return map.containsKey(type); + } + + } +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/CondIsTagged.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java similarity index 71% rename from src/main/java/org/skriptlang/skript/bukkit/tags/CondIsTagged.java rename to src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java index 691197e3334..6a6c42b949f 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/CondIsTagged.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java @@ -1,5 +1,6 @@ -package org.skriptlang.skript.bukkit.tags; +package org.skriptlang.skript.bukkit.tags.elements; +import ch.njol.skript.aliases.ItemType; import ch.njol.skript.conditions.base.PropertyCondition; import ch.njol.skript.lang.Condition; import ch.njol.skript.lang.Expression; @@ -8,7 +9,9 @@ import org.bukkit.Keyed; import org.bukkit.Tag; import org.bukkit.event.Event; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.tags.TagModule; public class CondIsTagged extends Condition { @@ -37,12 +40,13 @@ public boolean check(Event event) { return isNegated(); boolean and = this.tags.getAnd(); return elements.check(event, element -> { - Keyed value = TagModule.getKeyed(element); - if (value == null) + boolean isAny = (element instanceof ItemType itemType && !itemType.isAll()); + Keyed[] values = TagModule.getKeyed(element); + if (values == null) return false; for (Tag tag : tags) { - if (tag.isTagged(value)) { + if (isTagged(tag, values, !isAny)) { if (!and) return true; } else if (and) { @@ -53,6 +57,18 @@ public boolean check(Event event) { }, isNegated()); } + private boolean isTagged(Tag tag, Keyed @NotNull [] values, boolean allTagged) { + for (Keyed value : values) { + if (tag.isTagged(value)) { + if (!allTagged) + return true; + } else if (allTagged) { + return false; + } + } + return allTagged; + } + @Override public String toString(@Nullable Event event, boolean debug) { String plural = elements.isSingle() ? "is" : "are"; diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java new file mode 100644 index 00000000000..feba4f74a85 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java @@ -0,0 +1,72 @@ +package org.skriptlang.skript.bukkit.tags.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.util.Kleenean; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.tags.TagModule; +import org.skriptlang.skript.bukkit.tags.TagType; + +public class ExprTag extends SimpleExpression { + + static { + Skript.registerExpression(ExprTag.class, Tag.class, ExpressionType.COMBINED, + "[minecraft] " + TagType.getFullPattern() + " tag %string%"); + } + + Expression name; + int type; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + //noinspection unchecked + name = (Expression) expressions[0]; + type = parseResult.mark - 1; + return true; + } + + @Override + protected Tag @Nullable [] get(Event event) { + String name = this.name.getSingle(event); + if (name == null) + return null; + + NamespacedKey key = NamespacedKey.fromString(name); + if (key == null) + return null; + + Tag tag; + TagType[] types = TagType.getType(type); + for (TagType type : types) { + tag = TagModule.TAGS.getTag(type, key); + if (tag != null) + return new Tag[]{tag}; + } + + return null; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + @SuppressWarnings("rawtypes") + public Class getReturnType() { + return Tag.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + String registry = type == -1 ? "" : TagType.getType(type)[0].pattern(); + return "minecraft " + registry + "tag " + name.toString(event, debug); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagContents.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java similarity index 97% rename from src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagContents.java rename to src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java index 9ac05bb2efe..6fc9fe8b540 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagContents.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.tags; +package org.skriptlang.skript.bukkit.tags.elements; import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java new file mode 100644 index 00000000000..b172762b640 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java @@ -0,0 +1,92 @@ +package org.skriptlang.skript.bukkit.tags.elements; + +import ch.njol.skript.Skript; +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.expressions.base.PropertyExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import org.bukkit.Keyed; +import org.bukkit.Tag; +import org.bukkit.event.Event; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.tags.TagModule; +import org.skriptlang.skript.bukkit.tags.TagType; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ThreadLocalRandom; + +public class ExprTagsOf extends PropertyExpression { + + static { + Skript.registerExpression(ExprTagsOf.class, Tag.class, ExpressionType.PROPERTY, + "[all [[of] the]] [minecraft] " + TagType.getFullPattern() + " tags of %itemtype/entity/entitydata%", + "%itemtype/entity/entitydata%'[s] [minecraft] tags"); + } + + int type; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + this.setExpr(expressions[0]); + type = parseResult.mark - 1; + return true; + } + + @Override + protected Tag @Nullable [] get(Event event, Object @NotNull [] source) { + if (source.length == 0) + return null; + boolean isAny = (source[0] instanceof ItemType itemType && !itemType.isAll()); + Keyed[] values = TagModule.getKeyed(source[0]); + if (values == null) + return null; + // choose single material if it's something like `any log` + if (isAny) { + ThreadLocalRandom random = ThreadLocalRandom.current(); + values = new Keyed[]{values[random.nextInt(0, values.length)]}; + } + + Set> tags = new TreeSet<>(Comparator.comparing(Keyed::key)); + for (Keyed value : values) { + tags.addAll(getTags(value)); + } + + return tags.toArray(new Tag[0]); + } + + public Collection> getTags(T value) { + List> tags = new ArrayList<>(); + //noinspection unchecked + Class clazz = (Class) value.getClass(); + for (Tag tag : TagModule.TAGS.getTags(clazz)) { + if (tag.isTagged(value)) + tags.add(tag); + } + return tags; + } + + @Override + public boolean isSingle() { + return false; + } + + @Override + public Class getReturnType() { + return Tag.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + String registry = type == -1 ? "" : TagType.getType(type)[0].pattern(); + //noinspection DataFlowIssue + return "minecraft " + registry + "tags of " + getExpr().toString(event, debug); + } +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOfType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java similarity index 51% rename from src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOfType.java rename to src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java index a77a467d90b..e68ce7d1e0b 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/ExprTagsOfType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java @@ -1,4 +1,4 @@ -package org.skriptlang.skript.bukkit.tags; +package org.skriptlang.skript.bukkit.tags.elements; import ch.njol.skript.Skript; import ch.njol.skript.lang.Expression; @@ -6,27 +6,22 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; -import org.bukkit.Bukkit; import org.bukkit.Keyed; -import org.bukkit.Material; import org.bukkit.Tag; -import org.bukkit.entity.EntityType; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.tags.TagModule; +import org.skriptlang.skript.bukkit.tags.TagType; -import java.util.Collections; import java.util.Comparator; -import java.util.List; import java.util.Set; import java.util.TreeSet; -import static org.skriptlang.skript.bukkit.tags.TagModule.REGISTRIES; - public class ExprTagsOfType extends SimpleExpression { static { Skript.registerExpression(ExprTagsOfType.class, Tag.class, ExpressionType.SIMPLE, - "[all [[of] the]] [minecraft] " + TagModule.REGISTRIES_PATTERN + " tags"); + "[all [[of] the]] [minecraft] " + TagType.getFullPattern() + " tags"); } int type; @@ -38,30 +33,12 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is @Override protected Tag @Nullable [] get(Event event) { - + TagType[] types = TagType.getType(type); Set> tags = new TreeSet<>(Comparator.comparing(Keyed::key)); - List registries; - if (type == -1) { - registries = REGISTRIES; - } else { - registries = Collections.singletonList(REGISTRIES.get(type)); - } - for (TagModule.RegistryInfo registry : registries) { - tags.addAll((java.util.Collection>) Bukkit.getTags(registry.registry(), registry.type())); - } - - // try paper keys if they exist - if (!TagModule.PAPER_TAGS_EXIST) - return tags.toArray(new Tag[0]); - - // fallback to paper material tags - if (type == -1 || REGISTRIES.get(type).type() == Material.class) { - tags.addAll(TagModule.PAPER_MATERIAL_TAGS); - } - - // fallback to paper entity tags - if (type == -1 || REGISTRIES.get(type).type() == EntityType.class) { - tags.addAll(TagModule.PAPER_ENTITY_TAGS); + for (TagType type : types) { + for (Tag tag : TagModule.TAGS.getTags(type)) { + tags.add(tag); + } } return tags.toArray(new Tag[0]); } @@ -78,7 +55,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { - String registry = type == -1 ? "" : REGISTRIES.get(type).pattern() + " "; + String registry = type == -1 ? "" : TagType.getType(type)[0].pattern(); return "all of the minecraft " + registry + "tags"; } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java new file mode 100644 index 00000000000..88f70636b98 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java @@ -0,0 +1,29 @@ +package org.skriptlang.skript.bukkit.tags.sources; + +import org.bukkit.Bukkit; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.tags.TagType; + +public class BukkitTagSource extends TagSource { + + private final String registry; + + public BukkitTagSource(String registry, TagType type) { + super(type); + this.registry = registry; + } + + @Override + public @NotNull Iterable> getAllTags() { + return Bukkit.getTags(registry, getTypes()[0].type()); + } + + @Override + public @Nullable Tag getTag(NamespacedKey key) { + return Bukkit.getTag(registry, key, getTypes()[0].type()); + } +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java new file mode 100644 index 00000000000..fe68ce06ca3 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java @@ -0,0 +1,37 @@ +package org.skriptlang.skript.bukkit.tags.sources; + +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.tags.TagType; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class CustomTagSource extends TagSource { + + final Map> tags; + + @SafeVarargs + public CustomTagSource(@NotNull Iterable> tags, TagType... types) { + super(types); + this.tags = new HashMap<>(); + for (Tag tag : tags) { + this.tags.put(tag.getKey(), tag); + } + } + + @Override + public Iterable> getAllTags() { + return Collections.unmodifiableCollection(tags.values()); + } + + @Override + public @Nullable Tag getTag(NamespacedKey key) { + return tags.get(key); + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java new file mode 100644 index 00000000000..7e5802789b9 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java @@ -0,0 +1,58 @@ +package org.skriptlang.skript.bukkit.tags.sources; + +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; +import org.jetbrains.annotations.NotNull; +import org.skriptlang.skript.bukkit.tags.TagType; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public class PaperTagSource extends CustomTagSource { + + private static @NotNull Iterable> getPaperTags(@NotNull Iterable> tags) { + List> modified_tags = new ArrayList<>(); + for (Tag tag : tags) { + modified_tags.add(new PaperTag<>(tag)); + } + return modified_tags; + } + + @SafeVarargs + public PaperTagSource(Iterable> tags, TagType... types) { + super(getPaperTags(tags), types); + } + + /** + * Wrapper for Paper tags to remove "_settag" from their key. + * @param + */ + private static class PaperTag implements Tag { + + private final Tag paperTag; + private final NamespacedKey key; + + public PaperTag(@NotNull Tag paperTag) { + this.paperTag = paperTag; + this.key = NamespacedKey.fromString(paperTag.getKey().toString().replace("_settag", "")); + } + + @Override + public boolean isTagged(@NotNull T1 item) { + return paperTag.isTagged(item); + } + + @Override + public @NotNull Set getValues() { + return paperTag.getValues(); + } + + @Override + public @NotNull NamespacedKey getKey() { + return key; + } + } + +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagSource.java new file mode 100644 index 00000000000..c775efce1f8 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagSource.java @@ -0,0 +1,52 @@ +package org.skriptlang.skript.bukkit.tags.sources; + +import ch.njol.util.coll.iterator.CheckedIterator; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.tags.TagType; + +import java.util.Iterator; +import java.util.function.Predicate; + +/** + * A source for {@link org.bukkit.Tag}s, be it Bukkit's tag registries, Paper's handmade tags, or + * custom tags made by the user. + * @param The type of tags this source will return. + * For example, the Bukkit "items" tag registry would return {@link org.bukkit.Material}s. + */ +public abstract class TagSource { + + private final TagType[] types; + + @SafeVarargs + protected TagSource(TagType... types) { + this.types = types; + } + + /** + * @return All the tags associated with this source. + */ + public abstract Iterable> getAllTags(); + + public Iterable> getAllTagsMatching(Predicate> predicate) { + Iterator> tagIterator = getAllTags().iterator(); + return new Iterable<>() { + @Override + public @NotNull Iterator> iterator() { + return new CheckedIterator<>(tagIterator, predicate::test); + } + }; + } + + public abstract @Nullable Tag getTag(NamespacedKey key); + + public TagType[] getTypes() { + return types; + } + + + +} From c7cc80a86240ea6135ebee5f1dbe0cd1a9c46057 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:56:17 -0400 Subject: [PATCH 06/21] Add origin filtering --- .../skript/bukkit/tags/TagModule.java | 12 +---- .../skriptlang/skript/bukkit/tags/Tags.java | 33 ++++++++------ .../skript/bukkit/tags/elements/ExprTag.java | 17 +++++-- .../bukkit/tags/elements/ExprTagsOf.java | 19 +++++--- .../bukkit/tags/elements/ExprTagsOfType.java | 14 ++++-- .../bukkit/tags/sources/BukkitTagSource.java | 2 +- .../bukkit/tags/sources/CustomTagSource.java | 4 +- .../bukkit/tags/sources/PaperTagSource.java | 2 +- .../skript/bukkit/tags/sources/TagOrigin.java | 45 +++++++++++++++++++ .../skript/bukkit/tags/sources/TagSource.java | 8 +++- 10 files changed, 114 insertions(+), 42 deletions(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java index b5d0d1ed1c9..914159b908c 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java @@ -9,8 +9,6 @@ import ch.njol.skript.lang.ParseContext; import ch.njol.skript.registrations.Classes; import ch.njol.skript.util.slot.Slot; -import com.destroystokyo.paper.MaterialSetTag; -import io.papermc.paper.tag.EntitySetTag; import org.bukkit.Keyed; import org.bukkit.Tag; import org.bukkit.block.Block; @@ -52,18 +50,12 @@ public boolean canParse(ParseContext context) { @Override public String toString(Tag tag, int flags) { - String key = tag.getKey().toString(); - if (TagModule.PAPER_TAGS_EXIST && (tag instanceof MaterialSetTag || tag instanceof EntitySetTag)) - key = key.replace("_settag", ""); - return "minecraft tag \"" + key + "\""; + return "tag \"" + tag.getKey() + "\""; } @Override public String toVariableNameString(Tag tag) { - String key = tag.getKey().toString(); - if (TagModule.PAPER_TAGS_EXIST && (tag instanceof MaterialSetTag || tag instanceof EntitySetTag)) - key = key.replace("_settag", ""); - return "minecraft tag: " + key; + return "tag: " + tag.getKey(); } })); diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java b/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java index 3e9bb478021..bf453c26061 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java @@ -14,6 +14,7 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.tags.sources.BukkitTagSource; import org.skriptlang.skript.bukkit.tags.sources.PaperTagSource; +import org.skriptlang.skript.bukkit.tags.sources.TagOrigin; import org.skriptlang.skript.bukkit.tags.sources.TagSource; import java.lang.reflect.Field; @@ -55,12 +56,12 @@ public Tags() { } } - public Iterable> getTags(Class typeClass) { + public Iterable> getTags(TagOrigin origin, Class typeClass) { List>> tagIterators = new ArrayList<>(); for (TagType type : tagSourceMap.map.keys()) { if (type.type() == typeClass) //noinspection unchecked - tagIterators.add(getTags((TagType) type).iterator()); + tagIterators.add(getTags(origin, (TagType) type).iterator()); } return new Iterable<>() { @Override @@ -70,12 +71,12 @@ public Iterable> getTags(Class typeClass) { }; } - public Iterable> getTags(TagType type) { + public Iterable> getTags(TagOrigin origin, TagType type) { if (!tagSourceMap.containsKey(type)) - return null; - Iterator> tagSources = tagSourceMap.get(type).iterator(); + return List.of(); + Iterator> tagSources = tagSourceMap.get(origin, type).iterator(); if (!tagSources.hasNext()) - return null; + return List.of(); return new Iterable<>() { @Override public @NotNull Iterator> iterator() { @@ -120,8 +121,8 @@ public Tag next() { }; } - public Iterable> getTagsMatching(TagType type, Predicate> predicate) { - Iterator> tagIterator = getTags(type).iterator(); + public Iterable> getTagsMatching(TagOrigin origin, TagType type, Predicate> predicate) { + Iterator> tagIterator = getTags(origin, type).iterator(); return new Iterable<>() { @Override public @NotNull Iterator> iterator() { @@ -130,9 +131,9 @@ public Iterable> getTagsMatching(TagType type, Predi }; } - public @Nullable Tag getTag(TagType type, NamespacedKey key) { + public @Nullable Tag getTag(TagOrigin origin, TagType type, NamespacedKey key) { Tag tag; - for (TagSource source : tagSourceMap.get(type)) { + for (TagSource source : tagSourceMap.get(origin, type)) { tag = source.getTag(key); if (tag != null) return tag; @@ -147,14 +148,18 @@ public void put(TagType key, TagSource value) { map.put(key, value); } - public @NotNull List> get(TagType key) { - //noinspection unchecked - return (List>) (List>) map.get(key); + public @NotNull List> get(TagOrigin origin, TagType key) { + List> sources = new ArrayList<>(); + for (TagSource source : map.get(key)) { + if (source.getOrigin().matches(origin)) + //noinspection unchecked + sources.add((TagSource) source); + } + return sources; } public boolean containsKey(TagType type) { return map.containsKey(type); } - } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java index feba4f74a85..c54e9cda296 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java @@ -12,22 +12,27 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.tags.TagModule; import org.skriptlang.skript.bukkit.tags.TagType; +import org.skriptlang.skript.bukkit.tags.sources.TagOrigin; public class ExprTag extends SimpleExpression { static { Skript.registerExpression(ExprTag.class, Tag.class, ExpressionType.COMBINED, - "[minecraft] " + TagType.getFullPattern() + " tag %string%"); + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tag %string%"); } Expression name; int type; + TagOrigin origin; + boolean datapackOnly; @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { //noinspection unchecked name = (Expression) expressions[0]; type = parseResult.mark - 1; + origin = TagOrigin.fromParseTags(parseResult.tags); + datapackOnly = origin == TagOrigin.BUKKIT && parseResult.hasTag("datapack"); return true; } @@ -44,9 +49,13 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is Tag tag; TagType[] types = TagType.getType(type); for (TagType type : types) { - tag = TagModule.TAGS.getTag(type, key); - if (tag != null) + tag = TagModule.TAGS.getTag(origin, type, key); + if (tag != null + // ensures that only datapack/minecraft tags are sent when specifically requested + && (origin != TagOrigin.BUKKIT || (datapackOnly ^ tag.getKey().getNamespace().equals("minecraft"))) + ) { return new Tag[]{tag}; + } } return null; @@ -66,7 +75,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { String registry = type == -1 ? "" : TagType.getType(type)[0].pattern(); - return "minecraft " + registry + "tag " + name.toString(event, debug); + return origin.toString(datapackOnly) + registry + "tag " + name.toString(event, debug); } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java index b172762b640..1a77fb69dfc 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java @@ -14,6 +14,7 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.tags.TagModule; import org.skriptlang.skript.bukkit.tags.TagType; +import org.skriptlang.skript.bukkit.tags.sources.TagOrigin; import java.util.ArrayList; import java.util.Collection; @@ -27,16 +28,20 @@ public class ExprTagsOf extends PropertyExpression { static { Skript.registerExpression(ExprTagsOf.class, Tag.class, ExpressionType.PROPERTY, - "[all [[of] the]] [minecraft] " + TagType.getFullPattern() + " tags of %itemtype/entity/entitydata%", - "%itemtype/entity/entitydata%'[s] [minecraft] tags"); + "[all [[of] the]] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags of %itemtype/entity/entitydata%", + "%itemtype/entity/entitydata%'[s] [:minecraft|:paper|:custom] tags"); } int type; + TagOrigin origin; + boolean datapackOnly; @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { this.setExpr(expressions[0]); type = parseResult.mark - 1; + origin = TagOrigin.fromParseTags(parseResult.tags); + datapackOnly = origin == TagOrigin.BUKKIT && parseResult.hasTag("datapack"); return true; } @@ -59,14 +64,18 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is tags.addAll(getTags(value)); } - return tags.toArray(new Tag[0]); + return tags.stream() + .filter(tag -> + // ensures that only datapack/minecraft tags are sent when specifically requested + (origin != TagOrigin.BUKKIT || (datapackOnly ^ tag.getKey().getNamespace().equals("minecraft")))) + .toArray(Tag[]::new); } public Collection> getTags(T value) { List> tags = new ArrayList<>(); //noinspection unchecked Class clazz = (Class) value.getClass(); - for (Tag tag : TagModule.TAGS.getTags(clazz)) { + for (Tag tag : TagModule.TAGS.getTags(origin, clazz)) { if (tag.isTagged(value)) tags.add(tag); } @@ -87,6 +96,6 @@ public Class getReturnType() { public String toString(@Nullable Event event, boolean debug) { String registry = type == -1 ? "" : TagType.getType(type)[0].pattern(); //noinspection DataFlowIssue - return "minecraft " + registry + "tags of " + getExpr().toString(event, debug); + return origin.toString(datapackOnly) + registry + "tags of " + getExpr().toString(event, debug); } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java index e68ce7d1e0b..f2ebd134389 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java @@ -12,6 +12,7 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.tags.TagModule; import org.skriptlang.skript.bukkit.tags.TagType; +import org.skriptlang.skript.bukkit.tags.sources.TagOrigin; import java.util.Comparator; import java.util.Set; @@ -21,13 +22,18 @@ public class ExprTagsOfType extends SimpleExpression { static { Skript.registerExpression(ExprTagsOfType.class, Tag.class, ExpressionType.SIMPLE, - "[all [[of] the]] [minecraft] " + TagType.getFullPattern() + " tags"); + "[all [[of] the]] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags"); } + int type; + TagOrigin origin; + boolean datapackOnly; @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { type = parseResult.mark - 1; + origin = TagOrigin.fromParseTags(parseResult.tags); + datapackOnly = origin == TagOrigin.BUKKIT && parseResult.hasTag("datapack"); return true; } @@ -36,7 +42,9 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is TagType[] types = TagType.getType(type); Set> tags = new TreeSet<>(Comparator.comparing(Keyed::key)); for (TagType type : types) { - for (Tag tag : TagModule.TAGS.getTags(type)) { + for (Tag tag : TagModule.TAGS.getTagsMatching(origin, type, + tag -> (origin != TagOrigin.BUKKIT || (datapackOnly ^ tag.getKey().getNamespace().equals("minecraft")))) + ) { tags.add(tag); } } @@ -56,6 +64,6 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { String registry = type == -1 ? "" : TagType.getType(type)[0].pattern(); - return "all of the minecraft " + registry + "tags"; + return "all of the " + origin.toString(datapackOnly) + registry + "tags"; } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java index 88f70636b98..02dd0430ae7 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java @@ -13,7 +13,7 @@ public class BukkitTagSource extends TagSource { private final String registry; public BukkitTagSource(String registry, TagType type) { - super(type); + super(TagOrigin.BUKKIT, type); this.registry = registry; } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java index fe68ce06ca3..cb0462b646d 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java @@ -16,8 +16,8 @@ public class CustomTagSource extends TagSource { final Map> tags; @SafeVarargs - public CustomTagSource(@NotNull Iterable> tags, TagType... types) { - super(types); + public CustomTagSource(TagOrigin origin, @NotNull Iterable> tags, TagType... types) { + super(origin, types); this.tags = new HashMap<>(); for (Tag tag : tags) { this.tags.put(tag.getKey(), tag); diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java index 7e5802789b9..88cd0c91e0c 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java @@ -22,7 +22,7 @@ public class PaperTagSource extends CustomTagSource { @SafeVarargs public PaperTagSource(Iterable> tags, TagType... types) { - super(getPaperTags(tags), types); + super(TagOrigin.PAPER, getPaperTags(tags), types); } /** diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java new file mode 100644 index 00000000000..6d9406b0ef9 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java @@ -0,0 +1,45 @@ +package org.skriptlang.skript.bukkit.tags.sources; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public enum TagOrigin { + BUKKIT, + PAPER, + SKRIPT, + ANY; + + @Contract(pure = true) + public static @NotNull String getFullPattern() { + return "[:minecraft|:datapack|:paper|:custom]"; + } + + @Contract(value = "_ -> new", pure = true) + public static TagOrigin fromParseTags(@NotNull List tags) { + TagOrigin origin = TagOrigin.ANY; + if (tags.contains("minecraft") || tags.contains("datapack")) { + origin = TagOrigin.BUKKIT; + } else if (tags.contains("paper")) { + origin = TagOrigin.PAPER; + } else if (tags.contains("custom")) { + origin = TagOrigin.SKRIPT; + } + return origin; + } + + public boolean matches(TagOrigin other) { + return this == other || this == ANY || other == ANY; + } + + @Contract(pure = true) + public @NotNull String toString(boolean datapackOnly) { + return switch (this) { + case BUKKIT -> datapackOnly ? "datapack " : "minecraft "; + case PAPER -> "paper "; + case SKRIPT -> "custom "; + case ANY -> ""; + }; + } +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagSource.java index c775efce1f8..8485d09176b 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagSource.java @@ -20,10 +20,12 @@ public abstract class TagSource { private final TagType[] types; + private final TagOrigin origin; @SafeVarargs - protected TagSource(TagType... types) { + protected TagSource(TagOrigin origin, TagType... types) { this.types = types; + this.origin = origin; } /** @@ -47,6 +49,8 @@ public TagType[] getTypes() { return types; } - + public TagOrigin getOrigin() { + return origin; + } } From 9e843182314cece891132d66bf9c240a0e1d9bbc Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 3 Oct 2024 15:05:18 -0400 Subject: [PATCH 07/21] populate omitted namespaces --- .../skript/bukkit/tags/elements/ExprTag.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java index c54e9cda296..3e6c8201d36 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java @@ -42,7 +42,19 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is if (name == null) return null; - NamespacedKey key = NamespacedKey.fromString(name); + // get key + NamespacedKey key; + if (name.contains(":")) { + key = NamespacedKey.fromString(name); + } else { + // populate namespace if not provided + String namespace = switch (origin) { + case ANY, BUKKIT -> "minecraft"; + case PAPER -> "paper"; + case SKRIPT -> "skript"; + }; + key = new NamespacedKey(namespace, name); + } if (key == null) return null; From a509e465e1a41adf3f86e02f43b5cd124b5fbb37 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 3 Oct 2024 15:55:34 -0400 Subject: [PATCH 08/21] implement simplify for future use cases --- .../skriptlang/skript/bukkit/tags/elements/ExprTag.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java index 3e6c8201d36..c5debc33612 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java @@ -3,8 +3,10 @@ import ch.njol.skript.Skript; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; +import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.skript.lang.util.SimpleLiteral; import ch.njol.util.Kleenean; import org.bukkit.NamespacedKey; import org.bukkit.Tag; @@ -90,4 +92,11 @@ public String toString(@Nullable Event event, boolean debug) { return origin.toString(datapackOnly) + registry + "tag " + name.toString(event, debug); } + @Override + public Expression simplify() { + if (name instanceof Literal) + return new SimpleLiteral<>(getArray(null), Tag.class, true); + return this; + } + } From ed88f9a9f4a0f271995eea951dc5d82155039000 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 3 Oct 2024 21:19:27 -0400 Subject: [PATCH 09/21] all the documentation you could ever want! --- .../skript/bukkit/tags/TagModule.java | 10 ++++- .../skript/bukkit/tags/TagType.java | 39 +++++++++++++++--- .../skriptlang/skript/bukkit/tags/Tags.java | 40 +++++++++++++++++++ .../bukkit/tags/elements/CondIsTagged.java | 24 +++++++++++ .../skript/bukkit/tags/elements/ExprTag.java | 28 +++++++++++++ .../bukkit/tags/elements/ExprTagContents.java | 17 ++++++++ .../bukkit/tags/elements/ExprTagsOf.java | 30 +++++++++++++- .../bukkit/tags/elements/ExprTagsOfType.java | 20 ++++++++++ .../bukkit/tags/sources/BukkitTagSource.java | 8 ++++ .../bukkit/tags/sources/CustomTagSource.java | 9 +++++ .../bukkit/tags/sources/PaperTagSource.java | 16 +++++++- .../skript/bukkit/tags/sources/TagOrigin.java | 38 ++++++++++++++++++ .../skript/bukkit/tags/sources/TagSource.java | 20 ++++++++++ 13 files changed, 289 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java index 914159b908c..9b9bd5661ef 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java @@ -63,7 +63,15 @@ public String toVariableNameString(Tag tag) { TAGS = new Tags(); } - + /** + * Retrieves a Keyed array based on the type of the provided input object. + * + * @param input the input object to determine the keyed value, can be of type Entity, + * EntityData, ItemType, ItemStack, Slot, Block, or BlockData. + * @return a Keyed array corresponding to the input's type, or null if the input is null + * or if no corresponding Keyed value can be determined. ItemTypes may return multiple values, + * though everything else will return a single element array. + */ @Contract(value = "null -> null", pure = true) public static @Nullable Keyed[] getKeyed(Object input) { Keyed value = null; diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java index afecd31354b..2a7014fecce 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java @@ -1,5 +1,8 @@ package org.skriptlang.skript.bukkit.tags; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.util.Kleenean; import org.bukkit.Keyed; import org.bukkit.Material; import org.bukkit.entity.EntityType; @@ -11,6 +14,17 @@ import java.util.Collections; import java.util.List; +/** + * The type of a tag. Represents a category or context that the tags apply in. + * For example, {@link #ITEMS} tags apply to {@link Material}s, like {@link #BLOCKS}, but in item form rather than as + * placed blocks. + *
+ * This class also contains a static registry of all tag types. + * + * @param pattern The pattern to use when construction the selection Skript pattern. + * @param type The class this tag type applies to. + * @param see type. + */ public record TagType(String pattern, Class type) { private static final List> REGISTERED_TAG_TYPES = new ArrayList<>(); @@ -23,26 +37,39 @@ public record TagType(String pattern, Class type) { TagType.addType(ITEMS, BLOCKS, ENTITIES); } - - public static void addType(TagType... type) { + /** + * Adds types to the registered tag types. + * @param type The types to add. + */ + private static void addType(TagType... type) { REGISTERED_TAG_TYPES.addAll(List.of(type)); } - public static void addType(String pattern, Class type) { - REGISTERED_TAG_TYPES.add(new TagType<>(pattern, type)); - } - + /** + * @return An unmodifiable list of all the registered types. + */ @Contract(pure = true) public static @NotNull @UnmodifiableView List> getTypes() { return Collections.unmodifiableList(REGISTERED_TAG_TYPES); } + /** + * Gets tag types by index. If a negative value is used, gets all the tag types. + * @param i The index of the type to get. + * @return The type at that index, or all tags if index < 0. + */ public static TagType @NotNull [] getType(int i) { if (i < 0) return REGISTERED_TAG_TYPES.toArray(new TagType[0]); return new TagType[]{REGISTERED_TAG_TYPES.get(i)}; } + /** + * @return Returns an optional choice pattern for use in Skript patterns. Contains parse marks. + * Subtract 1 from the parse mark and pass the value to {@link #getType(int)} to get the + * selected tag type in + * {@link ch.njol.skript.lang.SyntaxElement#init(Expression[], int, Kleenean, SkriptParser.ParseResult)}. + */ public static @NotNull String getFullPattern() { StringBuilder fullPattern = new StringBuilder("["); int numRegistries = REGISTERED_TAG_TYPES.size(); diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java b/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java index bf453c26061..13f1bfb0581 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java @@ -23,10 +23,16 @@ import java.util.List; import java.util.function.Predicate; +/** + * A class in charge of storing and handling all the tags Skript can access. + */ public class Tags { private final TagSourceMap tagSourceMap = new TagSourceMap(); + /** + * Each new instance will create a new set of tag sources, in an effort to be reload safe. + */ public Tags() { tagSourceMap.put(TagType.ITEMS, new BukkitTagSource<>("items", TagType.ITEMS)); tagSourceMap.put(TagType.BLOCKS, new BukkitTagSource<>("blocks", TagType.BLOCKS)); @@ -56,6 +62,13 @@ public Tags() { } } + /** + * Gets all the tags of a specific origin that are applicable to a given class. + * @param origin The origin to filter by. + * @param typeClass The class the tags should be applicable to. + * @return Tags from the given origin that apply to the given class. + * @param see typeClass. + */ public Iterable> getTags(TagOrigin origin, Class typeClass) { List>> tagIterators = new ArrayList<>(); for (TagType type : tagSourceMap.map.keys()) { @@ -71,6 +84,13 @@ public Iterable> getTags(TagOrigin origin, Class ty }; } + /** + * Gets all the tags of a specific origin that are of a specific type. + * @param origin The origin to filter by. + * @param type The type of tags to get. + * @return Tags from the given origin that are of the given type. + * @param The class these tags apply to. + */ public Iterable> getTags(TagOrigin origin, TagType type) { if (!tagSourceMap.containsKey(type)) return List.of(); @@ -121,6 +141,15 @@ public Tag next() { }; } + /** + * Gets all the tags of a specific origin that are of a specific type. Filters the resulting tags using the given + * predicate. + * @param origin The origin to filter by. + * @param type The type of tags to get. + * @param predicate A predicate to filter the tags with. + * @return Tags from the given origin that are of the given type and that pass the filter. + * @param The class these tags apply to. + */ public Iterable> getTagsMatching(TagOrigin origin, TagType type, Predicate> predicate) { Iterator> tagIterator = getTags(origin, type).iterator(); return new Iterable<>() { @@ -131,6 +160,14 @@ public Iterable> getTagsMatching(TagOrigin origin, TagT }; } + /** + * Gets a specific tag of a specific origin that is of a specific type. + * @param origin The origin to filter by. + * @param type The type of tags to get. + * @param key The key of the tag to get. + * @return The tag that matched the above values. Null if no tag is found. + * @param The class these tags apply to. + */ public @Nullable Tag getTag(TagOrigin origin, TagType type, NamespacedKey key) { Tag tag; for (TagSource source : tagSourceMap.get(origin, type)) { @@ -141,6 +178,9 @@ public Iterable> getTagsMatching(TagOrigin origin, TagT return null; } + /** + * A MultiMap that maps TagTypes to multiple TagSources, matching generics. + */ private static class TagSourceMap { private final ArrayListMultimap, TagSource> map = ArrayListMultimap.create(); diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java index 6a6c42b949f..524b19a89f9 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java @@ -2,6 +2,11 @@ import ch.njol.skript.aliases.ItemType; import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Keywords; +import ch.njol.skript.doc.Name; +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; @@ -13,6 +18,18 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.tags.TagModule; +@Name("Is Tagged") +@Description({ + "Checks whether an item, block, entity, or entitydata is tagged as the given tag." +}) +@Examples({ + "if player's tool is tagged with minecraft tag \"enchantable/sharp_weapon\":", + "\tenchant player's tool with sharpness 1", + "", + "if all logs are tagged with tag \"minecraft:logs\"" +}) +@Since("INSERT VERSION") +@Keywords({"blocks", "minecraft tag", "type", "category"}) public class CondIsTagged extends Condition { static { @@ -57,6 +74,13 @@ public boolean check(Event event) { }, isNegated()); } + /** + * Helper method for checking if a series of values have a tag. + * @param tag The tag to check for. + * @param values The values to check against. + * @param allTagged Whether all values need to have the tag (true), or just one (false). + * @return Whether the values are tagged with the tag. + */ private boolean isTagged(Tag tag, Keyed @NotNull [] values, boolean allTagged) { for (Keyed value : values) { if (tag.isTagged(value)) { diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java index c5debc33612..e5df94d2770 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java @@ -1,6 +1,11 @@ package org.skriptlang.skript.bukkit.tags.elements; import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Keywords; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.Literal; @@ -16,6 +21,29 @@ import org.skriptlang.skript.bukkit.tags.TagType; import org.skriptlang.skript.bukkit.tags.sources.TagOrigin; +@Name("Tag") +@Description({ + "Represents a tag which can be used to classify items, blocks, or entities.", + "Tags are composed of a value and an optional namespace: \"minecraft:oak_logs\".", + "If you omit the namespace, one will be provided for you, depending on what kind of tag you're using. " + + "For example, `tag \"doors\"` will be the tag \"minecraft:doors\", " + + "while `paper tag \"doors\"` will be \"paper:doors\".", + "`minecraft tag` will search through the vanilla tags, `datapack tag` will search for datapack-provided tags " + + "(a namespace is required here!), `paper tag` will search for Paper's custom tags if you are running Paper, " + + "and `custom tag` will look in the \"skript\" namespace for custom tags you've registered.", + "You can also filter by tag types using \"item\", \"block\", or \"entity\"." +}) +@Examples({ + "minecraft tag \"dirt\" # minecraft:dirt", + "paper tag \"doors\" # paper:doors", + "tag \"skript:custom_dirt\" # skript:custom_dirt", + "skript tag \"dirt\" # skript:dirt", + "datapack tag \"dirt\" # minecraft:dirt", + "datapack tag \"my_pack:custom_dirt\" # my_pack:custom_dirt", + "tag \"minecraft:mineable/pickaxe\" # minecraft:mineable/pickaxe", +}) +@Since("INSERT VERSION") +@Keywords({"blocks", "minecraft tag", "type", "category"}) public class ExprTag extends SimpleExpression { static { diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java index 6fc9fe8b540..61f2f92c48c 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java @@ -3,6 +3,11 @@ import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; import ch.njol.skript.bukkitutil.EntityUtils; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Keywords; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.SkriptParser.ParseResult; @@ -17,6 +22,18 @@ import java.util.Objects; +@Name("Tags Contents") +@Description({ + "Returns all the values that a tag contains.", + "For item and block tags, this will return items. For entity tags, " + + "it will return entity datas (a creeper, a zombie)." +}) +@Examples({ + "broadcast tag values of minecraft tag \"dirt\"", + "broadcast (first element of player's tool's block tags)'s tag contents" +}) +@Since("INSERT VERSION") +@Keywords({"blocks", "minecraft tag", "type", "category"}) public class ExprTagContents extends SimpleExpression { static { diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java index 1a77fb69dfc..484018d699b 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java @@ -2,6 +2,11 @@ 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.Keywords; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.PropertyExpression; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; @@ -24,12 +29,27 @@ import java.util.TreeSet; import java.util.concurrent.ThreadLocalRandom; +@Name("Tags of X") +@Description({ + "Returns all the tags of an item, block, or entity.", + "`minecraft tag` will return only the vanilla tags, `datapack tag` will return only datapack-provided tags, " + + "`paper tag` will return only Paper's custom tags (if you are running Paper), " + + "and `custom tag` will look in the \"skript\" namespace for custom tags you've registered.", + "You can also filter by tag types using \"item\", \"block\", or \"entity\"." +}) +@Examples({ + "broadcast minecraft tags of dirt", + "send true if paper item tags of target block contains paper tag \"doors\"", + "broadcast player's tool's block tags" +}) +@Since("INSERT VERSION") +@Keywords({"blocks", "minecraft tag", "type", "category"}) public class ExprTagsOf extends PropertyExpression { static { Skript.registerExpression(ExprTagsOf.class, Tag.class, ExpressionType.PROPERTY, "[all [[of] the]] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags of %itemtype/entity/entitydata%", - "%itemtype/entity/entitydata%'[s] [:minecraft|:paper|:custom] tags"); + "%itemtype/entity/entitydata%'[s] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags"); } int type; @@ -71,7 +91,13 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is .toArray(Tag[]::new); } - public Collection> getTags(T value) { + /** + * Helper method for getting the tags of a value. + * @param value The value to get the tags of. + * @return The tags the value is a part of. + * @param The type of the value. + */ + public Collection> getTags(@NotNull T value) { List> tags = new ArrayList<>(); //noinspection unchecked Class clazz = (Class) value.getClass(); diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java index f2ebd134389..4d725cda7fe 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java @@ -1,6 +1,11 @@ package org.skriptlang.skript.bukkit.tags.elements; import ch.njol.skript.Skript; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Keywords; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.SkriptParser.ParseResult; @@ -18,6 +23,21 @@ import java.util.Set; import java.util.TreeSet; +@Name("All Tags of a Type") +@Description({ + "Returns all the tags.", + "`minecraft tag` will return only the vanilla tags, `datapack tag` will return only datapack-provided tags, " + + "`paper tag` will return only Paper's custom tags (if you are running Paper), " + + "and `custom tag` will look in the \"skript\" namespace for custom tags you've registered.", + "You can also filter by tag types using \"item\", \"block\", or \"entity\"." +}) +@Examples({ + "broadcast minecraft tags", + "send paper entity tags", + "broadcast all block tags" +}) +@Since("INSERT VERSION") +@Keywords({"blocks", "minecraft tag", "type", "category"}) public class ExprTagsOfType extends SimpleExpression { static { diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java index 02dd0430ae7..8b09a3fe3c3 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java @@ -8,10 +8,18 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.tags.TagType; +/** + * A set of tags provided by Bukkit. + * @param The class of the tags of this source. + */ public class BukkitTagSource extends TagSource { private final String registry; + /** + * @param registry The name of the registry to use. For example, {@link Tag#REGISTRY_ITEMS}. + * @param type The type of tag this represents. To continue the example, {@link TagType#ITEMS}. + */ public BukkitTagSource(String registry, TagType type) { super(TagOrigin.BUKKIT, type); this.registry = registry; diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java index cb0462b646d..4900ba06516 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java @@ -11,10 +11,19 @@ import java.util.HashMap; import java.util.Map; +/** + * A custom source of tags that stores its own tags. + * @param The class of the tags provided by this source. + */ public class CustomTagSource extends TagSource { final Map> tags; + /** + * @param origin The origin of this source. + * @param tags The tags this source will own. + * @param types The tag types this source will represent. + */ @SafeVarargs public CustomTagSource(TagOrigin origin, @NotNull Iterable> tags, TagType... types) { super(origin, types); diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java index 88cd0c91e0c..ebab102bf83 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java @@ -10,8 +10,18 @@ import java.util.List; import java.util.Set; +/** + * A set of tags provided by Paper. + * @param The class of tag this source provides. + */ public class PaperTagSource extends CustomTagSource { + /** + * Creates {@link PaperTag}s from the raw tags. Removes _settag. + * @param tags The raw tags provided by Paper. + * @return The modified tags with _settag removed from their keys. + * @param The class of the tags. + */ private static @NotNull Iterable> getPaperTags(@NotNull Iterable> tags) { List> modified_tags = new ArrayList<>(); for (Tag tag : tags) { @@ -20,6 +30,10 @@ public class PaperTagSource extends CustomTagSource { return modified_tags; } + /** + * @param tags The raw tags from Paper. + * @param types The tag types this source represents. + */ @SafeVarargs public PaperTagSource(Iterable> tags, TagType... types) { super(TagOrigin.PAPER, getPaperTags(tags), types); @@ -27,7 +41,7 @@ public PaperTagSource(Iterable> tags, TagType... types) { /** * Wrapper for Paper tags to remove "_settag" from their key. - * @param + * @param The class of the tag. */ private static class PaperTag implements Tag { diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java index 6d9406b0ef9..7f4a51d8444 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java @@ -1,21 +1,47 @@ package org.skriptlang.skript.bukkit.tags.sources; +import org.bukkit.event.Event; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import java.util.List; public enum TagOrigin { + /** + * Bukkit supplies both native minecraft tags and datapack tags. + */ BUKKIT, + /** + * Paper supplies a set of custom tags they curate. + */ PAPER, + /** + * Custom tags registered via Skript. + */ SKRIPT, + /** + * Used when asking for tags, matches all origins. + */ ANY; + /** + * Returns an optional choice of all the origins (minecraft, datapack, paper, and custom). + * Contains parse tags. + * @see #fromParseTags(List) + */ @Contract(pure = true) public static @NotNull String getFullPattern() { return "[:minecraft|:datapack|:paper|:custom]"; } + /** + * Determines the origin of tags based on the parse tags provided. + * + * @param tags the list of tags to parse for determining the origin. + * @return the determined {@code TagOrigin}. + * Returns {@code TagOrigin.ANY} if no specific origin is found. + * @see #getFullPattern() + */ @Contract(value = "_ -> new", pure = true) public static TagOrigin fromParseTags(@NotNull List tags) { TagOrigin origin = TagOrigin.ANY; @@ -29,10 +55,22 @@ public static TagOrigin fromParseTags(@NotNull List tags) { return origin; } + /** + * Checks if the current TagOrigin matches another TagOrigin, considering ANY as a wildcard. + * + * @param other The other TagOrigin to be matched against. + * @return {@code true} if the TagOrigins match (i.e., they are the same, or either is {@link #ANY}). + */ public boolean matches(TagOrigin other) { return this == other || this == ANY || other == ANY; } + /** + * Returns a string for use in {@link ch.njol.skript.lang.Debuggable#toString(Event, boolean)} methods. + * Includes a trailing space. + * @param datapackOnly Whether to output "datapack " or "minecraft " for {@link #BUKKIT}. + * @return a string representing the origin, with a trailing space. + */ @Contract(pure = true) public @NotNull String toString(boolean datapackOnly) { return switch (this) { diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagSource.java index 8485d09176b..ec933de34d6 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagSource.java @@ -22,6 +22,10 @@ public abstract class TagSource { private final TagType[] types; private final TagOrigin origin; + /** + * @param origin The origin of this source. + * @param types The tag types this source represents. + */ @SafeVarargs protected TagSource(TagOrigin origin, TagType... types) { this.types = types; @@ -33,6 +37,11 @@ protected TagSource(TagOrigin origin, TagType... types) { */ public abstract Iterable> getAllTags(); + /** + * For use in getting specific subsets of tags. + * @param predicate A Predicate used to filter tags. + * @return All the tags from this source, filtered based on the predicate. + */ public Iterable> getAllTagsMatching(Predicate> predicate) { Iterator> tagIterator = getAllTags().iterator(); return new Iterable<>() { @@ -43,12 +52,23 @@ public Iterable> getAllTagsMatching(Predicate> predicate) { }; } + /** + * Gets a specific tag by the key. + * @param key The key to use to find the tag. + * @return The tag associated with the key. Null if no such tag exists. + */ public abstract @Nullable Tag getTag(NamespacedKey key); + /** + * @return All the tag types that are represented by this source. + */ public TagType[] getTypes() { return types; } + /** + * @return The origin of this source. + */ public TagOrigin getOrigin() { return origin; } From 9b8719854127eea37a67665058db129585dde8c9 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 3 Oct 2024 21:21:06 -0400 Subject: [PATCH 10/21] gatekeep gaslight girlboss the paper tags --- .../org/skriptlang/skript/bukkit/tags/elements/ExprTag.java | 2 ++ .../skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java | 2 ++ .../skript/bukkit/tags/elements/ExprTagsOfType.java | 2 ++ .../skriptlang/skript/bukkit/tags/sources/TagOrigin.java | 6 +++++- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java index e5df94d2770..47be17da57e 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java @@ -5,6 +5,7 @@ import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Keywords; import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; @@ -43,6 +44,7 @@ "tag \"minecraft:mineable/pickaxe\" # minecraft:mineable/pickaxe", }) @Since("INSERT VERSION") +@RequiredPlugins("Paper (paper tags)") @Keywords({"blocks", "minecraft tag", "type", "category"}) public class ExprTag extends SimpleExpression { diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java index 484018d699b..42eee827dfd 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java @@ -6,6 +6,7 @@ import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Keywords; import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.PropertyExpression; import ch.njol.skript.lang.Expression; @@ -43,6 +44,7 @@ "broadcast player's tool's block tags" }) @Since("INSERT VERSION") +@RequiredPlugins("Paper (paper tags)") @Keywords({"blocks", "minecraft tag", "type", "category"}) public class ExprTagsOf extends PropertyExpression { diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java index 4d725cda7fe..afcd9a5f532 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java @@ -5,6 +5,7 @@ import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Keywords; import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.RequiredPlugins; import ch.njol.skript.doc.Since; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.ExpressionType; @@ -37,6 +38,7 @@ "broadcast all block tags" }) @Since("INSERT VERSION") +@RequiredPlugins("Paper (paper tags)") @Keywords({"blocks", "minecraft tag", "type", "category"}) public class ExprTagsOfType extends SimpleExpression { diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java index 7f4a51d8444..b2f76014b5c 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java @@ -3,6 +3,7 @@ import org.bukkit.event.Event; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import org.skriptlang.skript.bukkit.tags.TagModule; import java.util.List; @@ -26,12 +27,15 @@ public enum TagOrigin { /** * Returns an optional choice of all the origins (minecraft, datapack, paper, and custom). + * Will not include paper on non-paper servers. * Contains parse tags. * @see #fromParseTags(List) */ @Contract(pure = true) public static @NotNull String getFullPattern() { - return "[:minecraft|:datapack|:paper|:custom]"; + if (TagModule.PAPER_TAGS_EXIST) + return "[:minecraft|:datapack|:paper|:custom]"; + return "[:minecraft|:datapack|:custom]"; } /** From fcf4c88db1ffd0b97a2f082bc729eaf001c371b1 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 3 Oct 2024 21:34:02 -0400 Subject: [PATCH 11/21] basic tests and fix comparisons Tests are kept deliberately small due to the volatile nature of tag contents. --- .../java/org/skriptlang/skript/bukkit/tags/TagModule.java | 5 +++++ .../skript/tests/syntaxes/expressions/ExprTagContents.sk | 7 +++++++ src/test/skript/tests/syntaxes/expressions/ExprTagsOf.sk | 7 +++++++ .../skript/tests/syntaxes/expressions/ExprTagsOfType.sk | 7 +++++++ 4 files changed, 26 insertions(+) create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprTagContents.sk create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprTagsOf.sk create mode 100644 src/test/skript/tests/syntaxes/expressions/ExprTagsOfType.sk diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java index 9b9bd5661ef..c0113cd8044 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java @@ -17,6 +17,8 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.lang.comparator.Comparators; +import org.skriptlang.skript.lang.comparator.Relation; import java.io.IOException; @@ -59,6 +61,9 @@ public String toVariableNameString(Tag tag) { } })); + // compare tags by keys, not by object instance. + Comparators.registerComparator(Tag.class, Tag.class, (a, b) -> Relation.get(a.getKey().equals(b.getKey()))); + // init tags TAGS = new Tags(); } diff --git a/src/test/skript/tests/syntaxes/expressions/ExprTagContents.sk b/src/test/skript/tests/syntaxes/expressions/ExprTagContents.sk new file mode 100644 index 00000000000..312c545e40c --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprTagContents.sk @@ -0,0 +1,7 @@ +test "tags contents": + assert tag contents of tag "dirt" contains dirt with "dirt isn't dirt" + + assert tag contents of block tag "slabs" contains oak slab with "oak slab is not a slab" + assert tag contents of item tag "slabs" contains oak slab with "oak slab is not a slab" + + assert tag contents of entity tag "minecraft:skeletons" contains a skeleton with "skeleton is not a skeleton" diff --git a/src/test/skript/tests/syntaxes/expressions/ExprTagsOf.sk b/src/test/skript/tests/syntaxes/expressions/ExprTagsOf.sk new file mode 100644 index 00000000000..370e6e14743 --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprTagsOf.sk @@ -0,0 +1,7 @@ +test "tags of": + assert tags of dirt contains tag "dirt" with "dirt isn't dirt" + + assert block tags of oak slab contain block tag "slabs" with "oak slab is not a slab" + assert item tags of oak slab contain item tag "slabs" with "oak slab is not a slab" + + assert tags of a skeleton contain entity tag "minecraft:skeletons" with "skeleton is not a skeleton" diff --git a/src/test/skript/tests/syntaxes/expressions/ExprTagsOfType.sk b/src/test/skript/tests/syntaxes/expressions/ExprTagsOfType.sk new file mode 100644 index 00000000000..2469bbb029c --- /dev/null +++ b/src/test/skript/tests/syntaxes/expressions/ExprTagsOfType.sk @@ -0,0 +1,7 @@ +test "all tags": + assert all tags contains tag "dirt" with "dirt isn't a tag" + + assert block tags contain block tag "slabs" with "oak slab is not a block tag" + assert paper item tags contain item tag "paper:doors" with "paper:doors is not an paper item tag" + + assert minecraft entity tags contain entity tag "minecraft:skeletons" with "skeletons is not a tag" From c19703e57868fd0c6f48ec03e166e0a8bc3d7f81 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Thu, 3 Oct 2024 22:54:37 -0400 Subject: [PATCH 12/21] custom tags! --- .../skript/bukkit/tags/SkriptTag.java | 38 +++++ .../skript/bukkit/tags/TagType.java | 58 ++++++- .../skriptlang/skript/bukkit/tags/Tags.java | 5 + .../bukkit/tags/elements/EffRegisterTag.java | 158 ++++++++++++++++++ .../skript/bukkit/tags/elements/ExprTag.java | 2 +- .../bukkit/tags/elements/ExprTagsOf.java | 2 +- .../bukkit/tags/elements/ExprTagsOfType.java | 2 +- .../bukkit/tags/sources/SkriptTagSource.java | 27 +++ .../tests/syntaxes/effects/EffRegisterTag.sk | 7 + 9 files changed, 290 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/SkriptTag.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java create mode 100644 src/test/skript/tests/syntaxes/effects/EffRegisterTag.sk diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/SkriptTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/SkriptTag.java new file mode 100644 index 00000000000..35fcad143f9 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/SkriptTag.java @@ -0,0 +1,38 @@ +package org.skriptlang.skript.bukkit.tags; + +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.UnmodifiableView; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class SkriptTag implements Tag { + + private final Set contents; + private final NamespacedKey key; + + public SkriptTag(NamespacedKey key, Collection contents) { + this.contents = new HashSet<>(contents); + this.key = key; + } + + @Override + public boolean isTagged(@NotNull T item) { + return contents.contains(item); + } + + @Override + public @NotNull @UnmodifiableView Set getValues() { + return Collections.unmodifiableSet(contents); + } + + @Override + public @NotNull NamespacedKey getKey() { + return key; + } +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java index 2a7014fecce..ea1a18606e2 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java @@ -21,22 +21,58 @@ *
* This class also contains a static registry of all tag types. * - * @param pattern The pattern to use when construction the selection Skript pattern. - * @param type The class this tag type applies to. * @param see type. */ -public record TagType(String pattern, Class type) { +public class TagType { private static final List> REGISTERED_TAG_TYPES = new ArrayList<>(); public static final TagType ITEMS = new TagType<>("item", Material.class); public static final TagType BLOCKS = new TagType<>("block", Material.class); - public static final TagType ENTITIES = new TagType<>("entity [type]", EntityType.class); + public static final TagType ENTITIES = new TagType<>("entity [type]", "entity type", EntityType.class); static { TagType.addType(ITEMS, BLOCKS, ENTITIES); } + private final String pattern; + private final String toString; + private final Class type; + + /** + * @param pattern The pattern to use when construction the selection Skript pattern. + * @param type The class this tag type applies to. + */ + public TagType(String pattern, Class type) { + this.pattern = pattern; + this.type = type; + this.toString = pattern; + } + + /** + * @param pattern The pattern to use when construction the selection Skript pattern. + * @param toString The string to use when printing a toString. + * @param type The class this tag type applies to. + */ + public TagType(String pattern, String toString, Class type) { + this.pattern = pattern; + this.type = type; + this.toString = toString; + } + + public String pattern() { + return pattern; + } + + public Class type() { + return type; + } + + @Override + public String toString() { + return toString; + } + /** * Adds types to the registered tag types. * @param type The types to add. @@ -71,14 +107,24 @@ private static void addType(TagType... type) { * {@link ch.njol.skript.lang.SyntaxElement#init(Expression[], int, Kleenean, SkriptParser.ParseResult)}. */ public static @NotNull String getFullPattern() { - StringBuilder fullPattern = new StringBuilder("["); + return getFullPattern(false); + } + /** + * @param required whether the choice should be optional or required. + * @return Returns a choice pattern for use in Skript patterns. Contains parse marks. + * Subtract 1 from the parse mark and pass the value to {@link #getType(int)} to get the + * selected tag type in + * {@link ch.njol.skript.lang.SyntaxElement#init(Expression[], int, Kleenean, SkriptParser.ParseResult)}. + */ + public static @NotNull String getFullPattern(boolean required) { + StringBuilder fullPattern = new StringBuilder(required ? "(" : "["); int numRegistries = REGISTERED_TAG_TYPES.size(); for (int i = 0; i < numRegistries; i++) { fullPattern.append(i + 1).append(":").append(REGISTERED_TAG_TYPES.get(i).pattern()); if (i + 1 != numRegistries) fullPattern.append("|"); } - fullPattern.append("]"); + fullPattern.append(required ? ")" : "]"); return fullPattern.toString(); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java b/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java index 13f1bfb0581..6acfc871421 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java @@ -14,6 +14,7 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.tags.sources.BukkitTagSource; import org.skriptlang.skript.bukkit.tags.sources.PaperTagSource; +import org.skriptlang.skript.bukkit.tags.sources.SkriptTagSource; import org.skriptlang.skript.bukkit.tags.sources.TagOrigin; import org.skriptlang.skript.bukkit.tags.sources.TagSource; @@ -60,6 +61,10 @@ public Tags() { tagSourceMap.put(TagType.ENTITIES, paperEntityTags); } catch (IllegalAccessException ignored) {} } + + tagSourceMap.put(TagType.ITEMS, SkriptTagSource.ITEMS); + tagSourceMap.put(TagType.BLOCKS, SkriptTagSource.BLOCKS); + tagSourceMap.put(TagType.ENTITIES, SkriptTagSource.ENTITIES); } /** diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java new file mode 100644 index 00000000000..55496945e00 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java @@ -0,0 +1,158 @@ +package org.skriptlang.skript.bukkit.tags.elements; + +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.Keywords; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; +import ch.njol.skript.lang.Effect; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptParser; +import ch.njol.util.Kleenean; +import org.bukkit.Keyed; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; +import org.bukkit.entity.EntityType; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.tags.SkriptTag; +import org.skriptlang.skript.bukkit.tags.TagModule; +import org.skriptlang.skript.bukkit.tags.TagType; +import org.skriptlang.skript.bukkit.tags.sources.SkriptTagSource; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.regex.Pattern; + +@Name("Register Tag") +@Description({ + "Registers a new tag containing either items or entity datas. Note that items will NOT keep any information other " + + "than their type, so adding `diamond sword named \"test\"` to a tag is the same as adding `diamond sword`", + "Item tags should be used for contexts where the item is not placed down, while block tags should be used " + + "for contexts where the item is placed. For example, and item tag could be \"skript:edible\", " + + "while a block tag would be \"skript:needs_water_above\".", + "All custom tags will be given the namespace \"skript\", followed by the name you give it. The name must only " + + "include the characters A to Z, 0 to 9, and '/', '.', '_', and '-'. Otherwise, the tag will not register.", + "", + "Please note that two tags can share a name if they are of different types. Registering a new tag of the same " + + "name and type will overwrite the existing tag. Tags will reset on server shutdown." +}) +@Examples({ + "register a new custom entity tag named \"fish\" using cod, salmon, tropical fish, and pufferfish", + "register an item tag named \"skript:wasp_weapons/swords\" containing diamond sword and netherite sword", + "register block tag named \"pokey\" containing sweet berry bush and bamboo sapling", + "", + "on player move:", + "\tblock at player is tagged as tag \"skript:pokey\"", + "\tdamage the player by 1 heart" +}) +@Since("INSERT VERSION") +@Keywords({"blocks", "minecraft tag", "type", "category"}) +public class EffRegisterTag extends Effect { + + private static final Pattern KEY_PATTERN = Pattern.compile("[a-zA-Z0-9/._-]+"); + + static { + Skript.registerEffect(EffRegisterTag.class, + "register [a[n]] [new] [custom] " + TagType.getFullPattern(true) + + " tag named %string% (containing|using) %entitydatas/itemtypes%"); + } + + private Expression name; + private Expression contents; + TagType type; + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + //noinspection unchecked + name = (Expression) expressions[0]; + if (name instanceof Literal literal) { + String key = literal.getSingle(); + if (key.startsWith("skript:")) + key = key.substring(7); + if (!KEY_PATTERN.matcher(key).matches()) { + Skript.error("Tag names can only contain the following characters: 'a-z', '0-9', '/', '.', '_', and '-'."); + return false; + } + } + + contents = expressions[1]; + type = TagType.getType(parseResult.mark - 1)[0]; + return true; + } + + @Override + protected void execute(Event event) { + String name = this.name.getSingle(event); + if (name == null) + return; + + if (name.startsWith("skript:")) + name = name.substring(7); + + if (!KEY_PATTERN.matcher(name).matches()) + return; + + NamespacedKey key = new NamespacedKey(Skript.getInstance(), name); + + Object[] contents = this.contents.getArray(event); + if (contents.length == 0) + return; + + + if (this.type.type() == Material.class) { + Tag tag = getMaterialTag(key, contents); + if (this.type == TagType.ITEMS) { + SkriptTagSource.ITEMS.addTag(tag); + } else if (this.type == TagType.BLOCKS) { + SkriptTagSource.BLOCKS.addTag(tag); + } + + } else if (this.type.type() == EntityType.class) { + Tag tag = getEntityTag(key, contents); + SkriptTagSource.ENTITIES.addTag(tag); + } + } + + @Contract("_, _ -> new") + private @NotNull Tag getMaterialTag(NamespacedKey key, Object @NotNull [] contents) { + ThreadLocalRandom random = ThreadLocalRandom.current(); + List tagContents = new ArrayList<>(); + for (Object object : contents) { + Keyed[] values = TagModule.getKeyed(object); + if (object instanceof ItemType itemType && !itemType.isAll()) { + // add random + tagContents.add((Material) values[random.nextInt(0, values.length)]); + } else { + for (Keyed value : values) { + tagContents.add((Material) value); + } + } + } + return new SkriptTag<>(key, tagContents); + } + + @Contract("_, _ -> new") + private @NotNull Tag getEntityTag(NamespacedKey key, Object @NotNull [] contents) { + List tagContents = new ArrayList<>(); + for (Object object : contents) { + for (Keyed value : TagModule.getKeyed(object)) { + tagContents.add((EntityType) value); + } + } + return new SkriptTag<>(key, tagContents); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "register a new " + type.toString() + " tag named " + name.toString(event, debug) + " containing " + + contents.toString(event, debug); + } +} diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java index 47be17da57e..334ade33e79 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java @@ -118,7 +118,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { - String registry = type == -1 ? "" : TagType.getType(type)[0].pattern(); + String registry = type == -1 ? "" : TagType.getType(type)[0].toString(); return origin.toString(datapackOnly) + registry + "tag " + name.toString(event, debug); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java index 42eee827dfd..c334001cb53 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java @@ -122,7 +122,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { - String registry = type == -1 ? "" : TagType.getType(type)[0].pattern(); + String registry = type == -1 ? "" : TagType.getType(type)[0].toString(); //noinspection DataFlowIssue return origin.toString(datapackOnly) + registry + "tags of " + getExpr().toString(event, debug); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java index afcd9a5f532..72c10cde1d5 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java @@ -85,7 +85,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { - String registry = type == -1 ? "" : TagType.getType(type)[0].pattern(); + String registry = type == -1 ? "" : TagType.getType(type)[0].toString(); return "all of the " + origin.toString(datapackOnly) + registry + "tags"; } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java new file mode 100644 index 00000000000..16c3b1e4732 --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java @@ -0,0 +1,27 @@ +package org.skriptlang.skript.bukkit.tags.sources; + +import ch.njol.util.coll.iterator.EmptyIterable; +import org.bukkit.Keyed; +import org.bukkit.Material; +import org.bukkit.Tag; +import org.bukkit.entity.EntityType; +import org.skriptlang.skript.bukkit.tags.TagType; + +public class SkriptTagSource extends CustomTagSource { + + public static final SkriptTagSource ITEMS = new SkriptTagSource<>(TagType.ITEMS); + public static final SkriptTagSource BLOCKS = new SkriptTagSource<>(TagType.BLOCKS); + public static final SkriptTagSource ENTITIES = new SkriptTagSource<>(TagType.ENTITIES); + + /** + * @param types The tag types this source will represent. + */ + @SafeVarargs + public SkriptTagSource(TagType... types) { + super(TagOrigin.SKRIPT, new EmptyIterable<>(), types); + } + + public void addTag(Tag tag) { + tags.put(tag.getKey(), tag); + } +} diff --git a/src/test/skript/tests/syntaxes/effects/EffRegisterTag.sk b/src/test/skript/tests/syntaxes/effects/EffRegisterTag.sk new file mode 100644 index 00000000000..d3cde7b75aa --- /dev/null +++ b/src/test/skript/tests/syntaxes/effects/EffRegisterTag.sk @@ -0,0 +1,7 @@ +test "register tags": + register a custom item tag named "oak" containing oak log, oak planks, and oak wood + assert custom tag "oak" is set with "tag was not registered" + assert tag contents of tag "skript:oak" contains oak wood, oak log, and oak planks with "tag doesn't contain the right items" + + register an entity type tag named "skript:little_guy" using a baby zombie + assert a baby zombie is tagged as custom tag "little_guy" with "failed to classify baby zombie as a little guy" From 593e5f45f22bfbb98f39e8a473b57e565ca8089e Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Fri, 4 Oct 2024 11:05:04 -0400 Subject: [PATCH 13/21] add ways to turn tag into a string --- .../skript/bukkit/tags/TagModule.java | 5 ++++ .../bukkit/tags/elements/ExprTagKey.java | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagKey.java diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java index c0113cd8044..71254e3d1fe 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java @@ -19,6 +19,8 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.lang.comparator.Comparators; import org.skriptlang.skript.lang.comparator.Relation; +import org.skriptlang.skript.lang.converter.Converter; +import org.skriptlang.skript.lang.converter.Converters; import java.io.IOException; @@ -64,6 +66,9 @@ public String toVariableNameString(Tag tag) { // compare tags by keys, not by object instance. Comparators.registerComparator(Tag.class, Tag.class, (a, b) -> Relation.get(a.getKey().equals(b.getKey()))); + // converter to String + Converters.registerConverter(Tag.class, String.class, tag -> tag.getKey().toString(), Converter.NO_LEFT_CHAINING); + // init tags TAGS = new Tags(); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagKey.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagKey.java new file mode 100644 index 00000000000..39ff1eed89e --- /dev/null +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagKey.java @@ -0,0 +1,29 @@ +package org.skriptlang.skript.bukkit.tags.elements; + +import ch.njol.skript.expressions.base.SimplePropertyExpression; +import org.bukkit.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ExprTagKey extends SimplePropertyExpression, String> { + + static { + register(ExprTagKey.class, String.class, "[namespace[d]] key", "minecrafttags"); + } + + @Override + public @Nullable String convert(@NotNull Tag from) { + return from.getKey().toString(); + } + + @Override + protected String getPropertyName() { + return "namespaced key"; + } + + @Override + public Class getReturnType() { + return String.class; + } + +} From fbb5e0d1cdc2b3bbcbe2412539d2d16f192103ff Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Fri, 4 Oct 2024 20:08:44 -0400 Subject: [PATCH 14/21] a few more examples --- .../org/skriptlang/skript/bukkit/tags/elements/ExprTag.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java index 334ade33e79..c088b7dd004 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java @@ -38,10 +38,11 @@ "minecraft tag \"dirt\" # minecraft:dirt", "paper tag \"doors\" # paper:doors", "tag \"skript:custom_dirt\" # skript:custom_dirt", - "skript tag \"dirt\" # skript:dirt", - "datapack tag \"dirt\" # minecraft:dirt", + "custom tag \"dirt\" # skript:dirt", + "datapack block tag \"dirt\" # minecraft:dirt", "datapack tag \"my_pack:custom_dirt\" # my_pack:custom_dirt", "tag \"minecraft:mineable/pickaxe\" # minecraft:mineable/pickaxe", + "custom item tag \"blood_magic/sacrificial\" # skript:blood_magic/sacrificial" }) @Since("INSERT VERSION") @RequiredPlugins("Paper (paper tags)") From a106964df286f23a061587d28884136987688dea Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Sat, 12 Oct 2024 18:49:52 -0400 Subject: [PATCH 15/21] requested changes --- src/main/java/ch/njol/util/Pair.java | 16 ++++++++-------- .../skript/bukkit/tags/SkriptTag.java | 1 + .../skript/bukkit/tags/TagType.java | 19 +++++++++++++++---- .../skriptlang/skript/bukkit/tags/Tags.java | 19 +++++++++++++------ .../bukkit/tags/elements/CondIsTagged.java | 2 +- .../bukkit/tags/elements/EffRegisterTag.java | 6 +++--- .../skript/bukkit/tags/elements/ExprTag.java | 15 +++++++-------- .../bukkit/tags/elements/ExprTagContents.java | 17 +++++++++++++++++ .../bukkit/tags/elements/ExprTagKey.java | 18 +++++++++++++++++- .../bukkit/tags/elements/ExprTagsOf.java | 12 ++++++------ .../bukkit/tags/elements/ExprTagsOfType.java | 9 ++++----- .../syntaxes/expressions/ExprTagsOfType.sk | 2 +- 12 files changed, 93 insertions(+), 43 deletions(-) diff --git a/src/main/java/ch/njol/util/Pair.java b/src/main/java/ch/njol/util/Pair.java index d3b79975861..58a4027c7a0 100644 --- a/src/main/java/ch/njol/util/Pair.java +++ b/src/main/java/ch/njol/util/Pair.java @@ -21,21 +21,21 @@ public Pair() { second = null; } - public Pair(final @Nullable T1 first, final @Nullable T2 second) { + public Pair(@Nullable T1 first, @Nullable T2 second) { this.first = first; this.second = second; } - public Pair(final @NotNull Entry e) { - this.first = e.getKey(); - this.second = e.getValue(); + public Pair(@NotNull Entry entry) { + this.first = entry.getKey(); + this.second = entry.getValue(); } public @UnknownNullability T1 getFirst() { return first; } - public void setFirst(final @Nullable T1 first) { + public void setFirst(@Nullable T1 first) { this.first = first; } @@ -43,7 +43,7 @@ public void setFirst(final @Nullable T1 first) { return second; } - public void setSecond(final @Nullable T2 second) { + public void setSecond(@Nullable T2 second) { this.second = second; } @@ -64,8 +64,8 @@ public final boolean equals(@Nullable Object obj) { return true; if (!(obj instanceof Entry entry)) return false; - final T1 first = this.first; - final T2 second = this.second; + T1 first = this.first; + T2 second = this.second; return (first == null ? entry.getKey() == null : first.equals(entry.getKey())) && (second == null ? entry.getValue() == null : second.equals(entry.getValue())); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/SkriptTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/SkriptTag.java index 35fcad143f9..c3014703b7b 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/SkriptTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/SkriptTag.java @@ -35,4 +35,5 @@ public boolean isTagged(@NotNull T item) { public @NotNull NamespacedKey getKey() { return key; } + } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java index ea1a18606e2..ba7ab961702 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java @@ -40,7 +40,7 @@ public class TagType { private final Class type; /** - * @param pattern The pattern to use when construction the selection Skript pattern. + * @param pattern The pattern to use when constructing the selection Skript pattern. * @param type The class this tag type applies to. */ public TagType(String pattern, Class type) { @@ -50,7 +50,7 @@ public TagType(String pattern, Class type) { } /** - * @param pattern The pattern to use when construction the selection Skript pattern. + * @param pattern The pattern to use when constructing the selection Skript pattern. * @param toString The string to use when printing a toString. * @param type The class this tag type applies to. */ @@ -100,9 +100,20 @@ private static void addType(TagType... type) { return new TagType[]{REGISTERED_TAG_TYPES.get(i)}; } + /** + * Gets tag types by parser mark. Equivalent to {@code getType(i - 1)}. + * @param i The index of the type to get. + * @return The type at that index, or all tags if index < 0. + * @see #getType(int) + * @see #getFullPattern() + */ + public static TagType @NotNull [] fromParseMark(int i) { + return getType(i - 1); + } + /** * @return Returns an optional choice pattern for use in Skript patterns. Contains parse marks. - * Subtract 1 from the parse mark and pass the value to {@link #getType(int)} to get the + * Pass the parse mark to {@link #fromParseMark(int)} to get the * selected tag type in * {@link ch.njol.skript.lang.SyntaxElement#init(Expression[], int, Kleenean, SkriptParser.ParseResult)}. */ @@ -112,7 +123,7 @@ private static void addType(TagType... type) { /** * @param required whether the choice should be optional or required. * @return Returns a choice pattern for use in Skript patterns. Contains parse marks. - * Subtract 1 from the parse mark and pass the value to {@link #getType(int)} to get the + * Pass the parse mark to {@link #fromParseMark(int)} to get the * selected tag type in * {@link ch.njol.skript.lang.SyntaxElement#init(Expression[], int, Kleenean, SkriptParser.ParseResult)}. */ diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java b/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java index 6acfc871421..cd2915e9206 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java @@ -71,15 +71,21 @@ public Tags() { * Gets all the tags of a specific origin that are applicable to a given class. * @param origin The origin to filter by. * @param typeClass The class the tags should be applicable to. - * @return Tags from the given origin that apply to the given class. + * @param types Tag types to check with. Leaving this empty will check all tag types. + * @return Tags from the given origin and types that apply to the given class. * @param see typeClass. */ - public Iterable> getTags(TagOrigin origin, Class typeClass) { + public Iterable> getTags(TagOrigin origin, Class typeClass, TagType... types) { List>> tagIterators = new ArrayList<>(); - for (TagType type : tagSourceMap.map.keys()) { - if (type.type() == typeClass) + if (types == null) + types = tagSourceMap.map.keys().toArray(new TagType[0]); + for (TagType type : types) { + if (type.type() == typeClass) { //noinspection unchecked - tagIterators.add(getTags(origin, (TagType) type).iterator()); + Iterator> iterator = getTags(origin, (TagType) type).iterator(); + if (iterator.hasNext()) + tagIterators.add(iterator); + } } return new Iterable<>() { @Override @@ -155,7 +161,7 @@ public Tag next() { * @return Tags from the given origin that are of the given type and that pass the filter. * @param The class these tags apply to. */ - public Iterable> getTagsMatching(TagOrigin origin, TagType type, Predicate> predicate) { + public Iterable> getMatchingTags(TagOrigin origin, TagType type, Predicate> predicate) { Iterator> tagIterator = getTags(origin, type).iterator(); return new Iterable<>() { @Override @@ -207,4 +213,5 @@ public boolean containsKey(TagType type) { return map.containsKey(type); } } + } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java index 524b19a89f9..a94836e1068 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java @@ -20,7 +20,7 @@ @Name("Is Tagged") @Description({ - "Checks whether an item, block, entity, or entitydata is tagged as the given tag." + "Checks whether an item, block, entity, or entitydata is tagged with the given tag." }) @Examples({ "if player's tool is tagged with minecraft tag \"enchantable/sharp_weapon\":", diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java index 55496945e00..def741052ea 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java @@ -10,7 +10,7 @@ import ch.njol.skript.lang.Effect; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.Literal; -import ch.njol.skript.lang.SkriptParser; +import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.util.Kleenean; import org.bukkit.Keyed; import org.bukkit.Material; @@ -67,10 +67,10 @@ public class EffRegisterTag extends Effect { private Expression name; private Expression contents; - TagType type; + private TagType type; @Override - public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) { + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { //noinspection unchecked name = (Expression) expressions[0]; if (name instanceof Literal literal) { diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java index c088b7dd004..345cee64013 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java @@ -42,7 +42,7 @@ "datapack block tag \"dirt\" # minecraft:dirt", "datapack tag \"my_pack:custom_dirt\" # my_pack:custom_dirt", "tag \"minecraft:mineable/pickaxe\" # minecraft:mineable/pickaxe", - "custom item tag \"blood_magic/sacrificial\" # skript:blood_magic/sacrificial" + "custom item tag \"blood_magic_sk/can_sacrifice_with\" # skript:blood_magic_sk/can_sacrifice_with" }) @Since("INSERT VERSION") @RequiredPlugins("Paper (paper tags)") @@ -54,16 +54,16 @@ public class ExprTag extends SimpleExpression { TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tag %string%"); } - Expression name; - int type; - TagOrigin origin; - boolean datapackOnly; + private Expression name; + TagType[] types; + private TagOrigin origin; + private boolean datapackOnly; @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { //noinspection unchecked name = (Expression) expressions[0]; - type = parseResult.mark - 1; + types = TagType.fromParseMark(parseResult.mark); origin = TagOrigin.fromParseTags(parseResult.tags); datapackOnly = origin == TagOrigin.BUKKIT && parseResult.hasTag("datapack"); return true; @@ -92,7 +92,6 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is return null; Tag tag; - TagType[] types = TagType.getType(type); for (TagType type : types) { tag = TagModule.TAGS.getTag(origin, type, key); if (tag != null @@ -119,7 +118,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { - String registry = type == -1 ? "" : TagType.getType(type)[0].toString(); + String registry = types.length > 1 ? "" : types[0].toString(); return origin.toString(datapackOnly) + registry + "tag " + name.toString(event, debug); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java index 61f2f92c48c..1a2a5fb103e 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java @@ -12,6 +12,7 @@ import ch.njol.skript.lang.ExpressionType; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.util.SimpleExpression; +import ch.njol.skript.util.Utils; import ch.njol.util.Kleenean; import org.bukkit.Material; import org.bukkit.Tag; @@ -19,6 +20,7 @@ import org.bukkit.event.Event; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.bukkit.tags.TagType; import java.util.Objects; @@ -43,11 +45,19 @@ public class ExprTagContents extends SimpleExpression { } private Expression> tag; + private TagType @Nullable [] tagTypes; @Override public boolean init(Expression @NotNull [] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { //noinspection unchecked tag = (Expression>) expressions[0]; + if (expressions[0] instanceof ExprTag exprTag) { + tagTypes = exprTag.types; + } else if (expressions[0] instanceof ExprTagsOf exprTagsOf) { + tagTypes = exprTagsOf.types; + } else if (expressions[0] instanceof ExprTagsOfType exprTagsOfType) { + tagTypes = exprTagsOfType.types; + } return true; } @@ -76,6 +86,13 @@ public boolean isSingle() { @Override public Class getReturnType() { + if (tagTypes != null) { + Class[] possibleTypes = new Class[tagTypes.length]; + for (int i = 0; i < tagTypes.length; i++) { + possibleTypes[i] = tagTypes[i].type(); + } + return Utils.getSuperType(possibleTypes); + } return Object.class; } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagKey.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagKey.java index 39ff1eed89e..1fda044bf25 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagKey.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagKey.java @@ -1,14 +1,30 @@ package org.skriptlang.skript.bukkit.tags.elements; +import ch.njol.skript.doc.Description; +import ch.njol.skript.doc.Examples; +import ch.njol.skript.doc.Keywords; +import ch.njol.skript.doc.Name; +import ch.njol.skript.doc.Since; import ch.njol.skript.expressions.base.SimplePropertyExpression; import org.bukkit.Tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +// TODO: adapt to generic expression after Any X is merged + +@Name("Tag Namespaced Key") +@Description("The namespaced key of a minecraft tag. This takes the form of \"namespace:key\", e.g. \"minecraft:dirt\".") +@Examples({ + "broadcast namespaced keys of the tags of player's tool", + "if the key of {_my-tag} is \"minecraft:stone\":", + "\treturn true" +}) +@Since("INSERT VERSION") +@Keywords({"minecraft tag", "type", "key", "namespace"}) public class ExprTagKey extends SimplePropertyExpression, String> { static { - register(ExprTagKey.class, String.class, "[namespace[d]] key", "minecrafttags"); + register(ExprTagKey.class, String.class, "[namespace[d]] key[s]", "minecrafttags"); } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java index c334001cb53..2e29dc81509 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java @@ -41,7 +41,7 @@ @Examples({ "broadcast minecraft tags of dirt", "send true if paper item tags of target block contains paper tag \"doors\"", - "broadcast player's tool's block tags" + "broadcast the block tags of player's tool" }) @Since("INSERT VERSION") @RequiredPlugins("Paper (paper tags)") @@ -50,18 +50,18 @@ public class ExprTagsOf extends PropertyExpression { static { Skript.registerExpression(ExprTagsOf.class, Tag.class, ExpressionType.PROPERTY, - "[all [[of] the]] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags of %itemtype/entity/entitydata%", + "[all [of]] [the] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags of %itemtype/entity/entitydata%", "%itemtype/entity/entitydata%'[s] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags"); } - int type; + TagType[] types; TagOrigin origin; boolean datapackOnly; @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { this.setExpr(expressions[0]); - type = parseResult.mark - 1; + types = TagType.fromParseMark(parseResult.mark); origin = TagOrigin.fromParseTags(parseResult.tags); datapackOnly = origin == TagOrigin.BUKKIT && parseResult.hasTag("datapack"); return true; @@ -103,7 +103,7 @@ public Collection> getTags(@NotNull T value) { List> tags = new ArrayList<>(); //noinspection unchecked Class clazz = (Class) value.getClass(); - for (Tag tag : TagModule.TAGS.getTags(origin, clazz)) { + for (Tag tag : TagModule.TAGS.getTags(origin, clazz, types)) { if (tag.isTagged(value)) tags.add(tag); } @@ -122,7 +122,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { - String registry = type == -1 ? "" : TagType.getType(type)[0].toString(); + String registry = types.length > 1 ? "" : types[0].toString(); //noinspection DataFlowIssue return origin.toString(datapackOnly) + registry + "tags of " + getExpr().toString(event, debug); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java index 72c10cde1d5..19abb5dcb62 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java @@ -47,13 +47,13 @@ public class ExprTagsOfType extends SimpleExpression { "[all [[of] the]] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags"); } - int type; + TagType[] types; TagOrigin origin; boolean datapackOnly; @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { - type = parseResult.mark - 1; + types = TagType.fromParseMark(parseResult.mark); origin = TagOrigin.fromParseTags(parseResult.tags); datapackOnly = origin == TagOrigin.BUKKIT && parseResult.hasTag("datapack"); return true; @@ -61,10 +61,9 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is @Override protected Tag @Nullable [] get(Event event) { - TagType[] types = TagType.getType(type); Set> tags = new TreeSet<>(Comparator.comparing(Keyed::key)); for (TagType type : types) { - for (Tag tag : TagModule.TAGS.getTagsMatching(origin, type, + for (Tag tag : TagModule.TAGS.getMatchingTags(origin, type, tag -> (origin != TagOrigin.BUKKIT || (datapackOnly ^ tag.getKey().getNamespace().equals("minecraft")))) ) { tags.add(tag); @@ -85,7 +84,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { - String registry = type == -1 ? "" : TagType.getType(type)[0].toString(); + String registry = types.length > 1 ? "" : types[0].toString(); return "all of the " + origin.toString(datapackOnly) + registry + "tags"; } } diff --git a/src/test/skript/tests/syntaxes/expressions/ExprTagsOfType.sk b/src/test/skript/tests/syntaxes/expressions/ExprTagsOfType.sk index 2469bbb029c..8938b392c36 100644 --- a/src/test/skript/tests/syntaxes/expressions/ExprTagsOfType.sk +++ b/src/test/skript/tests/syntaxes/expressions/ExprTagsOfType.sk @@ -1,7 +1,7 @@ test "all tags": assert all tags contains tag "dirt" with "dirt isn't a tag" - assert block tags contain block tag "slabs" with "oak slab is not a block tag" + assert block tags contain block tag "slabs" with "slabs is not a block tag" assert paper item tags contain item tag "paper:doors" with "paper:doors is not an paper item tag" assert minecraft entity tags contain entity tag "minecraft:skeletons" with "skeletons is not a tag" From f1203b2e0edfb19c2c3deda4114424fd2265b3af Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Sun, 10 Nov 2024 11:22:44 -0500 Subject: [PATCH 16/21] plural exprtags and parity between tag toString and toVariableString --- .../skript/bukkit/tags/TagModule.java | 4 +- .../skript/bukkit/tags/elements/ExprTag.java | 75 ++++++++++--------- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java index 71254e3d1fe..6cbfd9d1e9b 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java @@ -54,12 +54,12 @@ public boolean canParse(ParseContext context) { @Override public String toString(Tag tag, int flags) { - return "tag \"" + tag.getKey() + "\""; + return "tag " + tag.getKey(); } @Override public String toVariableNameString(Tag tag) { - return "tag: " + tag.getKey(); + return toString(tag, 0); } })); diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java index 345cee64013..5ffeca029a5 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java @@ -22,6 +22,9 @@ import org.skriptlang.skript.bukkit.tags.TagType; import org.skriptlang.skript.bukkit.tags.sources.TagOrigin; +import java.util.ArrayList; +import java.util.List; + @Name("Tag") @Description({ "Represents a tag which can be used to classify items, blocks, or entities.", @@ -30,7 +33,7 @@ "For example, `tag \"doors\"` will be the tag \"minecraft:doors\", " + "while `paper tag \"doors\"` will be \"paper:doors\".", "`minecraft tag` will search through the vanilla tags, `datapack tag` will search for datapack-provided tags " + - "(a namespace is required here!), `paper tag` will search for Paper's custom tags if you are running Paper, " + + "(a namespace is required here!), `paper tag` will search for Paper's custom tags if you are running Paper, " + "and `custom tag` will look in the \"skript\" namespace for custom tags you've registered.", "You can also filter by tag types using \"item\", \"block\", or \"entity\"." }) @@ -51,10 +54,10 @@ public class ExprTag extends SimpleExpression { static { Skript.registerExpression(ExprTag.class, Tag.class, ExpressionType.COMBINED, - TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tag %string%"); + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tag %strings%"); } - private Expression name; + private Expression names; TagType[] types; private TagOrigin origin; private boolean datapackOnly; @@ -62,7 +65,7 @@ public class ExprTag extends SimpleExpression { @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { //noinspection unchecked - name = (Expression) expressions[0]; + names = (Expression) expressions[0]; types = TagType.fromParseMark(parseResult.mark); origin = TagOrigin.fromParseTags(parseResult.tags); datapackOnly = origin == TagOrigin.BUKKIT && parseResult.hasTag("datapack"); @@ -71,43 +74,45 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is @Override protected Tag @Nullable [] get(Event event) { - String name = this.name.getSingle(event); - if (name == null) - return null; + String[] names = this.names.getArray(event); + List> tags = new ArrayList<>(); - // get key - NamespacedKey key; - if (name.contains(":")) { - key = NamespacedKey.fromString(name); - } else { - // populate namespace if not provided - String namespace = switch (origin) { - case ANY, BUKKIT -> "minecraft"; - case PAPER -> "paper"; - case SKRIPT -> "skript"; - }; - key = new NamespacedKey(namespace, name); - } - if (key == null) - return null; + String namespace = switch (origin) { + case ANY, BUKKIT -> "minecraft"; + case PAPER -> "paper"; + case SKRIPT -> "skript"; + }; - Tag tag; - for (TagType type : types) { - tag = TagModule.TAGS.getTag(origin, type, key); - if (tag != null - // ensures that only datapack/minecraft tags are sent when specifically requested - && (origin != TagOrigin.BUKKIT || (datapackOnly ^ tag.getKey().getNamespace().equals("minecraft"))) - ) { - return new Tag[]{tag}; + nextName: for (String name : names) { + // get key + NamespacedKey key; + if (name.contains(":")) { + key = NamespacedKey.fromString(name); + } else { + // populate namespace if not provided + key = new NamespacedKey(namespace, name); } - } + if (key == null) + continue; - return null; + Tag tag; + for (TagType type : types) { + tag = TagModule.TAGS.getTag(origin, type, key); + if (tag != null + // ensures that only datapack/minecraft tags are sent when specifically requested + && (origin != TagOrigin.BUKKIT || (datapackOnly ^ tag.getKey().getNamespace().equals("minecraft"))) + ) { + tags.add(tag); + continue nextName; // ensure 1:1 + } + } + } + return tags.toArray(new Tag[0]); } @Override public boolean isSingle() { - return true; + return names.isSingle(); } @Override @@ -119,12 +124,12 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { String registry = types.length > 1 ? "" : types[0].toString(); - return origin.toString(datapackOnly) + registry + "tag " + name.toString(event, debug); + return origin.toString(datapackOnly) + registry + "tag " + names.toString(event, debug); } @Override public Expression simplify() { - if (name instanceof Literal) + if (names instanceof Literal) return new SimpleLiteral<>(getArray(null), Tag.class, true); return this; } From cd6e6997f2669c9472dfb3024deb23bd40a2a187 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Sun, 15 Dec 2024 02:38:05 -0500 Subject: [PATCH 17/21] Fix over-zealous refactor --- .../skript/bukkit/tags/SkriptTag.java | 7 ++++- .../skript/bukkit/tags/TagModule.java | 14 ++++----- .../tags/{Tags.java => TagRegistry.java} | 29 ++++++------------- .../skript/bukkit/tags/TagType.java | 7 ++--- .../bukkit/tags/elements/CondIsTagged.java | 4 +-- .../bukkit/tags/elements/EffRegisterTag.java | 22 +++++++++----- .../skript/bukkit/tags/elements/ExprTag.java | 2 +- .../bukkit/tags/elements/ExprTagsOf.java | 5 ++-- .../bukkit/tags/elements/ExprTagsOfType.java | 5 ++-- .../bukkit/tags/sources/BukkitTagSource.java | 1 + .../bukkit/tags/sources/PaperTagSource.java | 6 ++-- .../bukkit/tags/sources/SkriptTagSource.java | 3 +- .../skript/bukkit/tags/sources/TagOrigin.java | 5 ++++ 13 files changed, 57 insertions(+), 53 deletions(-) rename src/main/java/org/skriptlang/skript/bukkit/tags/{Tags.java => TagRegistry.java} (88%) diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/SkriptTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/SkriptTag.java index c3014703b7b..e565d0a3304 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/SkriptTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/SkriptTag.java @@ -11,14 +11,19 @@ import java.util.HashSet; import java.util.Set; +/** + * Represents a custom tag created by the Skript user. + * Implementation of {@link Tag} with a custom set of contents. + * @param The type of the contents. + */ public class SkriptTag implements Tag { private final Set contents; private final NamespacedKey key; public SkriptTag(NamespacedKey key, Collection contents) { - this.contents = new HashSet<>(contents); this.key = key; + this.contents = new HashSet<>(contents); } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java index 6cbfd9d1e9b..54a0dc4cf61 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java @@ -19,8 +19,6 @@ import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.lang.comparator.Comparators; import org.skriptlang.skript.lang.comparator.Relation; -import org.skriptlang.skript.lang.converter.Converter; -import org.skriptlang.skript.lang.converter.Converters; import java.io.IOException; @@ -30,15 +28,13 @@ public class TagModule { public static final boolean PAPER_TAGS_EXIST = Skript.classExists("com.destroystokyo.paper.MaterialTags"); // tag object - public static Tags TAGS; + public static TagRegistry tagRegistry; public static void load() throws IOException { // abort if no class exists if (!Skript.classExists("org.bukkit.Tag")) return; - // load classes (todo: replace with registering methods after regitration api - Skript.getAddonInstance().loadClasses("org.skriptlang.skript.bukkit", "tags"); // Classes Classes.registerClass(new ClassInfo<>(Tag.class, "minecrafttag") @@ -63,14 +59,14 @@ public String toVariableNameString(Tag tag) { } })); + // load classes (todo: replace with registering methods after registration api + Skript.getAddonInstance().loadClasses("org.skriptlang.skript.bukkit", "tags"); + // compare tags by keys, not by object instance. Comparators.registerComparator(Tag.class, Tag.class, (a, b) -> Relation.get(a.getKey().equals(b.getKey()))); - // converter to String - Converters.registerConverter(Tag.class, String.class, tag -> tag.getKey().toString(), Converter.NO_LEFT_CHAINING); - // init tags - TAGS = new Tags(); + tagRegistry = new TagRegistry(); } /** diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagRegistry.java similarity index 88% rename from src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java rename to src/main/java/org/skriptlang/skript/bukkit/tags/TagRegistry.java index cd2915e9206..617f8abc834 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/Tags.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagRegistry.java @@ -27,14 +27,14 @@ /** * A class in charge of storing and handling all the tags Skript can access. */ -public class Tags { +public class TagRegistry { private final TagSourceMap tagSourceMap = new TagSourceMap(); /** * Each new instance will create a new set of tag sources, in an effort to be reload safe. */ - public Tags() { + TagRegistry() { tagSourceMap.put(TagType.ITEMS, new BukkitTagSource<>("items", TagType.ITEMS)); tagSourceMap.put(TagType.BLOCKS, new BukkitTagSource<>("blocks", TagType.BLOCKS)); tagSourceMap.put(TagType.ENTITIES, new BukkitTagSource<>("entity_types", TagType.ENTITIES)); @@ -72,7 +72,7 @@ public Tags() { * @param origin The origin to filter by. * @param typeClass The class the tags should be applicable to. * @param types Tag types to check with. Leaving this empty will check all tag types. - * @return Tags from the given origin and types that apply to the given class. + * @return TagRegistry from the given origin and types that apply to the given class. * @param see typeClass. */ public Iterable> getTags(TagOrigin origin, Class typeClass, TagType... types) { @@ -80,7 +80,7 @@ public Iterable> getTags(TagOrigin origin, Class typ if (types == null) types = tagSourceMap.map.keys().toArray(new TagType[0]); for (TagType type : types) { - if (type.type() == typeClass) { + if (typeClass.isAssignableFrom(type.type())) { //noinspection unchecked Iterator> iterator = getTags(origin, (TagType) type).iterator(); if (iterator.hasNext()) @@ -99,7 +99,7 @@ public Iterable> getTags(TagOrigin origin, Class typ * Gets all the tags of a specific origin that are of a specific type. * @param origin The origin to filter by. * @param type The type of tags to get. - * @return Tags from the given origin that are of the given type. + * @return TagRegistry from the given origin that are of the given type. * @param The class these tags apply to. */ public Iterable> getTags(TagOrigin origin, TagType type) { @@ -114,21 +114,16 @@ public Iterable> getTags(TagOrigin origin, TagType t return new Iterator<>() { // private Iterator> currentTagIter = tagSources.next().getAllTags().iterator(); - private Iterator> nextTagIter; @Override public boolean hasNext() { // does the current source have more tags if (currentTagIter.hasNext()) return true; - // is there another source in the pipeline? if so, check it. - if (nextTagIter != null) - return nextTagIter.hasNext(); - // if there's no known next source, check if have one. - // if we do, mark it as the next source. + // if we have another tag source, mark it as the next source. if (tagSources.hasNext()) { - nextTagIter = tagSources.next().getAllTags().iterator(); - return nextTagIter.hasNext(); + currentTagIter = tagSources.next().getAllTags().iterator(); + return currentTagIter.hasNext(); } return false; } @@ -138,12 +133,6 @@ public Tag next() { // if current source has more, get more. if (currentTagIter.hasNext()) return currentTagIter.next(); - // if current source is dry, switch to using the next source - if (nextTagIter != null && nextTagIter.hasNext()) { - currentTagIter = nextTagIter; - nextTagIter = null; - return currentTagIter.next(); - } throw new IllegalStateException("Called next without calling hasNext to set the next tag iterator."); } // @@ -158,7 +147,7 @@ public Tag next() { * @param origin The origin to filter by. * @param type The type of tags to get. * @param predicate A predicate to filter the tags with. - * @return Tags from the given origin that are of the given type and that pass the filter. + * @return TagRegistry from the given origin that are of the given type and that pass the filter. * @param The class these tags apply to. */ public Iterable> getMatchingTags(TagOrigin origin, TagType type, Predicate> predicate) { diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java index ba7ab961702..6446250a3ef 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java @@ -44,9 +44,7 @@ public class TagType { * @param type The class this tag type applies to. */ public TagType(String pattern, Class type) { - this.pattern = pattern; - this.type = type; - this.toString = pattern; + this(pattern, pattern, type); } /** @@ -77,7 +75,7 @@ public String toString() { * Adds types to the registered tag types. * @param type The types to add. */ - private static void addType(TagType... type) { + public static void addType(TagType... type) { REGISTERED_TAG_TYPES.addAll(List.of(type)); } @@ -120,6 +118,7 @@ private static void addType(TagType... type) { public static @NotNull String getFullPattern() { return getFullPattern(false); } + /** * @param required whether the choice should be optional or required. * @return Returns a choice pattern for use in Skript patterns. Contains parse marks. diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java index a94836e1068..5553c27076a 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java @@ -59,8 +59,8 @@ public boolean check(Event event) { return elements.check(event, element -> { boolean isAny = (element instanceof ItemType itemType && !itemType.isAll()); Keyed[] values = TagModule.getKeyed(element); - if (values == null) - return false; + if (values == null) + return false; for (Tag tag : tags) { if (isTagged(tag, values, !isAny)) { diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java index def741052ea..6d9f6b6634c 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java @@ -61,7 +61,7 @@ public class EffRegisterTag extends Effect { static { Skript.registerEffect(EffRegisterTag.class, - "register [a[n]] [new] [custom] " + TagType.getFullPattern(true) + + "register [a[n]] [custom] " + TagType.getFullPattern(true) + " tag named %string% (containing|using) %entitydatas/itemtypes%"); } @@ -74,9 +74,7 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is //noinspection unchecked name = (Expression) expressions[0]; if (name instanceof Literal literal) { - String key = literal.getSingle(); - if (key.startsWith("skript:")) - key = key.substring(7); + String key = removeSkriptNamespace(literal.getSingle()); if (!KEY_PATTERN.matcher(key).matches()) { Skript.error("Tag names can only contain the following characters: 'a-z', '0-9', '/', '.', '_', and '-'."); return false; @@ -94,8 +92,7 @@ protected void execute(Event event) { if (name == null) return; - if (name.startsWith("skript:")) - name = name.substring(7); + name = removeSkriptNamespace(name); if (!KEY_PATTERN.matcher(name).matches()) return; @@ -121,6 +118,12 @@ protected void execute(Event event) { } } + private static @NotNull String removeSkriptNamespace(@NotNull String key) { + if (key.startsWith("skript:")) + key = key.substring(7); + return key; + } + @Contract("_, _ -> new") private @NotNull Tag getMaterialTag(NamespacedKey key, Object @NotNull [] contents) { ThreadLocalRandom random = ThreadLocalRandom.current(); @@ -132,7 +135,8 @@ protected void execute(Event event) { tagContents.add((Material) values[random.nextInt(0, values.length)]); } else { for (Keyed value : values) { - tagContents.add((Material) value); + if (value instanceof Material material) + tagContents.add(material); } } } @@ -144,7 +148,8 @@ protected void execute(Event event) { List tagContents = new ArrayList<>(); for (Object object : contents) { for (Keyed value : TagModule.getKeyed(object)) { - tagContents.add((EntityType) value); + if (value instanceof EntityType entityType) + tagContents.add(entityType); } } return new SkriptTag<>(key, tagContents); @@ -155,4 +160,5 @@ public String toString(@Nullable Event event, boolean debug) { return "register a new " + type.toString() + " tag named " + name.toString(event, debug) + " containing " + contents.toString(event, debug); } + } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java index 5ffeca029a5..2e103aef0d8 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java @@ -97,7 +97,7 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is Tag tag; for (TagType type : types) { - tag = TagModule.TAGS.getTag(origin, type, key); + tag = TagModule.tagRegistry.getTag(origin, type, key); if (tag != null // ensures that only datapack/minecraft tags are sent when specifically requested && (origin != TagOrigin.BUKKIT || (datapackOnly ^ tag.getKey().getNamespace().equals("minecraft"))) diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java index 2e29dc81509..e8a38741676 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java @@ -50,7 +50,7 @@ public class ExprTagsOf extends PropertyExpression { static { Skript.registerExpression(ExprTagsOf.class, Tag.class, ExpressionType.PROPERTY, - "[all [of]] [the] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags of %itemtype/entity/entitydata%", + "[all [[of] the]|the] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags of %itemtype/entity/entitydata%", "%itemtype/entity/entitydata%'[s] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags"); } @@ -103,7 +103,7 @@ public Collection> getTags(@NotNull T value) { List> tags = new ArrayList<>(); //noinspection unchecked Class clazz = (Class) value.getClass(); - for (Tag tag : TagModule.TAGS.getTags(origin, clazz, types)) { + for (Tag tag : TagModule.tagRegistry.getTags(origin, clazz, types)) { if (tag.isTagged(value)) tags.add(tag); } @@ -126,4 +126,5 @@ public String toString(@Nullable Event event, boolean debug) { //noinspection DataFlowIssue return origin.toString(datapackOnly) + registry + "tags of " + getExpr().toString(event, debug); } + } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java index 19abb5dcb62..88b8818024c 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java @@ -44,7 +44,7 @@ public class ExprTagsOfType extends SimpleExpression { static { Skript.registerExpression(ExprTagsOfType.class, Tag.class, ExpressionType.SIMPLE, - "[all [[of] the]] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags"); + "[all [[of] the]|the] " + TagOrigin.getFullPattern() + " " + TagType.getFullPattern() + " tags"); } TagType[] types; @@ -63,7 +63,7 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is protected Tag @Nullable [] get(Event event) { Set> tags = new TreeSet<>(Comparator.comparing(Keyed::key)); for (TagType type : types) { - for (Tag tag : TagModule.TAGS.getMatchingTags(origin, type, + for (Tag tag : TagModule.tagRegistry.getMatchingTags(origin, type, tag -> (origin != TagOrigin.BUKKIT || (datapackOnly ^ tag.getKey().getNamespace().equals("minecraft")))) ) { tags.add(tag); @@ -87,4 +87,5 @@ public String toString(@Nullable Event event, boolean debug) { String registry = types.length > 1 ? "" : types[0].toString(); return "all of the " + origin.toString(datapackOnly) + registry + "tags"; } + } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java index 8b09a3fe3c3..ccf74ce6bd0 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/BukkitTagSource.java @@ -34,4 +34,5 @@ public BukkitTagSource(String registry, TagType type) { public @Nullable Tag getTag(NamespacedKey key) { return Bukkit.getTag(registry, key, getTypes()[0].type()); } + } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java index ebab102bf83..49f41ed1446 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java @@ -23,11 +23,11 @@ public class PaperTagSource extends CustomTagSource { * @param The class of the tags. */ private static @NotNull Iterable> getPaperTags(@NotNull Iterable> tags) { - List> modified_tags = new ArrayList<>(); + List> modifiedTags = new ArrayList<>(); for (Tag tag : tags) { - modified_tags.add(new PaperTag<>(tag)); + modifiedTags.add(new PaperTag<>(tag)); } - return modified_tags; + return modifiedTags; } /** diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java index 16c3b1e4732..e5ee280a409 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java @@ -14,7 +14,7 @@ public class SkriptTagSource extends CustomTagSource { public static final SkriptTagSource ENTITIES = new SkriptTagSource<>(TagType.ENTITIES); /** - * @param types The tag types this source will represent. + * @param types The tag types this source will represent. */ @SafeVarargs public SkriptTagSource(TagType... types) { @@ -24,4 +24,5 @@ public SkriptTagSource(TagType... types) { public void addTag(Tag tag) { tags.put(tag.getKey(), tag); } + } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java index b2f76014b5c..af08bb5331f 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java @@ -7,6 +7,10 @@ import java.util.List; +/** + * The origin of a tag, eg. from Bukkit, from Paper, from a custom Skript tag, or from anywhere. + * Used for classification and filtering tags. + */ public enum TagOrigin { /** * Bukkit supplies both native minecraft tags and datapack tags. @@ -84,4 +88,5 @@ public boolean matches(TagOrigin other) { case ANY -> ""; }; } + } From 3fc9856901a60153426bfba811d328b316f71349 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Sun, 15 Dec 2024 14:12:38 -0500 Subject: [PATCH 18/21] Requested changes --- .../skript/bukkit/tags/TagModule.java | 1 - .../skript/bukkit/tags/TagRegistry.java | 26 +++++-------------- .../skript/bukkit/tags/TagType.java | 4 ++- .../bukkit/tags/elements/CondIsTagged.java | 6 ++--- .../bukkit/tags/elements/EffRegisterTag.java | 9 ++++--- .../skript/bukkit/tags/elements/ExprTag.java | 4 +-- .../bukkit/tags/elements/ExprTagContents.java | 2 +- .../bukkit/tags/elements/ExprTagsOf.java | 5 ++-- .../bukkit/tags/elements/ExprTagsOfType.java | 8 +++--- .../bukkit/tags/sources/CustomTagSource.java | 8 +++--- .../bukkit/tags/sources/PaperTagSource.java | 3 ++- .../bukkit/tags/sources/SkriptTagSource.java | 16 ++++++++---- .../skript/bukkit/tags/sources/TagOrigin.java | 16 +++++++----- 13 files changed, 53 insertions(+), 55 deletions(-) diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java index 54a0dc4cf61..71987b74857 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagModule.java @@ -35,7 +35,6 @@ public static void load() throws IOException { if (!Skript.classExists("org.bukkit.Tag")) return; - // Classes Classes.registerClass(new ClassInfo<>(Tag.class, "minecrafttag") .user("minecraft ?tags?") diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagRegistry.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagRegistry.java index 617f8abc834..98d6fb7f515 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagRegistry.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagRegistry.java @@ -62,6 +62,7 @@ public class TagRegistry { } catch (IllegalAccessException ignored) {} } + SkriptTagSource.makeDefaultSources(); tagSourceMap.put(TagType.ITEMS, SkriptTagSource.ITEMS); tagSourceMap.put(TagType.BLOCKS, SkriptTagSource.BLOCKS); tagSourceMap.put(TagType.ENTITIES, SkriptTagSource.ENTITIES); @@ -111,32 +112,17 @@ public Iterable> getTags(TagOrigin origin, TagType t return new Iterable<>() { @Override public @NotNull Iterator> iterator() { - return new Iterator<>() { - // - private Iterator> currentTagIter = tagSources.next().getAllTags().iterator(); - + return Iterators.concat(new Iterator>>() { @Override public boolean hasNext() { - // does the current source have more tags - if (currentTagIter.hasNext()) - return true; - // if we have another tag source, mark it as the next source. - if (tagSources.hasNext()) { - currentTagIter = tagSources.next().getAllTags().iterator(); - return currentTagIter.hasNext(); - } - return false; + return tagSources.hasNext(); } @Override - public Tag next() { - // if current source has more, get more. - if (currentTagIter.hasNext()) - return currentTagIter.next(); - throw new IllegalStateException("Called next without calling hasNext to set the next tag iterator."); + public Iterator> next() { + return tagSources.next().getAllTags().iterator(); } - // - }; + }); } }; } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java index 6446250a3ef..1a3fb986048 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java @@ -76,7 +76,9 @@ public String toString() { * @param type The types to add. */ public static void addType(TagType... type) { - REGISTERED_TAG_TYPES.addAll(List.of(type)); + synchronized (REGISTERED_TAG_TYPES) { + REGISTERED_TAG_TYPES.addAll(List.of(type)); + } } /** diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java index 5553c27076a..53bac73628e 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/CondIsTagged.java @@ -2,6 +2,7 @@ import ch.njol.skript.aliases.ItemType; import ch.njol.skript.conditions.base.PropertyCondition; +import ch.njol.skript.conditions.base.PropertyCondition.PropertyType; import ch.njol.skript.doc.Description; import ch.njol.skript.doc.Examples; import ch.njol.skript.doc.Keywords; @@ -95,9 +96,8 @@ private boolean isTagged(Tag tag, Keyed @NotNull [] values, boolean allTa @Override public String toString(@Nullable Event event, boolean debug) { - String plural = elements.isSingle() ? "is" : "are"; - String negated = isNegated() ? " not" : ""; - return elements.toString(event, debug) + " " + plural + negated + " tagged as " + tags.toString(event, debug); + return PropertyCondition.toString(this, PropertyType.BE, event, debug, elements, + " tagged as " + tags.toString(event, debug)); } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java index 6d9f6b6634c..ff70a6ed2d0 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java @@ -11,6 +11,7 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.Literal; import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.SyntaxStringBuilder; import ch.njol.util.Kleenean; import org.bukkit.Keyed; import org.bukkit.Material; @@ -76,7 +77,8 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is if (name instanceof Literal literal) { String key = removeSkriptNamespace(literal.getSingle()); if (!KEY_PATTERN.matcher(key).matches()) { - Skript.error("Tag names can only contain the following characters: 'a-z', '0-9', '/', '.', '_', and '-'."); + Skript.error("Tag names can only contain the following characters: letters, numbers, and some symbols: " + + "'/', '.', '_', and '-'"); return false; } } @@ -157,8 +159,9 @@ protected void execute(Event event) { @Override public String toString(@Nullable Event event, boolean debug) { - return "register a new " + type.toString() + " tag named " + name.toString(event, debug) + " containing " + - contents.toString(event, debug); + return new SyntaxStringBuilder(event, debug) + .append("register a new", type.toString(), "tag named", name, "containing", contents) + .toString(); } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java index 2e103aef0d8..2de27c8e2d4 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTag.java @@ -123,8 +123,8 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { - String registry = types.length > 1 ? "" : types[0].toString(); - return origin.toString(datapackOnly) + registry + "tag " + names.toString(event, debug); + String registry = types.length > 1 ? "" : " " + types[0].toString(); + return origin.toString(datapackOnly) + registry + " tag " + names.toString(event, debug); } @Override diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java index 1a2a5fb103e..4a47581f829 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java @@ -40,7 +40,7 @@ public class ExprTagContents extends SimpleExpression { static { Skript.registerExpression(ExprTagContents.class, Object.class, ExpressionType.PROPERTY, - "tag (contents|values) of %minecrafttag%", + "[the] tag (contents|values) of %minecrafttag%", "%minecrafttag%'[s] tag (contents|values)"); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java index e8a38741676..4c6a3e7dbd8 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOf.java @@ -122,9 +122,8 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { - String registry = types.length > 1 ? "" : types[0].toString(); - //noinspection DataFlowIssue - return origin.toString(datapackOnly) + registry + "tags of " + getExpr().toString(event, debug); + String registry = types.length > 1 ? "" : " " + types[0].toString(); + return origin.toString(datapackOnly) + registry + " tags of " + getExpr().toString(event, debug); } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java index 88b8818024c..86895f8db1a 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java @@ -48,8 +48,8 @@ public class ExprTagsOfType extends SimpleExpression { } TagType[] types; - TagOrigin origin; - boolean datapackOnly; + private TagOrigin origin; + private boolean datapackOnly; @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { @@ -84,8 +84,8 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { - String registry = types.length > 1 ? "" : types[0].toString(); - return "all of the " + origin.toString(datapackOnly) + registry + "tags"; + String registry = types.length > 1 ? "" : " " + types[0].toString(); + return "all of the " + origin.toString(datapackOnly) + registry + " tags"; } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java index 4900ba06516..364621734ef 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/CustomTagSource.java @@ -8,14 +8,14 @@ import org.skriptlang.skript.bukkit.tags.TagType; import java.util.Collections; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * A custom source of tags that stores its own tags. * @param The class of the tags provided by this source. */ -public class CustomTagSource extends TagSource { +public sealed class CustomTagSource extends TagSource permits PaperTagSource, SkriptTagSource { final Map> tags; @@ -25,9 +25,9 @@ public class CustomTagSource extends TagSource { * @param types The tag types this source will represent. */ @SafeVarargs - public CustomTagSource(TagOrigin origin, @NotNull Iterable> tags, TagType... types) { + CustomTagSource(TagOrigin origin, @NotNull Iterable> tags, TagType... types) { super(origin, types); - this.tags = new HashMap<>(); + this.tags = new ConcurrentHashMap<>(); for (Tag tag : tags) { this.tags.put(tag.getKey(), tag); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java index 49f41ed1446..1a7bbb58624 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/PaperTagSource.java @@ -14,7 +14,7 @@ * A set of tags provided by Paper. * @param The class of tag this source provides. */ -public class PaperTagSource extends CustomTagSource { +public final class PaperTagSource extends CustomTagSource { /** * Creates {@link PaperTag}s from the raw tags. Removes _settag. @@ -67,6 +67,7 @@ public boolean isTagged(@NotNull T1 item) { public @NotNull NamespacedKey getKey() { return key; } + } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java index e5ee280a409..55bec0a56d5 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java @@ -7,17 +7,23 @@ import org.bukkit.entity.EntityType; import org.skriptlang.skript.bukkit.tags.TagType; -public class SkriptTagSource extends CustomTagSource { +public final class SkriptTagSource extends CustomTagSource { - public static final SkriptTagSource ITEMS = new SkriptTagSource<>(TagType.ITEMS); - public static final SkriptTagSource BLOCKS = new SkriptTagSource<>(TagType.BLOCKS); - public static final SkriptTagSource ENTITIES = new SkriptTagSource<>(TagType.ENTITIES); + public static SkriptTagSource ITEMS; + public static SkriptTagSource BLOCKS; + public static SkriptTagSource ENTITIES; + + public static void makeDefaultSources() { + ITEMS = new SkriptTagSource<>(TagType.ITEMS); + BLOCKS = new SkriptTagSource<>(TagType.BLOCKS); + ENTITIES = new SkriptTagSource<>(TagType.ENTITIES); + } /** * @param types The tag types this source will represent. */ @SafeVarargs - public SkriptTagSource(TagType... types) { + private SkriptTagSource(TagType... types) { super(TagOrigin.SKRIPT, new EmptyIterable<>(), types); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java index af08bb5331f..82ff9c2f089 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/TagOrigin.java @@ -5,7 +5,7 @@ import org.jetbrains.annotations.NotNull; import org.skriptlang.skript.bukkit.tags.TagModule; -import java.util.List; +import java.util.Collection; /** * The origin of a tag, eg. from Bukkit, from Paper, from a custom Skript tag, or from anywhere. @@ -16,14 +16,17 @@ public enum TagOrigin { * Bukkit supplies both native minecraft tags and datapack tags. */ BUKKIT, + /** * Paper supplies a set of custom tags they curate. */ PAPER, + /** * Custom tags registered via Skript. */ SKRIPT, + /** * Used when asking for tags, matches all origins. */ @@ -33,7 +36,7 @@ public enum TagOrigin { * Returns an optional choice of all the origins (minecraft, datapack, paper, and custom). * Will not include paper on non-paper servers. * Contains parse tags. - * @see #fromParseTags(List) + * @see #fromParseTags(Collection) */ @Contract(pure = true) public static @NotNull String getFullPattern() { @@ -51,7 +54,7 @@ public enum TagOrigin { * @see #getFullPattern() */ @Contract(value = "_ -> new", pure = true) - public static TagOrigin fromParseTags(@NotNull List tags) { + public static TagOrigin fromParseTags(@NotNull Collection tags) { TagOrigin origin = TagOrigin.ANY; if (tags.contains("minecraft") || tags.contains("datapack")) { origin = TagOrigin.BUKKIT; @@ -75,16 +78,15 @@ public boolean matches(TagOrigin other) { /** * Returns a string for use in {@link ch.njol.skript.lang.Debuggable#toString(Event, boolean)} methods. - * Includes a trailing space. * @param datapackOnly Whether to output "datapack " or "minecraft " for {@link #BUKKIT}. * @return a string representing the origin, with a trailing space. */ @Contract(pure = true) public @NotNull String toString(boolean datapackOnly) { return switch (this) { - case BUKKIT -> datapackOnly ? "datapack " : "minecraft "; - case PAPER -> "paper "; - case SKRIPT -> "custom "; + case BUKKIT -> datapackOnly ? "datapack" : "minecraft"; + case PAPER -> "paper"; + case SKRIPT -> "custom"; case ANY -> ""; }; } From 3daec9673cb94633f3fbf4eeac2ebdd9d4b21107 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Fri, 20 Dec 2024 18:45:25 -0500 Subject: [PATCH 19/21] Requested changes --- .../skript/bukkit/tags/TagRegistry.java | 40 +++++++++++++++---- .../skript/bukkit/tags/TagType.java | 2 +- .../bukkit/tags/elements/EffRegisterTag.java | 6 +-- .../bukkit/tags/elements/ExprTagContents.java | 2 +- .../bukkit/tags/elements/ExprTagsOfType.java | 3 +- .../bukkit/tags/sources/SkriptTagSource.java | 27 +++++++++++-- 6 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagRegistry.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagRegistry.java index 98d6fb7f515..7bbd2eb2d5c 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagRegistry.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagRegistry.java @@ -41,16 +41,40 @@ public class TagRegistry { if (TagModule.PAPER_TAGS_EXIST) { try { - List> materialTags = new ArrayList<>(); + List> itemTags = new ArrayList<>(); + List> blockTags = new ArrayList<>(); + List> blockAndItemTag = new ArrayList<>(); for (Field field : MaterialTags.class.getDeclaredFields()) { - if (field.canAccess(null)) + if (field.canAccess(null)) { //noinspection unchecked - materialTags.add((Tag) field.get(null)); + Tag tag = (Tag) field.get(null); + boolean hasItem = false; + boolean hasBlock = false; + for (Material material : tag.getValues()) { + if (!hasBlock && material.isBlock()) { + blockTags.add(tag); + hasBlock = true; + } + if (!hasItem && material.isItem()) { + itemTags.add(tag); + hasItem = true; + } + if (hasItem && hasBlock) { + blockAndItemTag.add(tag); + break; + } + } + } } - PaperTagSource paperMaterialTags = new PaperTagSource<>(materialTags, TagType.BLOCKS, TagType.ITEMS); + PaperTagSource paperMaterialTags = new PaperTagSource<>(blockAndItemTag, TagType.BLOCKS, TagType.ITEMS); + PaperTagSource paperItemTags = new PaperTagSource<>(itemTags, TagType.ITEMS); + PaperTagSource paperBlockTags = new PaperTagSource<>(blockTags, TagType.BLOCKS); tagSourceMap.put(TagType.BLOCKS, paperMaterialTags); tagSourceMap.put(TagType.ITEMS, paperMaterialTags); + tagSourceMap.put(TagType.BLOCKS, paperBlockTags); + tagSourceMap.put(TagType.ITEMS, paperItemTags); + List> entityTags = new ArrayList<>(); for (Field field : EntityTags.class.getDeclaredFields()) { if (field.canAccess(null)) @@ -63,9 +87,9 @@ public class TagRegistry { } SkriptTagSource.makeDefaultSources(); - tagSourceMap.put(TagType.ITEMS, SkriptTagSource.ITEMS); - tagSourceMap.put(TagType.BLOCKS, SkriptTagSource.BLOCKS); - tagSourceMap.put(TagType.ENTITIES, SkriptTagSource.ENTITIES); + tagSourceMap.put(TagType.ITEMS, SkriptTagSource.ITEMS()); + tagSourceMap.put(TagType.BLOCKS, SkriptTagSource.BLOCKS()); + tagSourceMap.put(TagType.ENTITIES, SkriptTagSource.ENTITIES()); } /** @@ -168,6 +192,7 @@ public Iterable> getMatchingTags(TagOrigin origin, TagT * A MultiMap that maps TagTypes to multiple TagSources, matching generics. */ private static class TagSourceMap { + private final ArrayListMultimap, TagSource> map = ArrayListMultimap.create(); public void put(TagType key, TagSource value) { @@ -187,6 +212,7 @@ public void put(TagType key, TagSource value) { public boolean containsKey(TagType type) { return map.containsKey(type); } + } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java index 1a3fb986048..d1d23072dda 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java @@ -25,7 +25,7 @@ */ public class TagType { - private static final List> REGISTERED_TAG_TYPES = new ArrayList<>(); + private static final List> REGISTERED_TAG_TYPES = Collections.synchronizedList(new ArrayList<>()); public static final TagType ITEMS = new TagType<>("item", Material.class); public static final TagType BLOCKS = new TagType<>("block", Material.class); diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java index ff70a6ed2d0..c9a723f5df6 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/EffRegisterTag.java @@ -109,14 +109,14 @@ protected void execute(Event event) { if (this.type.type() == Material.class) { Tag tag = getMaterialTag(key, contents); if (this.type == TagType.ITEMS) { - SkriptTagSource.ITEMS.addTag(tag); + SkriptTagSource.ITEMS().addTag(tag); } else if (this.type == TagType.BLOCKS) { - SkriptTagSource.BLOCKS.addTag(tag); + SkriptTagSource.BLOCKS().addTag(tag); } } else if (this.type.type() == EntityType.class) { Tag tag = getEntityTag(key, contents); - SkriptTagSource.ENTITIES.addTag(tag); + SkriptTagSource.ENTITIES().addTag(tag); } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java index 4a47581f829..334abbf3463 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagContents.java @@ -98,7 +98,7 @@ public Class getReturnType() { @Override public String toString(@Nullable Event event, boolean debug) { - return "tag contents of " + tag.toString(event, debug); + return "the tag contents of " + tag.toString(event, debug); } } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java index 86895f8db1a..d13874ebd47 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/elements/ExprTagsOfType.java @@ -13,6 +13,7 @@ import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; import org.bukkit.Tag; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; @@ -64,7 +65,7 @@ public boolean init(Expression[] expressions, int matchedPattern, Kleenean is Set> tags = new TreeSet<>(Comparator.comparing(Keyed::key)); for (TagType type : types) { for (Tag tag : TagModule.tagRegistry.getMatchingTags(origin, type, - tag -> (origin != TagOrigin.BUKKIT || (datapackOnly ^ tag.getKey().getNamespace().equals("minecraft")))) + tag -> (origin != TagOrigin.BUKKIT || (datapackOnly ^ tag.getKey().getNamespace().equals(NamespacedKey.MINECRAFT)))) ) { tags.add(tag); } diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java index 55bec0a56d5..b197878f989 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/sources/SkriptTagSource.java @@ -9,9 +9,9 @@ public final class SkriptTagSource extends CustomTagSource { - public static SkriptTagSource ITEMS; - public static SkriptTagSource BLOCKS; - public static SkriptTagSource ENTITIES; + private static SkriptTagSource ITEMS; + private static SkriptTagSource BLOCKS; + private static SkriptTagSource ENTITIES; public static void makeDefaultSources() { ITEMS = new SkriptTagSource<>(TagType.ITEMS); @@ -31,4 +31,25 @@ public void addTag(Tag tag) { tags.put(tag.getKey(), tag); } + /** + * @return Skript tag source for item contexts + */ + public static SkriptTagSource ITEMS() { + return ITEMS; + } + + /** + * @return Skript tag source for block contexts + */ + public static SkriptTagSource BLOCKS() { + return BLOCKS; + } + + /** + * @return Skript tag source for entities + */ + public static SkriptTagSource ENTITIES() { + return ENTITIES; + } + } From a85d42096efaf6e1749de84c0e752e977ac519a6 Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Fri, 27 Dec 2024 15:41:49 -0800 Subject: [PATCH 20/21] Update src/main/java/ch/njol/util/Pair.java Co-authored-by: Efnilite <35348263+Efnilite@users.noreply.github.com> --- src/main/java/ch/njol/util/Pair.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ch/njol/util/Pair.java b/src/main/java/ch/njol/util/Pair.java index 58a4027c7a0..25bb2cc0b83 100644 --- a/src/main/java/ch/njol/util/Pair.java +++ b/src/main/java/ch/njol/util/Pair.java @@ -89,7 +89,6 @@ public final int hashCode() { } @Override - public @UnknownNullability T2 setValue(@Nullable T2 value) { T2 old = second; second = value; From 89f40e3f736fcbc1ee9a9311ea98eec25f5b63ca Mon Sep 17 00:00:00 2001 From: sovdee <10354869+sovdeeth@users.noreply.github.com> Date: Sun, 29 Dec 2024 18:36:42 -0500 Subject: [PATCH 21/21] Update src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java Co-authored-by: Patrick Miller --- src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java index d1d23072dda..e0dc3aecfdb 100644 --- a/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java +++ b/src/main/java/org/skriptlang/skript/bukkit/tags/TagType.java @@ -76,9 +76,7 @@ public String toString() { * @param type The types to add. */ public static void addType(TagType... type) { - synchronized (REGISTERED_TAG_TYPES) { - REGISTERED_TAG_TYPES.addAll(List.of(type)); - } + REGISTERED_TAG_TYPES.addAll(List.of(type)); } /**