geforkt von Mirrors/Paper
SPIGOT-4347: Add API to allow storing arbitrary values on ItemStacks
Dieser Commit ist enthalten in:
Ursprung
a4c555b6b1
Commit
38e4c013b6
20
nms-patches/MojangsonParser.patch
Normale Datei
20
nms-patches/MojangsonParser.patch
Normale Datei
@ -0,0 +1,20 @@
|
|||||||
|
--- a/net/minecraft/server/MojangsonParser.java
|
||||||
|
+++ b/net/minecraft/server/MojangsonParser.java
|
||||||
|
@@ -82,7 +82,7 @@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- private NBTBase b(String s) {
|
||||||
|
+ public NBTBase b(String s) { // PAIL
|
||||||
|
try {
|
||||||
|
if (MojangsonParser.i.matcher(s).matches()) {
|
||||||
|
return new NBTTagFloat(Float.parseFloat(s.substring(0, s.length() - 1)));
|
||||||
|
@@ -207,7 +207,7 @@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- private NBTBase h() throws CommandSyntaxException {
|
||||||
|
+ public NBTBase h() throws CommandSyntaxException { // PAIL
|
||||||
|
this.a('[');
|
||||||
|
int i = this.n.getCursor();
|
||||||
|
char c0 = this.n.read();
|
@ -0,0 +1,217 @@
|
|||||||
|
package org.bukkit.craftbukkit.inventory;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Primitives;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import net.minecraft.server.NBTBase;
|
||||||
|
import net.minecraft.server.NBTTagByte;
|
||||||
|
import net.minecraft.server.NBTTagByteArray;
|
||||||
|
import net.minecraft.server.NBTTagCompound;
|
||||||
|
import net.minecraft.server.NBTTagDouble;
|
||||||
|
import net.minecraft.server.NBTTagFloat;
|
||||||
|
import net.minecraft.server.NBTTagInt;
|
||||||
|
import net.minecraft.server.NBTTagIntArray;
|
||||||
|
import net.minecraft.server.NBTTagLong;
|
||||||
|
import net.minecraft.server.NBTTagLongArray;
|
||||||
|
import net.minecraft.server.NBTTagShort;
|
||||||
|
import net.minecraft.server.NBTTagString;
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
|
import org.bukkit.craftbukkit.inventory.tags.CraftCustomItemTagContainer;
|
||||||
|
import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a registry that contains the used adapters for.
|
||||||
|
*/
|
||||||
|
public final class CraftCustomTagTypeRegistry {
|
||||||
|
|
||||||
|
private final Function<Class, CustomTagAdapter> CREATE_ADAPTER = this::createAdapter;
|
||||||
|
|
||||||
|
private class CustomTagAdapter<T, Z extends NBTBase> {
|
||||||
|
|
||||||
|
private final Function<T, Z> builder;
|
||||||
|
private final Function<Z, T> extractor;
|
||||||
|
|
||||||
|
private final Class<T> primitiveType;
|
||||||
|
private final Class<Z> nbtBaseType;
|
||||||
|
|
||||||
|
public CustomTagAdapter(Class<T> primitiveType, Class<Z> nbtBaseType, Function<T, Z> builder, Function<Z, T> extractor) {
|
||||||
|
this.primitiveType = primitiveType;
|
||||||
|
this.nbtBaseType = nbtBaseType;
|
||||||
|
this.builder = builder;
|
||||||
|
this.extractor = extractor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will extract the value stored in the tag, according to
|
||||||
|
* the expected primitive type.
|
||||||
|
*
|
||||||
|
* @param base the base to extract from
|
||||||
|
* @return the value stored inside of the tag
|
||||||
|
* @throws ClassCastException if the passed base is not an instanced of
|
||||||
|
* the defined base type and therefore is not applicable to the
|
||||||
|
* extractor function
|
||||||
|
*/
|
||||||
|
T extract(NBTBase base) {
|
||||||
|
Validate.isInstanceOf(nbtBaseType, base, "The provided NBTBase was of the type %s. Expected type %s", base.getClass().getSimpleName(), nbtBaseType.getSimpleName());
|
||||||
|
return this.extractor.apply(nbtBaseType.cast(base));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a tag instance wrapping around the provided value object.
|
||||||
|
*
|
||||||
|
* @param value the value to store inside the created tag
|
||||||
|
* @return the new tag instance
|
||||||
|
* @throws ClassCastException if the passed value object is not of the
|
||||||
|
* defined primitive type and therefore is not applicable to the builder
|
||||||
|
* function
|
||||||
|
*/
|
||||||
|
Z build(Object value) {
|
||||||
|
Validate.isInstanceOf(primitiveType, value, "The provided value was of the type %s. Expected type %s", value.getClass().getSimpleName(), primitiveType.getSimpleName());
|
||||||
|
return this.builder.apply(primitiveType.cast(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the tag instance matches the adapters one.
|
||||||
|
*
|
||||||
|
* @param base the base to check
|
||||||
|
* @return if the tag was an instance of the set type
|
||||||
|
*/
|
||||||
|
boolean isInstance(NBTBase base) {
|
||||||
|
return this.nbtBaseType.isInstance(base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<Class, CustomTagAdapter> adapters = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a suitable adapter instance for the primitive class type
|
||||||
|
*
|
||||||
|
* @param type the type to create an adapter for
|
||||||
|
* @param <T> the generic type of that class
|
||||||
|
* @return the created adapter instance
|
||||||
|
* @throws IllegalArgumentException if no suitable tag type adapter for this
|
||||||
|
* type was found
|
||||||
|
*/
|
||||||
|
private <T> CustomTagAdapter createAdapter(Class<T> type) {
|
||||||
|
if (!Primitives.isWrapperType(type)) {
|
||||||
|
type = Primitives.wrap(type); //Make sure we will always "switch" over the wrapper types
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Primitives
|
||||||
|
*/
|
||||||
|
if (Objects.equals(Byte.class, type)) {
|
||||||
|
return createAdapter(Byte.class, NBTTagByte.class, NBTTagByte::new, NBTTagByte::g); // PAIL: rename asByte
|
||||||
|
}
|
||||||
|
if (Objects.equals(Short.class, type)) {
|
||||||
|
return createAdapter(Short.class, NBTTagShort.class, NBTTagShort::new, NBTTagShort::f); // PAIL: rename asShort
|
||||||
|
}
|
||||||
|
if (Objects.equals(Integer.class, type)) {
|
||||||
|
return createAdapter(Integer.class, NBTTagInt.class, NBTTagInt::new, NBTTagInt::e); // PAIL: rename asInteger
|
||||||
|
}
|
||||||
|
if (Objects.equals(Long.class, type)) {
|
||||||
|
return createAdapter(Long.class, NBTTagLong.class, NBTTagLong::new, NBTTagLong::d); // PAIL: rename asLong
|
||||||
|
}
|
||||||
|
if (Objects.equals(Float.class, type)) {
|
||||||
|
return createAdapter(Float.class, NBTTagFloat.class, NBTTagFloat::new, NBTTagFloat::i); // PAIL: rename asFloat
|
||||||
|
}
|
||||||
|
if (Objects.equals(Double.class, type)) {
|
||||||
|
return createAdapter(Double.class, NBTTagDouble.class, NBTTagDouble::new, NBTTagDouble::asDouble);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
String
|
||||||
|
*/
|
||||||
|
if (Objects.equals(String.class, type)) {
|
||||||
|
return createAdapter(String.class, NBTTagString.class, NBTTagString::new, NBTTagString::b_); // PAIL: rename getString
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Primitive Arrays
|
||||||
|
*/
|
||||||
|
if (Objects.equals(byte[].class, type)) {
|
||||||
|
return createAdapter(byte[].class, NBTTagByteArray.class, array -> new NBTTagByteArray(Arrays.copyOf(array, array.length)), n -> Arrays.copyOf(n.c(), n.size())); // PAIL: rename getByteArray
|
||||||
|
}
|
||||||
|
if (Objects.equals(int[].class, type)) {
|
||||||
|
return createAdapter(int[].class, NBTTagIntArray.class, array -> new NBTTagIntArray(Arrays.copyOf(array, array.length)), n -> Arrays.copyOf(n.d(), n.size())); // PAIL: rename getIntegerArray
|
||||||
|
}
|
||||||
|
if (Objects.equals(long[].class, type)) {
|
||||||
|
return createAdapter(long[].class, NBTTagLongArray.class, array -> new NBTTagLongArray(Arrays.copyOf(array, array.length)), n -> Arrays.copyOf(n.d(), n.size())); // PAIL: rename getLongArray
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note that this will map the interface CustomItemTagContainer directly to the CraftBukkit implementation
|
||||||
|
Passing any other instance of this form to the tag type registry will throw a ClassCastException as defined in CustomTagAdapter#build
|
||||||
|
*/
|
||||||
|
if (Objects.equals(CustomItemTagContainer.class, type)) {
|
||||||
|
return createAdapter(CraftCustomItemTagContainer.class, NBTTagCompound.class, CraftCustomItemTagContainer::toTagCompound, tag -> {
|
||||||
|
CraftCustomItemTagContainer container = new CraftCustomItemTagContainer(this);
|
||||||
|
for (String key : tag.getKeys()) {
|
||||||
|
container.put(key, tag.get(key));
|
||||||
|
}
|
||||||
|
return container;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Could not find a valid CustomTagAdapter implementation for the requested type " + type.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T, Z extends NBTBase> CustomTagAdapter<T, Z> createAdapter(Class<T> primitiveType, Class<Z> nbtBaseType, Function<T, Z> builder, Function<Z, T> extractor) {
|
||||||
|
return new CustomTagAdapter<>(primitiveType, nbtBaseType, builder, extractor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the passed value into a tag instance.
|
||||||
|
*
|
||||||
|
* @param type the type of the passed value
|
||||||
|
* @param value the value to be stored in the tag
|
||||||
|
* @param <T> the generic type of the value
|
||||||
|
* @return the created tag instance
|
||||||
|
* @throws IllegalArgumentException if no suitable tag type adapter for this
|
||||||
|
* type was found
|
||||||
|
*/
|
||||||
|
public <T> NBTBase wrap(Class<T> type, T value) {
|
||||||
|
return this.adapters.computeIfAbsent(type, CREATE_ADAPTER).build(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the tag instance matches the provided primitive type.
|
||||||
|
*
|
||||||
|
* @param type the type of the primitive value
|
||||||
|
* @param base the base instance to check
|
||||||
|
* @param <T> the generic type of the type
|
||||||
|
* @return if the base stores values of the primitive type passed
|
||||||
|
* @throws IllegalArgumentException if no suitable tag type adapter for this
|
||||||
|
* type was found
|
||||||
|
*/
|
||||||
|
public <T> boolean isInstanceOf(Class<T> type, NBTBase base) {
|
||||||
|
return this.adapters.computeIfAbsent(type, CREATE_ADAPTER).isInstance(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the value out of the provided tag.
|
||||||
|
*
|
||||||
|
* @param type the type of the value to extract
|
||||||
|
* @param tag the tag to extract the value from
|
||||||
|
* @param <T> the generic type of the value stored inside the tag
|
||||||
|
* @return the extracted value
|
||||||
|
* @throws IllegalArgumentException if the passed base is not an instanced
|
||||||
|
* of the defined base type and therefore is not applicable to the extractor
|
||||||
|
* function
|
||||||
|
* @throws IllegalArgumentException if the found object is not of type
|
||||||
|
* passed
|
||||||
|
* @throws IllegalArgumentException if no suitable tag type adapter for this
|
||||||
|
* type was found
|
||||||
|
*/
|
||||||
|
public <T> T extract(Class<T> type, NBTBase tag) throws ClassCastException, IllegalArgumentException {
|
||||||
|
CustomTagAdapter adapter = this.adapters.computeIfAbsent(type, CREATE_ADAPTER);
|
||||||
|
Validate.isTrue(adapter.isInstance(tag), "`The found tag instance cannot store %s as it is a %s", type.getSimpleName(), tag.getClass().getSimpleName());
|
||||||
|
|
||||||
|
Object foundValue = adapter.extract(tag);
|
||||||
|
Validate.isInstanceOf(type, foundValue, "The found object is of the type %s. Expected type %s", foundValue.getClass().getSimpleName(), type.getSimpleName());
|
||||||
|
return type.cast(foundValue);
|
||||||
|
}
|
||||||
|
}
|
@ -42,8 +42,10 @@ import org.bukkit.craftbukkit.Overridden;
|
|||||||
import org.bukkit.craftbukkit.attribute.CraftAttributeInstance;
|
import org.bukkit.craftbukkit.attribute.CraftAttributeInstance;
|
||||||
import org.bukkit.craftbukkit.attribute.CraftAttributeMap;
|
import org.bukkit.craftbukkit.attribute.CraftAttributeMap;
|
||||||
import org.bukkit.craftbukkit.inventory.CraftMetaItem.ItemMetaKey.Specific;
|
import org.bukkit.craftbukkit.inventory.CraftMetaItem.ItemMetaKey.Specific;
|
||||||
|
import org.bukkit.craftbukkit.inventory.tags.CraftCustomItemTagContainer;
|
||||||
import org.bukkit.craftbukkit.util.CraftChatMessage;
|
import org.bukkit.craftbukkit.util.CraftChatMessage;
|
||||||
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
|
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
|
||||||
|
import org.bukkit.craftbukkit.util.CraftNBTTagConfigSerializer;
|
||||||
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.inventory.EquipmentSlot;
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
@ -51,6 +53,7 @@ import org.bukkit.inventory.ItemFlag;
|
|||||||
import org.bukkit.inventory.meta.Damageable;
|
import org.bukkit.inventory.meta.Damageable;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.inventory.meta.Repairable;
|
import org.bukkit.inventory.meta.Repairable;
|
||||||
|
import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
@ -244,6 +247,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
|||||||
static final ItemMetaKey UNBREAKABLE = new ItemMetaKey("Unbreakable");
|
static final ItemMetaKey UNBREAKABLE = new ItemMetaKey("Unbreakable");
|
||||||
@Specific(Specific.To.NBT)
|
@Specific(Specific.To.NBT)
|
||||||
static final ItemMetaKey DAMAGE = new ItemMetaKey("Damage");
|
static final ItemMetaKey DAMAGE = new ItemMetaKey("Damage");
|
||||||
|
static final ItemMetaKey BUKKIT_CUSTOM_TAG = new ItemMetaKey("PublicBukkitValues");
|
||||||
|
|
||||||
private IChatBaseComponent displayName;
|
private IChatBaseComponent displayName;
|
||||||
private IChatBaseComponent locName;
|
private IChatBaseComponent locName;
|
||||||
@ -256,9 +260,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
|||||||
private int damage;
|
private int damage;
|
||||||
|
|
||||||
private static final Set<String> HANDLED_TAGS = Sets.newHashSet();
|
private static final Set<String> HANDLED_TAGS = Sets.newHashSet();
|
||||||
|
private static final CraftCustomTagTypeRegistry TAG_TYPE_REGISTRY = new CraftCustomTagTypeRegistry();
|
||||||
|
|
||||||
private NBTTagCompound internalTag;
|
private NBTTagCompound internalTag;
|
||||||
private final Map<String, NBTBase> unhandledTags = new HashMap<String, NBTBase>();
|
private final Map<String, NBTBase> unhandledTags = new HashMap<String, NBTBase>();
|
||||||
|
private final CraftCustomItemTagContainer publicItemTagContainer = new CraftCustomItemTagContainer(TAG_TYPE_REGISTRY);
|
||||||
|
|
||||||
CraftMetaItem(CraftMetaItem meta) {
|
CraftMetaItem(CraftMetaItem meta) {
|
||||||
if (meta == null) {
|
if (meta == null) {
|
||||||
@ -285,6 +291,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
|||||||
this.unbreakable = meta.unbreakable;
|
this.unbreakable = meta.unbreakable;
|
||||||
this.damage = meta.damage;
|
this.damage = meta.damage;
|
||||||
this.unhandledTags.putAll(meta.unhandledTags);
|
this.unhandledTags.putAll(meta.unhandledTags);
|
||||||
|
this.publicItemTagContainer.putAll(meta.publicItemTagContainer.getRaw());
|
||||||
|
|
||||||
this.internalTag = meta.internalTag;
|
this.internalTag = meta.internalTag;
|
||||||
if (this.internalTag != null) {
|
if (this.internalTag != null) {
|
||||||
@ -339,6 +346,13 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
|||||||
if (tag.hasKey(DAMAGE.NBT)) {
|
if (tag.hasKey(DAMAGE.NBT)) {
|
||||||
damage = tag.getInt(DAMAGE.NBT);
|
damage = tag.getInt(DAMAGE.NBT);
|
||||||
}
|
}
|
||||||
|
if (tag.hasKey(BUKKIT_CUSTOM_TAG.NBT)) {
|
||||||
|
NBTTagCompound compound = tag.getCompound(BUKKIT_CUSTOM_TAG.NBT);
|
||||||
|
Set<String> keys = compound.getKeys();
|
||||||
|
for (String key : keys) {
|
||||||
|
publicItemTagContainer.put(key, compound.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Set<String> keys = tag.getKeys();
|
Set<String> keys = tag.getKeys();
|
||||||
for (String key : keys) {
|
for (String key : keys) {
|
||||||
@ -476,6 +490,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
|||||||
Logger.getLogger(CraftMetaItem.class.getName()).log(Level.SEVERE, null, ex);
|
Logger.getLogger(CraftMetaItem.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map nbtMap = SerializableMeta.getObject(Map.class, map, BUKKIT_CUSTOM_TAG.BUKKIT, true);
|
||||||
|
if (nbtMap != null) {
|
||||||
|
this.publicItemTagContainer.putAll((NBTTagCompound) CraftNBTTagConfigSerializer.deserialize(nbtMap));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void deserializeInternal(NBTTagCompound tag, Object context) {
|
void deserializeInternal(NBTTagCompound tag, Object context) {
|
||||||
@ -575,6 +594,16 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
|||||||
for (Map.Entry<String, NBTBase> e : unhandledTags.entrySet()) {
|
for (Map.Entry<String, NBTBase> e : unhandledTags.entrySet()) {
|
||||||
itemTag.set(e.getKey(), e.getValue());
|
itemTag.set(e.getKey(), e.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!publicItemTagContainer.isEmpty()) {
|
||||||
|
NBTTagCompound bukkitCustomCompound = new NBTTagCompound();
|
||||||
|
Map<String, NBTBase> rawPublicMap = publicItemTagContainer.getRaw();
|
||||||
|
|
||||||
|
for (Map.Entry<String, NBTBase> nbtBaseEntry : rawPublicMap.entrySet()) {
|
||||||
|
bukkitCustomCompound.set(nbtBaseEntry.getKey(), nbtBaseEntry.getValue());
|
||||||
|
}
|
||||||
|
itemTag.set(BUKKIT_CUSTOM_TAG.NBT, bukkitCustomCompound);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static NBTTagList createStringList(List<String> list) {
|
static NBTTagList createStringList(List<String> list) {
|
||||||
@ -659,7 +688,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
|||||||
|
|
||||||
@Overridden
|
@Overridden
|
||||||
boolean isEmpty() {
|
boolean isEmpty() {
|
||||||
return !(hasDisplayName() || hasLocalizedName() || hasEnchants() || hasLore() || hasRepairCost() || !unhandledTags.isEmpty() || hideFlag != 0 || isUnbreakable() || hasDamage() || hasAttributeModifiers());
|
return !(hasDisplayName() || hasLocalizedName() || hasEnchants() || hasLore() || hasRepairCost() || !unhandledTags.isEmpty() || !publicItemTagContainer.isEmpty() || hideFlag != 0 || isUnbreakable() || hasDamage() || hasAttributeModifiers());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
@ -926,6 +955,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
|||||||
return removed > 0;
|
return removed > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CustomItemTagContainer getCustomTagContainer() {
|
||||||
|
return this.publicItemTagContainer;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean compareModifiers(Multimap<Attribute, AttributeModifier> first, Multimap<Attribute, AttributeModifier> second) {
|
private static boolean compareModifiers(Multimap<Attribute, AttributeModifier> first, Multimap<Attribute, AttributeModifier> second) {
|
||||||
if (first == null || second == null) {
|
if (first == null || second == null) {
|
||||||
return false;
|
return false;
|
||||||
@ -986,6 +1020,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
|||||||
&& (this.hasRepairCost() ? that.hasRepairCost() && this.repairCost == that.repairCost : !that.hasRepairCost())
|
&& (this.hasRepairCost() ? that.hasRepairCost() && this.repairCost == that.repairCost : !that.hasRepairCost())
|
||||||
&& (this.hasAttributeModifiers() ? that.hasAttributeModifiers() && compareModifiers(this.attributeModifiers, that.attributeModifiers) : !that.hasAttributeModifiers())
|
&& (this.hasAttributeModifiers() ? that.hasAttributeModifiers() && compareModifiers(this.attributeModifiers, that.attributeModifiers) : !that.hasAttributeModifiers())
|
||||||
&& (this.unhandledTags.equals(that.unhandledTags))
|
&& (this.unhandledTags.equals(that.unhandledTags))
|
||||||
|
&& (this.publicItemTagContainer.equals(that.publicItemTagContainer))
|
||||||
&& (this.hideFlag == that.hideFlag)
|
&& (this.hideFlag == that.hideFlag)
|
||||||
&& (this.isUnbreakable() == that.isUnbreakable())
|
&& (this.isUnbreakable() == that.isUnbreakable())
|
||||||
&& (this.hasDamage() ? that.hasDamage() && this.damage == that.damage : !that.hasDamage());
|
&& (this.hasDamage() ? that.hasDamage() && this.damage == that.damage : !that.hasDamage());
|
||||||
@ -1015,6 +1050,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
|||||||
hash = 61 * hash + (hasEnchants() ? this.enchantments.hashCode() : 0);
|
hash = 61 * hash + (hasEnchants() ? this.enchantments.hashCode() : 0);
|
||||||
hash = 61 * hash + (hasRepairCost() ? this.repairCost : 0);
|
hash = 61 * hash + (hasRepairCost() ? this.repairCost : 0);
|
||||||
hash = 61 * hash + unhandledTags.hashCode();
|
hash = 61 * hash + unhandledTags.hashCode();
|
||||||
|
hash = 61 * hash + (!publicItemTagContainer.isEmpty() ? publicItemTagContainer.hashCode() : 0);
|
||||||
hash = 61 * hash + hideFlag;
|
hash = 61 * hash + hideFlag;
|
||||||
hash = 61 * hash + (isUnbreakable() ? 1231 : 1237);
|
hash = 61 * hash + (isUnbreakable() ? 1231 : 1237);
|
||||||
hash = 61 * hash + (hasDamage() ? this.damage : 0);
|
hash = 61 * hash + (hasDamage() ? this.damage : 0);
|
||||||
@ -1104,6 +1140,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!publicItemTagContainer.isEmpty()) { // Store custom tags, wrapped in their compound
|
||||||
|
builder.put(BUKKIT_CUSTOM_TAG.BUKKIT, publicItemTagContainer.serialize());
|
||||||
|
}
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1199,6 +1239,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
|
|||||||
HIDEFLAGS.NBT,
|
HIDEFLAGS.NBT,
|
||||||
UNBREAKABLE.NBT,
|
UNBREAKABLE.NBT,
|
||||||
DAMAGE.NBT,
|
DAMAGE.NBT,
|
||||||
|
BUKKIT_CUSTOM_TAG.NBT,
|
||||||
ATTRIBUTES.NBT,
|
ATTRIBUTES.NBT,
|
||||||
ATTRIBUTES_IDENTIFIER.NBT,
|
ATTRIBUTES_IDENTIFIER.NBT,
|
||||||
ATTRIBUTES_NAME.NBT,
|
ATTRIBUTES_NAME.NBT,
|
||||||
|
@ -0,0 +1,133 @@
|
|||||||
|
package org.bukkit.craftbukkit.inventory.tags;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.server.NBTBase;
|
||||||
|
import net.minecraft.server.NBTTagCompound;
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.craftbukkit.inventory.CraftCustomTagTypeRegistry;
|
||||||
|
import org.bukkit.craftbukkit.util.CraftNBTTagConfigSerializer;
|
||||||
|
import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
|
||||||
|
import org.bukkit.inventory.meta.tags.ItemTagAdapterContext;
|
||||||
|
import org.bukkit.inventory.meta.tags.ItemTagType;
|
||||||
|
|
||||||
|
public final class CraftCustomItemTagContainer implements CustomItemTagContainer {
|
||||||
|
|
||||||
|
private final Map<String, NBTBase> customTags = new HashMap<>();
|
||||||
|
private final CraftCustomTagTypeRegistry tagTypeRegistry;
|
||||||
|
private final CraftItemTagAdapterContext adapterContext;
|
||||||
|
|
||||||
|
public CraftCustomItemTagContainer(Map<String, NBTBase> customTags, CraftCustomTagTypeRegistry tagTypeRegistry) {
|
||||||
|
this(tagTypeRegistry);
|
||||||
|
this.customTags.putAll(customTags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CraftCustomItemTagContainer(CraftCustomTagTypeRegistry tagTypeRegistry) {
|
||||||
|
this.tagTypeRegistry = tagTypeRegistry;
|
||||||
|
this.adapterContext = new CraftItemTagAdapterContext(this.tagTypeRegistry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T, Z> void setCustomTag(NamespacedKey key, ItemTagType<T, Z> type, Z value) {
|
||||||
|
Validate.notNull(key, "The provided key for the custom value was null");
|
||||||
|
Validate.notNull(type, "The provided type for the custom value was null");
|
||||||
|
Validate.notNull(value, "The provided value for the custom value was null");
|
||||||
|
|
||||||
|
this.customTags.put(key.toString(), tagTypeRegistry.wrap(type.getPrimitiveType(), type.toPrimitive(value, adapterContext)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T, Z> boolean hasCustomTag(NamespacedKey key, ItemTagType<T, Z> type) {
|
||||||
|
Validate.notNull(key, "The provided key for the custom value was null");
|
||||||
|
Validate.notNull(type, "The provided type for the custom value was null");
|
||||||
|
|
||||||
|
NBTBase value = this.customTags.get(key.toString());
|
||||||
|
if (value == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tagTypeRegistry.isInstanceOf(type.getPrimitiveType(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T, Z> Z getCustomTag(NamespacedKey key, ItemTagType<T, Z> type) {
|
||||||
|
Validate.notNull(key, "The provided key for the custom value was null");
|
||||||
|
Validate.notNull(type, "The provided type for the custom value was null");
|
||||||
|
|
||||||
|
NBTBase value = this.customTags.get(key.toString());
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type.fromPrimitive(tagTypeRegistry.extract(type.getPrimitiveType(), value), adapterContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCustomTag(NamespacedKey key) {
|
||||||
|
Validate.notNull(key, "The provided key for the custom value was null");
|
||||||
|
|
||||||
|
this.customTags.remove(key.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return this.customTags.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemTagAdapterContext getAdapterContext() {
|
||||||
|
return this.adapterContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof CraftCustomItemTagContainer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, NBTBase> myRawMap = getRaw();
|
||||||
|
Map<String, NBTBase> theirRawMap = ((CraftCustomItemTagContainer) obj).getRaw();
|
||||||
|
|
||||||
|
return Objects.equals(myRawMap, theirRawMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NBTTagCompound toTagCompound() {
|
||||||
|
NBTTagCompound tag = new NBTTagCompound();
|
||||||
|
for (Entry<String, NBTBase> entry : this.customTags.entrySet()) {
|
||||||
|
tag.set(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(String key, NBTBase base) {
|
||||||
|
this.customTags.put(key, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putAll(Map<String, NBTBase> map) {
|
||||||
|
this.customTags.putAll(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putAll(NBTTagCompound compound) {
|
||||||
|
for (String key : compound.getKeys()) {
|
||||||
|
this.customTags.put(key, compound.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, NBTBase> getRaw() {
|
||||||
|
return this.customTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hashCode = 3;
|
||||||
|
hashCode += this.customTags.hashCode(); // We will simply add the maps hashcode
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> serialize() {
|
||||||
|
return (Map<String, Object>) CraftNBTTagConfigSerializer.serialize(toTagCompound());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package org.bukkit.craftbukkit.inventory.tags;
|
||||||
|
|
||||||
|
import org.bukkit.craftbukkit.inventory.CraftCustomTagTypeRegistry;
|
||||||
|
import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
|
||||||
|
import org.bukkit.inventory.meta.tags.ItemTagAdapterContext;
|
||||||
|
|
||||||
|
public final class CraftItemTagAdapterContext implements ItemTagAdapterContext {
|
||||||
|
|
||||||
|
private final CraftCustomTagTypeRegistry registry;
|
||||||
|
|
||||||
|
public CraftItemTagAdapterContext(CraftCustomTagTypeRegistry registry) {
|
||||||
|
this.registry = registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new and empty tag container instance
|
||||||
|
*
|
||||||
|
* @return the fresh container instance
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CustomItemTagContainer newTagContainer() {
|
||||||
|
return new CraftCustomItemTagContainer(this.registry);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
package org.bukkit.craftbukkit.util;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.StringReader;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import net.minecraft.server.MojangsonParser;
|
||||||
|
import net.minecraft.server.NBTBase;
|
||||||
|
import net.minecraft.server.NBTList;
|
||||||
|
import net.minecraft.server.NBTTagCompound;
|
||||||
|
import net.minecraft.server.NBTTagList;
|
||||||
|
import net.minecraft.server.NBTTagString;
|
||||||
|
|
||||||
|
public class CraftNBTTagConfigSerializer {
|
||||||
|
|
||||||
|
private static final Pattern ARRAY = Pattern.compile("^\\[.*]");
|
||||||
|
private static final MojangsonParser MOJANGSON_PARSER = new MojangsonParser(new StringReader(""));
|
||||||
|
|
||||||
|
public static Object serialize(NBTBase base) {
|
||||||
|
if (base instanceof NBTTagCompound) {
|
||||||
|
Map<String, Object> innerMap = new HashMap<>();
|
||||||
|
for (String key : ((NBTTagCompound) base).getKeys()) {
|
||||||
|
innerMap.put(key, serialize(((NBTTagCompound) base).get(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return innerMap;
|
||||||
|
} else if (base instanceof NBTTagList) {
|
||||||
|
List<Object> baseList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < ((NBTList) base).size(); i++) {
|
||||||
|
baseList.add(serialize(((NBTList) base).get(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseList;
|
||||||
|
} else if (base instanceof NBTTagString) {
|
||||||
|
return base.b_(); //PAIL Rename getString
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NBTBase deserialize(Object object) {
|
||||||
|
if (object instanceof Map) {
|
||||||
|
NBTTagCompound compound = new NBTTagCompound();
|
||||||
|
for (Map.Entry<String, Object> entry : ((Map<String, Object>) object).entrySet()) {
|
||||||
|
compound.set(entry.getKey(), deserialize(entry.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return compound;
|
||||||
|
} else if (object instanceof List) {
|
||||||
|
List<Object> list = (List<Object>) object;
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
return new NBTTagList(); // Default
|
||||||
|
}
|
||||||
|
|
||||||
|
NBTTagList tagList = new NBTTagList();
|
||||||
|
for (Object tag : list) {
|
||||||
|
tagList.add(deserialize(tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
return tagList;
|
||||||
|
} else if (object instanceof String) {
|
||||||
|
String string = (String) object;
|
||||||
|
|
||||||
|
if (ARRAY.matcher(string).matches()) {
|
||||||
|
try {
|
||||||
|
return new MojangsonParser(new StringReader(string)).h(); // PAIL Rename parseTagList
|
||||||
|
} catch (CommandSyntaxException e) {
|
||||||
|
throw new RuntimeException("Could not deserialize found list ", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return MOJANGSON_PARSER.b(string); // PAIL Rename parse tagBase
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException("Could not deserialize NBTBase");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,302 @@
|
|||||||
|
package org.bukkit.craftbukkit.inventory;
|
||||||
|
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.minecraft.server.NBTBase;
|
||||||
|
import net.minecraft.server.NBTTagCompound;
|
||||||
|
import net.minecraft.server.NBTTagIntArray;
|
||||||
|
import net.minecraft.server.NBTTagList;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.craftbukkit.inventory.tags.CraftCustomItemTagContainer;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
|
||||||
|
import org.bukkit.inventory.meta.tags.ItemTagAdapterContext;
|
||||||
|
import org.bukkit.inventory.meta.tags.ItemTagType;
|
||||||
|
import org.bukkit.support.AbstractTestingBase;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class ItemMetaCustomValueTest extends AbstractTestingBase {
|
||||||
|
|
||||||
|
private static NamespacedKey VALID_KEY;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
VALID_KEY = new NamespacedKey("test", "validkey");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sets a test
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testSetNoAdapter() {
|
||||||
|
ItemMeta itemMeta = createNewItemMeta();
|
||||||
|
itemMeta.getCustomTagContainer().setCustomTag(VALID_KEY, new PrimitiveTagType<>(boolean.class), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Contains a tag
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testHasNoAdapter() {
|
||||||
|
ItemMeta itemMeta = createNewItemMeta();
|
||||||
|
itemMeta.getCustomTagContainer().setCustomTag(VALID_KEY, ItemTagType.INTEGER, 1); // We gotta set this so we at least try to compare it
|
||||||
|
itemMeta.getCustomTagContainer().hasCustomTag(VALID_KEY, new PrimitiveTagType<>(boolean.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Getting a tag
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testGetNoAdapter() {
|
||||||
|
ItemMeta itemMeta = createNewItemMeta();
|
||||||
|
itemMeta.getCustomTagContainer().setCustomTag(VALID_KEY, ItemTagType.INTEGER, 1); //We gotta set this so we at least try to compare it
|
||||||
|
itemMeta.getCustomTagContainer().getCustomTag(VALID_KEY, new PrimitiveTagType<>(boolean.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testGetWrongType() {
|
||||||
|
ItemMeta itemMeta = createNewItemMeta();
|
||||||
|
itemMeta.getCustomTagContainer().setCustomTag(VALID_KEY, ItemTagType.INTEGER, 1);
|
||||||
|
itemMeta.getCustomTagContainer().getCustomTag(VALID_KEY, ItemTagType.STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDifferentNamespace() {
|
||||||
|
NamespacedKey namespacedKeyA = new NamespacedKey("plugin-a", "damage");
|
||||||
|
NamespacedKey namespacedKeyB = new NamespacedKey("plugin-b", "damage");
|
||||||
|
|
||||||
|
ItemMeta meta = createNewItemMeta();
|
||||||
|
meta.getCustomTagContainer().setCustomTag(namespacedKeyA, ItemTagType.LONG, 15L);
|
||||||
|
meta.getCustomTagContainer().setCustomTag(namespacedKeyB, ItemTagType.LONG, 160L);
|
||||||
|
|
||||||
|
assertEquals(15L, (long) meta.getCustomTagContainer().getCustomTag(namespacedKeyA, ItemTagType.LONG));
|
||||||
|
assertEquals(160L, (long) meta.getCustomTagContainer().getCustomTag(namespacedKeyB, ItemTagType.LONG));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemMeta createNewItemMeta() {
|
||||||
|
return Bukkit.getItemFactory().getItemMeta(Material.DIAMOND_PICKAXE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NamespacedKey requestKey(String keyName) {
|
||||||
|
return new NamespacedKey("test-plugin", keyName.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Removing a tag
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testNBTTagStoring() {
|
||||||
|
CraftMetaItem itemMeta = createComplexItemMeta();
|
||||||
|
|
||||||
|
NBTTagCompound compound = new NBTTagCompound();
|
||||||
|
itemMeta.applyToItem(compound);
|
||||||
|
|
||||||
|
assertEquals(itemMeta, new CraftMetaItem(compound));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMapStoring() {
|
||||||
|
CraftMetaItem itemMeta = createComplexItemMeta();
|
||||||
|
|
||||||
|
Map<String, Object> serialize = itemMeta.serialize();
|
||||||
|
assertEquals(itemMeta, new CraftMetaItem(serialize));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testYAMLStoring() {
|
||||||
|
ItemStack stack = new ItemStack(Material.DIAMOND);
|
||||||
|
CraftMetaItem meta = createComplexItemMeta();
|
||||||
|
stack.setItemMeta(meta);
|
||||||
|
|
||||||
|
YamlConfiguration configuration = new YamlConfiguration();
|
||||||
|
configuration.set("testpath", stack);
|
||||||
|
|
||||||
|
String configValue = configuration.saveToString();
|
||||||
|
YamlConfiguration loadedConfig = YamlConfiguration.loadConfiguration(new StringReader(configValue));
|
||||||
|
|
||||||
|
assertEquals(stack, loadedConfig.getSerializable("testpath", ItemStack.class));
|
||||||
|
assertNotEquals(new ItemStack(Material.DIAMOND), loadedConfig.getSerializable("testpath", ItemStack.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
private CraftMetaItem createComplexItemMeta() {
|
||||||
|
CraftMetaItem itemMeta = (CraftMetaItem) createNewItemMeta();
|
||||||
|
itemMeta.setDisplayName("Item Display Name");
|
||||||
|
|
||||||
|
itemMeta.getCustomTagContainer().setCustomTag(requestKey("custom-long"), ItemTagType.LONG, 4L); //Add random primitive values
|
||||||
|
itemMeta.getCustomTagContainer().setCustomTag(requestKey("custom-byte-array"), ItemTagType.BYTE_ARRAY, new byte[]{
|
||||||
|
0, 1, 2, 10
|
||||||
|
});
|
||||||
|
itemMeta.getCustomTagContainer().setCustomTag(requestKey("custom-string"), ItemTagType.STRING, "Hello there world");
|
||||||
|
|
||||||
|
CustomItemTagContainer innerContainer = itemMeta.getCustomTagContainer().getAdapterContext().newTagContainer(); //Add a inner container
|
||||||
|
innerContainer.setCustomTag(VALID_KEY, ItemTagType.LONG, 5L);
|
||||||
|
itemMeta.getCustomTagContainer().setCustomTag(requestKey("custom-inner-compound"), ItemTagType.TAG_CONTAINER, innerContainer);
|
||||||
|
|
||||||
|
Map<String, NBTBase> rawMap = ((CraftCustomItemTagContainer) itemMeta.getCustomTagContainer()).getRaw(); //Adds a tag list as well (even tho is has no API yet)
|
||||||
|
NBTTagList nbtList = new NBTTagList();
|
||||||
|
nbtList.add(new NBTTagIntArray(Arrays.asList(1, 5, 3)));
|
||||||
|
nbtList.add(new NBTTagIntArray(Arrays.asList(42, 51)));
|
||||||
|
rawMap.put("nbttaglist", nbtList);
|
||||||
|
return itemMeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Test complex object storage
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void storeUUIDOnItemTest() {
|
||||||
|
ItemMeta itemMeta = createNewItemMeta();
|
||||||
|
UUIDItemTagType uuidItemTagType = new UUIDItemTagType();
|
||||||
|
UUID uuid = UUID.fromString("434eea72-22a6-4c61-b5ef-945874a5c478");
|
||||||
|
|
||||||
|
itemMeta.getCustomTagContainer().setCustomTag(VALID_KEY, uuidItemTagType, uuid);
|
||||||
|
assertTrue(itemMeta.getCustomTagContainer().hasCustomTag(VALID_KEY, uuidItemTagType));
|
||||||
|
assertEquals(uuid, itemMeta.getCustomTagContainer().getCustomTag(VALID_KEY, uuidItemTagType));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void encapsulatedContainers() {
|
||||||
|
NamespacedKey innerKey = new NamespacedKey("plugin-a", "inner");
|
||||||
|
|
||||||
|
ItemMeta meta = createNewItemMeta();
|
||||||
|
ItemTagAdapterContext context = meta.getCustomTagContainer().getAdapterContext();
|
||||||
|
|
||||||
|
CustomItemTagContainer thirdContainer = context.newTagContainer();
|
||||||
|
thirdContainer.setCustomTag(VALID_KEY, ItemTagType.LONG, 3L);
|
||||||
|
|
||||||
|
CustomItemTagContainer secondContainer = context.newTagContainer();
|
||||||
|
secondContainer.setCustomTag(VALID_KEY, ItemTagType.LONG, 2L);
|
||||||
|
secondContainer.setCustomTag(innerKey, ItemTagType.TAG_CONTAINER, thirdContainer);
|
||||||
|
|
||||||
|
meta.getCustomTagContainer().setCustomTag(VALID_KEY, ItemTagType.LONG, 1L);
|
||||||
|
meta.getCustomTagContainer().setCustomTag(innerKey, ItemTagType.TAG_CONTAINER, secondContainer);
|
||||||
|
|
||||||
|
assertEquals(3L, meta.getCustomTagContainer()
|
||||||
|
.getCustomTag(innerKey, ItemTagType.TAG_CONTAINER)
|
||||||
|
.getCustomTag(innerKey, ItemTagType.TAG_CONTAINER)
|
||||||
|
.getCustomTag(VALID_KEY, ItemTagType.LONG).longValue());
|
||||||
|
|
||||||
|
assertEquals(2L, meta.getCustomTagContainer()
|
||||||
|
.getCustomTag(innerKey, ItemTagType.TAG_CONTAINER)
|
||||||
|
.getCustomTag(VALID_KEY, ItemTagType.LONG).longValue());
|
||||||
|
|
||||||
|
assertEquals(1L, meta.getCustomTagContainer()
|
||||||
|
.getCustomTag(VALID_KEY, ItemTagType.LONG).longValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
class UUIDItemTagType implements ItemTagType<byte[], UUID> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<byte[]> getPrimitiveType() {
|
||||||
|
return byte[].class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<UUID> getComplexType() {
|
||||||
|
return UUID.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toPrimitive(UUID complex, ItemTagAdapterContext context) {
|
||||||
|
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
|
||||||
|
bb.putLong(complex.getMostSignificantBits());
|
||||||
|
bb.putLong(complex.getLeastSignificantBits());
|
||||||
|
return bb.array();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID fromPrimitive(byte[] primitive, ItemTagAdapterContext context) {
|
||||||
|
ByteBuffer bb = ByteBuffer.wrap(primitive);
|
||||||
|
long firstLong = bb.getLong();
|
||||||
|
long secondLong = bb.getLong();
|
||||||
|
return new UUID(firstLong, secondLong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrimitiveCustomTags() {
|
||||||
|
ItemMeta itemMeta = createNewItemMeta();
|
||||||
|
|
||||||
|
testPrimitiveCustomTag(itemMeta, ItemTagType.BYTE, (byte) 1);
|
||||||
|
testPrimitiveCustomTag(itemMeta, ItemTagType.SHORT, (short) 1);
|
||||||
|
testPrimitiveCustomTag(itemMeta, ItemTagType.INTEGER, 1);
|
||||||
|
testPrimitiveCustomTag(itemMeta, ItemTagType.LONG, 1L);
|
||||||
|
testPrimitiveCustomTag(itemMeta, ItemTagType.FLOAT, 1.34F);
|
||||||
|
testPrimitiveCustomTag(itemMeta, ItemTagType.DOUBLE, 151.123);
|
||||||
|
|
||||||
|
testPrimitiveCustomTag(itemMeta, ItemTagType.STRING, "test");
|
||||||
|
|
||||||
|
testPrimitiveCustomTag(itemMeta, ItemTagType.BYTE_ARRAY, new byte[]{
|
||||||
|
1, 4, 2, Byte.MAX_VALUE
|
||||||
|
});
|
||||||
|
testPrimitiveCustomTag(itemMeta, ItemTagType.INTEGER_ARRAY, new int[]{
|
||||||
|
1, 4, 2, Integer.MAX_VALUE
|
||||||
|
});
|
||||||
|
testPrimitiveCustomTag(itemMeta, ItemTagType.LONG_ARRAY, new long[]{
|
||||||
|
1L, 4L, 2L, Long.MAX_VALUE
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T, Z> void testPrimitiveCustomTag(ItemMeta meta, ItemTagType<T, Z> type, Z value) {
|
||||||
|
NamespacedKey tagKey = new NamespacedKey("test", String.valueOf(type.hashCode()));
|
||||||
|
|
||||||
|
meta.getCustomTagContainer().setCustomTag(tagKey, type, value);
|
||||||
|
assertTrue(meta.getCustomTagContainer().hasCustomTag(tagKey, type));
|
||||||
|
|
||||||
|
Z foundValue = meta.getCustomTagContainer().getCustomTag(tagKey, type);
|
||||||
|
if (foundValue.getClass().isArray()) { // Compare arrays using reflection access
|
||||||
|
int length = Array.getLength(foundValue);
|
||||||
|
int originalLength = Array.getLength(value);
|
||||||
|
for (int i = 0; i < length && i < originalLength; i++) {
|
||||||
|
assertEquals(Array.get(value, i), Array.get(foundValue, i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assertEquals(foundValue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
meta.getCustomTagContainer().removeCustomTag(tagKey);
|
||||||
|
assertFalse(meta.getCustomTagContainer().hasCustomTag(tagKey, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrimitiveTagType<T> implements ItemTagType<T, T> {
|
||||||
|
|
||||||
|
private final Class<T> primitiveType;
|
||||||
|
|
||||||
|
PrimitiveTagType(Class<T> primitiveType) {
|
||||||
|
this.primitiveType = primitiveType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<T> getPrimitiveType() {
|
||||||
|
return primitiveType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<T> getComplexType() {
|
||||||
|
return primitiveType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T toPrimitive(T complex, ItemTagAdapterContext context) {
|
||||||
|
return complex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T fromPrimitive(T primitive, ItemTagAdapterContext context) {
|
||||||
|
return primitive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren