From 5869669498251f432371b725b6e0f95e18956354 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sun, 3 Jan 2021 20:09:42 -0800 Subject: [PATCH] abstract custom set tags, add entity tags --- .../0153-Add-Material-Tags.patch | 424 +++++++++++++----- 1 file changed, 316 insertions(+), 108 deletions(-) diff --git a/Spigot-API-Patches/0153-Add-Material-Tags.patch b/Spigot-API-Patches/0153-Add-Material-Tags.patch index f25cb722a..7fa147f73 100644 --- a/Spigot-API-Patches/0153-Add-Material-Tags.patch +++ b/Spigot-API-Patches/0153-Add-Material-Tags.patch @@ -6,12 +6,14 @@ Subject: [PATCH] Add Material Tags This adds a bunch of useful and missing Tags to be able to identify items that are related to each other by a trait. +Co-authored-by: Jake Potrebic + diff --git a/src/main/java/com/destroystokyo/paper/MaterialSetTag.java b/src/main/java/com/destroystokyo/paper/MaterialSetTag.java new file mode 100644 -index 0000000000000000000000000000000000000000..c91ea2a0679a7f3a5627b5a008e0b39df3332889 +index 0000000000000000000000000000000000000000..a02a02aa0c87e0f0ed9e509e4dcab01565b3d92a --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/MaterialSetTag.java -@@ -0,0 +1,190 @@ +@@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018 Daniel Ennis (Aikar) MIT License + */ @@ -19,10 +21,9 @@ index 0000000000000000000000000000000000000000..c91ea2a0679a7f3a5627b5a008e0b39d +package com.destroystokyo.paper; + +import com.google.common.collect.Lists; -+import com.google.common.collect.Sets; ++import io.papermc.paper.tag.BaseTag; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; -+import org.bukkit.Tag; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; @@ -36,10 +37,7 @@ index 0000000000000000000000000000000000000000..c91ea2a0679a7f3a5627b5a008e0b39d +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + -+public class MaterialSetTag implements Tag { -+ -+ private final NamespacedKey key; -+ private final Set materials; ++public class MaterialSetTag extends BaseTag { + + /** + * @deprecated Use NamespacedKey version of constructor @@ -74,103 +72,23 @@ index 0000000000000000000000000000000000000000..c91ea2a0679a7f3a5627b5a008e0b39d + } + + public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Collection materials) { -+ this.key = key != null ? key : NamespacedKey.randomKey(); -+ this.materials = Sets.newEnumSet(materials, Material.class); ++ this(key != null ? key : NamespacedKey.randomKey(), materials, ((Predicate) Material::isLegacy).negate()); ++ } ++ ++ public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Collection materials, @NotNull Predicate...globalPredicates) { ++ super(Material.class, key != null ? key : NamespacedKey.randomKey(), materials, globalPredicates); + } + + @NotNull + @Override -+ public NamespacedKey getKey() { -+ return key; ++ protected Set getAllPossibleValues() { ++ return Stream.of(Material.values()).collect(Collectors.toSet()); + } + ++ @Override + @NotNull -+ public MaterialSetTag add(@NotNull Tag... tags) { -+ for (Tag tag : tags) { -+ add(tag.getValues()); -+ } -+ return this; -+ } -+ -+ @NotNull -+ public MaterialSetTag add(@NotNull MaterialSetTag... tags) { -+ for (Tag tag : tags) { -+ add(tag.getValues()); -+ } -+ return this; -+ } -+ -+ @NotNull -+ public MaterialSetTag add(@NotNull Material... material) { -+ this.materials.addAll(Lists.newArrayList(material)); -+ return this; -+ } -+ -+ @NotNull -+ public MaterialSetTag add(@NotNull Collection materials) { -+ this.materials.addAll(materials); -+ return this; -+ } -+ -+ @NotNull -+ public MaterialSetTag contains(@NotNull String with) { -+ return add(mat -> mat.name().contains(with)); -+ } -+ -+ @NotNull -+ public MaterialSetTag endsWith(@NotNull String with) { -+ return add(mat -> mat.name().endsWith(with)); -+ } -+ -+ -+ @NotNull -+ public MaterialSetTag startsWith(@NotNull String with) { -+ return add(mat -> mat.name().startsWith(with)); -+ } -+ @NotNull -+ public MaterialSetTag add(@NotNull Predicate filter) { -+ add(Stream.of(Material.values()).filter(((Predicate) Material::isLegacy).negate()).filter(filter).collect(Collectors.toList())); -+ return this; -+ } -+ -+ @NotNull -+ public MaterialSetTag not(@NotNull MaterialSetTag tags) { -+ not(tags.getValues()); -+ return this; -+ } -+ -+ @NotNull -+ public MaterialSetTag not(@NotNull Material... material) { -+ this.materials.removeAll(Lists.newArrayList(material)); -+ return this; -+ } -+ -+ @NotNull -+ public MaterialSetTag not(@NotNull Collection materials) { -+ this.materials.removeAll(materials); -+ return this; -+ } -+ -+ @NotNull -+ public MaterialSetTag not(@NotNull Predicate filter) { -+ not(Stream.of(Material.values()).filter(((Predicate) Material::isLegacy).negate()).filter(filter).collect(Collectors.toList())); -+ return this; -+ } -+ -+ @NotNull -+ public MaterialSetTag notEndsWith(@NotNull String with) { -+ return not(mat -> mat.name().endsWith(with)); -+ } -+ -+ -+ @NotNull -+ public MaterialSetTag notStartsWith(@NotNull String with) { -+ return not(mat -> mat.name().startsWith(with)); -+ } -+ -+ @NotNull -+ public Set getValues() { -+ return this.materials; ++ protected String getName(@NotNull Material value) { ++ return value.name(); + } + + public boolean isTagged(@NotNull BlockData block) { @@ -190,16 +108,7 @@ index 0000000000000000000000000000000000000000..c91ea2a0679a7f3a5627b5a008e0b39d + } + + public boolean isTagged(@NotNull Material material) { -+ return this.materials.contains(material); -+ } -+ -+ @NotNull -+ public MaterialSetTag ensureSize(@NotNull String label, int size) { -+ long actual = this.materials.stream().filter(((Predicate) Material::isLegacy).negate()).count(); -+ if (size != actual) { -+ throw new IllegalStateException(label + " - Expected " + size + " materials, got " + actual); -+ } -+ return this; ++ return this.tagged.contains(material); + } +} diff --git a/src/main/java/com/destroystokyo/paper/MaterialTags.java b/src/main/java/com/destroystokyo/paper/MaterialTags.java @@ -764,6 +673,275 @@ index 0000000000000000000000000000000000000000..3f36165d89ae4aaa153dcb9ddbb8c58a + .add(Material.TRIDENT, Material.SHIELD, Material.FISHING_ROD, Material.SHEARS, Material.FLINT_AND_STEEL, Material.CARROT_ON_A_STICK, Material.WARPED_FUNGUS_ON_A_STICK) + .ensureSize("ENCHANTABLE", 65); +} +diff --git a/src/main/java/io/papermc/paper/tag/BaseTag.java b/src/main/java/io/papermc/paper/tag/BaseTag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c8777d2298c80c9579635000044e2d0a987cc15b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/tag/BaseTag.java +@@ -0,0 +1,159 @@ ++package io.papermc.paper.tag; ++ ++import com.google.common.collect.Lists; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Tag; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.Collection; ++import java.util.EnumSet; ++import java.util.HashSet; ++import java.util.List; ++import java.util.Set; ++import java.util.function.Predicate; ++import java.util.stream.Collectors; ++ ++public abstract class BaseTag> implements Tag { ++ ++ protected final NamespacedKey key; ++ protected final Set tagged; ++ private final List> globalPredicates; ++ ++ public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull Predicate filter) { ++ this(clazz, key); ++ add(filter); ++ } ++ ++ public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull T...values) { ++ this(clazz, key, Lists.newArrayList(values)); ++ } ++ ++ public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull Collection values) { ++ this(clazz, key, values, o -> true); ++ } ++ ++ public BaseTag(@NotNull Class clazz, @NotNull NamespacedKey key, @NotNull Collection values, @NotNull Predicate... globalPredicates) { ++ this.key = key != null ? key : NamespacedKey.randomKey(); ++ this.tagged = clazz.isEnum() ? createEnumSet(clazz) : new HashSet<>(); ++ this.globalPredicates = Lists.newArrayList(globalPredicates); ++ } ++ ++ private Set createEnumSet(Class enumClass) { ++ assert enumClass.isEnum(); ++ return (Set) EnumSet.noneOf((Class) enumClass); ++ } ++ ++ @NotNull ++ @Override ++ public NamespacedKey getKey() { ++ return key; ++ } ++ ++ @NotNull ++ @Override ++ public Set getValues() { ++ return tagged; ++ } ++ ++ @Override ++ public boolean isTagged(@NotNull T item) { ++ return tagged.contains(item); ++ } ++ ++ @NotNull ++ public C add(@NotNull Tag...tags) { ++ for (Tag tag : tags) { ++ add(tag.getValues()); ++ } ++ return (C) this; ++ } ++ ++ @NotNull ++ public C add(@NotNull T...values) { ++ this.tagged.addAll(Lists.newArrayList(values)); ++ return (C) this; ++ } ++ ++ @NotNull ++ public C add(@NotNull Collection collection) { ++ this.tagged.addAll(collection); ++ return (C) this; ++ } ++ ++ @NotNull ++ public C add(@NotNull Predicate filter) { ++ return add(getAllPossibleValues().stream().filter(globalPredicates.stream().reduce(Predicate::or).orElse(t -> true)).filter(filter).collect(Collectors.toSet())); ++ } ++ ++ @NotNull ++ public C contains(@NotNull String with) { ++ return add(value -> getName(value).contains(with)); ++ } ++ ++ @NotNull ++ public C endsWith(@NotNull String with) { ++ return add(value -> getName(value).endsWith(with)); ++ } ++ ++ @NotNull ++ public C startsWith(@NotNull String with) { ++ return add(value -> getName(value).startsWith(with)); ++ } ++ ++ @NotNull ++ public C not(@NotNull Tag...tags) { ++ for (Tag tag : tags) { ++ not(tag.getValues()); ++ } ++ return (C) this; ++ } ++ ++ @NotNull ++ public C not(@NotNull T...values) { ++ this.tagged.removeAll(Lists.newArrayList(values)); ++ return (C) this; ++ } ++ ++ @NotNull ++ public C not(@NotNull Collection values) { ++ this.tagged.removeAll(values); ++ return (C) this; ++ } ++ ++ @NotNull ++ public C not(@NotNull Predicate filter) { ++ not(getAllPossibleValues().stream().filter(globalPredicates.stream().reduce(Predicate::or).orElse(t -> true)).filter(filter).collect(Collectors.toSet())); ++ return (C) this; ++ } ++ ++ @NotNull ++ public C notContains(@NotNull String with) { ++ return not(value -> getName(value).contains(with)); ++ } ++ ++ @NotNull ++ public C notEndsWith(@NotNull String with) { ++ return not(value -> getName(value).endsWith(with)); ++ } ++ ++ @NotNull ++ public C notStartsWith(@NotNull String with) { ++ return not(value -> getName(value).startsWith(with)); ++ } ++ ++ @NotNull ++ public C ensureSize(@NotNull String label, int size) { ++ long actual = this.tagged.stream().filter(globalPredicates.stream().reduce(Predicate::or).orElse(t -> true)).count(); ++ if (size != actual) { ++ throw new IllegalStateException(key.toString() + ": " + label + " - Expected " + size + " values, got " + actual); ++ } ++ return (C) this; ++ } ++ ++ @NotNull ++ protected abstract Set getAllPossibleValues(); ++ ++ @NotNull ++ protected abstract String getName(@NotNull T value); ++} +diff --git a/src/main/java/io/papermc/paper/tag/EntitySetTag.java b/src/main/java/io/papermc/paper/tag/EntitySetTag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c89c4619aaf388197834d98eb95af2f1e93db871 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/tag/EntitySetTag.java +@@ -0,0 +1,42 @@ ++package io.papermc.paper.tag; ++ ++import org.bukkit.NamespacedKey; ++import org.bukkit.entity.EntityType; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.Collection; ++import java.util.Set; ++import java.util.function.Predicate; ++import java.util.stream.Collectors; ++import java.util.stream.Stream; ++ ++public class EntitySetTag extends BaseTag { ++ ++ public EntitySetTag(@NotNull NamespacedKey key, @NotNull Predicate filter) { ++ super(EntityType.class, key, filter); ++ } ++ ++ public EntitySetTag(@NotNull NamespacedKey key, @NotNull EntityType... values) { ++ super(EntityType.class, key, values); ++ } ++ ++ public EntitySetTag(@NotNull NamespacedKey key, @NotNull Collection values) { ++ super(EntityType.class, key, values); ++ } ++ ++ public EntitySetTag(@NotNull NamespacedKey key, @NotNull Collection values, @NotNull Predicate... globalPredicates) { ++ super(EntityType.class, key, values, globalPredicates); ++ } ++ ++ @NotNull ++ @Override ++ protected Set getAllPossibleValues() { ++ return Stream.of(EntityType.values()).collect(Collectors.toSet()); ++ } ++ ++ @NotNull ++ @Override ++ protected String getName(@NotNull EntityType value) { ++ return value.name(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/tag/EntityTags.java b/src/main/java/io/papermc/paper/tag/EntityTags.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9266c9d77e2eef7cd717dc729834a190f1fc7c1d +--- /dev/null ++++ b/src/main/java/io/papermc/paper/tag/EntityTags.java +@@ -0,0 +1,50 @@ ++package io.papermc.paper.tag; ++ ++import org.bukkit.NamespacedKey; ++ ++import static org.bukkit.entity.EntityType.*; ++ ++public class EntityTags { ++ ++ private static NamespacedKey keyFor(String key) { ++ //noinspection deprecation ++ return new NamespacedKey("paper", key + "_settag"); ++ } ++ ++ /** ++ * Covers undead mobs ++ * @see https://minecraft.gamepedia.com/Mob#Undead_mobs ++ */ ++ public static final EntitySetTag UNDEADS = new EntitySetTag(keyFor("undeads")) ++ .add(DROWNED, HUSK, PHANTOM, SKELETON, SKELETON_HORSE, STRAY, WITHER, WITHER_SKELETON, ZOGLIN, ZOMBIE, ZOMBIE_HORSE, ZOMBIE_VILLAGER, ZOMBIFIED_PIGLIN) ++ .ensureSize("UNDEADS", 13); ++ ++ /** ++ * Covers all horses ++ */ ++ public static final EntitySetTag HORSES = new EntitySetTag(keyFor("horses")) ++ .contains("HORSE") ++ .ensureSize("HORSES", 3); ++ ++ /** ++ * Covers all minecarts ++ */ ++ public static final EntitySetTag MINECARTS = new EntitySetTag(keyFor("minecarts")) ++ .contains("MINECART") ++ .ensureSize("MINECARTS", 7); ++ ++ /** ++ * Covers mobs that split into smaller mobs ++ */ ++ public static final EntitySetTag SPLITTING_MOBS = new EntitySetTag(keyFor("splitting_mobs")) ++ .add(SLIME, MAGMA_CUBE) ++ .ensureSize("SLIMES", 2); ++ ++ /** ++ * Covers all water based mobs ++ * @see https://minecraft.gamepedia.com/Mob#Water-based_mobs ++ */ ++ public static final EntitySetTag WATER_BASED = new EntitySetTag(keyFor("water_based")) ++ .add(DOLPHIN, SQUID, GUARDIAN, ELDER_GUARDIAN, TURTLE, COD, SALMON, PUFFERFISH, TROPICAL_FISH) ++ .ensureSize("WATER_BASED", 9); ++} diff --git a/src/test/java/com/destroystokyo/paper/MaterialTagsTest.java b/src/test/java/com/destroystokyo/paper/MaterialTagsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..328c51471dc12e81c1a1b643455337b3fef4d14a @@ -795,6 +973,36 @@ index 0000000000000000000000000000000000000000..328c51471dc12e81c1a1b643455337b3 + } + } +} +diff --git a/src/test/java/io/papermc/paper/EntityTagsTest.java b/src/test/java/io/papermc/paper/EntityTagsTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..06bb9d1180361d3d00c699796bbacbce5bef2177 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/EntityTagsTest.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper; ++ ++import com.destroystokyo.paper.MaterialTags; ++import io.papermc.paper.tag.EntityTags; ++import org.bukkit.Bukkit; ++import org.bukkit.TestServer; ++import org.junit.Test; ++ ++import java.util.logging.Level; ++ ++public class EntityTagsTest { ++ ++ @Test ++ public void testInitialize() { ++ try { ++ TestServer.getInstance(); ++ EntityTags.HORSES.getValues(); ++ assert true; ++ } catch (Throwable e) { ++ Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e); ++ assert false; ++ } ++ } ++} diff --git a/src/test/java/org/bukkit/TestServer.java b/src/test/java/org/bukkit/TestServer.java index 61993528e6975c38d82213e9b5caf996fe777328..5f9d348241210689eaf41a39ace5948e7a237b12 100644 --- a/src/test/java/org/bukkit/TestServer.java