Implement ItemFactory and ItemMeta values. Adds BUKKIT-15

By: Wesley Wolfe <weswolf@aol.com>
This commit is contained in:
CraftBukkit/Spigot
2012-12-17 01:31:41 -06:00
parent 9d7ccb79f2
commit 1d39ac678a
46 changed files with 3701 additions and 222 deletions

View File

@@ -71,6 +71,7 @@ import org.bukkit.conversations.Conversable;
import org.bukkit.craftbukkit.help.SimpleHelpMap;
import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe;
import org.bukkit.craftbukkit.inventory.CraftInventoryCustom;
import org.bukkit.craftbukkit.inventory.CraftItemFactory;
import org.bukkit.craftbukkit.inventory.CraftRecipe;
import org.bukkit.craftbukkit.inventory.CraftShapedRecipe;
import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe;
@@ -161,6 +162,7 @@ public final class CraftServer implements Server {
static {
ConfigurationSerialization.registerClass(CraftOfflinePlayer.class);
CraftItemFactory.instance();
}
public CraftServer(MinecraftServer console, ServerConfigurationManagerAbstract server) {
@@ -1320,4 +1322,8 @@ public final class CraftServer implements Server {
Collections.sort(completions, String.CASE_INSENSITIVE_ORDER);
return completions;
}
public CraftItemFactory getItemFactory() {
return CraftItemFactory.instance();
}
}

View File

@@ -283,8 +283,7 @@ public class CraftWorld implements World {
public org.bukkit.entity.Item dropItem(Location loc, ItemStack item) {
Validate.notNull(item, "Cannot drop a Null item.");
Validate.isTrue(item.getTypeId() != 0, "Cannot drop AIR.");
CraftItemStack clone = new CraftItemStack(item);
EntityItem entity = new EntityItem(world, loc.getX(), loc.getY(), loc.getZ(), clone.getHandle());
EntityItem entity = new EntityItem(world, loc.getX(), loc.getY(), loc.getZ(), CraftItemStack.asNMSCopy(item));
entity.pickupDelay = 10;
world.addEntity(entity);
// TODO this is inconsistent with how Entity.getBukkitEntity() works.

View File

@@ -0,0 +1,14 @@
package org.bukkit.craftbukkit;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicates a method needs to be overridden in sub classes
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Overridden {
}

View File

@@ -74,11 +74,11 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
}
public ItemStack getItemOnCursor() {
return new CraftItemStack(getHandle().inventory.getCarried());
return CraftItemStack.asCraftMirror(getHandle().inventory.getCarried());
}
public void setItemOnCursor(ItemStack item) {
net.minecraft.server.ItemStack stack = CraftItemStack.createNMSItemStack(item);
net.minecraft.server.ItemStack stack = CraftItemStack.asNMSCopy(item);
getHandle().inventory.setCarried(stack);
if (this instanceof CraftPlayer) {
((EntityPlayer) getHandle()).broadcastCarriedItem(); // Send set slot for cursor

View File

@@ -22,11 +22,11 @@ public class CraftItem extends CraftEntity implements Item {
}
public ItemStack getItemStack() {
return new CraftItemStack(item.itemStack);
return CraftItemStack.asCraftMirror(item.itemStack);
}
public void setItemStack(ItemStack stack) {
item.itemStack = CraftItemStack.createNMSItemStack(stack);
item.itemStack = CraftItemStack.asNMSCopy(stack);
}
public int getPickupDelay() {

View File

@@ -20,12 +20,12 @@ public class CraftItemFrame extends CraftHanging implements ItemFrame {
getHandle().getDataWatcher().a(2, 5);
getHandle().getDataWatcher().h(2);
} else {
getHandle().a(CraftItemStack.createNMSItemStack(item));
getHandle().a(CraftItemStack.asNMSCopy(item));
}
}
public org.bukkit.inventory.ItemStack getItem() {
return CraftItemStack.asBukkitStack(getHandle().i());
return CraftItemStack.asBukkitCopy(getHandle().i());
}
public Rotation getRotation() {

View File

@@ -115,7 +115,7 @@ public class CraftEventFactory {
private static PlayerEvent getPlayerBucketEvent(boolean isFilling, EntityHuman who, int clickedX, int clickedY, int clickedZ, int clickedFace, ItemStack itemstack, net.minecraft.server.Item item) {
Player player = (who == null) ? null : (Player) who.getBukkitEntity();
CraftItemStack itemInHand = new CraftItemStack(new ItemStack(item));
CraftItemStack itemInHand = CraftItemStack.asNewCraftStack(item);
Material bucket = Material.getMaterial(itemstack.id);
CraftWorld craftWorld = (CraftWorld) player.getWorld();
@@ -150,7 +150,7 @@ public class CraftEventFactory {
public static PlayerInteractEvent callPlayerInteractEvent(EntityHuman who, Action action, int clickedX, int clickedY, int clickedZ, int clickedFace, ItemStack itemstack) {
Player player = (who == null) ? null : (Player) who.getBukkitEntity();
CraftItemStack itemInHand = new CraftItemStack(itemstack);
CraftItemStack itemInHand = CraftItemStack.asCraftMirror(itemstack);
CraftWorld craftWorld = (CraftWorld) player.getWorld();
CraftServer craftServer = (CraftServer) player.getServer();
@@ -185,7 +185,7 @@ public class CraftEventFactory {
*/
public static EntityShootBowEvent callEntityShootBowEvent(EntityLiving who, ItemStack itemstack, EntityArrow entityArrow, float force) {
LivingEntity shooter = (LivingEntity) who.getBukkitEntity();
CraftItemStack itemInHand = new CraftItemStack(itemstack);
CraftItemStack itemInHand = CraftItemStack.asCraftMirror(itemstack);
Arrow arrow = (Arrow) entityArrow.getBukkitEntity();
if (itemInHand != null && (itemInHand.getType() == Material.AIR || itemInHand.getAmount() == 0)) {
@@ -203,7 +203,7 @@ public class CraftEventFactory {
*/
public static BlockDamageEvent callBlockDamageEvent(EntityHuman who, int x, int y, int z, ItemStack itemstack, boolean instaBreak) {
Player player = (who == null) ? null : (Player) who.getBukkitEntity();
CraftItemStack itemInHand = new CraftItemStack(itemstack);
CraftItemStack itemInHand = CraftItemStack.asCraftMirror(itemstack);
CraftWorld craftWorld = (CraftWorld) player.getWorld();
CraftServer craftServer = (CraftServer) player.getServer();
@@ -317,13 +317,7 @@ public class CraftEventFactory {
for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
if (stack == null || stack.getType() == Material.AIR) continue;
if (stack instanceof CraftItemStack) {
// Use the internal item to preserve possible data.
victim.a(((CraftItemStack) stack).getHandle(), 0.0f);
}
else {
world.dropItemNaturally(entity.getLocation(), stack);
}
world.dropItemNaturally(entity.getLocation(), stack);
}
return event;
@@ -344,12 +338,7 @@ public class CraftEventFactory {
for (org.bukkit.inventory.ItemStack stack : event.getDrops()) {
if (stack == null || stack.getType() == Material.AIR) continue;
if (stack instanceof CraftItemStack) {
// Use the internal item to preserve possible data.
victim.a(((CraftItemStack) stack).getHandle(), 0.0f);
} else {
world.dropItemNaturally(entity.getLocation(), stack);
}
world.dropItemNaturally(entity.getLocation(), stack);
}
return event;
@@ -519,14 +508,14 @@ public class CraftEventFactory {
public static ItemStack callPreCraftEvent(InventoryCrafting matrix, ItemStack result, InventoryView lastCraftView, boolean isRepair) {
CraftInventoryCrafting inventory = new CraftInventoryCrafting(matrix, matrix.resultInventory);
inventory.setResult(new CraftItemStack(result));
inventory.setResult(CraftItemStack.asCraftMirror(result));
PrepareItemCraftEvent event = new PrepareItemCraftEvent(inventory, lastCraftView, isRepair);
Bukkit.getPluginManager().callEvent(event);
org.bukkit.inventory.ItemStack bitem = event.getInventory().getResult();
return CraftItemStack.createNMSItemStack(bitem);
return CraftItemStack.asNMSCopy(bitem);
}
public static ProjectileLaunchEvent callProjectileLaunchEvent(Entity entity) {
@@ -556,7 +545,7 @@ public class CraftEventFactory {
}
public static void callPlayerItemBreakEvent(EntityHuman human, ItemStack brokenItem) {
CraftItemStack item = new CraftItemStack(brokenItem);
CraftItemStack item = CraftItemStack.asCraftMirror(brokenItem);
PlayerItemBreakEvent event = new PlayerItemBreakEvent((Player) human.getBukkitEntity(), item);
Bukkit.getPluginManager().callEvent(event);
}

View File

@@ -75,11 +75,11 @@ public class CraftEntityEquipment implements EntityEquipment {
}
private ItemStack getEquipment(int slot) {
return CraftItemStack.asBukkitStack(entity.getHandle().getEquipment(slot));
return CraftItemStack.asBukkitCopy(entity.getHandle().getEquipment(slot));
}
private void setEquipment(int slot, ItemStack stack) {
entity.getHandle().setEquipment(slot, CraftItemStack.createNMSItemStack(stack));
entity.getHandle().setEquipment(slot, CraftItemStack.asNMSCopy(stack));
}
public void clear() {

View File

@@ -20,6 +20,6 @@ public class CraftFurnaceRecipe extends FurnaceRecipe implements CraftRecipe {
public void addToCraftingManager() {
ItemStack result = this.getResult();
ItemStack input = this.getInput();
RecipesFurnace.getInstance().registerRecipe(input.getTypeId(), CraftItemStack.createNMSItemStack(result), 0.1f);
RecipesFurnace.getInstance().registerRecipe(input.getTypeId(), CraftItemStack.asNMSCopy(result), 0.1f);
}
}

View File

@@ -44,7 +44,7 @@ public class CraftInventory implements Inventory {
public ItemStack getItem(int index) {
net.minecraft.server.ItemStack item = getInventory().getItem(index);
return item == null ? null : new CraftItemStack(item);
return item == null ? null : CraftItemStack.asCraftMirror(item);
}
public ItemStack[] getContents() {
@@ -52,7 +52,7 @@ public class CraftInventory implements Inventory {
net.minecraft.server.ItemStack[] mcItems = getInventory().getContents();
for (int i = 0; i < mcItems.length; i++) {
items[i] = mcItems[i] == null ? null : new CraftItemStack(mcItems[i]);
items[i] = mcItems[i] == null ? null : CraftItemStack.asCraftMirror(mcItems[i]);
}
return items;
@@ -69,13 +69,13 @@ public class CraftInventory implements Inventory {
if (i >= items.length) {
mcItems[i] = null;
} else {
mcItems[i] = CraftItemStack.createNMSItemStack(items[i]);
mcItems[i] = CraftItemStack.asNMSCopy(items[i]);
}
}
}
public void setItem(int index, ItemStack item) {
getInventory().setItem(index, ((item == null || item.getTypeId() == 0) ? null : CraftItemStack.createNMSItemStack(item)));
getInventory().setItem(index, ((item == null || item.getTypeId() == 0) ? null : CraftItemStack.asNMSCopy(item)));
}
public boolean contains(int materialId) {
@@ -229,7 +229,7 @@ public class CraftInventory implements Inventory {
public int firstPartial(ItemStack item) {
ItemStack[] inventory = getContents();
ItemStack filteredItem = new CraftItemStack(item);
ItemStack filteredItem = CraftItemStack.asCraftCopy(item);
if (item == null) {
return -1;
}
@@ -269,8 +269,7 @@ public class CraftInventory implements Inventory {
} else {
// More than a single stack!
if (item.getAmount() > getMaxItemStack()) {
CraftItemStack stack = new CraftItemStack(item.getTypeId(), getMaxItemStack(), item.getDurability());
stack.addUnsafeEnchantments(item.getEnchantments());
CraftItemStack stack = CraftItemStack.asCraftCopy(item);
setItem(firstFree, stack);
item.setAmount(item.getAmount() - getMaxItemStack());
} else {

View File

@@ -47,13 +47,13 @@ public class CraftInventoryCrafting extends CraftInventory implements CraftingIn
int i = 0;
for (i = 0; i < mcResultItems.length; i++ ) {
items[i] = new CraftItemStack(mcResultItems[i]);
items[i] = CraftItemStack.asCraftMirror(mcResultItems[i]);
}
net.minecraft.server.ItemStack[] mcItems = getMatrixInventory().getContents();
for (int j = 0; j < mcItems.length; j++) {
items[i + j] = new CraftItemStack(mcItems[j]);
items[i + j] = CraftItemStack.asCraftMirror(mcItems[j]);
}
return items;
@@ -68,19 +68,19 @@ public class CraftInventoryCrafting extends CraftInventory implements CraftingIn
public CraftItemStack getItem(int index) {
if (index < getResultInventory().getSize()) {
net.minecraft.server.ItemStack item = getResultInventory().getItem(index);
return item == null ? null : new CraftItemStack(item);
return item == null ? null : CraftItemStack.asCraftMirror(item);
} else {
net.minecraft.server.ItemStack item = getMatrixInventory().getItem(index - getResultInventory().getSize());
return item == null ? null : new CraftItemStack(item);
return item == null ? null : CraftItemStack.asCraftMirror(item);
}
}
@Override
public void setItem(int index, ItemStack item) {
if (index < getResultInventory().getSize()) {
getResultInventory().setItem(index, (item == null ? null : CraftItemStack.createNMSItemStack(item)));
getResultInventory().setItem(index, (item == null ? null : CraftItemStack.asNMSCopy(item)));
} else {
getMatrixInventory().setItem((index - getResultInventory().getSize()), (item == null ? null : CraftItemStack.createNMSItemStack(item)));
getMatrixInventory().setItem((index - getResultInventory().getSize()), (item == null ? null : CraftItemStack.asNMSCopy(item)));
}
}
@@ -89,7 +89,7 @@ public class CraftInventoryCrafting extends CraftInventory implements CraftingIn
net.minecraft.server.ItemStack[] matrix = getMatrixInventory().getContents();
for (int i = 0; i < matrix.length; i++ ) {
items[i] = new CraftItemStack(matrix[i]);
items[i] = CraftItemStack.asCraftMirror(matrix[i]);
}
return items;
@@ -97,7 +97,7 @@ public class CraftInventoryCrafting extends CraftInventory implements CraftingIn
public ItemStack getResult() {
net.minecraft.server.ItemStack item = getResultInventory().getItem(0);
if(item != null) return new CraftItemStack(item);
if(item != null) return CraftItemStack.asCraftMirror(item);
return null;
}
@@ -114,7 +114,7 @@ public class CraftInventoryCrafting extends CraftInventory implements CraftingIn
if (item == null || item.getTypeId() <= 0) {
mcItems[i] = null;
} else {
mcItems[i] = CraftItemStack.createNMSItemStack(item);
mcItems[i] = CraftItemStack.asNMSCopy(item);
}
} else {
mcItems[i] = null;
@@ -127,7 +127,7 @@ public class CraftInventoryCrafting extends CraftInventory implements CraftingIn
if (item == null || item.getTypeId() <= 0) {
contents[0] = null;
} else {
contents[0] = CraftItemStack.createNMSItemStack(item);
contents[0] = CraftItemStack.asNMSCopy(item);
}
}

View File

@@ -66,7 +66,7 @@ public class CraftInventoryCustom extends CraftInventory {
this.setItem(i, null);
result = stack;
} else {
result = new ItemStack(stack.id, j, stack.getData(), stack.getEnchantments());
result = CraftItemStack.copyNMSStack(stack, j);
stack.count -= j;
}
this.update();
@@ -81,7 +81,7 @@ public class CraftInventoryCustom extends CraftInventory {
this.setItem(i, null);
result = stack;
} else {
result = new ItemStack(stack.id, 1, stack.getData(), stack.getEnchantments());
result = CraftItemStack.copyNMSStack(stack, 1);
stack.count -= 1;
}
return result;

View File

@@ -22,7 +22,7 @@ public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.i
}
public ItemStack getItemInHand() {
return new CraftItemStack(getInventory().getItemInHand());
return CraftItemStack.asCraftMirror(getInventory().getItemInHand());
}
public void setItemInHand(ItemStack stack) {
@@ -70,7 +70,7 @@ public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.i
ItemStack[] ret = new ItemStack[mcItems.length];
for (int i = 0; i < mcItems.length; i++) {
ret[i] = new CraftItemStack(mcItems[i]);
ret[i] = CraftItemStack.asCraftMirror(mcItems[i]);
}
return ret;
}

View File

@@ -49,7 +49,7 @@ public class CraftInventoryView extends InventoryView {
@Override
public void setItem(int slot, ItemStack item) {
net.minecraft.server.ItemStack stack = CraftItemStack.createNMSItemStack(item);
net.minecraft.server.ItemStack stack = CraftItemStack.asNMSCopy(item);
if (slot != -999) {
container.getSlot(slot).set(stack);
} else {
@@ -62,7 +62,7 @@ public class CraftInventoryView extends InventoryView {
if (slot == -999) {
return null;
}
return new CraftItemStack(container.getSlot(slot).getItem());
return CraftItemStack.asCraftMirror(container.getSlot(slot).getItem());
}
public boolean isInTop(int rawSlot) {

View File

@@ -0,0 +1,123 @@
package org.bukkit.craftbukkit.inventory;
import org.apache.commons.lang.Validate;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public final class CraftItemFactory implements ItemFactory {
static final Color DEFAULT_LEATHER_COLOR = Color.fromRGB(0xA06540);
private static final CraftItemFactory instance;
static {
instance = new CraftItemFactory();
ConfigurationSerialization.registerClass(CraftMetaItem.SerializableMeta.class);
}
private CraftItemFactory() {
}
public boolean isApplicable(ItemMeta meta, ItemStack itemstack) {
if (itemstack == null) {
return false;
}
return isApplicable(meta, itemstack.getType());
}
public boolean isApplicable(ItemMeta meta, Material type) {
if (type == null || meta == null) {
return false;
}
if (!(meta instanceof CraftMetaItem)) {
throw new IllegalArgumentException("Meta of " + meta.getClass().toString() + " not created by " + CraftItemFactory.class.getName());
}
return ((CraftMetaItem) meta).applicableTo(type);
}
public ItemMeta getItemMeta(Material material) {
Validate.notNull(material, "Material cannot be null");
return getItemMeta(material, null);
}
private ItemMeta getItemMeta(Material material, CraftMetaItem meta) {
switch (material) {
case AIR:
return null;
case WRITTEN_BOOK:
case BOOK_AND_QUILL:
return meta instanceof CraftMetaBook ? meta : new CraftMetaBook(meta);
case SKULL_ITEM:
return meta instanceof CraftMetaSkull ? meta : new CraftMetaSkull(meta);
case LEATHER_HELMET:
case LEATHER_CHESTPLATE:
case LEATHER_LEGGINGS:
case LEATHER_BOOTS:
return meta instanceof CraftMetaLeatherArmor ? meta : new CraftMetaLeatherArmor(meta);
case POTION:
return meta instanceof CraftMetaPotion ? meta : new CraftMetaPotion(meta);
case MAP:
return meta instanceof CraftMetaMap ? meta : new CraftMetaMap(meta);
default:
return new CraftMetaItem(meta);
}
}
public boolean equals(ItemMeta meta1, ItemMeta meta2) {
if (meta1 == meta2) {
return true;
}
if (meta1 != null && !(meta1 instanceof CraftMetaItem)) {
throw new IllegalArgumentException("First meta of " + meta1.getClass().getName() + " does not belong to " + CraftItemFactory.class.getName());
}
if (meta2 != null && !(meta2 instanceof CraftMetaItem)) {
throw new IllegalArgumentException("Second meta " + meta2.getClass().getName() + " does not belong to " + CraftItemFactory.class.getName());
}
if (meta1 == null) {
return ((CraftMetaItem) meta2).isEmpty();
}
if (meta2 == null) {
return ((CraftMetaItem) meta1).isEmpty();
}
return equals((CraftMetaItem) meta1, (CraftMetaItem) meta2);
}
boolean equals(CraftMetaItem meta1, CraftMetaItem meta2) {
/*
* This couldn't be done inside of the objects themselves, else force recursion.
* This is a fairly clean way of implementing it, by dividing the methods into purposes and letting each method perform its own function.
*
* The common and uncommon were split, as both could have variables not applicable to the other, like a skull and book.
* Each object needs its chance to say "hey wait a minute, we're not equal," but without the redundancy of using the 1.equals(2) && 2.equals(1) checking the 'commons' twice.
*
* Doing it this way fills all conditions of the .equals() method.
*/
return meta1.equalsCommon(meta2) && meta1.notUncommon(meta2) && meta2.notUncommon(meta1);
}
public static CraftItemFactory instance() {
return instance;
}
public ItemMeta asMetaFor(ItemMeta meta, ItemStack stack) {
Validate.notNull(stack, "Stack cannot be null");
return asMetaFor(meta, stack.getType());
}
public ItemMeta asMetaFor(ItemMeta meta, Material material) {
Validate.notNull(material, "Material cannot be null");
if (!(meta instanceof CraftMetaItem)) {
throw new IllegalArgumentException("Meta of " + (meta != null ? meta.getClass().toString() : "null") + " not created by " + CraftItemFactory.class.getName());
}
return getItemMeta(material, (CraftMetaItem) meta);
}
public Color getDefaultLeatherColor() {
return DEFAULT_LEATHER_COLOR;
}
}

View File

@@ -1,134 +1,150 @@
package org.bukkit.craftbukkit.inventory;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.server.EnchantmentManager;
import net.minecraft.server.NBTTagCompound;
import net.minecraft.server.NBTTagList;
import org.apache.commons.lang.Validate;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.Material;
import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.inventory.meta.ItemMeta;
import com.google.common.collect.ImmutableMap;
@DelegateDeserialization(ItemStack.class)
public class CraftItemStack extends ItemStack {
protected net.minecraft.server.ItemStack item;
public final class CraftItemStack extends ItemStack {
public CraftItemStack(net.minecraft.server.ItemStack item) {
super(
item != null ? item.id: 0,
item != null ? item.count : 0,
(short)(item != null ? item.getData() : 0)
);
this.item = item;
public static net.minecraft.server.ItemStack asNMSCopy(ItemStack original) {
if (original instanceof CraftItemStack) {
CraftItemStack stack = (CraftItemStack) original;
return stack.handle == null ? null : stack.handle.cloneItemStack();
}
if (original == null || original.getTypeId() <= 0) {
return null;
}
net.minecraft.server.ItemStack stack = new net.minecraft.server.ItemStack(original.getTypeId(), original.getAmount(), original.getDurability());
if (original.hasItemMeta()) {
setItemMeta(stack, original.getItemMeta());
}
return stack;
}
public CraftItemStack(ItemStack item) {
this(item.getTypeId(), item.getAmount(), item.getDurability());
addUnsafeEnchantments(item.getEnchantments());
public static net.minecraft.server.ItemStack copyNMSStack(net.minecraft.server.ItemStack original, int amount) {
net.minecraft.server.ItemStack stack = original.cloneItemStack();
stack.count = amount;
return stack;
}
/* 'Overwritten' constructors from ItemStack, yay for Java sucking */
public CraftItemStack(final int type) {
this(type, 1);
}
public CraftItemStack(final Material type) {
this(type, 1);
}
public CraftItemStack(final int type, final int amount) {
this(type, amount, (byte) 0);
}
public CraftItemStack(final Material type, final int amount) {
this(type.getId(), amount);
}
public CraftItemStack(final int type, final int amount, final short damage) {
this(type, amount, damage, null);
}
public CraftItemStack(final Material type, final int amount, final short damage) {
this(type.getId(), amount, damage);
}
public CraftItemStack(final Material type, final int amount, final short damage, final Byte data) {
this(type.getId(), amount, damage, data);
}
public CraftItemStack(int type, int amount, short damage, Byte data) {
this(new net.minecraft.server.ItemStack(type, amount, data != null ? data : damage));
}
/*
* Unsure if we have to sync before each of these calls the values in 'item'
* are all public.
/**
* Copies the NMS stack to return as a strictly-Bukkit stack
*/
public static ItemStack asBukkitCopy(net.minecraft.server.ItemStack original) {
if (original == null) {
return new ItemStack(Material.AIR);
}
ItemStack stack = new ItemStack(original.id, original.count, (short) original.getData());
if (hasItemMeta(original)) {
stack.setItemMeta(getItemMeta(original));
}
return stack;
}
@Override
public Material getType() {
super.setTypeId(item != null ? item.id : 0); // sync, needed?
return super.getType();
public static CraftItemStack asCraftMirror(net.minecraft.server.ItemStack original) {
return new CraftItemStack(original);
}
public static CraftItemStack asCraftCopy(ItemStack original) {
if (original instanceof CraftItemStack) {
CraftItemStack stack = (CraftItemStack) original;
return new CraftItemStack(stack.handle == null ? null : stack.handle.cloneItemStack());
}
return new CraftItemStack(original);
}
public static CraftItemStack asNewCraftStack(net.minecraft.server.Item item) {
return asNewCraftStack(item, 1);
}
public static CraftItemStack asNewCraftStack(net.minecraft.server.Item item, int amount) {
return new CraftItemStack(item.id, amount, (short) 0, null);
}
net.minecraft.server.ItemStack handle;
/**
* Mirror
*/
private CraftItemStack(net.minecraft.server.ItemStack item) {
this.handle = item;
}
private CraftItemStack(ItemStack item) {
this(item.getTypeId(), item.getAmount(), item.getDurability(), item.hasItemMeta() ? item.getItemMeta() : null);
}
private CraftItemStack(int typeId, int amount, short durability, ItemMeta itemMeta) {
setTypeId(typeId);
setAmount(amount);
setDurability(durability);
setItemMeta(itemMeta);
}
@Override
public int getTypeId() {
super.setTypeId(item != null ? item.id : 0); // sync, needed?
return item != null ? item.id : 0;
return handle != null ? handle.id : 0;
}
@Override
public void setTypeId(int type) {
if (type == 0) {
super.setTypeId(0);
super.setAmount(0);
item = null;
if (getTypeId() == type) {
return;
} else if (type == 0) {
handle = null;
} else if (handle == null) {
handle = new net.minecraft.server.ItemStack(type, 1, 0);
} else {
if (item == null) {
item = new net.minecraft.server.ItemStack(type, 1, 0);
super.setTypeId(type);
super.setAmount(1);
super.setDurability((short) 0);
} else {
item.id = type;
super.setTypeId(item.id);
handle.id = type;
if (hasItemMeta()) {
// This will create the appropriate item meta, which will contain all the data we intend to keep
setItemMeta(handle, getItemMeta(handle));
}
}
setData(null);
}
@Override
public int getAmount() {
super.setAmount(item != null ? item.count : 0); // sync, needed?
return (item != null ? item.count : 0);
return handle != null ? handle.count : 0;
}
@Override
public void setAmount(int amount) {
if (handle == null) {
return;
}
if (amount == 0) {
super.setTypeId(0);
super.setAmount(0);
item = null;
handle = null;
} else {
super.setAmount(amount);
item.count = amount;
handle.count = amount;
}
}
@Override
public void setDurability(final short durability) {
// Ignore damage if item is null
if (item != null) {
super.setDurability(durability);
item.setData(durability);
if (handle != null) {
handle.setData(durability);
}
}
@Override
public short getDurability() {
if (item != null) {
super.setDurability((short) item.getData()); // sync, needed?
return (short) item.getData();
if (handle != null) {
return (short) handle.getData();
} else {
return -1;
}
@@ -136,14 +152,46 @@ public class CraftItemStack extends ItemStack {
@Override
public int getMaxStackSize() {
return (item == null) ? 0 : item.getItem().getMaxStackSize();
return (handle == null) ? Material.AIR.getMaxStackSize() : handle.getItem().getMaxStackSize();
}
@Override
public void addUnsafeEnchantment(Enchantment ench, int level) {
Map<Enchantment, Integer> enchantments = getEnchantments();
enchantments.put(ench, level);
rebuildEnchantments(enchantments);
Validate.notNull(ench, "Cannot add null enchantment");
if (!makeTag(handle)) {
return;
}
NBTTagList list = getEnchantmentList(handle), listCopy;
if (list == null) {
list = new NBTTagList("ench");
handle.tag.set("ench", list);
}
int size = list.size();
for (int i = 0; i < size; i++) {
NBTTagCompound tag = (NBTTagCompound) list.get(i);
short id = tag.getShort("id");
if (id == ench.getId()) {
tag.setShort("lvl", (short) level);
return;
}
}
NBTTagCompound tag = new NBTTagCompound();
tag.setShort("id", (short) ench.getId());
tag.setShort("lvl", (short) level);
list.add(tag);
}
static boolean makeTag(net.minecraft.server.ItemStack item) {
if (item == null) {
return false;
}
if (item.tag != null) {
return true;
}
item.tag = new NBTTagCompound();
return true;
}
@Override
@@ -153,31 +201,65 @@ public class CraftItemStack extends ItemStack {
@Override
public int getEnchantmentLevel(Enchantment ench) {
if (item == null) return 0;
return EnchantmentManager.getEnchantmentLevel(ench.getId(), item);
Validate.notNull(ench, "Cannot find null enchantment");
if (handle == null) {
return 0;
}
return EnchantmentManager.getEnchantmentLevel(ench.getId(), handle);
}
@Override
public int removeEnchantment(Enchantment ench) {
Map<Enchantment, Integer> enchantments = getEnchantments();
Integer previous = enchantments.remove(ench);
Validate.notNull(ench, "Cannot remove null enchantment");
rebuildEnchantments(enchantments);
NBTTagList list = getEnchantmentList(handle), listCopy;
if (list == null) {
return 0;
}
int index = Integer.MIN_VALUE, size = list.size(), level;
return (previous == null) ? 0 : previous;
for (int i = 0; i < size; i++) {
short id = ((NBTTagCompound) list.get(i)).getShort("id");
if (id == ench.getId()) {
index = i;
break;
}
}
if (index == Integer.MIN_VALUE) {
return 0;
}
if (index == 0 && size == 0) {
handle.tag.o("ench");
if (handle.tag.d()) {
handle.tag = null;
}
}
listCopy = new NBTTagList("ench");
level = Integer.MAX_VALUE;
for (int i = 0; i < size; i++) {
if (i == index) {
level = ((NBTTagCompound) list.get(i)).getShort("id");
continue;
}
listCopy.add(list.get(i));
}
handle.tag.set("ench", listCopy);
return level;
}
@Override
public Map<Enchantment, Integer> getEnchantments() {
return getEnchantments(item);
return getEnchantments(handle);
}
public static Map<Enchantment, Integer> getEnchantments(net.minecraft.server.ItemStack item) {
Map<Enchantment, Integer> result = new HashMap<Enchantment, Integer>();
static Map<Enchantment, Integer> getEnchantments(net.minecraft.server.ItemStack item) {
ImmutableMap.Builder<Enchantment, Integer> result = ImmutableMap.builder();
NBTTagList list = (item == null) ? null : item.getEnchantments();
if (list == null) {
return result;
return result.build();
}
for (int i = 0; i < list.size(); i++) {
@@ -187,66 +269,111 @@ public class CraftItemStack extends ItemStack {
result.put(Enchantment.getById(id), (int) level);
}
return result;
return result.build();
}
private void rebuildEnchantments(Map<Enchantment, Integer> enchantments) {
if (item == null) return;
NBTTagCompound tag = item.tag;
NBTTagList list = new NBTTagList("ench");
if (tag == null) {
tag = item.tag = new NBTTagCompound();
}
for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
NBTTagCompound subtag = new NBTTagCompound();
subtag.setShort("id", (short) entry.getKey().getId());
subtag.setShort("lvl", (short) (int) entry.getValue());
list.add(subtag);
}
if (enchantments.isEmpty()) {
tag.remove("ench");
} else {
tag.set("ench", list);
}
}
public net.minecraft.server.ItemStack getHandle() {
return item;
static NBTTagList getEnchantmentList(net.minecraft.server.ItemStack item) {
return item == null ? null : item.getEnchantments();
}
@Override
public CraftItemStack clone() {
CraftItemStack itemStack = (CraftItemStack) super.clone();
if (this.item != null) {
itemStack.item = this.item.cloneItemStack();
if (this.handle != null) {
itemStack.handle = this.handle.cloneItemStack();
}
return itemStack;
}
public static net.minecraft.server.ItemStack createNMSItemStack(ItemStack original) {
if (original == null || original.getTypeId() <= 0) {
return null;
} else if (original instanceof CraftItemStack) {
return ((CraftItemStack) original).getHandle();
}
return new CraftItemStack(original).getHandle();
@Override
public ItemMeta getItemMeta() {
return getItemMeta(handle);
}
/**
* Copies the NMS stack to return as a strictly-Bukkit stack
*/
public static ItemStack asBukkitStack(net.minecraft.server.ItemStack original) {
if (original == null) {
return new ItemStack(Material.AIR);
static ItemMeta getItemMeta(net.minecraft.server.ItemStack item) {
if (!hasItemMeta(item)) {
return CraftItemFactory.instance().getItemMeta(getType(item));
}
ItemStack stack = new ItemStack(original.id, original.count, (short) original.getData());
stack.addUnsafeEnchantments(getEnchantments(original));
return stack;
switch (getType(item)) {
case WRITTEN_BOOK:
case BOOK_AND_QUILL:
return new CraftMetaBook(item.tag);
case SKULL_ITEM:
return new CraftMetaSkull(item.tag);
case LEATHER_HELMET:
case LEATHER_CHESTPLATE:
case LEATHER_LEGGINGS:
case LEATHER_BOOTS:
return new CraftMetaLeatherArmor(item.tag);
case POTION:
return new CraftMetaPotion(item.tag);
case MAP:
return new CraftMetaMap(item.tag);
default:
return new CraftMetaItem(item.tag);
}
}
static Material getType(net.minecraft.server.ItemStack item) {
Material material = Material.getMaterial(item == null ? 0 : item.id);
return material == null ? Material.AIR : material;
}
@Override
public boolean setItemMeta(ItemMeta itemMeta) {
return setItemMeta(handle, itemMeta);
}
static boolean setItemMeta(net.minecraft.server.ItemStack item, ItemMeta itemMeta) {
if (item == null) {
return false;
}
if (itemMeta == null) {
item.tag = null;
return true;
}
if (!CraftItemFactory.instance().isApplicable(itemMeta, getType(item))) {
return false;
}
NBTTagCompound tag = new NBTTagCompound();
item.setTag(tag);
((CraftMetaItem) itemMeta).applyToItem(tag);
return true;
}
@Override
public boolean isSimilar(ItemStack stack) {
if (stack == null) {
return false;
}
if (stack == this) {
return true;
}
if (!(stack instanceof CraftItemStack)) {
return stack.getClass() == ItemStack.class && stack.isSimilar(this);
}
CraftItemStack that = (CraftItemStack) stack;
if (handle == that.handle) {
return true;
}
if (handle == null || that.handle == null) {
return false;
}
if (!(that.getTypeId() == getTypeId() && getDurability() == that.getDurability())) {
return false;
}
return hasItemMeta() ? that.hasItemMeta() && handle.tag.equals(that.handle.tag) : !that.hasItemMeta();
}
@Override
public boolean hasItemMeta() {
return hasItemMeta(handle);
}
static boolean hasItemMeta(net.minecraft.server.ItemStack item) {
return !(item == null || item.tag == null || item.tag.d());
}
}

View File

@@ -0,0 +1,272 @@
package org.bukkit.craftbukkit.inventory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import net.minecraft.server.NBTTagCompound;
import net.minecraft.server.NBTTagList;
import net.minecraft.server.NBTTagString;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta;
import org.bukkit.inventory.meta.BookMeta;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap.Builder;
@DelegateDeserialization(SerializableMeta.class)
class CraftMetaBook extends CraftMetaItem implements BookMeta {
static final ItemMetaKey BOOK_TITLE = new ItemMetaKey("title");
static final ItemMetaKey BOOK_AUTHOR = new ItemMetaKey("author");
static final ItemMetaKey BOOK_PAGES = new ItemMetaKey("pages");
static final int MAX_PAGE_LENGTH = 256;
static final int MAX_TITLE_LENGTH = 0xffff;
private String title;
private String author;
private List<String> pages = new ArrayList<String>();
CraftMetaBook(CraftMetaItem meta) {
super(meta);
if (!(meta instanceof CraftMetaBook)) {
return;
}
CraftMetaBook bookMeta = (CraftMetaBook) meta;
this.title = bookMeta.title;
this.author = bookMeta.author;
pages.addAll(bookMeta.pages);
}
CraftMetaBook(NBTTagCompound tag) {
super(tag);
if (tag.hasKey(BOOK_TITLE.NBT)) {
this.title = tag.getString(BOOK_TITLE.NBT);
}
if (tag.hasKey(BOOK_AUTHOR.NBT)) {
this.author = tag.getString(BOOK_AUTHOR.NBT);
}
if (tag.hasKey(BOOK_PAGES.NBT)) {
NBTTagList pages = tag.getList(BOOK_PAGES.NBT);
String[] pageArray = new String[pages.size()];
for (int i = 0; i < pages.size(); i++) {
String page = ((NBTTagString) pages.get(i)).data;
pageArray[i] = page;
}
addPage(pageArray);
}
}
CraftMetaBook(Map<String, Object> map) {
super(map);
setAuthor(SerializableMeta.getString(map, BOOK_AUTHOR.BUKKIT, true));
setTitle(SerializableMeta.getString(map, BOOK_TITLE.BUKKIT, true));
Collection<?> pages = SerializableMeta.getObject(Collection.class, map, BOOK_PAGES.BUKKIT, true);
CraftMetaItem.safelyAdd(pages, this.pages, MAX_PAGE_LENGTH);
}
@Override
void applyToItem(NBTTagCompound itemData) {
super.applyToItem(itemData);
if (hasTitle()) {
itemData.setString(BOOK_TITLE.NBT, this.title);
}
if (hasAuthor()) {
itemData.setString(BOOK_AUTHOR.NBT, this.author);
}
if (hasPages()) {
NBTTagList itemPages = new NBTTagList(BOOK_PAGES.NBT);
for (int i = 1; i < pages.size() + 1; i++) {
itemPages.add(new NBTTagString(String.valueOf(i), pages.get(i - 1)));
}
itemData.set(BOOK_PAGES.NBT, itemPages);
}
}
@Override
boolean isEmpty() {
return super.isEmpty() && isBookEmpty();
}
boolean isBookEmpty() {
return !(hasPages() || hasAuthor() || hasTitle());
}
@Override
boolean applicableTo(Material type) {
switch (type) {
case WRITTEN_BOOK:
case BOOK_AND_QUILL:
return true;
default:
return false;
}
}
public boolean hasAuthor() {
return !Strings.isNullOrEmpty(author);
}
public boolean hasTitle() {
return !Strings.isNullOrEmpty(title);
}
public boolean hasPages() {
return !pages.isEmpty();
}
public String getTitle() {
return this.title;
}
public boolean setTitle(final String title) {
if (title == null) {
this.title = null;
return true;
} else if (title.length() > MAX_TITLE_LENGTH) {
return false;
}
this.title = title;
return true;
}
public String getAuthor() {
return this.author;
}
public void setAuthor(final String author) {
this.author = author;
}
public String getPage(final int page) {
Validate.isTrue(isValidPage(page), "Invalid page number");
return pages.get(page - 1);
}
public void setPage(final int page, final String text) {
if (!isValidPage(page)) {
throw new IllegalArgumentException("Invalid page number " + page + "/" + pages.size());
}
pages.set(page - 1, text == null ? "" : text.length() > MAX_PAGE_LENGTH ? text.substring(0, MAX_PAGE_LENGTH) : text);
}
public void setPages(final String... pages) {
this.pages.clear();
addPage(pages);
}
public void addPage(final String... pages) {
for (String page : pages) {
if (page == null) {
page = "";
} else if (page.length() > MAX_PAGE_LENGTH) {
page = page.substring(0, MAX_PAGE_LENGTH);
}
this.pages.add(page);
}
}
public int getPageCount() {
return pages.size();
}
public List<String> getPages() {
return ImmutableList.copyOf(pages);
}
public void setPages(List<String> pages) {
this.pages.clear();
CraftMetaItem.safelyAdd(pages, this.pages, MAX_PAGE_LENGTH);
}
private boolean isValidPage(int page) {
return page > 0 && page <= pages.size();
}
@Override
public CraftMetaBook clone() {
CraftMetaBook meta = (CraftMetaBook) super.clone();
meta.pages = new ArrayList<String>(pages);
return meta;
}
@Override
int applyHash() {
final int original;
int hash = original = super.applyHash();
if (hasTitle()) {
hash = 61 * hash + this.title.hashCode();
}
if (hasAuthor()) {
hash = 61 * hash + 13 * this.author.hashCode();
}
if (hasPages()) {
hash = 61 * hash + 17 * this.pages.hashCode();
}
return original != hash ? CraftMetaBook.class.hashCode() ^ hash : hash;
}
@Override
boolean equalsCommon(CraftMetaItem meta) {
if (!super.equalsCommon(meta)) {
return false;
}
if (meta instanceof CraftMetaBook) {
CraftMetaBook that = (CraftMetaBook) meta;
return (hasTitle() ? that.hasTitle() && this.title.equals(that.title) : !that.hasTitle())
&& (hasAuthor() ? that.hasAuthor() && this.author.equals(that.author) : !that.hasAuthor())
&& (hasPages() ? that.hasPages() && this.pages.equals(that.pages) : !that.hasPages());
}
return true;
}
@Override
boolean notUncommon(CraftMetaItem meta) {
return super.notUncommon(meta) && (meta instanceof CraftMetaBook || isBookEmpty());
}
@Override
Builder<String, Object> serialize(Builder<String, Object> builder) {
super.serialize(builder);
if (hasTitle()) {
builder.put(BOOK_TITLE.BUKKIT, title);
}
if (hasAuthor()) {
builder.put(BOOK_AUTHOR.BUKKIT, author);
}
if (hasPages()) {
builder.put(BOOK_PAGES.BUKKIT, pages);
}
return builder;
}
@Override
SerializableMeta.Deserializers deserializer() {
return SerializableMeta.Deserializers.BOOK;
}
}

View File

@@ -0,0 +1,510 @@
package org.bukkit.craftbukkit.inventory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import net.minecraft.server.NBTBase;
import net.minecraft.server.NBTTagCompound;
import net.minecraft.server.NBTTagList;
import net.minecraft.server.NBTTagString;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.configuration.serialization.SerializableAs;
import org.bukkit.craftbukkit.Overridden;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.Repairable;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
* Children must include the following:
*
* <li> Constructor(CraftMetaItem meta)
* <li> Constructor(NBTTagCompound tag)
* <li> Constructor(Map<String, Object> map)
* <br><br>
* <li> void applyToItem(NBTTagCompound tag)
* <li> boolean applicableTo(Material type)
* <br><br>
* <li> boolean notUncommon(CraftMetaItem meta)
* <li> boolean equalsCommon(CraftMetaItem meta)
* <br><br>
* <li> boolean isEmpty()
* <li> boolean is{Type}Empty()
* <br><br>
* <li> int applyHash()
* <li> public Class clone()
* <br><br>
* <li> Builder<String, Object> serialize(Builder<String, Object> builder)
* <li> SerializableMeta.Deserializers deserializer()
*/
@DelegateDeserialization(CraftMetaItem.SerializableMeta.class)
class CraftMetaItem implements ItemMeta, Repairable {
static class ItemMetaKey {
final String BUKKIT;
final String NBT;
ItemMetaKey(final String both) {
this(both, both);
}
ItemMetaKey(final String nbt, final String bukkit) {
this.NBT = nbt;
this.BUKKIT = bukkit;
}
}
@SerializableAs("ItemMeta")
public static class SerializableMeta implements ConfigurationSerializable {
static final String TYPE_FIELD = "meta-type";
enum Deserializers {
BOOK {
@Override
CraftMetaBook deserialize(Map<String, Object> map) {
return new CraftMetaBook(map);
}
},
SKULL {
@Override
CraftMetaSkull deserialize(Map<String, Object> map) {
return new CraftMetaSkull(map);
}
},
LEATHER_ARMOR {
@Override
CraftMetaLeatherArmor deserialize(Map<String, Object> map) {
return new CraftMetaLeatherArmor(map);
}
},
MAP {
@Override
CraftMetaMap deserialize(Map<String, Object> map) {
return new CraftMetaMap(map);
}
},
POTION {
@Override
CraftMetaPotion deserialize(Map<String, Object> map) {
return new CraftMetaPotion(map);
}
},
UNSPECIFIC {
@Override
CraftMetaItem deserialize(Map<String, Object> map) {
return new CraftMetaItem(map);
}
};
abstract CraftMetaItem deserialize(Map<String, Object> map);
}
private SerializableMeta() {
}
public static ItemMeta deserialize(Map<String, Object> map) {
Validate.notNull(map, "Cannot deserialize null map");
String type = getString(map, TYPE_FIELD, false);
Deserializers deserializer = Deserializers.valueOf(type);
if (deserializer == null) {
throw new IllegalArgumentException(type + " is not a valid " + TYPE_FIELD);
}
return deserializer.deserialize(map);
}
public Map<String, Object> serialize() {
throw new AssertionError();
}
static String getString(Map<?, ?> map, Object field, boolean nullable) {
return getObject(String.class, map, field, nullable);
}
static boolean getBoolean(Map<?, ?> map, Object field) {
Boolean value = getObject(Boolean.class, map, field, true);
return value != null && value;
}
static <T> T getObject(Class<T> clazz, Map<?, ?> map, Object field, boolean nullable) {
final Object object = map.get(field);
if (clazz.isInstance(object)) {
return clazz.cast(object);
}
if (object == null) {
if (!nullable) {
throw new NoSuchElementException(map + " does not contain " + field);
}
return null;
}
throw new IllegalArgumentException(field + "(" + object + ") is not a valid " + clazz);
}
}
static final ItemMetaKey NAME = new ItemMetaKey("Name", "display-name");
static final ItemMetaKey DISPLAY = new ItemMetaKey("display");
static final ItemMetaKey LORE = new ItemMetaKey("Lore", "lore");
static final ItemMetaKey ENCHANTMENTS = new ItemMetaKey("ench", "enchants");
static final ItemMetaKey ENCHANTMENTS_ID = new ItemMetaKey("id");
static final ItemMetaKey ENCHANTMENTS_LVL = new ItemMetaKey("lvl");
static final ItemMetaKey REPAIR = new ItemMetaKey("RepairCost", "repair-cost");
private String displayName;
private List<String> lore;
private Map<Enchantment, Integer> enchantments;
private int repairCost;
CraftMetaItem(CraftMetaItem meta) {
if (meta == null) {
return;
}
this.displayName = meta.displayName;
if (meta.hasLore()) {
this.lore = new ArrayList<String>(meta.lore);
}
if (meta.hasEnchants()) {
this.enchantments = new HashMap<Enchantment, Integer>(meta.enchantments);
}
this.repairCost = meta.repairCost;
}
CraftMetaItem(NBTTagCompound tag) {
if (tag.hasKey(DISPLAY.NBT)) {
NBTTagCompound display = tag.getCompound(DISPLAY.NBT);
if (display.hasKey(NAME.NBT)) {
displayName = display.getString(NAME.NBT);
}
if (display.hasKey(LORE.NBT)) {
NBTTagList list = display.getList(LORE.NBT);
lore = new ArrayList<String>(list.size());
for (int index = 0; index < list.size(); index++) {
String line = ((NBTTagString) list.get(index)).data;
lore.add(line);
}
}
}
if (tag.hasKey(ENCHANTMENTS.NBT)) {
NBTTagList ench = tag.getList(ENCHANTMENTS.NBT);
enchantments = new HashMap<Enchantment, Integer>(ench.size());
for (int i = 0; i < ench.size(); i++) {
short id = ((NBTTagCompound) ench.get(i)).getShort(ENCHANTMENTS_ID.NBT);
short level = ((NBTTagCompound) ench.get(i)).getShort(ENCHANTMENTS_LVL.NBT);
addEnchant(Enchantment.getById(id), (int) level, true);
}
}
if (tag.hasKey(REPAIR.NBT)) {
repairCost = tag.getInt(REPAIR.NBT);
}
}
CraftMetaItem(Map<String, Object> map) {
setDisplayName(SerializableMeta.getString(map, NAME.BUKKIT, true));
if (map.containsKey(LORE.BUKKIT)) {
lore = (List<String>) map.get(LORE.BUKKIT);
}
Map<?, ?> ench = SerializableMeta.getObject(Map.class, map, ENCHANTMENTS.BUKKIT, true);
if (ench != null) {
enchantments = new HashMap<Enchantment, Integer>(ench.size());
for (Map.Entry<?, ?> entry : ench.entrySet()) {
Enchantment enchantment = Enchantment.getByName(entry.getKey().toString());
if ((enchantment != null) && (entry.getValue() instanceof Integer)) {
addEnchant(enchantment, (Integer) entry.getValue(), true);
}
}
}
if (map.containsKey(REPAIR.BUKKIT)) {
repairCost = (Integer) map.get(REPAIR.BUKKIT);
}
}
@Overridden
void applyToItem(NBTTagCompound itemTag) {
if (hasDisplayName()) {
setDisplayTag(itemTag, NAME.NBT, new NBTTagString(NAME.NBT, displayName));
}
if (hasLore()) {
NBTTagList list = new NBTTagList(LORE.NBT);
for (int i = 0; i < lore.size(); i++) {
list.add(new NBTTagString(String.valueOf(i), lore.get(i)));
}
setDisplayTag(itemTag, LORE.NBT, list);
}
if (hasEnchants()) {
NBTTagList list = new NBTTagList(ENCHANTMENTS.NBT);
for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet()) {
NBTTagCompound subtag = new NBTTagCompound();
subtag.setShort(ENCHANTMENTS_ID.NBT, (short) entry.getKey().getId());
subtag.setShort(ENCHANTMENTS_LVL.NBT, (short) (int) entry.getValue());
list.add(subtag);
}
itemTag.set(ENCHANTMENTS.NBT, list);
}
if (hasRepairCost()) {
itemTag.setInt(REPAIR.NBT, repairCost);
}
}
void setDisplayTag(NBTTagCompound tag, String key, NBTBase value) {
final NBTTagCompound display = tag.getCompound(DISPLAY.NBT);
if (!tag.hasKey(DISPLAY.NBT)) {
tag.setCompound(DISPLAY.NBT, display);
}
display.set(key, value);
}
@Overridden
boolean applicableTo(Material type) {
return type != Material.AIR;
}
@Overridden
boolean isEmpty() {
return !(hasDisplayName() || hasEnchants() || hasLore());
}
public String getDisplayName() {
return displayName;
}
public final void setDisplayName(String name) {
this.displayName = name;
}
public boolean hasDisplayName() {
return !Strings.isNullOrEmpty(displayName);
}
public boolean hasLore() {
return this.lore != null && !this.lore.isEmpty();
}
public boolean hasRepairCost() {
return repairCost > 0;
}
public boolean hasEnchant(Enchantment ench) {
return hasEnchants() ? enchantments.containsKey(ench) : false;
}
public int getEnchantLevel(Enchantment ench) {
Integer level = hasEnchants() ? enchantments.get(ench) : null;
if (level == null) {
return 0;
}
return level;
}
public Map<Enchantment, Integer> getEnchants() {
return hasEnchants() ? ImmutableMap.copyOf(enchantments) : ImmutableMap.<Enchantment, Integer>of();
}
public boolean addEnchant(Enchantment ench, int level, boolean ignoreRestrictions) {
if (enchantments == null) {
enchantments = new HashMap<Enchantment, Integer>(4);
}
if (ignoreRestrictions || level >= ench.getStartLevel() && level <= ench.getMaxLevel()) {
Integer old = enchantments.put(ench, level);
return old == null || old != level;
}
return false;
}
public boolean removeEnchant(Enchantment ench) {
return hasEnchants() ? enchantments.remove(ench) != null : false;
}
public boolean hasEnchants() {
return !(enchantments == null || enchantments.isEmpty());
}
public List<String> getLore() {
return this.lore == null ? null : new ArrayList<String>(this.lore);
}
public void setLore(List<String> lore) { // too tired to think if .clone is better
if (lore == null) {
this.lore = null;
} else {
if (this.lore == null) {
safelyAdd(lore, this.lore = new ArrayList<String>(lore.size()), Integer.MAX_VALUE);
} else {
this.lore.clear();
safelyAdd(lore, this.lore, Integer.MAX_VALUE);
}
}
}
public int getRepairCost() {
return repairCost;
}
public void setRepairCost(int cost) { // TODO: Does this have limits?
repairCost = cost;
}
@Override
public final boolean equals(Object object) {
if (object == null) {
return false;
}
if (object == this) {
return true;
}
if (!(object instanceof CraftMetaItem)) {
return false;
}
return CraftItemFactory.instance().equals(this, (ItemMeta) object);
}
/**
* This method is almost as weird as notUncommon.
* Only return false if your common internals are unequal.
* Checking your own internals is redundant if you are not common, as notUncommon is meant for checking those 'not common' variables.
*/
@Overridden
boolean equalsCommon(CraftMetaItem that) {
return ((this.hasDisplayName() ? that.hasDisplayName() && this.displayName.equals(that.displayName) : !that.hasDisplayName()))
&& (this.hasEnchants() ? that.hasEnchants() && this.enchantments.equals(that.enchantments) : !that.hasEnchants())
&& (this.hasLore() ? that.hasLore() && this.lore.equals(that.lore) : !that.hasLore())
&& (this.hasRepairCost() ? that.hasRepairCost() && this.repairCost == that.repairCost : !that.hasRepairCost());
}
/**
* This method is a bit weird...
* Return true if you are a common class OR your uncommon parts are empty.
* Empty uncommon parts implies the NBT data would be equivalent if both were applied to an item
*/
@Overridden
boolean notUncommon(CraftMetaItem meta) {
return true;
}
@Override
public final int hashCode() {
return applyHash();
}
@Overridden
int applyHash() {
int hash = 3;
hash = 61 * hash + (hasDisplayName() ? this.displayName.hashCode() : 0);
hash = 61 * hash + (hasLore() ? this.lore.hashCode() : 0);
hash = 61 * hash + (hasEnchants() ? this.enchantments.hashCode() : 0);
hash = 61 * hash + (hasRepairCost() ? this.repairCost : 0);
return hash;
}
@Overridden
@Override
public CraftMetaItem clone() {
try {
return (CraftMetaItem) super.clone();
} catch (CloneNotSupportedException e) {
throw new Error(e);
}
}
public final Map<String, Object> serialize() {
ImmutableMap.Builder<String, Object> map = ImmutableMap.builder();
map.put(SerializableMeta.TYPE_FIELD, deserializer().name());
serialize(map);
return map.build();
}
@Overridden
ImmutableMap.Builder<String, Object> serialize(ImmutableMap.Builder<String, Object> builder) {
if (hasDisplayName()) {
builder.put(NAME.BUKKIT, displayName);
}
if (hasLore()) {
builder.put(LORE.BUKKIT, ImmutableList.copyOf(lore));
}
if (hasEnchants()) {
ImmutableMap.Builder<String, Integer> enchantments = ImmutableMap.builder();
for (Map.Entry<Enchantment, Integer> enchant : this.enchantments.entrySet()) {
enchantments.put(enchant.getKey().getName(), enchant.getValue());
}
builder.put(ENCHANTMENTS.BUKKIT, enchantments.build());
}
if (hasRepairCost()) {
builder.put(REPAIR.BUKKIT, repairCost);
}
return builder;
}
@Overridden
SerializableMeta.Deserializers deserializer() {
return SerializableMeta.Deserializers.UNSPECIFIC;
}
static void safelyAdd(Collection<?> addFrom, Collection<String> addTo, int maxItemLength) {
if (addFrom == null) {
return;
}
for (Object object : addFrom) {
if (!(object instanceof String)) {
if (object != null) {
throw new IllegalArgumentException(addFrom + " cannot contain non-string " + object.getClass().getName());
}
addTo.add("");
} else {
String page = object.toString();
if (page.length() > maxItemLength) {
page = page.substring(0, maxItemLength);
}
addTo.add(page);
}
}
}
@Override
public final String toString() {
return serialize().toString(); // TODO: cry
}
}

View File

@@ -0,0 +1,137 @@
package org.bukkit.craftbukkit.inventory;
import static org.bukkit.craftbukkit.inventory.CraftItemFactory.DEFAULT_LEATHER_COLOR;
import java.util.Map;
import net.minecraft.server.NBTTagCompound;
import net.minecraft.server.NBTTagInt;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import com.google.common.collect.ImmutableMap.Builder;
@DelegateDeserialization(SerializableMeta.class)
class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta {
static final ItemMetaKey COLOR = new ItemMetaKey("color");
private Color color = DEFAULT_LEATHER_COLOR;
CraftMetaLeatherArmor(CraftMetaItem meta) {
super(meta);
if (!(meta instanceof CraftMetaLeatherArmor)) {
return;
}
CraftMetaLeatherArmor armorMeta = (CraftMetaLeatherArmor) meta;
this.color = armorMeta.color;
}
CraftMetaLeatherArmor(NBTTagCompound tag) {
super(tag);
if (tag.hasKey(DISPLAY.NBT)) {
NBTTagCompound display = tag.getCompound(DISPLAY.NBT);
if (display.hasKey(COLOR.NBT)) {
color = Color.fromRGB(display.getInt(COLOR.NBT));
}
}
}
CraftMetaLeatherArmor(Map<String, Object> map) {
super(map);
setColor(SerializableMeta.getObject(Color.class, map, COLOR.BUKKIT, true));
}
void applyToItem(NBTTagCompound itemTag) {
super.applyToItem(itemTag);
if (hasColor()) {
setDisplayTag(itemTag, COLOR.NBT, new NBTTagInt(COLOR.NBT, color.asRGB()));
}
}
@Override
boolean isEmpty() {
return super.isEmpty() && isLeatherArmorEmpty();
}
boolean isLeatherArmorEmpty() {
return !(hasColor());
}
boolean applicableTo(Material type) {
switch(type) {
case LEATHER_HELMET:
case LEATHER_CHESTPLATE:
case LEATHER_LEGGINGS:
case LEATHER_BOOTS:
return true;
default:
return false;
}
}
@Override
public CraftMetaLeatherArmor clone() {
return (CraftMetaLeatherArmor) super.clone();
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color == null ? DEFAULT_LEATHER_COLOR : color;
}
boolean hasColor() {
return !DEFAULT_LEATHER_COLOR.equals(color);
}
@Override
Builder<String, Object> serialize(Builder<String, Object> builder) {
super.serialize(builder);
if (hasColor()) {
builder.put(COLOR.BUKKIT, color);
}
return builder;
}
@Override
SerializableMeta.Deserializers deserializer() {
return SerializableMeta.Deserializers.LEATHER_ARMOR;
}
@Override
boolean equalsCommon(CraftMetaItem meta) {
if (!super.equalsCommon(meta)) {
return false;
}
if (meta instanceof CraftMetaLeatherArmor) {
CraftMetaLeatherArmor that = (CraftMetaLeatherArmor) meta;
return color.equals(that.color);
}
return true;
}
@Override
boolean notUncommon(CraftMetaItem meta) {
return super.notUncommon(meta) && (meta instanceof CraftMetaLeatherArmor || isLeatherArmorEmpty());
}
int applyHash() {
final int original;
int hash = original = super.applyHash();
if (hasColor()) {
hash ^= color.hashCode();
}
return original != hash ? CraftMetaSkull.class.hashCode() ^ hash : hash;
}
}

View File

@@ -0,0 +1,139 @@
package org.bukkit.craftbukkit.inventory;
import java.util.Map;
import net.minecraft.server.NBTTagCompound;
import org.bukkit.Material;
import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta;
import org.bukkit.inventory.meta.MapMeta;
import com.google.common.collect.ImmutableMap;
@DelegateDeserialization(SerializableMeta.class)
class CraftMetaMap extends CraftMetaItem implements MapMeta {
static final ItemMetaKey MAP_SCALING = new ItemMetaKey("map_is_scaling", "scaling");
static final byte SCALING_EMPTY = (byte) 0;
static final byte SCALING_TRUE = (byte) 1;
static final byte SCALING_FALSE = (byte) 2;
private byte scaling = SCALING_EMPTY;
CraftMetaMap(CraftMetaItem meta) {
super(meta);
if (!(meta instanceof CraftMetaMap)) {
return;
}
CraftMetaMap map = (CraftMetaMap) meta;
this.scaling = map.scaling;
}
CraftMetaMap(NBTTagCompound tag) {
super(tag);
if (tag.hasKey(MAP_SCALING.NBT)) {
this.scaling = tag.getBoolean(MAP_SCALING.NBT) ? SCALING_TRUE : SCALING_FALSE;
}
}
CraftMetaMap(Map<String, Object> map) {
super(map);
if (map.containsKey(MAP_SCALING.BUKKIT)) {
this.scaling = SerializableMeta.getBoolean(map, MAP_SCALING.BUKKIT) ? SCALING_TRUE : SCALING_FALSE;
}
}
@Override
void applyToItem(NBTTagCompound tag) {
super.applyToItem(tag);
if (hasScaling()) {
tag.setBoolean(MAP_SCALING.NBT, isScaling());
}
}
@Override
boolean applicableTo(Material type) {
switch (type) {
case MAP:
return true;
default:
return false;
}
}
@Override
boolean isEmpty() {
return super.isEmpty() && isMapEmpty();
}
boolean isMapEmpty() {
return !hasScaling();
}
boolean hasScaling() {
return scaling != SCALING_EMPTY;
}
public boolean isScaling() {
return scaling == SCALING_TRUE;
}
public void setScaling(boolean scaling) {
this.scaling = scaling ? SCALING_TRUE : SCALING_FALSE;
}
@Override
boolean equalsCommon(CraftMetaItem meta) {
if (!super.equalsCommon(meta)) {
return false;
}
if (meta instanceof CraftMetaMap) {
CraftMetaMap that = (CraftMetaMap) meta;
return (this.scaling == that.scaling);
}
return true;
}
@Override
boolean notUncommon(CraftMetaItem meta) {
return super.notUncommon(meta) && (meta instanceof CraftMetaMap || isMapEmpty());
}
@Override
int applyHash() {
final int original;
int hash = original = super.applyHash();
if (hasScaling()) {
hash ^= 0x22222222 << (isScaling() ? 1 : -1);
}
return original != hash ? CraftMetaMap.class.hashCode() ^ hash : hash;
}
public CraftMetaMap clone() {
return (CraftMetaMap) super.clone();
}
@Override
ImmutableMap.Builder<String, Object> serialize(ImmutableMap.Builder<String, Object> builder) {
super.serialize(builder);
if (hasScaling()) {
builder.put(MAP_SCALING.BUKKIT, scaling);
}
return builder;
}
@Override
SerializableMeta.Deserializers deserializer() {
return SerializableMeta.Deserializers.MAP;
}
}

View File

@@ -0,0 +1,260 @@
package org.bukkit.craftbukkit.inventory;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.minecraft.server.NBTTagCompound;
import net.minecraft.server.NBTTagList;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap.Builder;
@DelegateDeserialization(SerializableMeta.class)
class CraftMetaPotion extends CraftMetaItem implements PotionMeta {
static final ItemMetaKey AMPLIFIER = new ItemMetaKey("Amplifier", "amplifier");
static final ItemMetaKey AMBIENT = new ItemMetaKey("Ambient", "ambient");
static final ItemMetaKey DURATION = new ItemMetaKey("Duration", "duration");
static final ItemMetaKey POTION_EFFECTS = new ItemMetaKey("CustomPotionEffects", "custom-effects");
static final ItemMetaKey ID = new ItemMetaKey("ID", "potion-id");
private List<PotionEffect> customEffects;
CraftMetaPotion(CraftMetaItem meta) {
super(meta);
if (!(meta instanceof CraftMetaPotion)) {
return;
}
CraftMetaPotion potionMeta = (CraftMetaPotion) meta;
if (potionMeta.hasCustomEffects()) {
this.customEffects = new ArrayList<PotionEffect>(potionMeta.customEffects);
}
}
CraftMetaPotion(NBTTagCompound tag) {
super(tag);
if (tag.hasKey(POTION_EFFECTS.NBT)) {
NBTTagList list = tag.getList(POTION_EFFECTS.NBT);
int length = list.size();
if (length > 0) {
customEffects = new ArrayList<PotionEffect>(length);
for (int i = 0; i < length; i++) {
NBTTagCompound effect = (NBTTagCompound) list.get(i);
PotionEffectType type = PotionEffectType.getById(effect.getByte(ID.NBT));
int amp = effect.getByte(AMPLIFIER.NBT);
int duration = effect.getInt(DURATION.NBT);
boolean ambient = effect.getBoolean(AMBIENT.NBT);
customEffects.add(new PotionEffect(type, duration, amp, ambient));
}
}
}
}
CraftMetaPotion(Map<String, Object> map) {
super(map);
List<?> rawEffectList = SerializableMeta.getObject(List.class, map, POTION_EFFECTS.BUKKIT, true);
if (rawEffectList == null) {
return;
}
for (Object obj : rawEffectList) {
if (!(obj instanceof PotionEffect)) {
throw new IllegalArgumentException("Object in effect list is not valid. " + obj.getClass());
}
addCustomEffect((PotionEffect) obj, true);
}
}
@Override
void applyToItem(NBTTagCompound tag) {
super.applyToItem(tag);
if (hasCustomEffects()) {
NBTTagList effectList = new NBTTagList();
tag.set(POTION_EFFECTS.NBT, effectList);
for (PotionEffect effect : customEffects) {
NBTTagCompound effectData = new NBTTagCompound();
effectData.setByte(ID.NBT, (byte) effect.getType().getId());
effectData.setByte(AMPLIFIER.NBT, (byte) effect.getAmplifier());
effectData.setInt(DURATION.NBT, effect.getDuration());
effectData.setBoolean(AMBIENT.NBT, effect.isAmbient());
effectList.add(effectData);
}
}
}
@Override
boolean isEmpty() {
return super.isEmpty() && isPotionEmpty();
}
boolean isPotionEmpty() {
return !(hasCustomEffects());
}
@Override
boolean applicableTo(Material type) {
switch(type) {
case POTION:
return true;
default:
return false;
}
}
@Override
public CraftMetaPotion clone() {
CraftMetaPotion clone = (CraftMetaPotion) super.clone();
if (hasCustomEffects()) {
clone.customEffects = new ArrayList<PotionEffect>(customEffects);
}
return clone;
}
public boolean hasCustomEffects() {
return !(customEffects == null || customEffects.isEmpty());
}
public List<PotionEffect> getCustomEffects() {
if (hasCustomEffects()) {
return ImmutableList.copyOf(customEffects);
}
return ImmutableList.of();
}
public boolean addCustomEffect(PotionEffect effect, boolean overwrite) {
Validate.notNull(effect, "Potion effect must not be null");
int index = indexOfEffect(effect.getType());
if (index != -1) {
if (overwrite) {
PotionEffect old = customEffects.get(index);
if (old.getAmplifier() == effect.getAmplifier() && old.getDuration() == effect.getDuration() && old.isAmbient() == effect.isAmbient()) {
return false;
}
customEffects.set(index, effect);
return true;
} else {
return false;
}
} else {
if (customEffects == null) {
customEffects = new ArrayList<PotionEffect>();
}
customEffects.add(effect);
return true;
}
}
public boolean removeCustomEffect(PotionEffectType type) {
Validate.notNull(type, "Potion effect type must not be null");
if (!hasCustomEffects()) {
return false;
}
boolean changed = false;
Iterator<PotionEffect> iterator = customEffects.iterator();
while (iterator.hasNext()) {
PotionEffect effect = iterator.next();
if (effect.getType() == type) {
iterator.remove();
changed = true;
}
}
return changed;
}
public boolean hasCustomEffect(PotionEffectType type) {
Validate.notNull(type, "Potion effect type must not be null");
return indexOfEffect(type) != -1;
}
public boolean setMainEffect(PotionEffectType type) {
Validate.notNull(type, "Potion effect type must not be null");
int index = indexOfEffect(type);
if (index == -1 || index == 0) {
return false;
}
PotionEffect old = customEffects.get(0);
customEffects.set(0, customEffects.get(index));
customEffects.set(index, old);
return true;
}
private int indexOfEffect(PotionEffectType type) {
if (!hasCustomEffects()) {
return -1;
}
for (int i = 0; i < customEffects.size(); i++) {
if (customEffects.get(i).getType().equals(type)) {
return i;
}
}
return -1;
}
public boolean clearCustomEffects() {
boolean changed = hasCustomEffects();
customEffects = null;
return changed;
}
@Override
int applyHash() {
final int original;
int hash = original = super.applyHash();
if (hasCustomEffects()) {
hash = 73 * hash + customEffects.hashCode();
}
return original != hash ? CraftMetaPotion.class.hashCode() ^ hash : hash;
}
@Override
public boolean equalsCommon(CraftMetaItem meta) {
if (!super.equalsCommon(meta)) {
return false;
}
if (meta instanceof CraftMetaPotion) {
CraftMetaPotion that = (CraftMetaPotion) meta;
return (this.hasCustomEffects() ? that.hasCustomEffects() && this.customEffects.equals(that.customEffects) : !that.hasCustomEffects());
}
return true;
}
@Override
boolean notUncommon(CraftMetaItem meta) {
return super.notUncommon(meta) && (meta instanceof CraftMetaPotion || isPotionEmpty());
}
@Override
Builder<String, Object> serialize(Builder<String, Object> builder) {
super.serialize(builder);
if (hasCustomEffects()) {
builder.put(POTION_EFFECTS.BUKKIT, ImmutableList.copyOf(this.customEffects));
}
return builder;
}
@Override
SerializableMeta.Deserializers deserializer() {
return SerializableMeta.Deserializers.POTION;
}
}

View File

@@ -0,0 +1,134 @@
package org.bukkit.craftbukkit.inventory;
import java.util.Map;
import net.minecraft.server.NBTTagCompound;
import org.bukkit.Material;
import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta;
import org.bukkit.inventory.meta.SkullMeta;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap.Builder;
@DelegateDeserialization(SerializableMeta.class)
class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
static final ItemMetaKey SKULL_OWNER = new ItemMetaKey("SkullOwner", "skull-owner");
static final int MAX_OWNER_LENGTH = 16;
private String player;
CraftMetaSkull(CraftMetaItem meta) {
super(meta);
if (!(meta instanceof CraftMetaSkull)) {
return;
}
CraftMetaSkull skullMeta = (CraftMetaSkull) meta;
this.player = skullMeta.player;
}
CraftMetaSkull(NBTTagCompound tag) {
super(tag);
if (tag.hasKey(SKULL_OWNER.NBT)) {
player = tag.getString(SKULL_OWNER.NBT);
}
}
CraftMetaSkull(Map<String, Object> map) {
super(map);
setOwner(SerializableMeta.getString(map, SKULL_OWNER.BUKKIT, true));
}
@Override
void applyToItem(NBTTagCompound tag) {
super.applyToItem(tag);
if (hasOwner()) {
tag.setString(SKULL_OWNER.NBT, player);
}
}
@Override
boolean isEmpty() {
return super.isEmpty() && isSkullEmpty();
}
boolean isSkullEmpty() {
return !(hasOwner());
}
@Override
boolean applicableTo(Material type) {
switch(type) {
case SKULL_ITEM:
return true;
default:
return false;
}
}
@Override
public CraftMetaSkull clone() {
return (CraftMetaSkull) super.clone();
}
public boolean hasOwner() {
return !Strings.isNullOrEmpty(player);
}
public String getOwner() {
return player;
}
public boolean setOwner(String name) {
if (name != null && name.length() > MAX_OWNER_LENGTH) {
return false;
}
player = name;
return true;
}
@Override
int applyHash() {
final int original;
int hash = original = super.applyHash();
if (hasOwner()) {
hash = 61 * hash + player.hashCode();
}
return original != hash ? CraftMetaSkull.class.hashCode() ^ hash : hash;
}
@Override
boolean equalsCommon(CraftMetaItem meta) {
if (!super.equalsCommon(meta)) {
return false;
}
if (meta instanceof CraftMetaSkull) {
CraftMetaSkull that = (CraftMetaSkull) meta;
return (this.hasOwner() ? that.hasOwner() && this.player.equals(that.player) : !that.hasOwner());
}
return true;
}
@Override
boolean notUncommon(CraftMetaItem meta) {
return super.notUncommon(meta) && (meta instanceof CraftMetaSkull || isSkullEmpty());
}
@Override
Builder<String, Object> serialize(Builder<String, Object> builder) {
super.serialize(builder);
if (hasOwner()) {
return builder.put(SKULL_OWNER.BUKKIT, this.player);
}
return builder;
}
@Override
SerializableMeta.Deserializers deserializer() {
return SerializableMeta.Deserializers.SKULL;
}
}

View File

@@ -59,6 +59,6 @@ public class CraftShapedRecipe extends ShapedRecipe implements CraftRecipe {
data[i] = new net.minecraft.server.ItemStack(id, 1, dmg);
i++;
}
CraftingManager.getInstance().registerShapedRecipe(CraftItemStack.createNMSItemStack(this.getResult()), data);
CraftingManager.getInstance().registerShapedRecipe(CraftItemStack.asNMSCopy(this.getResult()), data);
}
}

View File

@@ -42,6 +42,6 @@ public class CraftShapelessRecipe extends ShapelessRecipe implements CraftRecipe
data[i] = new net.minecraft.server.ItemStack(id, 1, dmg);
i++;
}
CraftingManager.getInstance().registerShapelessRecipe(CraftItemStack.createNMSItemStack(this.getResult()), data);
CraftingManager.getInstance().registerShapelessRecipe(CraftItemStack.asNMSCopy(this.getResult()), data);
}
}

View File

@@ -34,7 +34,7 @@ public class RecipeIterator implements Iterator<Recipe> {
} else {
removeFrom = smelting;
int id = smelting.next();
CraftItemStack stack = new CraftItemStack(RecipesFurnace.getInstance().getResult(id));
CraftItemStack stack = CraftItemStack.asCraftMirror(RecipesFurnace.getInstance().getResult(id));
CraftFurnaceRecipe recipe = new CraftFurnaceRecipe(stack, new ItemStack(id, 1, (short) -1));
return recipe;
}