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>
Co-authored-by: Lena Kolb <lenakolb2204@gmail.com>
Co-authored-by: Layla Silbernberg <livsilbernberg@gmail.com>
Co-authored-by: Newwind <newwindserver@gmail.com>
This commit is contained in:
Aikar
2018-07-17 01:27:15 -04:00
parent 119dfa37f0
commit 6512e0749b
8 changed files with 1189 additions and 0 deletions

View File

@@ -0,0 +1,184 @@
package io.papermc.paper.tag;
import com.google.common.collect.Lists;
import java.util.Collections;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.Tag;
import org.jetbrains.annotations.ApiStatus;
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;
private boolean locked = false;
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;
this.tagged = clazz.isEnum() ? createEnumSet(clazz) : new HashSet<>();
this.tagged.addAll(values);
this.globalPredicates = Lists.newArrayList(globalPredicates);
}
private <E> Set<E> createEnumSet(Class<E> enumClass) {
assert enumClass.isEnum();
return (Set<E>) EnumSet.noneOf((Class<Enum>) enumClass);
}
public @NotNull C lock() {
this.locked = true;
return (C) this;
}
public boolean isLocked() {
return this.locked;
}
private void checkLock() {
if (this.locked) {
throw new UnsupportedOperationException("Tag (" + this.key + ") is locked");
}
}
@NotNull
@Override
public NamespacedKey getKey() {
return key;
}
@NotNull
@Override
public Set<T> getValues() {
return Collections.unmodifiableSet(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.checkLock();
this.tagged.addAll(Lists.newArrayList(values));
return (C) this;
}
@NotNull
public C add(@NotNull Collection<T> collection) {
this.checkLock();
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.checkLock();
this.tagged.removeAll(Lists.newArrayList(values));
return (C) this;
}
@NotNull
public C not(@NotNull Collection<T> values) {
this.checkLock();
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
@ApiStatus.Internal
protected abstract Set<T> getAllPossibleValues();
@NotNull
@ApiStatus.Internal
protected abstract String getName(@NotNull T value);
}

View File

@@ -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();
}
}

View File

@@ -0,0 +1,56 @@
package io.papermc.paper.tag;
import org.bukkit.NamespacedKey;
import static org.bukkit.entity.EntityType.*;
/**
* All tags in this class are unmodifiable, attempting to modify them will throw an
* {@link UnsupportedOperationException}.
*/
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.wiki/wiki/Mob#Undead_mobs">https://minecraft.wiki/wiki/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, BOGGED)
.ensureSize("UNDEADS", 14).lock();
/**
* Covers all horses
*/
public static final EntitySetTag HORSES = new EntitySetTag(keyFor("horses"))
.contains("HORSE")
.ensureSize("HORSES", 3).lock();
/**
* Covers all minecarts
*/
public static final EntitySetTag MINECARTS = new EntitySetTag(keyFor("minecarts"))
.contains("MINECART")
.ensureSize("MINECARTS", 7).lock();
/**
* 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).lock();
/**
* Covers all water based mobs
* @see <a href="https://minecraft.wiki/wiki/Mob#Aquatic_mobs">https://minecraft.wiki/wiki/Mob#Aquatic_mobs</a>
* @deprecated in favour of {@link org.bukkit.Tag#ENTITY_TYPES_AQUATIC}
*/
@Deprecated
public static final EntitySetTag WATER_BASED = new EntitySetTag(keyFor("water_based"))
.add(AXOLOTL, DOLPHIN, SQUID, GLOW_SQUID, GUARDIAN, ELDER_GUARDIAN, TURTLE, COD, SALMON, PUFFERFISH, TROPICAL_FISH, TADPOLE)
.ensureSize("WATER_BASED", 12).lock();
}