Replace ItemTag API with new API that also expands to Tiles and Entities

By: Bjarne Koll <LynxPlay101@gmail.com>
This commit is contained in:
CraftBukkit/Spigot 2019-04-25 14:36:46 +10:00
parent 4198bf7e21
commit c9a23d73a0
16 changed files with 797 additions and 221 deletions

View File

@ -319,7 +319,19 @@
IChatBaseComponent ichatbasecomponent = this.getCustomName(); IChatBaseComponent ichatbasecomponent = this.getCustomName();
if (ichatbasecomponent != null) { if (ichatbasecomponent != null) {
@@ -1414,6 +1595,42 @@ @@ -1331,6 +1512,11 @@
}
}
+ // CraftBukkit start - stores eventually existing bukkit values
+ if (this.bukkitEntity != null) {
+ this.bukkitEntity.storeBukkitValues(nbttagcompound);
+ }
+ // CraftBukkit end
return nbttagcompound;
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Saving entity NBT");
@@ -1414,6 +1600,42 @@
} else { } else {
throw new IllegalStateException("Entity has invalid position"); throw new IllegalStateException("Entity has invalid position");
} }
@ -362,7 +374,7 @@
} catch (Throwable throwable) { } catch (Throwable throwable) {
CrashReport crashreport = CrashReport.a(throwable, "Loading entity NBT"); CrashReport crashreport = CrashReport.a(throwable, "Loading entity NBT");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being loaded"); CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being loaded");
@@ -1489,9 +1706,22 @@ @@ -1489,9 +1711,22 @@
} else if (this.world.isClientSide) { } else if (this.world.isClientSide) {
return null; return null;
} else { } else {
@ -385,7 +397,7 @@
this.world.addEntity(entityitem); this.world.addEntity(entityitem);
return entityitem; return entityitem;
} }
@@ -1595,7 +1825,7 @@ @@ -1595,7 +1830,7 @@
} }
this.vehicle = entity; this.vehicle = entity;
@ -394,7 +406,7 @@
return true; return true;
} }
} }
@@ -1620,15 +1850,36 @@ @@ -1620,15 +1855,36 @@
Entity entity = this.vehicle; Entity entity = this.vehicle;
this.vehicle = null; this.vehicle = null;
@ -433,7 +445,7 @@
if (!this.world.isClientSide && entity instanceof EntityHuman && !(this.getRidingPassenger() instanceof EntityHuman)) { if (!this.world.isClientSide && entity instanceof EntityHuman && !(this.getRidingPassenger() instanceof EntityHuman)) {
this.passengers.add(0, entity); this.passengers.add(0, entity);
} else { } else {
@@ -1636,15 +1887,33 @@ @@ -1636,15 +1892,33 @@
} }
} }
@ -468,7 +480,7 @@
} }
protected boolean q(Entity entity) { protected boolean q(Entity entity) {
@@ -1687,7 +1956,7 @@ @@ -1687,7 +1961,7 @@
int i = this.ab(); int i = this.ab();
if (this.ai) { if (this.ai) {
@ -477,7 +489,7 @@
this.world.getMethodProfiler().enter("portal"); this.world.getMethodProfiler().enter("portal");
this.aj = i; this.aj = i;
this.portalCooldown = this.aW(); this.portalCooldown = this.aW();
@@ -1771,6 +2040,13 @@ @@ -1771,6 +2045,13 @@
} }
public void setSwimming(boolean flag) { public void setSwimming(boolean flag) {
@ -491,7 +503,7 @@
this.setFlag(4, flag); this.setFlag(4, flag);
} }
@@ -1831,16 +2107,56 @@ @@ -1831,16 +2112,56 @@
} }
public void setAirTicks(int i) { public void setAirTicks(int i) {
@ -551,7 +563,7 @@
} }
public void j(boolean flag) { public void j(boolean flag) {
@@ -1988,20 +2304,33 @@ @@ -1988,20 +2309,33 @@
@Nullable @Nullable
public Entity a(DimensionManager dimensionmanager) { public Entity a(DimensionManager dimensionmanager) {
@ -588,7 +600,7 @@
if (dimensionmanager1 == DimensionManager.THE_END && dimensionmanager == DimensionManager.OVERWORLD) { if (dimensionmanager1 == DimensionManager.THE_END && dimensionmanager == DimensionManager.OVERWORLD) {
blockposition = worldserver1.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING_NO_LEAVES, worldserver1.getSpawn()); blockposition = worldserver1.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING_NO_LEAVES, worldserver1.getSpawn());
} else if (dimensionmanager == DimensionManager.THE_END) { } else if (dimensionmanager == DimensionManager.THE_END) {
@@ -2039,6 +2368,25 @@ @@ -2039,6 +2373,25 @@
vec3d = shapedetector_c.b; vec3d = shapedetector_c.b;
f = (float) shapedetector_c.c; f = (float) shapedetector_c.c;
} }
@ -614,7 +626,7 @@
this.world.getMethodProfiler().exitEnter("reloading"); this.world.getMethodProfiler().exitEnter("reloading");
Entity entity = this.getEntityType().a((World) worldserver1); Entity entity = this.getEntityType().a((World) worldserver1);
@@ -2048,6 +2396,14 @@ @@ -2048,6 +2401,14 @@
entity.setPositionRotation(blockposition, entity.yaw + f, entity.pitch); entity.setPositionRotation(blockposition, entity.yaw + f, entity.pitch);
entity.setMot(vec3d); entity.setMot(vec3d);
worldserver1.addEntityTeleport(entity); worldserver1.addEntityTeleport(entity);
@ -629,7 +641,7 @@
} }
this.dead = true; this.dead = true;
@@ -2239,7 +2595,26 @@ @@ -2239,7 +2600,26 @@
} }
public void a(AxisAlignedBB axisalignedbb) { public void a(AxisAlignedBB axisalignedbb) {

View File

@ -1,15 +1,47 @@
--- a/net/minecraft/server/TileEntity.java --- a/net/minecraft/server/TileEntity.java
+++ b/net/minecraft/server/TileEntity.java +++ b/net/minecraft/server/TileEntity.java
@@ -4,6 +4,8 @@ @@ -3,9 +3,18 @@
import javax.annotation.Nullable;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
+// CraftBukkit start
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer;
+import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry;
+import org.bukkit.inventory.InventoryHolder;
+// CraftBukkit end
+import org.bukkit.inventory.InventoryHolder; // CraftBukkit
+
public abstract class TileEntity { public abstract class TileEntity {
+ // CraftBukkit start - data containers
+ private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
+ public final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(DATA_TYPE_REGISTRY);
+ // CraftBukkit end
private static final Logger LOGGER = LogManager.getLogger(); private static final Logger LOGGER = LogManager.getLogger();
@@ -55,8 +57,15 @@ private final TileEntityTypes<?> b;
@Nullable
@@ -35,6 +44,12 @@
public void load(NBTTagCompound nbttagcompound) {
this.position = new BlockPosition(nbttagcompound.getInt("x"), nbttagcompound.getInt("y"), nbttagcompound.getInt("z"));
+ // CraftBukkit start - read container
+ NBTTagCompound persistentDataTag = nbttagcompound.getCompound("PublicBukkitValues");
+ if (persistentDataTag != null) {
+ this.persistentDataContainer.putAll(persistentDataTag);
+ }
+ // CraftBukkit end
}
public NBTTagCompound save(NBTTagCompound nbttagcompound) {
@@ -51,12 +66,24 @@
nbttagcompound.setInt("x", this.position.getX());
nbttagcompound.setInt("y", this.position.getY());
nbttagcompound.setInt("z", this.position.getZ());
+ // CraftBukkit start - store container
+ if (!this.persistentDataContainer.isEmpty()) {
+ nbttagcompound.set("PublicBukkitValues", this.persistentDataContainer.toTagCompound());
+ }
+ // CraftBukkit end
return nbttagcompound;
} }
} }
@ -25,7 +57,7 @@
String s = nbttagcompound.getString("id"); String s = nbttagcompound.getString("id");
return (TileEntity) IRegistry.BLOCK_ENTITY_TYPE.getOptional(new MinecraftKey(s)).map((tileentitytypes) -> { return (TileEntity) IRegistry.BLOCK_ENTITY_TYPE.getOptional(new MinecraftKey(s)).map((tileentitytypes) -> {
@@ -68,6 +77,7 @@ @@ -68,6 +95,7 @@
} }
}).map((tileentity) -> { }).map((tileentity) -> {
try { try {
@ -33,7 +65,7 @@
tileentity.load(nbttagcompound); tileentity.load(nbttagcompound);
return tileentity; return tileentity;
} catch (Throwable throwable) { } catch (Throwable throwable) {
@@ -157,4 +167,13 @@ @@ -157,4 +185,13 @@
public TileEntityTypes<?> q() { public TileEntityTypes<?> q() {
return this.b; return this.b;
} }

View File

@ -6,9 +6,11 @@ import net.minecraft.server.TileEntity;
import net.minecraft.server.World; import net.minecraft.server.World;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.TileState;
import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.persistence.PersistentDataContainer;
public class CraftBlockEntityState<T extends TileEntity> extends CraftBlockState { public class CraftBlockEntityState<T extends TileEntity> extends CraftBlockState implements TileState {
private final Class<T> tileEntityClass; private final Class<T> tileEntityClass;
private final T tileEntity; private final T tileEntity;
@ -118,4 +120,9 @@ public class CraftBlockEntityState<T extends TileEntity> extends CraftBlockState
return result; return result;
} }
@Override
public PersistentDataContainer getPersistentDataContainer() {
return this.getSnapshot().persistentDataContainer;
}
} }

View File

@ -146,6 +146,8 @@ import org.bukkit.block.PistonMoveReaction;
import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer;
import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry;
import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftChatMessage;
import org.bukkit.craftbukkit.util.CraftVector; import org.bukkit.craftbukkit.util.CraftVector;
import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent;
@ -163,10 +165,12 @@ import org.bukkit.util.Vector;
public abstract class CraftEntity implements org.bukkit.entity.Entity { public abstract class CraftEntity implements org.bukkit.entity.Entity {
private static PermissibleBase perm; private static PermissibleBase perm;
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
protected final CraftServer server; protected final CraftServer server;
protected Entity entity; protected Entity entity;
private EntityDamageEvent lastDamageEvent; private EntityDamageEvent lastDamageEvent;
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(DATA_TYPE_REGISTRY);
public CraftEntity(final CraftServer server, final Entity entity) { public CraftEntity(final CraftServer server, final Entity entity) {
this.server = server; this.server = server;
@ -884,6 +888,24 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return CraftBlock.notchToBlockFace(getHandle().getAdjustedDirection()); return CraftBlock.notchToBlockFace(getHandle().getAdjustedDirection());
} }
@Override
public CraftPersistentDataContainer getPersistentDataContainer() {
return persistentDataContainer;
}
public void storeBukkitValues(NBTTagCompound c) {
if (!this.persistentDataContainer.isEmpty()) {
c.set("BukkitValues", this.persistentDataContainer.toTagCompound());
}
}
public void readBukkitValues(NBTTagCompound c) {
NBTTagCompound base = c.getCompound("BukkitValues");
if (base != null) {
this.persistentDataContainer.putAll(base);
}
}
protected NBTTagCompound save() { protected NBTTagCompound save() {
NBTTagCompound nbttagcompound = new NBTTagCompound(); NBTTagCompound nbttagcompound = new NBTTagCompound();

View File

@ -62,7 +62,9 @@ import org.bukkit.craftbukkit.attribute.CraftAttributeInstance;
import org.bukkit.craftbukkit.attribute.CraftAttributeMap; import org.bukkit.craftbukkit.attribute.CraftAttributeMap;
import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.block.data.CraftBlockData;
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.inventory.tags.DeprecatedCustomTagContainer;
import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer;
import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry;
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.CraftNBTTagConfigSerializer;
@ -75,6 +77,7 @@ 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 org.bukkit.inventory.meta.tags.CustomItemTagContainer;
import org.bukkit.persistence.PersistentDataContainer;
/** /**
* Children must include the following: * Children must include the following:
@ -267,11 +270,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
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 static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
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); private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(DATA_TYPE_REGISTRY);
private int version = CraftMagicNumbers.INSTANCE.getDataVersion(); // Internal use only private int version = CraftMagicNumbers.INSTANCE.getDataVersion(); // Internal use only
@ -303,7 +306,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
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.persistentDataContainer.putAll(meta.persistentDataContainer.getRaw());
this.internalTag = meta.internalTag; this.internalTag = meta.internalTag;
if (this.internalTag != null) { if (this.internalTag != null) {
@ -375,7 +378,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
NBTTagCompound compound = tag.getCompound(BUKKIT_CUSTOM_TAG.NBT); NBTTagCompound compound = tag.getCompound(BUKKIT_CUSTOM_TAG.NBT);
Set<String> keys = compound.getKeys(); Set<String> keys = compound.getKeys();
for (String key : keys) { for (String key : keys) {
publicItemTagContainer.put(key, compound.get(key)); persistentDataContainer.put(key, compound.get(key));
} }
} }
@ -534,7 +537,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
Map nbtMap = SerializableMeta.getObject(Map.class, map, BUKKIT_CUSTOM_TAG.BUKKIT, true); Map nbtMap = SerializableMeta.getObject(Map.class, map, BUKKIT_CUSTOM_TAG.BUKKIT, true);
if (nbtMap != null) { if (nbtMap != null) {
this.publicItemTagContainer.putAll((NBTTagCompound) CraftNBTTagConfigSerializer.deserialize(nbtMap)); this.persistentDataContainer.putAll((NBTTagCompound) CraftNBTTagConfigSerializer.deserialize(nbtMap));
} }
} }
@ -648,9 +651,9 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
itemTag.set(e.getKey(), e.getValue()); itemTag.set(e.getKey(), e.getValue());
} }
if (!publicItemTagContainer.isEmpty()) { if (!persistentDataContainer.isEmpty()) {
NBTTagCompound bukkitCustomCompound = new NBTTagCompound(); NBTTagCompound bukkitCustomCompound = new NBTTagCompound();
Map<String, NBTBase> rawPublicMap = publicItemTagContainer.getRaw(); Map<String, NBTBase> rawPublicMap = persistentDataContainer.getRaw();
for (Map.Entry<String, NBTBase> nbtBaseEntry : rawPublicMap.entrySet()) { for (Map.Entry<String, NBTBase> nbtBaseEntry : rawPublicMap.entrySet()) {
bukkitCustomCompound.set(nbtBaseEntry.getKey(), nbtBaseEntry.getValue()); bukkitCustomCompound.set(nbtBaseEntry.getKey(), nbtBaseEntry.getValue());
@ -741,7 +744,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
@Overridden @Overridden
boolean isEmpty() { boolean isEmpty() {
return !(hasDisplayName() || hasLocalizedName() || hasEnchants() || hasLore() || hasCustomModelData() || hasBlockData() || hasRepairCost() || !unhandledTags.isEmpty() || !publicItemTagContainer.isEmpty() || hideFlag != 0 || isUnbreakable() || hasDamage() || hasAttributeModifiers()); return !(hasDisplayName() || hasLocalizedName() || hasEnchants() || hasLore() || hasCustomModelData() || hasBlockData() || hasRepairCost() || !unhandledTags.isEmpty() || !persistentDataContainer.isEmpty() || hideFlag != 0 || isUnbreakable() || hasDamage() || hasAttributeModifiers());
} }
public String getDisplayName() { public String getDisplayName() {
@ -1041,7 +1044,12 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
@Override @Override
public CustomItemTagContainer getCustomTagContainer() { public CustomItemTagContainer getCustomTagContainer() {
return this.publicItemTagContainer; return new DeprecatedCustomTagContainer(this.getPersistentDataContainer());
}
@Override
public PersistentDataContainer getPersistentDataContainer() {
return this.persistentDataContainer;
} }
private static boolean compareModifiers(Multimap<Attribute, AttributeModifier> first, Multimap<Attribute, AttributeModifier> second) { private static boolean compareModifiers(Multimap<Attribute, AttributeModifier> first, Multimap<Attribute, AttributeModifier> second) {
@ -1106,7 +1114,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
&& (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.persistentDataContainer.equals(that.persistentDataContainer))
&& (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())
@ -1139,7 +1147,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
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 + (!persistentDataContainer.isEmpty() ? persistentDataContainer.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);
@ -1240,8 +1248,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
} }
} }
if (!publicItemTagContainer.isEmpty()) { // Store custom tags, wrapped in their compound if (!persistentDataContainer.isEmpty()) { // Store custom tags, wrapped in their compound
builder.put(BUKKIT_CUSTOM_TAG.BUKKIT, publicItemTagContainer.serialize()); builder.put(BUKKIT_CUSTOM_TAG.BUKKIT, persistentDataContainer.serialize());
} }
return builder; return builder;

View File

@ -1,133 +0,0 @@
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());
}
}

View File

@ -1,24 +0,0 @@
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);
}
}

View File

@ -0,0 +1,48 @@
package org.bukkit.craftbukkit.inventory.tags;
import org.apache.commons.lang3.Validate;
import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer;
import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
import org.bukkit.inventory.meta.tags.ItemTagType;
import org.bukkit.persistence.PersistentDataAdapterContext;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
public final class DeprecatedContainerTagType<Z> implements PersistentDataType<PersistentDataContainer, Z> {
private final ItemTagType<CustomItemTagContainer, Z> deprecated;
DeprecatedContainerTagType(ItemTagType<CustomItemTagContainer, Z> deprecated) {
this.deprecated = deprecated;
}
@Override
public Class<PersistentDataContainer> getPrimitiveType() {
return PersistentDataContainer.class;
}
@Override
public Class<Z> getComplexType() {
return deprecated.getComplexType();
}
@Override
public PersistentDataContainer toPrimitive(Z complex, PersistentDataAdapterContext context) {
CustomItemTagContainer deprecated = this.deprecated.toPrimitive(complex, new DeprecatedItemAdapterContext(context));
Validate.isInstanceOf(DeprecatedCustomTagContainer.class, deprecated, "Could not wrap deprecated API due to foreign CustomItemTagContainer implementation %s", deprecated.getClass().getSimpleName());
DeprecatedCustomTagContainer tagContainer = (DeprecatedCustomTagContainer) deprecated;
PersistentDataContainer wrapped = tagContainer.getWrapped();
Validate.isInstanceOf(CraftPersistentDataContainer.class, wrapped, "Could not wrap deprecated API due to wrong deprecation wrapper %s", deprecated.getClass().getSimpleName());
CraftPersistentDataContainer craftTagContainer = (CraftPersistentDataContainer) wrapped;
return new CraftPersistentDataContainer(craftTagContainer.getRaw(), craftTagContainer.getDataTagTypeRegistry());
}
@Override
public Z fromPrimitive(PersistentDataContainer primitive, PersistentDataAdapterContext context) {
Validate.isInstanceOf(CraftPersistentDataContainer.class, primitive, "Could not wrap deprecated API due to foreign PersistentMetadataContainer implementation %s", primitive.getClass().getSimpleName());
return this.deprecated.fromPrimitive(new DeprecatedCustomTagContainer(primitive), new DeprecatedItemAdapterContext(context));
}
}

View File

@ -0,0 +1,68 @@
package org.bukkit.craftbukkit.inventory.tags;
import java.util.Objects;
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
import org.bukkit.inventory.meta.tags.ItemTagAdapterContext;
import org.bukkit.inventory.meta.tags.ItemTagType;
import org.bukkit.persistence.PersistentDataContainer;
/**
* The {@link DeprecatedCustomTagContainer} is a simply wrapper implementation
* that wraps the new api to still be usable with the old api parts.
*/
@SuppressWarnings("unchecked")
public final class DeprecatedCustomTagContainer implements CustomItemTagContainer {
private final PersistentDataContainer wrapped;
public DeprecatedCustomTagContainer(PersistentDataContainer wrapped) {
this.wrapped = wrapped;
}
@Override
public <T, Z> void setCustomTag(NamespacedKey key, ItemTagType<T, Z> type, Z value) {
if (Objects.equals(CustomItemTagContainer.class, type.getPrimitiveType())) {
wrapped.set(key, new DeprecatedContainerTagType<>((ItemTagType<CustomItemTagContainer, Z>) type), value);
} else {
wrapped.set(key, new DeprecatedItemTagType<>(type), value);
}
}
@Override
public <T, Z> boolean hasCustomTag(NamespacedKey key, ItemTagType<T, Z> type) {
if (Objects.equals(CustomItemTagContainer.class, type.getPrimitiveType())) {
return wrapped.has(key, new DeprecatedContainerTagType<>((ItemTagType<CustomItemTagContainer, Z>) type));
} else {
return wrapped.has(key, new DeprecatedItemTagType<>(type));
}
}
@Override
public <T, Z> Z getCustomTag(NamespacedKey key, ItemTagType<T, Z> type) {
if (Objects.equals(CustomItemTagContainer.class, type.getPrimitiveType())) {
return wrapped.get(key, new DeprecatedContainerTagType<>((ItemTagType<CustomItemTagContainer, Z>) type));
} else {
return wrapped.get(key, new DeprecatedItemTagType<>(type));
}
}
@Override
public void removeCustomTag(NamespacedKey key) {
wrapped.remove(key);
}
@Override
public boolean isEmpty() {
return wrapped.isEmpty();
}
@Override
public ItemTagAdapterContext getAdapterContext() {
return new DeprecatedItemAdapterContext(this.wrapped.getAdapterContext());
}
public PersistentDataContainer getWrapped() {
return wrapped;
}
}

View File

@ -0,0 +1,24 @@
package org.bukkit.craftbukkit.inventory.tags;
import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
import org.bukkit.inventory.meta.tags.ItemTagAdapterContext;
import org.bukkit.persistence.PersistentDataAdapterContext;
public final class DeprecatedItemAdapterContext implements ItemTagAdapterContext {
private final PersistentDataAdapterContext context;
public DeprecatedItemAdapterContext(PersistentDataAdapterContext context) {
this.context = context;
}
/**
* Creates a new and empty tag container instance.
*
* @return the fresh container instance
*/
@Override
public CustomItemTagContainer newTagContainer() {
return new DeprecatedCustomTagContainer(context.newPersistentDataContainer());
}
}

View File

@ -0,0 +1,34 @@
package org.bukkit.craftbukkit.inventory.tags;
import org.bukkit.inventory.meta.tags.ItemTagType;
import org.bukkit.persistence.PersistentDataAdapterContext;
import org.bukkit.persistence.PersistentDataType;
public final class DeprecatedItemTagType<T, Z> implements PersistentDataType<T, Z> {
private final ItemTagType<T, Z> deprecated;
public DeprecatedItemTagType(ItemTagType<T, Z> deprecated) {
this.deprecated = deprecated;
}
@Override
public Class<T> getPrimitiveType() {
return deprecated.getPrimitiveType();
}
@Override
public Class<Z> getComplexType() {
return deprecated.getComplexType();
}
@Override
public T toPrimitive(Z complex, PersistentDataAdapterContext context) {
return this.deprecated.toPrimitive(complex, new DeprecatedItemAdapterContext(context));
}
@Override
public Z fromPrimitive(T primitive, PersistentDataAdapterContext context) {
return this.deprecated.fromPrimitive(primitive, new DeprecatedItemAdapterContext(context));
}
}

View File

@ -0,0 +1,22 @@
package org.bukkit.craftbukkit.persistence;
import org.bukkit.persistence.PersistentDataAdapterContext;
public final class CraftPersistentDataAdapterContext implements PersistentDataAdapterContext {
private final CraftPersistentDataTypeRegistry registry;
public CraftPersistentDataAdapterContext(CraftPersistentDataTypeRegistry registry) {
this.registry = registry;
}
/**
* Creates a new and empty tag container instance
*
* @return the fresh container instance
*/
@Override
public CraftPersistentDataContainer newPersistentDataContainer() {
return new CraftPersistentDataContainer(this.registry);
}
}

View File

@ -0,0 +1,142 @@
package org.bukkit.craftbukkit.persistence;
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.util.CraftNBTTagConfigSerializer;
import org.bukkit.persistence.PersistentDataAdapterContext;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
public final class CraftPersistentDataContainer implements PersistentDataContainer {
private final Map<String, NBTBase> customDataTags = new HashMap<>();
private final CraftPersistentDataTypeRegistry registry;
private final CraftPersistentDataAdapterContext adapterContext;
public CraftPersistentDataContainer(Map<String, NBTBase> customTags, CraftPersistentDataTypeRegistry registry) {
this(registry);
this.customDataTags.putAll(customTags);
}
public CraftPersistentDataContainer(CraftPersistentDataTypeRegistry registry) {
this.registry = registry;
this.adapterContext = new CraftPersistentDataAdapterContext(this.registry);
}
@Override
public <T, Z> void set(NamespacedKey key, PersistentDataType<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.customDataTags.put(key.toString(), registry.wrap(type.getPrimitiveType(), type.toPrimitive(value, adapterContext)));
}
@Override
public <T, Z> boolean has(NamespacedKey key, PersistentDataType<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.customDataTags.get(key.toString());
if (value == null) {
return false;
}
return registry.isInstanceOf(type.getPrimitiveType(), value);
}
@Override
public <T, Z> Z get(NamespacedKey key, PersistentDataType<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.customDataTags.get(key.toString());
if (value == null) {
return null;
}
return type.fromPrimitive(registry.extract(type.getPrimitiveType(), value), adapterContext);
}
@Override
public <T, Z> Z getOrDefault(NamespacedKey key, PersistentDataType<T, Z> type, Z defaultValue) {
Z z = get(key, type);
return z != null ? z : defaultValue;
}
@Override
public void remove(NamespacedKey key) {
Validate.notNull(key, "The provided key for the custom value was null");
this.customDataTags.remove(key.toString());
}
@Override
public boolean isEmpty() {
return this.customDataTags.isEmpty();
}
@Override
public PersistentDataAdapterContext getAdapterContext() {
return this.adapterContext;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CraftPersistentDataContainer)) {
return false;
}
Map<String, NBTBase> myRawMap = getRaw();
Map<String, NBTBase> theirRawMap = ((CraftPersistentDataContainer) obj).getRaw();
return Objects.equals(myRawMap, theirRawMap);
}
public NBTTagCompound toTagCompound() {
NBTTagCompound tag = new NBTTagCompound();
for (Entry<String, NBTBase> entry : this.customDataTags.entrySet()) {
tag.set(entry.getKey(), entry.getValue());
}
return tag;
}
public void put(String key, NBTBase base) {
this.customDataTags.put(key, base);
}
public void putAll(Map<String, NBTBase> map) {
this.customDataTags.putAll(map);
}
public void putAll(NBTTagCompound compound) {
for (String key : compound.getKeys()) {
this.customDataTags.put(key, compound.get(key));
}
}
public Map<String, NBTBase> getRaw() {
return this.customDataTags;
}
public CraftPersistentDataTypeRegistry getDataTagTypeRegistry() {
return registry;
}
@Override
public int hashCode() {
int hashCode = 3;
hashCode += this.customDataTags.hashCode(); // We will simply add the maps hashcode
return hashCode;
}
public Map<String, Object> serialize() {
return (Map<String, Object>) CraftNBTTagConfigSerializer.serialize(toTagCompound());
}
}

View File

@ -1,11 +1,11 @@
package org.bukkit.craftbukkit.inventory; package org.bukkit.craftbukkit.persistence;
import com.google.common.primitives.Primitives;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
import com.google.common.primitives.Primitives;
import net.minecraft.server.NBTBase; import net.minecraft.server.NBTBase;
import net.minecraft.server.NBTTagByte; import net.minecraft.server.NBTTagByte;
import net.minecraft.server.NBTTagByteArray; import net.minecraft.server.NBTTagByteArray;
@ -19,17 +19,16 @@ import net.minecraft.server.NBTTagLongArray;
import net.minecraft.server.NBTTagShort; import net.minecraft.server.NBTTagShort;
import net.minecraft.server.NBTTagString; import net.minecraft.server.NBTTagString;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.bukkit.craftbukkit.inventory.tags.CraftCustomItemTagContainer; import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
/** /**
* This class represents a registry that contains the used adapters for. * This class represents a registry that contains the used adapters for.
*/ */
public final class CraftCustomTagTypeRegistry { public final class CraftPersistentDataTypeRegistry {
private final Function<Class, CustomTagAdapter> CREATE_ADAPTER = this::createAdapter; private final Function<Class, TagAdapter> CREATE_ADAPTER = this::createAdapter;
private class CustomTagAdapter<T, Z extends NBTBase> { private class TagAdapter<T, Z extends NBTBase> {
private final Function<T, Z> builder; private final Function<T, Z> builder;
private final Function<Z, T> extractor; private final Function<Z, T> extractor;
@ -37,7 +36,7 @@ public final class CraftCustomTagTypeRegistry {
private final Class<T> primitiveType; private final Class<T> primitiveType;
private final Class<Z> nbtBaseType; private final Class<Z> nbtBaseType;
public CustomTagAdapter(Class<T> primitiveType, Class<Z> nbtBaseType, Function<T, Z> builder, Function<Z, T> extractor) { public TagAdapter(Class<T> primitiveType, Class<Z> nbtBaseType, Function<T, Z> builder, Function<Z, T> extractor) {
this.primitiveType = primitiveType; this.primitiveType = primitiveType;
this.nbtBaseType = nbtBaseType; this.nbtBaseType = nbtBaseType;
this.builder = builder; this.builder = builder;
@ -49,7 +48,9 @@ public final class CraftCustomTagTypeRegistry {
* the expected primitive type. * the expected primitive type.
* *
* @param base the base to extract from * @param base the base to extract from
*
* @return the value stored inside of the tag * @return the value stored inside of the tag
*
* @throws ClassCastException if the passed base is not an instanced of * @throws ClassCastException if the passed base is not an instanced of
* the defined base type and therefore is not applicable to the * the defined base type and therefore is not applicable to the
* extractor function * extractor function
@ -63,7 +64,9 @@ public final class CraftCustomTagTypeRegistry {
* Builds a tag instance wrapping around the provided value object. * Builds a tag instance wrapping around the provided value object.
* *
* @param value the value to store inside the created tag * @param value the value to store inside the created tag
*
* @return the new tag instance * @return the new tag instance
*
* @throws ClassCastException if the passed value object is not of the * @throws ClassCastException if the passed value object is not of the
* defined primitive type and therefore is not applicable to the builder * defined primitive type and therefore is not applicable to the builder
* function * function
@ -77,6 +80,7 @@ public final class CraftCustomTagTypeRegistry {
* Returns if the tag instance matches the adapters one. * Returns if the tag instance matches the adapters one.
* *
* @param base the base to check * @param base the base to check
*
* @return if the tag was an instance of the set type * @return if the tag was an instance of the set type
*/ */
boolean isInstance(NBTBase base) { boolean isInstance(NBTBase base) {
@ -84,18 +88,20 @@ public final class CraftCustomTagTypeRegistry {
} }
} }
private final Map<Class, CustomTagAdapter> adapters = new HashMap<>(); private final Map<Class, TagAdapter> adapters = new HashMap<>();
/** /**
* Creates a suitable adapter instance for the primitive class type * Creates a suitable adapter instance for the primitive class type
* *
* @param type the type to create an adapter for * @param type the type to create an adapter for
* @param <T> the generic type of that class * @param <T> the generic type of that class
*
* @return the created adapter instance * @return the created adapter instance
*
* @throws IllegalArgumentException if no suitable tag type adapter for this * @throws IllegalArgumentException if no suitable tag type adapter for this
* type was found * type was found
*/ */
private <T> CustomTagAdapter createAdapter(Class<T> type) { private <T> TagAdapter createAdapter(Class<T> type) {
if (!Primitives.isWrapperType(type)) { if (!Primitives.isWrapperType(type)) {
type = Primitives.wrap(type); //Make sure we will always "switch" over the wrapper types type = Primitives.wrap(type); //Make sure we will always "switch" over the wrapper types
} }
@ -143,12 +149,12 @@ public final class CraftCustomTagTypeRegistry {
} }
/* /*
Note that this will map the interface CustomItemTagContainer directly to the CraftBukkit implementation Note that this will map the interface PersistentMetadataContainer 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 Passing any other instance of this form to the tag type registry will throw a ClassCastException as defined in TagAdapter#build
*/ */
if (Objects.equals(CustomItemTagContainer.class, type)) { if (Objects.equals(PersistentDataContainer.class, type)) {
return createAdapter(CraftCustomItemTagContainer.class, NBTTagCompound.class, CraftCustomItemTagContainer::toTagCompound, tag -> { return createAdapter(CraftPersistentDataContainer.class, NBTTagCompound.class, CraftPersistentDataContainer::toTagCompound, tag -> {
CraftCustomItemTagContainer container = new CraftCustomItemTagContainer(this); CraftPersistentDataContainer container = new CraftPersistentDataContainer(this);
for (String key : tag.getKeys()) { for (String key : tag.getKeys()) {
container.put(key, tag.get(key)); container.put(key, tag.get(key));
} }
@ -156,11 +162,11 @@ public final class CraftCustomTagTypeRegistry {
}); });
} }
throw new IllegalArgumentException("Could not find a valid CustomTagAdapter implementation for the requested type " + type.getSimpleName()); throw new IllegalArgumentException("Could not find a valid TagAdapter 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) { private <T, Z extends NBTBase> TagAdapter<T, Z> createAdapter(Class<T> primitiveType, Class<Z> nbtBaseType, Function<T, Z> builder, Function<Z, T> extractor) {
return new CustomTagAdapter<>(primitiveType, nbtBaseType, builder, extractor); return new TagAdapter<>(primitiveType, nbtBaseType, builder, extractor);
} }
/** /**
@ -169,7 +175,9 @@ public final class CraftCustomTagTypeRegistry {
* @param type the type of the passed value * @param type the type of the passed value
* @param value the value to be stored in the tag * @param value the value to be stored in the tag
* @param <T> the generic type of the value * @param <T> the generic type of the value
*
* @return the created tag instance * @return the created tag instance
*
* @throws IllegalArgumentException if no suitable tag type adapter for this * @throws IllegalArgumentException if no suitable tag type adapter for this
* type was found * type was found
*/ */
@ -183,7 +191,9 @@ public final class CraftCustomTagTypeRegistry {
* @param type the type of the primitive value * @param type the type of the primitive value
* @param base the base instance to check * @param base the base instance to check
* @param <T> the generic type of the type * @param <T> the generic type of the type
*
* @return if the base stores values of the primitive type passed * @return if the base stores values of the primitive type passed
*
* @throws IllegalArgumentException if no suitable tag type adapter for this * @throws IllegalArgumentException if no suitable tag type adapter for this
* type was found * type was found
*/ */
@ -197,7 +207,9 @@ public final class CraftCustomTagTypeRegistry {
* @param type the type of the value to extract * @param type the type of the value to extract
* @param tag the tag to extract the value from * @param tag the tag to extract the value from
* @param <T> the generic type of the value stored inside the tag * @param <T> the generic type of the value stored inside the tag
*
* @return the extracted value * @return the extracted value
*
* @throws IllegalArgumentException if the passed base is not an instanced * @throws IllegalArgumentException if the passed base is not an instanced
* of the defined base type and therefore is not applicable to the extractor * of the defined base type and therefore is not applicable to the extractor
* function * function
@ -207,7 +219,7 @@ public final class CraftCustomTagTypeRegistry {
* type was found * type was found
*/ */
public <T> T extract(Class<T> type, NBTBase tag) throws ClassCastException, IllegalArgumentException { public <T> T extract(Class<T> type, NBTBase tag) throws ClassCastException, IllegalArgumentException {
CustomTagAdapter adapter = this.adapters.computeIfAbsent(type, CREATE_ADAPTER); TagAdapter 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()); 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); Object foundValue = adapter.extract(tag);

View File

@ -4,18 +4,13 @@ import static org.junit.Assert.*;
import java.io.StringReader; import java.io.StringReader;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import net.minecraft.server.NBTBase;
import net.minecraft.server.NBTTagCompound; import net.minecraft.server.NBTTagCompound;
import net.minecraft.server.NBTTagIntArray;
import net.minecraft.server.NBTTagList;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.craftbukkit.inventory.tags.CraftCustomItemTagContainer;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.tags.CustomItemTagContainer; import org.bukkit.inventory.meta.tags.CustomItemTagContainer;
@ -25,7 +20,7 @@ import org.bukkit.support.AbstractTestingBase;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
public class ItemMetaCustomValueTest extends AbstractTestingBase { public class DeprecatedItemMetaCustomValueTest extends AbstractTestingBase {
private static NamespacedKey VALID_KEY; private static NamespacedKey VALID_KEY;
@ -166,12 +161,6 @@ public class ItemMetaCustomValueTest extends AbstractTestingBase {
CustomItemTagContainer innerContainer = itemMeta.getCustomTagContainer().getAdapterContext().newTagContainer(); //Add a inner container CustomItemTagContainer innerContainer = itemMeta.getCustomTagContainer().getAdapterContext().newTagContainer(); //Add a inner container
innerContainer.setCustomTag(VALID_KEY, ItemTagType.LONG, 5L); innerContainer.setCustomTag(VALID_KEY, ItemTagType.LONG, 5L);
itemMeta.getCustomTagContainer().setCustomTag(requestKey("custom-inner-compound"), ItemTagType.TAG_CONTAINER, innerContainer); 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; return itemMeta;
} }

View File

@ -0,0 +1,313 @@
package org.bukkit.craftbukkit.inventory;
import static org.junit.Assert.*;
import java.io.StringReader;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.UUID;
import net.minecraft.server.NBTTagCompound;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataAdapterContext;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.support.AbstractTestingBase;
import org.junit.Before;
import org.junit.Test;
public class PersistentDataContainerTest 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.getPersistentDataContainer().set(VALID_KEY, new PrimitiveTagType<>(boolean.class), true);
}
/*
Contains a tag
*/
@Test(expected = IllegalArgumentException.class)
public void testHasNoAdapter() {
ItemMeta itemMeta = createNewItemMeta();
itemMeta.getPersistentDataContainer().set(VALID_KEY, PersistentDataType.INTEGER, 1); // We gotta set this so we at least try to compare it
itemMeta.getPersistentDataContainer().has(VALID_KEY, new PrimitiveTagType<>(boolean.class));
}
/*
Getting a tag
*/
@Test(expected = IllegalArgumentException.class)
public void testGetNoAdapter() {
ItemMeta itemMeta = createNewItemMeta();
itemMeta.getPersistentDataContainer().set(VALID_KEY, PersistentDataType.INTEGER, 1); //We gotta set this so we at least try to compare it
itemMeta.getPersistentDataContainer().get(VALID_KEY, new PrimitiveTagType<>(boolean.class));
}
@Test(expected = IllegalArgumentException.class)
public void testGetWrongType() {
ItemMeta itemMeta = createNewItemMeta();
itemMeta.getPersistentDataContainer().set(VALID_KEY, PersistentDataType.INTEGER, 1);
itemMeta.getPersistentDataContainer().get(VALID_KEY, PersistentDataType.STRING);
}
@Test
public void testDifferentNamespace() {
NamespacedKey namespacedKeyA = new NamespacedKey("plugin-a", "damage");
NamespacedKey namespacedKeyB = new NamespacedKey("plugin-b", "damage");
ItemMeta meta = createNewItemMeta();
meta.getPersistentDataContainer().set(namespacedKeyA, PersistentDataType.LONG, 15L);
meta.getPersistentDataContainer().set(namespacedKeyB, PersistentDataType.LONG, 160L);
assertEquals(15L, (long) meta.getPersistentDataContainer().get(namespacedKeyA, PersistentDataType.LONG));
assertEquals(160L, (long) meta.getPersistentDataContainer().get(namespacedKeyB, PersistentDataType.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));
}
@Test
public void testCorrectType() {
ItemStack stack = new ItemStack(Material.DIAMOND);
CraftMetaItem meta = createComplexItemMeta();
meta.getPersistentDataContainer().set(requestKey("int"), PersistentDataType.STRING, "1");
meta.getPersistentDataContainer().set(requestKey("double"), PersistentDataType.STRING, "1.33");
stack.setItemMeta(meta);
YamlConfiguration configuration = new YamlConfiguration();
configuration.set("testpath", stack);
String configValue = configuration.saveToString();
YamlConfiguration loadedConfig = YamlConfiguration.loadConfiguration(new StringReader(configValue));
ItemStack newStack = loadedConfig.getSerializable("testpath", ItemStack.class);
assertTrue(newStack.getItemMeta().getPersistentDataContainer().has(requestKey("int"), PersistentDataType.STRING));
assertEquals(newStack.getItemMeta().getPersistentDataContainer().get(requestKey("int"), PersistentDataType.STRING), "1");
assertTrue(newStack.getItemMeta().getPersistentDataContainer().has(requestKey("double"), PersistentDataType.STRING));
assertEquals(newStack.getItemMeta().getPersistentDataContainer().get(requestKey("double"), PersistentDataType.STRING), "1.33");
}
private CraftMetaItem createComplexItemMeta() {
CraftMetaItem itemMeta = (CraftMetaItem) createNewItemMeta();
itemMeta.setDisplayName("Item Display Name");
itemMeta.getPersistentDataContainer().set(requestKey("custom-long"), PersistentDataType.LONG, 4L); //Add random primitive values
itemMeta.getPersistentDataContainer().set(requestKey("custom-byte-array"), PersistentDataType.BYTE_ARRAY, new byte[]{
0, 1, 2, 10
});
itemMeta.getPersistentDataContainer().set(requestKey("custom-string"), PersistentDataType.STRING, "Hello there world");
itemMeta.getPersistentDataContainer().set(requestKey("custom-int"), PersistentDataType.INTEGER, 3);
itemMeta.getPersistentDataContainer().set(requestKey("custom-double"), PersistentDataType.DOUBLE, 3.123);
PersistentDataContainer innerContainer = itemMeta.getPersistentDataContainer().getAdapterContext().newPersistentDataContainer(); //Add a inner container
innerContainer.set(VALID_KEY, PersistentDataType.LONG, 5L);
itemMeta.getPersistentDataContainer().set(requestKey("custom-inner-compound"), PersistentDataType.TAG_CONTAINER, innerContainer);
return itemMeta;
}
/*
Test complex object storage
*/
@Test
public void storeUUIDOnItemTest() {
ItemMeta itemMeta = createNewItemMeta();
UUIDPersistentDataType uuidPersistentDataType = new UUIDPersistentDataType();
UUID uuid = UUID.fromString("434eea72-22a6-4c61-b5ef-945874a5c478");
itemMeta.getPersistentDataContainer().set(VALID_KEY, uuidPersistentDataType, uuid);
assertTrue(itemMeta.getPersistentDataContainer().has(VALID_KEY, uuidPersistentDataType));
assertEquals(uuid, itemMeta.getPersistentDataContainer().get(VALID_KEY, uuidPersistentDataType));
}
@Test
public void encapsulatedContainers() {
NamespacedKey innerKey = new NamespacedKey("plugin-a", "inner");
ItemMeta meta = createNewItemMeta();
PersistentDataAdapterContext context = meta.getPersistentDataContainer().getAdapterContext();
PersistentDataContainer thirdContainer = context.newPersistentDataContainer();
thirdContainer.set(VALID_KEY, PersistentDataType.LONG, 3L);
PersistentDataContainer secondContainer = context.newPersistentDataContainer();
secondContainer.set(VALID_KEY, PersistentDataType.LONG, 2L);
secondContainer.set(innerKey, PersistentDataType.TAG_CONTAINER, thirdContainer);
meta.getPersistentDataContainer().set(VALID_KEY, PersistentDataType.LONG, 1L);
meta.getPersistentDataContainer().set(innerKey, PersistentDataType.TAG_CONTAINER, secondContainer);
assertEquals(3L, meta.getPersistentDataContainer()
.get(innerKey, PersistentDataType.TAG_CONTAINER)
.get(innerKey, PersistentDataType.TAG_CONTAINER)
.get(VALID_KEY, PersistentDataType.LONG).longValue());
assertEquals(2L, meta.getPersistentDataContainer()
.get(innerKey, PersistentDataType.TAG_CONTAINER)
.get(VALID_KEY, PersistentDataType.LONG).longValue());
assertEquals(1L, meta.getPersistentDataContainer()
.get(VALID_KEY, PersistentDataType.LONG).longValue());
}
class UUIDPersistentDataType implements PersistentDataType<byte[], UUID> {
@Override
public Class<byte[]> getPrimitiveType() {
return byte[].class;
}
@Override
public Class<UUID> getComplexType() {
return UUID.class;
}
@Override
public byte[] toPrimitive(UUID complex, PersistentDataAdapterContext 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, PersistentDataAdapterContext 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, PersistentDataType.BYTE, (byte) 1);
testPrimitiveCustomTag(itemMeta, PersistentDataType.SHORT, (short) 1);
testPrimitiveCustomTag(itemMeta, PersistentDataType.INTEGER, 1);
testPrimitiveCustomTag(itemMeta, PersistentDataType.LONG, 1L);
testPrimitiveCustomTag(itemMeta, PersistentDataType.FLOAT, 1.34F);
testPrimitiveCustomTag(itemMeta, PersistentDataType.DOUBLE, 151.123);
testPrimitiveCustomTag(itemMeta, PersistentDataType.STRING, "test");
testPrimitiveCustomTag(itemMeta, PersistentDataType.BYTE_ARRAY, new byte[]{
1, 4, 2, Byte.MAX_VALUE
});
testPrimitiveCustomTag(itemMeta, PersistentDataType.INTEGER_ARRAY, new int[]{
1, 4, 2, Integer.MAX_VALUE
});
testPrimitiveCustomTag(itemMeta, PersistentDataType.LONG_ARRAY, new long[]{
1L, 4L, 2L, Long.MAX_VALUE
});
}
private <T, Z> void testPrimitiveCustomTag(ItemMeta meta, PersistentDataType<T, Z> type, Z value) {
NamespacedKey tagKey = new NamespacedKey("test", String.valueOf(type.hashCode()));
meta.getPersistentDataContainer().set(tagKey, type, value);
assertTrue(meta.getPersistentDataContainer().has(tagKey, type));
Z foundValue = meta.getPersistentDataContainer().get(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.getPersistentDataContainer().remove(tagKey);
assertFalse(meta.getPersistentDataContainer().has(tagKey, type));
}
class PrimitiveTagType<T> implements PersistentDataType<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, PersistentDataAdapterContext context) {
return complex;
}
@Override
public T fromPrimitive(T primitive, PersistentDataAdapterContext context) {
return primitive;
}
}
}