abstract custom set tags, add entity tags

This commit is contained in:
Jake Potrebic 2021-01-03 20:09:42 -08:00 committed by MiniDigger | Martin
parent c7667378e7
commit 5869669498

View File

@ -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 <jake.m.potrebic@gmail.com>
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<Material> {
+
+ private final NamespacedKey key;
+ private final Set<Material> materials;
+public class MaterialSetTag extends BaseTag<Material, MaterialSetTag> {
+
+ /**
+ * @deprecated Use NamespacedKey version of constructor
@ -74,103 +72,23 @@ index 0000000000000000000000000000000000000000..c91ea2a0679a7f3a5627b5a008e0b39d
+ }
+
+ public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Collection<Material> materials) {
+ this.key = key != null ? key : NamespacedKey.randomKey();
+ this.materials = Sets.newEnumSet(materials, Material.class);
+ this(key != null ? key : NamespacedKey.randomKey(), materials, ((Predicate<Material>) Material::isLegacy).negate());
+ }
+
+ public MaterialSetTag(@Nullable NamespacedKey key, @NotNull Collection<Material> materials, @NotNull Predicate<Material>...globalPredicates) {
+ super(Material.class, key != null ? key : NamespacedKey.randomKey(), materials, globalPredicates);
+ }
+
+ @NotNull
+ @Override
+ public NamespacedKey getKey() {
+ return key;
+ protected Set<Material> getAllPossibleValues() {
+ return Stream.of(Material.values()).collect(Collectors.toSet());
+ }
+
+ @Override
+ @NotNull
+ public MaterialSetTag add(@NotNull Tag<Material>... tags) {
+ for (Tag<Material> tag : tags) {
+ add(tag.getValues());
+ }
+ return this;
+ }
+
+ @NotNull
+ public MaterialSetTag add(@NotNull MaterialSetTag... tags) {
+ for (Tag<Material> 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<Material> 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<Material> filter) {
+ add(Stream.of(Material.values()).filter(((Predicate<Material>) 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<Material> materials) {
+ this.materials.removeAll(materials);
+ return this;
+ }
+
+ @NotNull
+ public MaterialSetTag not(@NotNull Predicate<Material> filter) {
+ not(Stream.of(Material.values()).filter(((Predicate<Material>) 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<Material> 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>) 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<T extends Keyed, C extends BaseTag<T, C>> implements Tag<T> {
+
+ protected final NamespacedKey key;
+ protected final Set<T> tagged;
+ private final List<Predicate<T>> globalPredicates;
+
+ public BaseTag(@NotNull Class<T> clazz, @NotNull NamespacedKey key, @NotNull Predicate<T> filter) {
+ this(clazz, key);
+ add(filter);
+ }
+
+ public BaseTag(@NotNull Class<T> clazz, @NotNull NamespacedKey key, @NotNull T...values) {
+ this(clazz, key, Lists.newArrayList(values));
+ }
+
+ public BaseTag(@NotNull Class<T> clazz, @NotNull NamespacedKey key, @NotNull Collection<T> values) {
+ this(clazz, key, values, o -> true);
+ }
+
+ public BaseTag(@NotNull Class<T> clazz, @NotNull NamespacedKey key, @NotNull Collection<T> values, @NotNull Predicate<T>... globalPredicates) {
+ this.key = key != null ? key : NamespacedKey.randomKey();
+ this.tagged = clazz.isEnum() ? createEnumSet(clazz) : new HashSet<>();
+ this.globalPredicates = Lists.newArrayList(globalPredicates);
+ }
+
+ private <E> Set<E> createEnumSet(Class<E> enumClass) {
+ assert enumClass.isEnum();
+ return (Set<E>) EnumSet.noneOf((Class<Enum>) enumClass);
+ }
+
+ @NotNull
+ @Override
+ public NamespacedKey getKey() {
+ return key;
+ }
+
+ @NotNull
+ @Override
+ public Set<T> getValues() {
+ return tagged;
+ }
+
+ @Override
+ public boolean isTagged(@NotNull T item) {
+ return tagged.contains(item);
+ }
+
+ @NotNull
+ public C add(@NotNull Tag<T>...tags) {
+ for (Tag<T> 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<T> collection) {
+ this.tagged.addAll(collection);
+ return (C) this;
+ }
+
+ @NotNull
+ public C add(@NotNull Predicate<T> 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<T>...tags) {
+ for (Tag<T> 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<T> values) {
+ this.tagged.removeAll(values);
+ return (C) this;
+ }
+
+ @NotNull
+ public C not(@NotNull Predicate<T> 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<T> 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<EntityType, EntitySetTag> {
+
+ public EntitySetTag(@NotNull NamespacedKey key, @NotNull Predicate<EntityType> 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<EntityType> values) {
+ super(EntityType.class, key, values);
+ }
+
+ public EntitySetTag(@NotNull NamespacedKey key, @NotNull Collection<EntityType> values, @NotNull Predicate<EntityType>... globalPredicates) {
+ super(EntityType.class, key, values, globalPredicates);
+ }
+
+ @NotNull
+ @Override
+ protected Set<EntityType> 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 <a href="https://minecraft.gamepedia.com/Mob#Undead_mobs">https://minecraft.gamepedia.com/Mob#Undead_mobs</a>
+ */
+ 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 <a href="https://minecraft.gamepedia.com/Mob#Water-based_mobs">https://minecraft.gamepedia.com/Mob#Water-based_mobs</a>
+ */
+ 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