From 78f48258d8ab491065498492588acc5287a6fb6c Mon Sep 17 00:00:00 2001 From: Wesley Wolfe Date: Mon, 17 Dec 2012 01:31:41 -0600 Subject: [PATCH] Implement ItemFactory and ItemMeta values. Adds BUKKIT-15 --- pom.xml | 11 +- .../server/ContainerEnchantTable.java | 4 +- .../server/DispenseBehaviorBoat.java | 8 +- .../server/DispenseBehaviorEmptyBucket.java | 8 +- .../server/DispenseBehaviorFilledBucket.java | 10 +- .../server/DispenseBehaviorFireball.java | 8 +- .../server/DispenseBehaviorItem.java | 10 +- .../server/DispenseBehaviorMinecart.java | 10 +- .../server/DispenseBehaviorMonsterEgg.java | 10 +- .../server/DispenseBehaviorProjectile.java | 10 +- .../java/net/minecraft/server/EntityCow.java | 4 +- .../net/minecraft/server/EntityGhast.java | 4 +- .../net/minecraft/server/EntityIronGolem.java | 4 +- .../net/minecraft/server/EntityLiving.java | 2 +- .../net/minecraft/server/EntityMinecart.java | 2 +- .../net/minecraft/server/EntityPigZombie.java | 6 +- .../net/minecraft/server/EntityPlayer.java | 4 +- .../net/minecraft/server/EntitySkeleton.java | 2 +- .../java/net/minecraft/server/ItemBucket.java | 14 +- .../java/net/minecraft/server/ItemStack.java | 15 - .../net/minecraft/server/NBTTagCompound.java | 6 +- .../minecraft/server/NetServerHandler.java | 10 +- .../net/minecraft/server/ShapedRecipes.java | 2 +- .../minecraft/server/ShapelessRecipes.java | 2 +- .../minecraft/server/TileEntityFurnace.java | 8 +- .../org/bukkit/craftbukkit/CraftServer.java | 6 + .../org/bukkit/craftbukkit/CraftWorld.java | 3 +- .../org/bukkit/craftbukkit/Overridden.java | 14 + .../craftbukkit/entity/CraftHumanEntity.java | 4 +- .../bukkit/craftbukkit/entity/CraftItem.java | 4 +- .../craftbukkit/entity/CraftItemFrame.java | 4 +- .../craftbukkit/event/CraftEventFactory.java | 29 +- .../inventory/CraftEntityEquipment.java | 4 +- .../inventory/CraftFurnaceRecipe.java | 2 +- .../craftbukkit/inventory/CraftInventory.java | 13 +- .../inventory/CraftInventoryCrafting.java | 20 +- .../inventory/CraftInventoryCustom.java | 4 +- .../inventory/CraftInventoryPlayer.java | 4 +- .../inventory/CraftInventoryView.java | 4 +- .../inventory/CraftItemFactory.java | 123 +++++ .../craftbukkit/inventory/CraftItemStack.java | 409 +++++++++----- .../craftbukkit/inventory/CraftMetaBook.java | 272 ++++++++++ .../craftbukkit/inventory/CraftMetaItem.java | 510 ++++++++++++++++++ .../inventory/CraftMetaLeatherArmor.java | 137 +++++ .../craftbukkit/inventory/CraftMetaMap.java | 139 +++++ .../inventory/CraftMetaPotion.java | 260 +++++++++ .../craftbukkit/inventory/CraftMetaSkull.java | 134 +++++ .../inventory/CraftShapedRecipe.java | 2 +- .../inventory/CraftShapelessRecipe.java | 2 +- .../craftbukkit/inventory/RecipeIterator.java | 2 +- src/test/java/org/bukkit/DyeColorsTest.java | 39 ++ src/test/java/org/bukkit/PerMaterialTest.java | 11 +- .../inventory/CompositeSerialization.java | 61 +++ .../inventory/FactoryItemMaterialTest.java | 142 +++++ .../ItemMetaImplementationOverrideTest.java | 67 +++ .../craftbukkit/inventory/ItemMetaTest.java | 113 ++++ .../inventory/ItemStackBookTest.java | 212 ++++++++ .../inventory/ItemStackLeatherTest.java | 88 +++ .../ItemStackLoreEnchantmentTest.java | 240 +++++++++ .../inventory/ItemStackPotionsTest.java | 145 +++++ .../inventory/ItemStackSkullTest.java | 87 +++ .../craftbukkit/inventory/ItemStackTest.java | 428 +++++++++++++++ ...ckTest.java => NMSCraftItemStackTest.java} | 6 +- .../updater/BukkitDLUpdaterServiceTest.java | 9 +- .../java/org/bukkit/potion/PotionTest.java | 18 +- .../bukkit/support/AbstractTestingBase.java | 3 + .../org/bukkit/support/DummyEnchantments.java | 12 + .../java/org/bukkit/support/DummyPotions.java | 17 + .../java/org/bukkit/support/DummyServer.java | 79 +++ .../java/org/bukkit/support/Matchers.java | 30 ++ 70 files changed, 3773 insertions(+), 313 deletions(-) create mode 100644 src/main/java/org/bukkit/craftbukkit/Overridden.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java create mode 100644 src/test/java/org/bukkit/DyeColorsTest.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/CompositeSerialization.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/FactoryItemMaterialTest.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaImplementationOverrideTest.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/ItemStackBookTest.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLeatherTest.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLoreEnchantmentTest.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/ItemStackPotionsTest.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/ItemStackSkullTest.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/ItemStackTest.java rename src/test/java/org/bukkit/craftbukkit/inventory/{CraftItemStackTest.java => NMSCraftItemStackTest.java} (85%) create mode 100644 src/test/java/org/bukkit/support/DummyEnchantments.java create mode 100644 src/test/java/org/bukkit/support/DummyPotions.java create mode 100644 src/test/java/org/bukkit/support/DummyServer.java create mode 100644 src/test/java/org/bukkit/support/Matchers.java diff --git a/pom.xml b/pom.xml index 74be044951..d74308978f 100644 --- a/pom.xml +++ b/pom.xml @@ -142,7 +142,7 @@ org.hamcrest hamcrest-library - 1.2.1 + 1.3 test @@ -288,6 +288,15 @@ 2.11 ${basedir}/target/test-server + + org/bukkit/craftbukkit/updater/BukkitDLUpdaterServiceTest.java + org/bukkit/craftbukkit/inventory/ItemStackBookTest.java + org/bukkit/craftbukkit/inventory/ItemStackLeatherTest.java + org/bukkit/craftbukkit/inventory/ItemStackLoreEnchantmentTest.java + org/bukkit/craftbukkit/inventory/ItemStackPotionsTest.java + org/bukkit/craftbukkit/inventory/ItemStackSkullTest.java + org/bukkit/craftbukkit/inventory/ItemStackTest.java + diff --git a/src/main/java/net/minecraft/server/ContainerEnchantTable.java b/src/main/java/net/minecraft/server/ContainerEnchantTable.java index bb5f1079f9..9f66060705 100644 --- a/src/main/java/net/minecraft/server/ContainerEnchantTable.java +++ b/src/main/java/net/minecraft/server/ContainerEnchantTable.java @@ -124,7 +124,7 @@ public class ContainerEnchantTable extends Container { } // CraftBukkit start - CraftItemStack item = new CraftItemStack(itemstack); + CraftItemStack item = CraftItemStack.asCraftMirror(itemstack); PrepareItemEnchantEvent event = new PrepareItemEnchantEvent(player, this.getBukkitView(), this.world.getWorld().getBlockAt(this.x, this.y, this.z), item, this.costs, i); this.world.getServer().getPluginManager().callEvent(event); @@ -160,7 +160,7 @@ public class ContainerEnchantTable extends Container { EnchantmentInstance instance = (EnchantmentInstance) obj; enchants.put(org.bukkit.enchantments.Enchantment.getById(instance.enchantment.id), instance.level); } - CraftItemStack item = new CraftItemStack(itemstack); + CraftItemStack item = CraftItemStack.asCraftMirror(itemstack); EnchantItemEvent event = new EnchantItemEvent((Player) entityhuman.getBukkitEntity(), this.getBukkitView(), this.world.getWorld().getBlockAt(this.x, this.y, this.z), item, this.costs[i], enchants, i); this.world.getServer().getPluginManager().callEvent(event); diff --git a/src/main/java/net/minecraft/server/DispenseBehaviorBoat.java b/src/main/java/net/minecraft/server/DispenseBehaviorBoat.java index dfaf09ed4d..2840aa3ed9 100644 --- a/src/main/java/net/minecraft/server/DispenseBehaviorBoat.java +++ b/src/main/java/net/minecraft/server/DispenseBehaviorBoat.java @@ -41,9 +41,9 @@ public class DispenseBehaviorBoat extends DispenseBehaviorItem { // CraftBukkit start ItemStack itemstack1 = itemstack.a(1); org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockX(), isourceblock.getBlockY(), isourceblock.getBlockZ()); - org.bukkit.inventory.ItemStack bukkitItem = new CraftItemStack(itemstack1).clone(); + CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); - BlockDispenseEvent event = new BlockDispenseEvent(block, bukkitItem, new org.bukkit.util.Vector(d0, d1 + d3, d2)); + BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d0, d1 + d3, d2)); if (!BlockDispenser.eventFired) { world.getServer().getPluginManager().callEvent(event); } @@ -53,10 +53,10 @@ public class DispenseBehaviorBoat extends DispenseBehaviorItem { return itemstack; } - if (!event.getItem().equals(bukkitItem)) { + if (!event.getItem().equals(craftItem)) { itemstack.count++; // Chain to handler for new item - ItemStack eventStack = CraftItemStack.createNMSItemStack(event.getItem()); + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.a.a(eventStack.getItem()); if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { idispensebehavior.a(isourceblock, eventStack); diff --git a/src/main/java/net/minecraft/server/DispenseBehaviorEmptyBucket.java b/src/main/java/net/minecraft/server/DispenseBehaviorEmptyBucket.java index 31348bd6fe..b381e2239d 100644 --- a/src/main/java/net/minecraft/server/DispenseBehaviorEmptyBucket.java +++ b/src/main/java/net/minecraft/server/DispenseBehaviorEmptyBucket.java @@ -38,9 +38,9 @@ public class DispenseBehaviorEmptyBucket extends DispenseBehaviorItem { // CraftBukkit start org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); - org.bukkit.inventory.ItemStack bukkitItem = new CraftItemStack(itemstack).clone(); + CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack); - BlockDispenseEvent event = new BlockDispenseEvent(block, bukkitItem, new org.bukkit.util.Vector(0, 0, 0)); + BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); if (!BlockDispenser.eventFired) { world.getServer().getPluginManager().callEvent(event); } @@ -49,9 +49,9 @@ public class DispenseBehaviorEmptyBucket extends DispenseBehaviorItem { return itemstack; } - if (!event.getItem().equals(bukkitItem)) { + if (!event.getItem().equals(craftItem)) { // Chain to handler for new item - ItemStack eventStack = CraftItemStack.createNMSItemStack(event.getItem()); + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.a.a(eventStack.getItem()); if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { idispensebehavior.a(isourceblock, eventStack); diff --git a/src/main/java/net/minecraft/server/DispenseBehaviorFilledBucket.java b/src/main/java/net/minecraft/server/DispenseBehaviorFilledBucket.java index 8f1d9a84f9..309c1e6294 100644 --- a/src/main/java/net/minecraft/server/DispenseBehaviorFilledBucket.java +++ b/src/main/java/net/minecraft/server/DispenseBehaviorFilledBucket.java @@ -29,9 +29,9 @@ public class DispenseBehaviorFilledBucket extends DispenseBehaviorItem { int k2 = k + enumfacing.e(); if (world.isEmpty(i2, j, k2) || world.getMaterial(i2, j, k2).isBuildable()) { org.bukkit.block.Block block = world.getWorld().getBlockAt(i, j, k); - org.bukkit.inventory.ItemStack bukkitItem = new CraftItemStack(itemstack).clone(); + CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack); - BlockDispenseEvent event = new BlockDispenseEvent(block, bukkitItem, new org.bukkit.util.Vector(0, 0, 0)); + BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); if (!BlockDispenser.eventFired) { world.getServer().getPluginManager().callEvent(event); } @@ -40,9 +40,9 @@ public class DispenseBehaviorFilledBucket extends DispenseBehaviorItem { return itemstack; } - if (!event.getItem().equals(bukkitItem)) { + if (!event.getItem().equals(craftItem)) { // Chain to handler for new item - ItemStack eventStack = CraftItemStack.createNMSItemStack(event.getItem()); + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.a.a(eventStack.getItem()); if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { idispensebehavior.a(isourceblock, eventStack); @@ -50,7 +50,7 @@ public class DispenseBehaviorFilledBucket extends DispenseBehaviorItem { } } - itembucket = (ItemBucket) CraftItemStack.createNMSItemStack(event.getItem()).getItem(); + itembucket = (ItemBucket) CraftItemStack.asNMSCopy(event.getItem()).getItem(); } // CraftBukkit end diff --git a/src/main/java/net/minecraft/server/DispenseBehaviorFireball.java b/src/main/java/net/minecraft/server/DispenseBehaviorFireball.java index cc0bf8bb34..9eb4ca2b18 100644 --- a/src/main/java/net/minecraft/server/DispenseBehaviorFireball.java +++ b/src/main/java/net/minecraft/server/DispenseBehaviorFireball.java @@ -30,9 +30,9 @@ public class DispenseBehaviorFireball extends DispenseBehaviorItem { // CraftBukkit start ItemStack itemstack1 = itemstack.a(1); org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockX(), isourceblock.getBlockY(), isourceblock.getBlockZ()); - org.bukkit.inventory.ItemStack bukkitItem = new CraftItemStack(itemstack1).clone(); + CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); - BlockDispenseEvent event = new BlockDispenseEvent(block, bukkitItem, new org.bukkit.util.Vector(d3, d4, d5)); + BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d3, d4, d5)); if (!BlockDispenser.eventFired) { world.getServer().getPluginManager().callEvent(event); } @@ -42,10 +42,10 @@ public class DispenseBehaviorFireball extends DispenseBehaviorItem { return itemstack; } - if (!event.getItem().equals(bukkitItem)) { + if (!event.getItem().equals(craftItem)) { itemstack.count++; // Chain to handler for new item - ItemStack eventStack = CraftItemStack.createNMSItemStack(event.getItem()); + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.a.a(eventStack.getItem()); if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { idispensebehavior.a(isourceblock, eventStack); diff --git a/src/main/java/net/minecraft/server/DispenseBehaviorItem.java b/src/main/java/net/minecraft/server/DispenseBehaviorItem.java index 1337fefe0a..1e7161acf6 100644 --- a/src/main/java/net/minecraft/server/DispenseBehaviorItem.java +++ b/src/main/java/net/minecraft/server/DispenseBehaviorItem.java @@ -50,9 +50,9 @@ public class DispenseBehaviorItem implements IDispenseBehavior { // CraftBukkit start org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockX(), isourceblock.getBlockY(), isourceblock.getBlockZ()); - org.bukkit.inventory.ItemStack bukkitItem = new CraftItemStack(itemstack).clone(); + CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack); - BlockDispenseEvent event = new BlockDispenseEvent(block, bukkitItem, new org.bukkit.util.Vector(entityitem.motX, entityitem.motY, entityitem.motZ)); + BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(entityitem.motX, entityitem.motY, entityitem.motZ)); if (!BlockDispenser.eventFired) { world.getServer().getPluginManager().callEvent(event); } @@ -61,14 +61,14 @@ public class DispenseBehaviorItem implements IDispenseBehavior { return false; } - entityitem.itemStack = CraftItemStack.createNMSItemStack(event.getItem()); + entityitem.itemStack = CraftItemStack.asNMSCopy(event.getItem()); entityitem.motX = event.getVelocity().getX(); entityitem.motY = event.getVelocity().getY(); entityitem.motZ = event.getVelocity().getZ(); - if (!event.getItem().equals(bukkitItem)) { + if (!event.getItem().equals(craftItem)) { // Chain to handler for new item - ItemStack eventStack = CraftItemStack.createNMSItemStack(event.getItem()); + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.a.a(eventStack.getItem()); if (idispensebehavior != IDispenseBehavior.a && idispensebehavior.getClass() != DispenseBehaviorItem.class) { idispensebehavior.a(isourceblock, eventStack); diff --git a/src/main/java/net/minecraft/server/DispenseBehaviorMinecart.java b/src/main/java/net/minecraft/server/DispenseBehaviorMinecart.java index cc92846ea4..1ec5310eff 100644 --- a/src/main/java/net/minecraft/server/DispenseBehaviorMinecart.java +++ b/src/main/java/net/minecraft/server/DispenseBehaviorMinecart.java @@ -41,9 +41,9 @@ public class DispenseBehaviorMinecart extends DispenseBehaviorItem { // CraftBukkit start ItemStack itemstack1 = itemstack.a(1); org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockX(), isourceblock.getBlockY(), isourceblock.getBlockZ()); - org.bukkit.inventory.ItemStack bukkitItem = new CraftItemStack(itemstack1).clone(); + CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); - BlockDispenseEvent event = new BlockDispenseEvent(block, bukkitItem, new org.bukkit.util.Vector(d0, d1 + d3, d2)); + BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d0, d1 + d3, d2)); if (!BlockDispenser.eventFired) { world.getServer().getPluginManager().callEvent(event); } @@ -53,10 +53,10 @@ public class DispenseBehaviorMinecart extends DispenseBehaviorItem { return itemstack; } - if (!event.getItem().equals(bukkitItem)) { + if (!event.getItem().equals(craftItem)) { itemstack.count++; // Chain to handler for new item - ItemStack eventStack = CraftItemStack.createNMSItemStack(event.getItem()); + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.a.a(eventStack.getItem()); if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { idispensebehavior.a(isourceblock, eventStack); @@ -64,7 +64,7 @@ public class DispenseBehaviorMinecart extends DispenseBehaviorItem { } } - itemstack1 = CraftItemStack.createNMSItemStack(event.getItem()); + itemstack1 = CraftItemStack.asNMSCopy(event.getItem()); EntityMinecart entityminecart = new EntityMinecart(world, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), ((ItemMinecart) itemstack1.getItem()).a); // CraftBukkit end diff --git a/src/main/java/net/minecraft/server/DispenseBehaviorMonsterEgg.java b/src/main/java/net/minecraft/server/DispenseBehaviorMonsterEgg.java index 25e21d25bd..66ad86ec23 100644 --- a/src/main/java/net/minecraft/server/DispenseBehaviorMonsterEgg.java +++ b/src/main/java/net/minecraft/server/DispenseBehaviorMonsterEgg.java @@ -23,9 +23,9 @@ public class DispenseBehaviorMonsterEgg extends DispenseBehaviorItem { World world = isourceblock.k(); ItemStack itemstack1 = itemstack.a(1); org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockX(), isourceblock.getBlockY(), isourceblock.getBlockZ()); - org.bukkit.inventory.ItemStack bukkitItem = new CraftItemStack(itemstack1).clone(); + CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); - BlockDispenseEvent event = new BlockDispenseEvent(block, bukkitItem, new org.bukkit.util.Vector(d0, d1, d2)); + BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d0, d1, d2)); if (!BlockDispenser.eventFired) { world.getServer().getPluginManager().callEvent(event); } @@ -35,10 +35,10 @@ public class DispenseBehaviorMonsterEgg extends DispenseBehaviorItem { return itemstack; } - if (!event.getItem().equals(bukkitItem)) { + if (!event.getItem().equals(craftItem)) { itemstack.count++; // Chain to handler for new item - ItemStack eventStack = CraftItemStack.createNMSItemStack(event.getItem()); + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.a.a(eventStack.getItem()); if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { idispensebehavior.a(isourceblock, eventStack); @@ -46,7 +46,7 @@ public class DispenseBehaviorMonsterEgg extends DispenseBehaviorItem { } } - itemstack1 = CraftItemStack.createNMSItemStack(event.getItem()); + itemstack1 = CraftItemStack.asNMSCopy(event.getItem()); ItemMonsterEgg.a(isourceblock.k(), itemstack1.getData(), event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ()); // itemstack.a(1); // Handled during event processing // CraftBukkit end diff --git a/src/main/java/net/minecraft/server/DispenseBehaviorProjectile.java b/src/main/java/net/minecraft/server/DispenseBehaviorProjectile.java index 3968dd0ce7..984b1fc00d 100644 --- a/src/main/java/net/minecraft/server/DispenseBehaviorProjectile.java +++ b/src/main/java/net/minecraft/server/DispenseBehaviorProjectile.java @@ -18,9 +18,9 @@ public abstract class DispenseBehaviorProjectile extends DispenseBehaviorItem { // CraftBukkit start ItemStack itemstack1 = itemstack.a(1); org.bukkit.block.Block block = world.getWorld().getBlockAt(isourceblock.getBlockX(), isourceblock.getBlockY(), isourceblock.getBlockZ()); - org.bukkit.inventory.ItemStack bukkitItem = new CraftItemStack(itemstack1).clone(); + CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); - BlockDispenseEvent event = new BlockDispenseEvent(block, bukkitItem, new org.bukkit.util.Vector((double) enumfacing.c(), 0.10000000149011612D, (double) enumfacing.e())); + BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) enumfacing.c(), 0.10000000149011612D, (double) enumfacing.e())); if (!BlockDispenser.eventFired) { world.getServer().getPluginManager().callEvent(event); } @@ -30,13 +30,13 @@ public abstract class DispenseBehaviorProjectile extends DispenseBehaviorItem { return itemstack; } - if (!event.getItem().equals(bukkitItem)) { + if (!event.getItem().equals(craftItem)) { itemstack.count++; // Chain to handler for new item - ItemStack eventStack = CraftItemStack.createNMSItemStack(event.getItem()); + ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem()); IDispenseBehavior idispensebehavior = (IDispenseBehavior) BlockDispenser.a.a(eventStack.getItem()); if (idispensebehavior != IDispenseBehavior.a && idispensebehavior != this) { - idispensebehavior.a(isourceblock, CraftItemStack.createNMSItemStack(event.getItem())); + idispensebehavior.a(isourceblock, eventStack); return itemstack; } } diff --git a/src/main/java/net/minecraft/server/EntityCow.java b/src/main/java/net/minecraft/server/EntityCow.java index cc512b1b76..3bbdb2fa31 100644 --- a/src/main/java/net/minecraft/server/EntityCow.java +++ b/src/main/java/net/minecraft/server/EntityCow.java @@ -88,9 +88,9 @@ public class EntityCow extends EntityAnimal { } if (--itemstack.count <= 0) { - entityhuman.inventory.setItem(entityhuman.inventory.itemInHandIndex, CraftItemStack.createNMSItemStack(event.getItemStack())); + entityhuman.inventory.setItem(entityhuman.inventory.itemInHandIndex, CraftItemStack.asNMSCopy(event.getItemStack())); } else if (!entityhuman.inventory.pickup(new ItemStack(Item.MILK_BUCKET))) { - entityhuman.drop(CraftItemStack.createNMSItemStack(event.getItemStack())); + entityhuman.drop(CraftItemStack.asNMSCopy(event.getItemStack())); } // CraftBukkit end diff --git a/src/main/java/net/minecraft/server/EntityGhast.java b/src/main/java/net/minecraft/server/EntityGhast.java index 031ebb0efd..3dc67c08c3 100644 --- a/src/main/java/net/minecraft/server/EntityGhast.java +++ b/src/main/java/net/minecraft/server/EntityGhast.java @@ -208,13 +208,13 @@ public class EntityGhast extends EntityFlying implements IMonster { int k; if (j > 0) { - loot.add(new CraftItemStack(Item.GHAST_TEAR.id, j)); + loot.add(CraftItemStack.asNewCraftStack(Item.GHAST_TEAR, j)); } j = this.random.nextInt(3) + this.random.nextInt(1 + i); if (j > 0) { - loot.add(new CraftItemStack(Item.SULPHUR.id, j)); + loot.add(CraftItemStack.asNewCraftStack(Item.SULPHUR, j)); } org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, loot); diff --git a/src/main/java/net/minecraft/server/EntityIronGolem.java b/src/main/java/net/minecraft/server/EntityIronGolem.java index 5b6ab93d3f..e6e260fa83 100644 --- a/src/main/java/net/minecraft/server/EntityIronGolem.java +++ b/src/main/java/net/minecraft/server/EntityIronGolem.java @@ -150,13 +150,13 @@ public class EntityIronGolem extends EntityGolem { int k; if (j > 0) { - loot.add(new CraftItemStack(Block.RED_ROSE.id, j)); + loot.add(CraftItemStack.asNewCraftStack(Item.byId[Block.RED_ROSE.id], j)); } k = 3 + this.random.nextInt(3); if (k > 0) { - loot.add(new CraftItemStack(Item.IRON_INGOT.id, k)); + loot.add(CraftItemStack.asNewCraftStack(Item.IRON_INGOT, k)); } org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, loot); diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java index 5f6a40bb9e..08ffc62c9e 100644 --- a/src/main/java/net/minecraft/server/EntityLiving.java +++ b/src/main/java/net/minecraft/server/EntityLiving.java @@ -894,7 +894,7 @@ public abstract class EntityLiving extends Entity { if (k < 5) { ItemStack itemstack = this.l(k <= 0 ? 1 : 0); if (itemstack != null) { - loot.add(new org.bukkit.craftbukkit.inventory.CraftItemStack(itemstack)); + loot.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); } } } diff --git a/src/main/java/net/minecraft/server/EntityMinecart.java b/src/main/java/net/minecraft/server/EntityMinecart.java index 54c3584a82..29edbc3da5 100644 --- a/src/main/java/net/minecraft/server/EntityMinecart.java +++ b/src/main/java/net/minecraft/server/EntityMinecart.java @@ -188,7 +188,7 @@ public class EntityMinecart extends Entity implements IInventory { itemstack.count -= k; // CraftBukkit - include enchantments in the new itemstack - EntityItem entityitem = new EntityItem(this.world, this.locX + (double) f, this.locY + (double) f1, this.locZ + (double) f2, new ItemStack(itemstack.id, k, itemstack.getData(), itemstack.getEnchantments())); + EntityItem entityitem = new EntityItem(this.world, this.locX + (double) f, this.locY + (double) f1, this.locZ + (double) f2, org.bukkit.craftbukkit.inventory.CraftItemStack.copyNMSStack(itemstack, k)); float f3 = 0.05F; entityitem.motX = (double) ((float) this.random.nextGaussian() * f3); diff --git a/src/main/java/net/minecraft/server/EntityPigZombie.java b/src/main/java/net/minecraft/server/EntityPigZombie.java index 94c7ac00ba..d3bd681e0a 100644 --- a/src/main/java/net/minecraft/server/EntityPigZombie.java +++ b/src/main/java/net/minecraft/server/EntityPigZombie.java @@ -117,13 +117,13 @@ public class EntityPigZombie extends EntityZombie { int j = this.random.nextInt(2 + i); if (j > 0) { - loot.add(new CraftItemStack(Item.ROTTEN_FLESH.id, j)); + loot.add(CraftItemStack.asNewCraftStack(Item.ROTTEN_FLESH, j)); } j = this.random.nextInt(2 + i); if (j > 0) { - loot.add(new CraftItemStack(Item.GOLD_NUGGET.id, j)); + loot.add(CraftItemStack.asNewCraftStack(Item.GOLD_NUGGET, j)); } // Determine rare item drops and add them to the loot @@ -133,7 +133,7 @@ public class EntityPigZombie extends EntityZombie { if (k < 5) { ItemStack itemstack = this.l(k <= 0 ? 1 : 0); if (itemstack != null) { - loot.add(new CraftItemStack(itemstack)); + loot.add(CraftItemStack.asCraftMirror(itemstack)); } } } diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java index 35a679ad03..775e988bf4 100644 --- a/src/main/java/net/minecraft/server/EntityPlayer.java +++ b/src/main/java/net/minecraft/server/EntityPlayer.java @@ -240,13 +240,13 @@ public class EntityPlayer extends EntityHuman implements ICrafting { if (!keepInventory) { for (int i = 0; i < this.inventory.items.length; ++i) { if (this.inventory.items[i] != null) { - loot.add(new CraftItemStack(this.inventory.items[i])); + loot.add(CraftItemStack.asCraftMirror(this.inventory.items[i])); } } for (int i = 0; i < this.inventory.armor.length; ++i) { if (this.inventory.armor[i] != null) { - loot.add(new CraftItemStack(this.inventory.armor[i])); + loot.add(CraftItemStack.asCraftMirror(this.inventory.armor[i])); } } } diff --git a/src/main/java/net/minecraft/server/EntitySkeleton.java b/src/main/java/net/minecraft/server/EntitySkeleton.java index 39296ae3f9..aba1e88cdb 100644 --- a/src/main/java/net/minecraft/server/EntitySkeleton.java +++ b/src/main/java/net/minecraft/server/EntitySkeleton.java @@ -167,7 +167,7 @@ public class EntitySkeleton extends EntityMonster implements IRangedEntity { if (k < 5) { ItemStack itemstack = this.l(k <= 0 ? 1 : 0); if (itemstack != null) { - loot.add(new org.bukkit.craftbukkit.inventory.CraftItemStack(itemstack)); + loot.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); } } } diff --git a/src/main/java/net/minecraft/server/ItemBucket.java b/src/main/java/net/minecraft/server/ItemBucket.java index 5aa39216f9..9a1ee7742a 100644 --- a/src/main/java/net/minecraft/server/ItemBucket.java +++ b/src/main/java/net/minecraft/server/ItemBucket.java @@ -56,13 +56,13 @@ public class ItemBucket extends Item { return itemstack; } - ItemStack result = CraftItemStack.createNMSItemStack(event.getItemStack()); // CraftBukkit - TODO: Check this stuff later... Not sure how this behavior should work + ItemStack result = CraftItemStack.asNMSCopy(event.getItemStack()); // CraftBukkit - TODO: Check this stuff later... Not sure how this behavior should work if (--itemstack.count <= 0) { return result; // CraftBukkit } if (!entityhuman.inventory.pickup(result)) { // CraftBukkit - entityhuman.drop(CraftItemStack.createNMSItemStack(event.getItemStack())); // CraftBukkit + entityhuman.drop(CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit } return itemstack; @@ -81,13 +81,13 @@ public class ItemBucket extends Item { return itemstack; } - ItemStack result = CraftItemStack.createNMSItemStack(event.getItemStack()); // CraftBukkit - TODO: Check this stuff later... Not sure how this behavior should work + ItemStack result = CraftItemStack.asNMSCopy(event.getItemStack()); // CraftBukkit - TODO: Check this stuff later... Not sure how this behavior should work if (--itemstack.count <= 0) { return result; // CraftBukkit } if (!entityhuman.inventory.pickup(result)) { // CraftBukkit - entityhuman.drop(CraftItemStack.createNMSItemStack(event.getItemStack())); // CraftBukkit + entityhuman.drop(CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit } return itemstack; @@ -101,7 +101,7 @@ public class ItemBucket extends Item { return itemstack; } - return CraftItemStack.createNMSItemStack(event.getItemStack()); + return CraftItemStack.asNMSCopy(event.getItemStack()); } int clickedX = i, clickedY = j, clickedZ = k; @@ -144,7 +144,7 @@ public class ItemBucket extends Item { // CraftBukkit end if (this.a(world, d0, d1, d2, i, j, k) && !entityhuman.abilities.canInstantlyBuild) { - return CraftItemStack.createNMSItemStack(event.getItemStack()); // CraftBukkit + return CraftItemStack.asNMSCopy(event.getItemStack()); // CraftBukkit } } } else if (this.a == 0 && movingobjectposition.entity instanceof EntityCow) { @@ -156,7 +156,7 @@ public class ItemBucket extends Item { return itemstack; } - return CraftItemStack.createNMSItemStack(event.getItemStack()); + return CraftItemStack.asNMSCopy(event.getItemStack()); // CraftBukkit end } diff --git a/src/main/java/net/minecraft/server/ItemStack.java b/src/main/java/net/minecraft/server/ItemStack.java index ac6bc3c1b2..d0a60c2dd4 100644 --- a/src/main/java/net/minecraft/server/ItemStack.java +++ b/src/main/java/net/minecraft/server/ItemStack.java @@ -41,21 +41,6 @@ public final class ItemStack { this.setData(k); // CraftBukkit } - // CraftBukkit start - used to create a new ItemStack, specifying the enchantments at time of creation. - public ItemStack(int id, int count, int data, NBTTagList enchantments) { - this(id, count, data); - // taken from .addEnchantment - if (enchantments != null && Item.byId[this.id].getMaxStackSize() == 1) { - if (this.tag == null) { - this.setTag(new NBTTagCompound()); - } - - this.tag.set("ench", enchantments.clone()); // modify this part to use passed in enchantments list - // TODO Books, Skulls, Item Names, Item Lore - } - } - // CraftBukkit end - public static ItemStack a(NBTTagCompound nbttagcompound) { ItemStack itemstack = new ItemStack(); diff --git a/src/main/java/net/minecraft/server/NBTTagCompound.java b/src/main/java/net/minecraft/server/NBTTagCompound.java index 0b9beb7d7f..0e021c6659 100644 --- a/src/main/java/net/minecraft/server/NBTTagCompound.java +++ b/src/main/java/net/minecraft/server/NBTTagCompound.java @@ -35,13 +35,9 @@ public class NBTTagCompound extends NBTBase { } catch (java.io.IOException ex) { ex.printStackTrace(); } + // CraftBukkit end } - public void remove(String name) { - map.remove(name); - } - // CraftBukkit end - void load(DataInput datainput) { this.map.clear(); diff --git a/src/main/java/net/minecraft/server/NetServerHandler.java b/src/main/java/net/minecraft/server/NetServerHandler.java index 084d0aff6a..88afae4359 100644 --- a/src/main/java/net/minecraft/server/NetServerHandler.java +++ b/src/main/java/net/minecraft/server/NetServerHandler.java @@ -1230,11 +1230,11 @@ public class NetServerHandler extends NetHandler { if (cursor == null) { this.player.inventory.setCarried((ItemStack) null); } else { - this.player.inventory.setCarried(CraftItemStack.createNMSItemStack(cursor)); + this.player.inventory.setCarried(CraftItemStack.asNMSCopy(cursor)); } org.bukkit.inventory.ItemStack item = event.getCurrentItem(); if (item != null) { - itemstack = CraftItemStack.createNMSItemStack(item); + itemstack = CraftItemStack.asNMSCopy(item); if (packet102windowclick.slot == -999) { this.player.drop(itemstack); } else { @@ -1307,16 +1307,16 @@ public class NetServerHandler extends NetHandler { if (item == null) { this.player.defaultContainer.setItem(packet107setcreativeslot.slot, (ItemStack) null); } else { - this.player.defaultContainer.setItem(packet107setcreativeslot.slot, CraftItemStack.createNMSItemStack(item)); + this.player.defaultContainer.setItem(packet107setcreativeslot.slot, CraftItemStack.asNMSCopy(item)); } } else if (item != null) { - this.player.drop(CraftItemStack.createNMSItemStack(item)); + this.player.drop(CraftItemStack.asNMSCopy(item)); } return; case DENY: // TODO: Will this actually work? if (packet107setcreativeslot.slot > -1) { - this.player.netServerHandler.sendPacket(new Packet103SetSlot(this.player.defaultContainer.windowId, packet107setcreativeslot.slot, CraftItemStack.createNMSItemStack(item))); + this.player.netServerHandler.sendPacket(new Packet103SetSlot(this.player.defaultContainer.windowId, packet107setcreativeslot.slot, CraftItemStack.asNMSCopy(item))); } return; case DEFAULT: diff --git a/src/main/java/net/minecraft/server/ShapedRecipes.java b/src/main/java/net/minecraft/server/ShapedRecipes.java index 0a48d45ba7..e3126b6bf6 100644 --- a/src/main/java/net/minecraft/server/ShapedRecipes.java +++ b/src/main/java/net/minecraft/server/ShapedRecipes.java @@ -23,7 +23,7 @@ public class ShapedRecipes implements IRecipe { // CraftBukkit start public org.bukkit.inventory.ShapedRecipe toBukkitRecipe() { - CraftItemStack result = new CraftItemStack(this.result); + CraftItemStack result = CraftItemStack.asCraftMirror(this.result); CraftShapedRecipe recipe = new CraftShapedRecipe(result, this); switch (this.height) { case 1: diff --git a/src/main/java/net/minecraft/server/ShapelessRecipes.java b/src/main/java/net/minecraft/server/ShapelessRecipes.java index f14d78bec2..3c08c2a67b 100644 --- a/src/main/java/net/minecraft/server/ShapelessRecipes.java +++ b/src/main/java/net/minecraft/server/ShapelessRecipes.java @@ -22,7 +22,7 @@ public class ShapelessRecipes implements IRecipe { // CraftBukkit start @SuppressWarnings("unchecked") public org.bukkit.inventory.ShapelessRecipe toBukkitRecipe() { - CraftItemStack result = new CraftItemStack(this.result); + CraftItemStack result = CraftItemStack.asCraftMirror(this.result); CraftShapelessRecipe recipe = new CraftShapelessRecipe(result, this); for (ItemStack stack : (List) this.ingredients) { if (stack != null) { diff --git a/src/main/java/net/minecraft/server/TileEntityFurnace.java b/src/main/java/net/minecraft/server/TileEntityFurnace.java index bf4ed58d69..17b9611aa8 100644 --- a/src/main/java/net/minecraft/server/TileEntityFurnace.java +++ b/src/main/java/net/minecraft/server/TileEntityFurnace.java @@ -172,7 +172,7 @@ public class TileEntityFurnace extends TileEntity implements IInventory { if (!this.world.isStatic) { // CraftBukkit start - handle multiple elapsed ticks if (this.burnTime <= 0 && this.canBurn() && this.items[1] != null) { // CraftBukkit - == to <= - CraftItemStack fuel = new CraftItemStack(this.items[1]); + CraftItemStack fuel = CraftItemStack.asCraftMirror(this.items[1]); FurnaceBurnEvent furnaceBurnEvent = new FurnaceBurnEvent(this.world.getWorld().getBlockAt(this.x, this.y, this.z), fuel, fuelTime(this.items[1])); this.world.getServer().getPluginManager().callEvent(furnaceBurnEvent); @@ -237,8 +237,8 @@ public class TileEntityFurnace extends TileEntity implements IInventory { ItemStack itemstack = RecipesFurnace.getInstance().getResult(this.items[0].getItem().id); // CraftBukkit start - CraftItemStack source = new CraftItemStack(this.items[0]); - CraftItemStack result = new CraftItemStack(itemstack.cloneItemStack()); + CraftItemStack source = CraftItemStack.asCraftMirror(this.items[0]); + CraftItemStack result = CraftItemStack.asCraftMirror(itemstack.cloneItemStack()); FurnaceSmeltEvent furnaceSmeltEvent = new FurnaceSmeltEvent(this.world.getWorld().getBlockAt(this.x, this.y, this.z), source, result); this.world.getServer().getPluginManager().callEvent(furnaceSmeltEvent); @@ -247,7 +247,7 @@ public class TileEntityFurnace extends TileEntity implements IInventory { return; } - itemstack = CraftItemStack.createNMSItemStack(furnaceSmeltEvent.getResult()); + itemstack = CraftItemStack.asNMSCopy(furnaceSmeltEvent.getResult()); if (this.items[2] == null) { this.items[2] = itemstack.cloneItemStack(); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index b0a2e697cc..6f957c53ff 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -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(); + } } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 346b1833b7..19d891d7ba 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -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. diff --git a/src/main/java/org/bukkit/craftbukkit/Overridden.java b/src/main/java/org/bukkit/craftbukkit/Overridden.java new file mode 100644 index 0000000000..1c19c69f84 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/Overridden.java @@ -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 { +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java index 7dcdc7d2db..c4bd959a97 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java @@ -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 diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java index 049d52ee85..6bdfe3e72a 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java @@ -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() { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java index 9183e61265..ef95acd676 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItemFrame.java @@ -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() { diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index e225cbf49f..106db16e2d 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -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); } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java index c402cf8c8e..2aca0eae0e 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java @@ -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() { diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftFurnaceRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftFurnaceRecipe.java index 0df3989165..34efe17ecc 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftFurnaceRecipe.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftFurnaceRecipe.java @@ -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); } } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java index d60b1d8282..537a479ad5 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java @@ -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 { diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java index 81bde2c783..7bbf1df5c7 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCrafting.java @@ -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); } } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java index f54df7c4cd..6fb6cb8b89 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java @@ -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; diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java index 9b7172d3bc..85bec9b7c4 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java @@ -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; } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryView.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryView.java index 0e930914b5..6ffc73de6d 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryView.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryView.java @@ -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) { diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java new file mode 100644 index 0000000000..b2bcf344a0 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java @@ -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; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java index 84b28a98e2..7de7c1d00f 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java @@ -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 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 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 getEnchantments() { - return getEnchantments(item); + return getEnchantments(handle); } - public static Map getEnchantments(net.minecraft.server.ItemStack item) { - Map result = new HashMap(); + static Map getEnchantments(net.minecraft.server.ItemStack item) { + ImmutableMap.Builder 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 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 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()); } } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java new file mode 100644 index 0000000000..b49974b5f4 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java @@ -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 pages = new ArrayList(); + + 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 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 getPages() { + return ImmutableList.copyOf(pages); + } + + public void setPages(List 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(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 serialize(Builder 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; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java new file mode 100644 index 0000000000..87709d73db --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java @@ -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: + * + *
  • Constructor(CraftMetaItem meta) + *
  • Constructor(NBTTagCompound tag) + *
  • Constructor(Map map) + *

    + *
  • void applyToItem(NBTTagCompound tag) + *
  • boolean applicableTo(Material type) + *

    + *
  • boolean notUncommon(CraftMetaItem meta) + *
  • boolean equalsCommon(CraftMetaItem meta) + *

    + *
  • boolean isEmpty() + *
  • boolean is{Type}Empty() + *

    + *
  • int applyHash() + *
  • public Class clone() + *

    + *
  • Builder serialize(Builder builder) + *
  • 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 map) { + return new CraftMetaBook(map); + } + }, + SKULL { + @Override + CraftMetaSkull deserialize(Map map) { + return new CraftMetaSkull(map); + } + }, + LEATHER_ARMOR { + @Override + CraftMetaLeatherArmor deserialize(Map map) { + return new CraftMetaLeatherArmor(map); + } + }, + MAP { + @Override + CraftMetaMap deserialize(Map map) { + return new CraftMetaMap(map); + } + }, + POTION { + @Override + CraftMetaPotion deserialize(Map map) { + return new CraftMetaPotion(map); + } + }, + UNSPECIFIC { + @Override + CraftMetaItem deserialize(Map map) { + return new CraftMetaItem(map); + } + }; + + abstract CraftMetaItem deserialize(Map map); + } + + private SerializableMeta() { + } + + public static ItemMeta deserialize(Map 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 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 getObject(Class 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 lore; + private Map enchantments; + private int repairCost; + + CraftMetaItem(CraftMetaItem meta) { + if (meta == null) { + return; + } + + this.displayName = meta.displayName; + + if (meta.hasLore()) { + this.lore = new ArrayList(meta.lore); + } + + if (meta.hasEnchants()) { + this.enchantments = new HashMap(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(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(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 map) { + setDisplayName(SerializableMeta.getString(map, NAME.BUKKIT, true)); + + if (map.containsKey(LORE.BUKKIT)) { + lore = (List) map.get(LORE.BUKKIT); + } + + Map ench = SerializableMeta.getObject(Map.class, map, ENCHANTMENTS.BUKKIT, true); + if (ench != null) { + enchantments = new HashMap(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 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 getEnchants() { + return hasEnchants() ? ImmutableMap.copyOf(enchantments) : ImmutableMap.of(); + } + + public boolean addEnchant(Enchantment ench, int level, boolean ignoreRestrictions) { + if (enchantments == null) { + enchantments = new HashMap(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 getLore() { + return this.lore == null ? null : new ArrayList(this.lore); + } + + public void setLore(List 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(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 serialize() { + ImmutableMap.Builder map = ImmutableMap.builder(); + map.put(SerializableMeta.TYPE_FIELD, deserializer().name()); + serialize(map); + return map.build(); + } + + @Overridden + ImmutableMap.Builder serialize(ImmutableMap.Builder builder) { + if (hasDisplayName()) { + builder.put(NAME.BUKKIT, displayName); + } + + if (hasLore()) { + builder.put(LORE.BUKKIT, ImmutableList.copyOf(lore)); + } + + if (hasEnchants()) { + ImmutableMap.Builder enchantments = ImmutableMap.builder(); + for (Map.Entry 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 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 + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java new file mode 100644 index 0000000000..6cb3bb1fed --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java @@ -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 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 serialize(Builder 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; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java new file mode 100644 index 0000000000..0bd57c035d --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java @@ -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 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 serialize(ImmutableMap.Builder builder) { + super.serialize(builder); + + if (hasScaling()) { + builder.put(MAP_SCALING.BUKKIT, scaling); + } + + return builder; + } + + @Override + SerializableMeta.Deserializers deserializer() { + return SerializableMeta.Deserializers.MAP; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java new file mode 100644 index 0000000000..fa21f40d80 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java @@ -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 customEffects; + + CraftMetaPotion(CraftMetaItem meta) { + super(meta); + if (!(meta instanceof CraftMetaPotion)) { + return; + } + CraftMetaPotion potionMeta = (CraftMetaPotion) meta; + if (potionMeta.hasCustomEffects()) { + this.customEffects = new ArrayList(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(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 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(customEffects); + } + return clone; + } + + public boolean hasCustomEffects() { + return !(customEffects == null || customEffects.isEmpty()); + } + + public List 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(); + } + 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 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 serialize(Builder 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; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java new file mode 100644 index 0000000000..2bef968e7c --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java @@ -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 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 serialize(Builder builder) { + super.serialize(builder); + if (hasOwner()) { + return builder.put(SKULL_OWNER.BUKKIT, this.player); + } + return builder; + } + + @Override + SerializableMeta.Deserializers deserializer() { + return SerializableMeta.Deserializers.SKULL; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapedRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapedRecipe.java index 5d89d79df0..0f416a88fc 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapedRecipe.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapedRecipe.java @@ -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); } } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java index 919df56196..b06aa5484e 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftShapelessRecipe.java @@ -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); } } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java b/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java index c1f219362d..f8e864e46f 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/RecipeIterator.java @@ -34,7 +34,7 @@ public class RecipeIterator implements Iterator { } 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; } diff --git a/src/test/java/org/bukkit/DyeColorsTest.java b/src/test/java/org/bukkit/DyeColorsTest.java new file mode 100644 index 0000000000..296f49a48f --- /dev/null +++ b/src/test/java/org/bukkit/DyeColorsTest.java @@ -0,0 +1,39 @@ +package org.bukkit; + +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.server.EntitySheep; + +import org.bukkit.support.AbstractTestingBase; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class DyeColorsTest extends AbstractTestingBase { + + @Parameters(name= "{index}: {0}") + public static List data() { + List list = new ArrayList(); + for (DyeColor dye : DyeColor.values()) { + list.add(new Object[] {dye}); + } + return list; + } + + @Parameter public DyeColor dye; + + @Test + public void checkColor() { + Color color = dye.getColor(); + float[] nmsColorArray = EntitySheep.d[dye.getData()]; + Color nmsColor = Color.fromRGB((int) (nmsColorArray[0] * 255), (int) (nmsColorArray[1] * 255), (int) (nmsColorArray[2] * 255)); + assertThat(color, is(nmsColor)); + } +} diff --git a/src/test/java/org/bukkit/PerMaterialTest.java b/src/test/java/org/bukkit/PerMaterialTest.java index 766bce26a3..da2b46c14a 100644 --- a/src/test/java/org/bukkit/PerMaterialTest.java +++ b/src/test/java/org/bukkit/PerMaterialTest.java @@ -11,6 +11,8 @@ import net.minecraft.server.Item; import net.minecraft.server.ItemFood; import net.minecraft.server.ItemRecord; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.inventory.ItemStack; import org.bukkit.support.AbstractTestingBase; import org.bukkit.support.Util; import org.junit.BeforeClass; @@ -74,10 +76,17 @@ public class PerMaterialTest extends AbstractTestingBase { @Test public void maxStackSize() { + final ItemStack bukkit = new ItemStack(material); + final CraftItemStack craft = CraftItemStack.asCraftCopy(bukkit); if (material == Material.AIR) { - assertThat(material.getMaxStackSize(), is(64 /* Why can't I hold all of these AIR? */)); + final int MAX_AIR_STACK = 0 /* Why can't I hold all of these AIR? */; + assertThat(material.getMaxStackSize(), is(MAX_AIR_STACK)); + assertThat(bukkit.getMaxStackSize(), is(MAX_AIR_STACK)); + assertThat(craft.getMaxStackSize(), is(MAX_AIR_STACK)); } else { assertThat(material.getMaxStackSize(), is(Item.byId[material.getId()].getMaxStackSize())); + assertThat(bukkit.getMaxStackSize(), is(material.getMaxStackSize())); + assertThat(craft.getMaxStackSize(), is(material.getMaxStackSize())); } } diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/CompositeSerialization.java b/src/test/java/org/bukkit/craftbukkit/inventory/CompositeSerialization.java new file mode 100644 index 0000000000..1349a7f18d --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/CompositeSerialization.java @@ -0,0 +1,61 @@ +package org.bukkit.craftbukkit.inventory; + +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.support.AbstractTestingBase; +import org.junit.Test; + + +public class CompositeSerialization extends AbstractTestingBase { + + public YamlConfiguration getConfig() { + return new YamlConfiguration(); + } + + @Test + public void testSaveRestoreCompositeList() throws InvalidConfigurationException { + YamlConfiguration out = getConfig(); + + List stacks = new ArrayList(); + stacks.add(new ItemStack(1)); + stacks.add(new ItemStack(2)); + stacks.add(new ItemStack(3)); + stacks.add(new ItemStack(4, 17)); + stacks.add(new ItemStack(5, 63)); + stacks.add(new ItemStack(6, 1, (short) 1)); + stacks.add(new ItemStack(18, 32, (short) 2)); + + ItemStack item7 = new ItemStack(256); + item7.addUnsafeEnchantment(Enchantment.getById(1), 1); + stacks.add(item7); + + ItemStack item8 = new ItemStack(257); + item8.addUnsafeEnchantment(Enchantment.getById(2), 2); + item8.addUnsafeEnchantment(Enchantment.getById(3), 1); + item8.addUnsafeEnchantment(Enchantment.getById(4), 5); + item8.addUnsafeEnchantment(Enchantment.getById(5), 4); + stacks.add(item8); + + out.set("composite-list.abc.def", stacks); + String yaml = out.saveToString(); + + YamlConfiguration in = new YamlConfiguration(); + in.loadFromString(yaml); + List raw = in.getList("composite-list.abc.def"); + + assertThat(stacks, hasSize(raw.size())); + + for (int i = 0; i < 9; i++) { + assertThat(String.valueOf(i), (Object) stacks.get(i), is((Object) raw.get(i))); + } + } +} + diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/FactoryItemMaterialTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/FactoryItemMaterialTest.java new file mode 100644 index 0000000000..885964dd6b --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/FactoryItemMaterialTest.java @@ -0,0 +1,142 @@ +package org.bukkit.craftbukkit.inventory; + +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; + +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemFactory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.support.AbstractTestingBase; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class FactoryItemMaterialTest extends AbstractTestingBase { + static final ItemFactory factory = CraftItemFactory.instance(); + static final StringBuilder buffer = new StringBuilder(); + static final Material[] materials = Material.values(); + + static String name(Enum from, Enum to) { + if (from.getClass() == to.getClass()) { + return buffer.delete(0, Integer.MAX_VALUE).append(from.getClass().getName()).append(' ').append(from.name()).append(" to ").append(to.name()).toString(); + } + return buffer.delete(0, Integer.MAX_VALUE).append(from.getClass().getName()).append('(').append(from.name()).append(") to ").append(to.getClass().getName()).append('(').append(to.name()).append(')').toString(); + } + + @Parameters(name="Material[{index}]:{0}") + public static List data() { + List list = new ArrayList(); + for (Material material : materials) { + list.add(new Object[] {material}); + } + return list; + } + + @Parameter(0) public Material material; + + @Test + public void itemStack() { + ItemStack bukkitStack = new ItemStack(material); + CraftItemStack craftStack = CraftItemStack.asCraftCopy(bukkitStack); + ItemMeta meta = factory.getItemMeta(material); + if (meta == null) { + assertThat(material, is(Material.AIR)); + } else { + assertTrue(factory.isApplicable(meta, bukkitStack)); + assertTrue(factory.isApplicable(meta, craftStack)); + } + } + + @Test + public void generalCase() { + CraftMetaItem meta = (CraftMetaItem) factory.getItemMeta(material); + if (meta == null) { + assertThat(material, is(Material.AIR)); + } else { + assertTrue(factory.isApplicable(meta, material)); + assertTrue(meta.applicableTo(material)); + + meta = meta.clone(); + assertTrue(factory.isApplicable(meta, material)); + assertTrue(meta.applicableTo(material)); + } + } + + @Test + public void asMetaFor() { + final CraftMetaItem baseMeta = (CraftMetaItem) factory.getItemMeta(material); + if (baseMeta == null) { + assertThat(material, is(Material.AIR)); + return; + } + + for (Material other : materials) { + final ItemStack bukkitStack = new ItemStack(other); + final CraftItemStack craftStack = CraftItemStack.asCraftCopy(bukkitStack); + final CraftMetaItem otherMeta = (CraftMetaItem) factory.asMetaFor(baseMeta, other); + + final String testName = name(material, other); + + if (otherMeta == null) { + assertThat(testName, other, is(Material.AIR)); + continue; + } + + assertTrue(testName, factory.isApplicable(otherMeta, craftStack)); + assertTrue(testName, factory.isApplicable(otherMeta, bukkitStack)); + assertTrue(testName, factory.isApplicable(otherMeta, other)); + assertTrue(testName, otherMeta.applicableTo(other)); + } + } + + @Test + public void blankEqualities() { + if (material == Material.AIR) { + return; + } + final CraftMetaItem baseMeta = (CraftMetaItem) factory.getItemMeta(material); + final CraftMetaItem baseMetaClone = baseMeta.clone(); + + final ItemStack baseMetaStack = new ItemStack(material); + baseMetaStack.setItemMeta(baseMeta); + + assertThat(baseMeta, is(not(sameInstance(baseMetaStack.getItemMeta())))); + + assertTrue(factory.equals(baseMeta, null)); + assertTrue(factory.equals(null, baseMeta)); + + assertTrue(factory.equals(baseMeta, baseMetaClone)); + assertTrue(factory.equals(baseMetaClone, baseMeta)); + + assertThat(baseMeta, is(not(sameInstance(baseMetaClone)))); + + assertThat(baseMeta, is(baseMetaClone)); + assertThat(baseMetaClone, is(baseMeta)); + + for (Material other : materials) { + final String testName = name(material, other); + + final CraftMetaItem otherMeta = (CraftMetaItem) factory.asMetaFor(baseMetaClone, other); + + if (otherMeta == null) { + assertThat(testName, other, is(Material.AIR)); + continue; + } + + assertTrue(testName, factory.equals(baseMeta, otherMeta)); + assertTrue(testName, factory.equals(otherMeta, baseMeta)); + + assertThat(testName, baseMeta, is(otherMeta)); + assertThat(testName, otherMeta, is(baseMeta)); + + assertThat(testName, baseMeta.hashCode(), is(otherMeta.hashCode())); + } + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaImplementationOverrideTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaImplementationOverrideTest.java new file mode 100644 index 0000000000..ac0702a21d --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaImplementationOverrideTest.java @@ -0,0 +1,67 @@ +package org.bukkit.craftbukkit.inventory; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.craftbukkit.Overridden; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ItemMetaImplementationOverrideTest { + static final Class parent = CraftMetaItem.class; + static final Class annotation = Overridden.class; + + static final List testData = new ArrayList(); + static final Method[] methods; + + static final Class[] subclasses; + + static { + List> classes = new ArrayList>(); + + for (Material material : ItemStackTest.COMPOUND_MATERIALS) { + Class clazz = CraftItemFactory.instance().getItemMeta(material).getClass().asSubclass(parent); + if (clazz != parent) { + classes.add(clazz); + } + } + subclasses = classes.toArray(new Class[0]); + + + List list = new ArrayList(); + + for (Method method: parent.getDeclaredMethods()) { + if (method.isAnnotationPresent(annotation)) { + list.add(method); + } + } + + for (Class clazz : subclasses) { + for (Method method : list) { + testData.add(new Object[]{clazz, method, clazz.getSimpleName() + " contains " + method.getName()}); + } + } + + methods = list.toArray(new Method[list.size()]); + } + + @Parameters(name="[{index}]:{2}") + public static List data() { + return testData; + } + + @Parameter(0) public Class clazz; + @Parameter(1) public Method method; + @Parameter(2) public String name; + + @Test + public void testClass() throws Throwable { + clazz.getDeclaredMethod(method.getName(), method.getParameterTypes()); + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java new file mode 100644 index 0000000000..c95f499f51 --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java @@ -0,0 +1,113 @@ +package org.bukkit.craftbukkit.inventory; + +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; + +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.craftbukkit.inventory.ItemStackTest.StackProvider; +import org.bukkit.craftbukkit.inventory.ItemStackTest.StackWrapper; +import org.bukkit.craftbukkit.inventory.ItemStackTest.BukkitWrapper; +import org.bukkit.craftbukkit.inventory.ItemStackTest.CraftWrapper; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.inventory.meta.MapMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.support.AbstractTestingBase; +import org.junit.Test; + +public class ItemMetaTest extends AbstractTestingBase { + + @Test + public void testCrazyEquality() { + CraftItemStack craft = CraftItemStack.asCraftCopy(new ItemStack(1)); + craft.setItemMeta(craft.getItemMeta()); + ItemStack bukkit = new ItemStack(craft); + assertThat(craft, is(bukkit)); + assertThat(bukkit, is((ItemStack) craft)); + } + + @Test + public void testEachExtraData() { + final List providers = Arrays.asList( + new StackProvider(Material.BOOK_AND_QUILL) { + @Override ItemStack operate(final ItemStack cleanStack) { + final BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.setAuthor("Some author"); + meta.setPages("Page 1", "Page 2"); + meta.setTitle("A title"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new StackProvider(Material.SKULL_ITEM) { + @Override ItemStack operate(final ItemStack cleanStack) { + final SkullMeta meta = (SkullMeta) cleanStack.getItemMeta(); + meta.setOwner("Notch"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new StackProvider(Material.MAP) { + @Override ItemStack operate(final ItemStack cleanStack) { + final MapMeta meta = (MapMeta) cleanStack.getItemMeta(); + meta.setScaling(true); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new StackProvider(Material.LEATHER_BOOTS) { + @Override ItemStack operate(final ItemStack cleanStack) { + final LeatherArmorMeta meta = (LeatherArmorMeta) cleanStack.getItemMeta(); + meta.setColor(Color.FUCHSIA); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new StackProvider(Material.POTION) { + @Override ItemStack operate(final ItemStack cleanStack) { + final PotionMeta meta = (PotionMeta) cleanStack.getItemMeta(); + meta.addCustomEffect(PotionEffectType.CONFUSION.createEffect(1, 1), false); + cleanStack.setItemMeta(meta); + return cleanStack; + } + } + ); + + assertThat("Forgotten test?", providers, hasSize(ItemStackTest.COMPOUND_MATERIALS.length - 1 /* Normal item meta */)); + + for (final StackProvider provider : providers) { + downCastTest(new BukkitWrapper(provider)); + downCastTest(new CraftWrapper(provider)); + } + } + + private void downCastTest(final StackWrapper provider) { + final String name = provider.toString(); + final ItemStack blank = new ItemStack(1); + final ItemStack craftBlank = CraftItemStack.asCraftCopy(blank); + + downCastTest(name, provider.stack(), blank); + blank.setItemMeta(blank.getItemMeta()); + downCastTest(name, provider.stack(), blank); + + downCastTest(name, provider.stack(), craftBlank); + craftBlank.setItemMeta(craftBlank.getItemMeta()); + downCastTest(name, provider.stack(), craftBlank); + } + + private void downCastTest(final String name, final ItemStack stack, final ItemStack blank) { + assertThat(name, stack, is(not(blank))); + assertThat(name, stack.getItemMeta(), is(not(blank.getItemMeta()))); + + stack.setTypeId(1); + + assertThat(name, stack, is(blank)); + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackBookTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackBookTest.java new file mode 100644 index 0000000000..8321eefe72 --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackBookTest.java @@ -0,0 +1,212 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.base.Joiner; + +@RunWith(Parameterized.class) +public class ItemStackBookTest extends ItemStackTest { + + @Parameters(name="[{index}]:{" + NAME_PARAMETER + "}") + public static List data() { + return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, Material.WRITTEN_BOOK, Material.BOOK_AND_QUILL); + } + + static List operators() { + return CompoundOperator.compound( + Joiner.on('+'), + NAME_PARAMETER, + Long.parseLong("1110", 2), + ItemStackLoreEnchantmentTest.operators(), + Arrays.asList( + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.addPage("Page 1", "Page 2"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Pages vs. Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.addPage("Page 1", "Page 2"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + cleanStack.setItemMeta(cleanStack.getItemMeta()); + return cleanStack; + } + }, + "Pages vs. blank" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.addPage("Page 1", "Page 2"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.addPage("Page 2", "Page 1"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Pages switched" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.addPage("Page 1", "Page 2"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.addPage("Page 1"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Pages short" + } + ), + Arrays.asList( + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.setAuthor("AnAuthor"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Author vs. Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.setAuthor("AnAuthor"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + cleanStack.setItemMeta(cleanStack.getItemMeta()); + return cleanStack; + } + }, + "Author vs. blank" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.setAuthor("AnAuthor"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.setAuthor("AnotherAuthor"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Authors" + } + ), + Arrays.asList( + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.setTitle("Some title"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Title vs. Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.setTitle("Some title"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + cleanStack.setItemMeta(cleanStack.getItemMeta()); + return cleanStack; + } + }, + "title vs. blank" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.setTitle("Some title"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + BookMeta meta = (BookMeta) cleanStack.getItemMeta(); + meta.setTitle("Different title"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Titles" + } + ) + ); + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLeatherTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLeatherTest.java new file mode 100644 index 0000000000..a6f958310e --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLeatherTest.java @@ -0,0 +1,88 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.LeatherArmorMeta; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.base.Joiner; + +@RunWith(Parameterized.class) +public class ItemStackLeatherTest extends ItemStackTest { + + @Parameters(name="[{index}]:{" + NAME_PARAMETER + "}") + public static List data() { + return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, Material.LEATHER_BOOTS, Material.LEATHER_CHESTPLATE, Material.LEATHER_HELMET, Material.LEATHER_LEGGINGS); + } + + static List operators() { + return CompoundOperator.compound( + Joiner.on('+'), + NAME_PARAMETER, + Long.parseLong("10", 2), + ItemStackLoreEnchantmentTest.operators(), + Arrays.asList( + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + LeatherArmorMeta meta = (LeatherArmorMeta) cleanStack.getItemMeta(); + meta.setColor(Color.FUCHSIA); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Color vs Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + LeatherArmorMeta meta = (LeatherArmorMeta) cleanStack.getItemMeta(); + meta.setColor(Color.GRAY); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + LeatherArmorMeta meta = (LeatherArmorMeta) cleanStack.getItemMeta(); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Color vs Blank" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + LeatherArmorMeta meta = (LeatherArmorMeta) cleanStack.getItemMeta(); + meta.setColor(Color.MAROON); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + LeatherArmorMeta meta = (LeatherArmorMeta) cleanStack.getItemMeta(); + meta.setColor(Color.ORANGE); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Color vs Other" + } + ) + ); + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLoreEnchantmentTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLoreEnchantmentTest.java new file mode 100644 index 0000000000..d3604fbc5c --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLoreEnchantmentTest.java @@ -0,0 +1,240 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.Arrays; +import java.util.List; + +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.base.Joiner; + +@RunWith(Parameterized.class) +public class ItemStackLoreEnchantmentTest extends ItemStackTest { + + @Parameters(name="[{index}]:{" + NAME_PARAMETER + "}") + public static List data() { + return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, ItemStackTest.COMPOUND_MATERIALS); + } + + static List operators() { + return CompoundOperator.compound( + Joiner.on('+'), + NAME_PARAMETER, + ~0l, + Arrays.asList( + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + meta.setLore(Arrays.asList("First Lore", "Second Lore")); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Lore vs Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + meta.setLore(Arrays.asList("Some lore")); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Lore vs Blank" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + meta.setLore(Arrays.asList("Some more lore", "Another lore")); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + meta.setLore(Arrays.asList("Some more lore")); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Lore vs Other" + } + ), + Arrays.asList( + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + meta.setDisplayName("TestItemName"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Name vs Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + meta.setDisplayName("AnotherItemName"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Name vs Blank" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + meta.setDisplayName("The original ItemName"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + meta.setDisplayName("The other name"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Name vs Other" + } + ), + Arrays.asList( + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + cleanStack.addUnsafeEnchantment(Enchantment.DIG_SPEED, 2); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "EnchantStack vs Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + cleanStack.addUnsafeEnchantment(Enchantment.OXYGEN, 1); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "EnchantStack vs Blank" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + cleanStack.addUnsafeEnchantment(Enchantment.ARROW_DAMAGE, 1); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + cleanStack.addUnsafeEnchantment(Enchantment.ARROW_FIRE, 1); + return cleanStack; + } + }, + "EnchantStack vs OtherEnchantStack" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + meta.addEnchant(Enchantment.DURABILITY, 1, true); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Enchant vs Blank" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + meta.addEnchant(Enchantment.KNOCKBACK, 1, true); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Enchant vs Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + meta.addEnchant(Enchantment.PROTECTION_FIRE, 1, true); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + ItemMeta meta = cleanStack.getItemMeta(); + meta.addEnchant(Enchantment.PROTECTION_FIRE, 2, true); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Enchant vs Other" + } + ) + ); + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackPotionsTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackPotionsTest.java new file mode 100644 index 0000000000..e6aa2c46d7 --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackPotionsTest.java @@ -0,0 +1,145 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffectType; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.base.Joiner; + +@RunWith(Parameterized.class) +public class ItemStackPotionsTest extends ItemStackTest { + + @Parameters(name="[{index}]:{" + NAME_PARAMETER + "}") + public static List data() { + return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, Material.POTION); + } + + static List operators() { + return CompoundOperator.compound( + Joiner.on('+'), + NAME_PARAMETER, + Long.parseLong("10", 2), + ItemStackLoreEnchantmentTest.operators(), + Arrays.asList( + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + final PotionMeta meta = (PotionMeta) cleanStack.getItemMeta(); + meta.addCustomEffect(PotionEffectType.CONFUSION.createEffect(1, 1), false); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Potion vs Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + final PotionMeta meta = (PotionMeta) cleanStack.getItemMeta(); + meta.addCustomEffect(PotionEffectType.HARM.createEffect(2, 1), false); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + final PotionMeta meta = (PotionMeta) cleanStack.getItemMeta(); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Potion vs Blank" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + final PotionMeta meta = (PotionMeta) cleanStack.getItemMeta(); + meta.addCustomEffect(PotionEffectType.SLOW_DIGGING.createEffect(1, 1), false); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + final PotionMeta meta = (PotionMeta) cleanStack.getItemMeta(); + meta.addCustomEffect(PotionEffectType.FAST_DIGGING.createEffect(1, 1), false); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Potion vs Harder" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + final PotionMeta meta = (PotionMeta) cleanStack.getItemMeta(); + meta.addCustomEffect(PotionEffectType.JUMP.createEffect(1, 1), false); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + final PotionMeta meta = (PotionMeta) cleanStack.getItemMeta(); + meta.addCustomEffect(PotionEffectType.JUMP.createEffect(1, 1), false); + meta.addCustomEffect(PotionEffectType.REGENERATION.createEffect(1, 1), false); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Potion vs Better" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + final PotionMeta meta = (PotionMeta) cleanStack.getItemMeta(); + meta.addCustomEffect(PotionEffectType.SPEED.createEffect(10, 1), false); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + final PotionMeta meta = (PotionMeta) cleanStack.getItemMeta(); + meta.addCustomEffect(PotionEffectType.SPEED.createEffect(5, 1), false); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Potion vs Faster" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + final PotionMeta meta = (PotionMeta) cleanStack.getItemMeta(); + meta.addCustomEffect(PotionEffectType.INCREASE_DAMAGE.createEffect(1, 1), false); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + final PotionMeta meta = (PotionMeta) cleanStack.getItemMeta(); + meta.addCustomEffect(PotionEffectType.INCREASE_DAMAGE.createEffect(1, 2), false); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Potion vs Stronger" + } + ) + ); + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackSkullTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackSkullTest.java new file mode 100644 index 0000000000..ea6381fad0 --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackSkullTest.java @@ -0,0 +1,87 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.base.Joiner; + +@RunWith(Parameterized.class) +public class ItemStackSkullTest extends ItemStackTest { + + @Parameters(name="[{index}]:{" + NAME_PARAMETER + "}") + public static List data() { + return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, Material.SKULL_ITEM); + } + + static List operators() { + return CompoundOperator.compound( + Joiner.on('+'), + NAME_PARAMETER, + Long.parseLong("10", 2), + ItemStackLoreEnchantmentTest.operators(), + Arrays.asList( + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + SkullMeta meta = (SkullMeta) cleanStack.getItemMeta(); + meta.setOwner("Notch"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + SkullMeta meta = (SkullMeta) cleanStack.getItemMeta(); + meta.setOwner("Dinnerbone"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Name 1 vs. Name 2" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + SkullMeta meta = (SkullMeta) cleanStack.getItemMeta(); + meta.setOwner("Notch"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + SkullMeta meta = (SkullMeta) cleanStack.getItemMeta(); + meta.setOwner(null); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Name vs. Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + SkullMeta meta = (SkullMeta) cleanStack.getItemMeta(); + meta.setOwner("Notch"); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Name vs. None" + } + ) + ); + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackTest.java new file mode 100644 index 0000000000..4592e1dc19 --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackTest.java @@ -0,0 +1,428 @@ +package org.bukkit.craftbukkit.inventory; + +import static org.bukkit.support.Matchers.sameHash; +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.bukkit.Material; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemFactory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.support.AbstractTestingBase; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; + +@RunWith(Parameterized.class) +public class ItemStackTest extends AbstractTestingBase { + static abstract class StackProvider { + final Material material; + + StackProvider(Material material) { + this.material = material; + } + + ItemStack bukkit() { + return operate(cleanStack(material, false)); + } + + ItemStack craft() { + return operate(cleanStack(material, true)); + } + + abstract ItemStack operate(ItemStack cleanStack); + + static ItemStack cleanStack(Material material, boolean craft) { + final ItemStack stack = new ItemStack(material); + return craft ? CraftItemStack.asCraftCopy(stack) : stack; + } + + @Override + public String toString() { + return material.toString(); + } + + /** + * For each item in parameterList, it will apply nameFormat at nameIndex. + * For each item in parameterList for each item in materials, it will create a stack provider at each array index that contains an Operator. + * + * @param parameterList + * @param nameFormat + * @param nameIndex + * @param materials + * @return + */ + static List compound(final List parameterList, final String nameFormat, final int nameIndex, final Material...materials) { + final List out = new ArrayList(); + for (Object[] params : parameterList) { + final int len = params.length; + for (final Material material : materials) { + final Object[] paramsOut = params.clone(); + for (int i = 0; i < len; i++) { + final Object param = paramsOut[i]; + if (param instanceof Operator) { + final Operator operator = (Operator) param; + paramsOut[i] = new StackProvider(material) { + @Override + ItemStack operate(ItemStack cleanStack) { + return operator.operate(cleanStack); + } + }; + } + } + paramsOut[nameIndex] = String.format(nameFormat, paramsOut[nameIndex], material); + out.add(paramsOut); + } + } + return out; + } + } + + interface Operator { + ItemStack operate(ItemStack cleanStack); + } + + static class CompoundOperator implements Operator { + static class RecursiveContainer { + final Joiner joiner; + final Object[] strings; + final int nameParameter; + final List stack; + final List out; + final List[] lists; + + RecursiveContainer(Joiner joiner, Object[] strings, int nameParameter, List stack, List out, List[] lists) { + this.joiner = joiner; + this.strings = strings; + this.nameParameter = nameParameter; + this.stack = stack; + this.out = out; + this.lists = lists; + } + } + final Operator[] operators; + + CompoundOperator(Operator...operators) { + this.operators = operators; + } + + public ItemStack operate(ItemStack cleanStack) { + for (Operator operator : operators) { + operator.operate(cleanStack); + } + return cleanStack; + } + + @Override + public String toString() { + return Arrays.toString(operators); + } + + + /** + * This combines different tests into one large collection, combining no two tests from the same list. + * @param joiner used to join names + * @param nameParameter index of the name parameter + * @param singletonBitmask a list of bits representing the 'singletons' located in your originalLists. Lowest order bits represent the first items in originalLists. + * Singletons are exponentially linked with each other, such that, + * the output will contain every unique subset of only items from the singletons, + * as well as every unique subset that contains at least one item from each non-singleton. + * @param originalLists + * @return + */ + static List compound(final Joiner joiner, final int nameParameter, final long singletonBitmask, final List...originalLists) { + + final List out = new ArrayList(); + final List> singletons = new ArrayList>(); + final List> notSingletons = new ArrayList>(); + + { // Separate and prime the 'singletons' + int i = 0; + for (List list : originalLists) { + (((singletonBitmask >>> i++) & 0x1) == 0x1 ? singletons : notSingletons).add(list); + } + } + + for (final List primarySingleton : singletons) { + // Iterate over our singletons, to multiply the 'out' each time + for (final Object[] entry : out.toArray(EMPTY_ARRAY)) { + // Iterate over a snapshot of 'out' to prevent CMEs / infinite iteration + final int len = entry.length; + for (final Object[] singleton : primarySingleton) { + // Iterate over each item in our singleton for the current 'out' entry + final Object[] toOut = entry.clone(); + for (int i = 0; i < len; i++) { + // Iterate over each parameter + if (i == nameParameter) { + toOut[i] = joiner.join(toOut[i], singleton[i]); + } else if (toOut[i] instanceof Operator) { + final Operator op1 = (Operator) toOut[i]; + final Operator op2 = (Operator) singleton[i]; + toOut[i] = new Operator() { + public ItemStack operate(final ItemStack cleanStack) { + return op2.operate(op1.operate(cleanStack)); + } + }; + } + } + out.add(toOut); + } + } + out.addAll(primarySingleton); + } + + final List[] lists = new List[notSingletons.size() + 1]; + notSingletons.toArray(lists); + lists[lists.length - 1] = out; + + final RecursiveContainer methodParams = new RecursiveContainer(joiner, new Object[lists.length], nameParameter, new ArrayList(lists.length), new ArrayList(), lists); + + recursivelyCompound(methodParams, 0); + methodParams.out.addAll(out); + + return methodParams.out; + } + + private static void recursivelyCompound(final RecursiveContainer methodParams, final int level) { + final List stack = methodParams.stack; + + if (level == methodParams.lists.length) { + final Object[] firstParams = stack.get(0); + final int len = firstParams.length; + final int stackSize = stack.size(); + final Object[] params = new Object[len]; + + for (int i = 0; i < len; i++) { + final Object firstParam = firstParams[i]; + + if (firstParam instanceof Operator) { + final Operator[] operators = new Operator[stackSize]; + for (int j = 0; j < stackSize; j++) { + operators[j] = (Operator) stack.get(j)[i]; + } + + params[i] = new CompoundOperator(operators); + } else if (i == methodParams.nameParameter) { + final Object[] strings = methodParams.strings; + for (int j = 0; j < stackSize; j++) { + strings[j] = stack.get(j)[i]; + } + + params[i] = methodParams.joiner.join(strings); + } else { + params[i] = firstParam; + } + } + + methodParams.out.add(params); + } else { + final int marker = stack.size(); + + for (final Object[] params : methodParams.lists[level]) { + stack.add(params); + recursivelyCompound(methodParams, level + 1); + stack.remove(marker); + } + } + } + } + + interface StackWrapper { + ItemStack stack(); + } + + static class CraftWrapper implements StackWrapper { + final StackProvider provider; + + CraftWrapper(StackProvider provider) { + this.provider = provider; + } + + public ItemStack stack() { + return provider.craft(); + } + + @Override + public String toString() { + return "Craft " + provider; + } + } + + static class BukkitWrapper implements StackWrapper { + final StackProvider provider; + + BukkitWrapper(StackProvider provider) { + this.provider = provider; + } + + public ItemStack stack() { + return provider.bukkit(); + } + + @Override + public String toString() { + return "Bukkit " + provider; + } + } + + static class NoOpProvider extends StackProvider { + + NoOpProvider(Material material) { + super(material); + } + + @Override + ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + + @Override + public String toString() { + return "NoOp " + super.toString(); + } + } + + @Parameters(name="[{index}]:{" + NAME_PARAMETER + "}") + public static List data() { + return ImmutableList.of(); // TODO, test basic durability issues + } + + static final Object[][] EMPTY_ARRAY = new Object[0][]; + /** + * Materials that generate unique item meta types. + */ + static final Material[] COMPOUND_MATERIALS; + static final int NAME_PARAMETER = 2; + static { + COMPOUND_MATERIALS = new Object() { // Workaround for JDK5 + Material[] value() { + final ItemFactory factory = CraftItemFactory.instance(); + final Map, Material> possibleMaterials = new HashMap, Material>(); + for (final Material material : Material.values()) { + final ItemMeta meta = factory.getItemMeta(material); + if (meta == null || possibleMaterials.containsKey(meta.getClass())) + continue; + possibleMaterials.put(meta.getClass(), material); + + } + return possibleMaterials.values().toArray(new Material[possibleMaterials.size()]); + } + }.value(); + } + + @Parameter(0) public StackProvider provider; + @Parameter(1) public StackProvider unequalProvider; + @Parameter(NAME_PARAMETER) public String name; + + @Test + public void testBukkitInequality() { + final StackWrapper bukkitWrapper = new CraftWrapper(provider); + testInequality(bukkitWrapper, new BukkitWrapper(unequalProvider)); + testInequality(bukkitWrapper, new BukkitWrapper(new NoOpProvider(provider.material))); + } + + @Test + public void testCraftInequality() { + final StackWrapper craftWrapper = new CraftWrapper(provider); + testInequality(craftWrapper, new CraftWrapper(unequalProvider)); + testInequality(craftWrapper, new CraftWrapper(new NoOpProvider(provider.material))); + } + + @Test + public void testMixedInequality() { + final StackWrapper craftWrapper = new CraftWrapper(provider); + testInequality(craftWrapper, new BukkitWrapper(unequalProvider)); + testInequality(craftWrapper, new BukkitWrapper(new NoOpProvider(provider.material))); + + final StackWrapper bukkitWrapper = new CraftWrapper(provider); + testInequality(bukkitWrapper, new CraftWrapper(unequalProvider)); + testInequality(bukkitWrapper, new CraftWrapper(new NoOpProvider(provider.material))); + } + + static void testInequality(StackWrapper provider, StackWrapper unequalProvider) { + final ItemStack stack = provider.stack(); + final ItemStack stack2 = provider.stack(); + assertThat(stack, allOf(equalTo(stack), sameHash(stack))); + assertThat(stack, is(not(sameInstance(stack2)))); + assertThat(stack, allOf(equalTo(stack2), sameHash(stack2))); + + final ItemStack unequalStack = unequalProvider.stack(); + final ItemStack unequalStack2 = unequalProvider.stack(); + assertThat(unequalStack, allOf(equalTo(unequalStack), sameHash(unequalStack))); + assertThat(unequalStack, is(not(sameInstance(unequalStack2)))); + assertThat(unequalStack, allOf(equalTo(unequalStack2), sameHash(unequalStack2))); + + assertThat(stack, is(not(unequalStack))); + assertThat(unequalStack, is(not(stack))); + + final ItemStack newStack = new ItemStack(stack2); + assertThat(newStack, allOf(equalTo(stack), sameHash(stack))); + assertThat(newStack, is(not(unequalStack))); + assertThat(newStack.getItemMeta(), allOf(equalTo(stack.getItemMeta()), sameHash(stack.getItemMeta()))); + assertThat(newStack.getItemMeta(), is(not(unequalStack.getItemMeta()))); + + final ItemStack craftStack = CraftItemStack.asCraftCopy(stack2); + assertThat(craftStack, allOf(equalTo(stack), sameHash(stack))); + assertThat(craftStack, is(not(unequalStack))); + assertThat(craftStack.getItemMeta(), allOf(equalTo(stack.getItemMeta()), sameHash(stack.getItemMeta()))); + assertThat(craftStack.getItemMeta(), is(not(unequalStack.getItemMeta()))); + + final ItemStack newUnequalStack = new ItemStack(unequalStack2); + assertThat(newUnequalStack, allOf(equalTo(unequalStack), sameHash(unequalStack))); + assertThat(newUnequalStack, is(not(stack))); + assertThat(newUnequalStack.getItemMeta(), allOf(equalTo(unequalStack.getItemMeta()), sameHash(unequalStack.getItemMeta()))); + assertThat(newUnequalStack.getItemMeta(), is(not(stack.getItemMeta()))); + + final ItemStack newUnequalCraftStack = CraftItemStack.asCraftCopy(unequalStack2); + assertThat(newUnequalCraftStack, allOf(equalTo(unequalStack), sameHash(unequalStack))); + assertThat(newUnequalCraftStack, is(not(stack))); + assertThat(newUnequalCraftStack.getItemMeta(), allOf(equalTo(unequalStack.getItemMeta()), sameHash(unequalStack.getItemMeta()))); + assertThat(newUnequalCraftStack.getItemMeta(), is(not(stack.getItemMeta()))); + } + + @Test + public void testBukkitDeserialize() { + testDeserialize(new BukkitWrapper(provider), new BukkitWrapper(unequalProvider)); + } + + @Test + public void testCraftDeserialize() { + testDeserialize(new CraftWrapper(provider), new CraftWrapper(unequalProvider)); + } + + static void testDeserialize(StackWrapper provider, StackWrapper unequalProvider) { + final ItemStack stack = provider.stack(); + final ItemStack unequalStack = unequalProvider.stack(); + final YamlConfiguration configOut = new YamlConfiguration(); + + configOut.set("provider", stack); + configOut.set("unequal", unequalStack); + + final String out = '\n' + configOut.saveToString(); + final YamlConfiguration configIn = new YamlConfiguration(); + + try { + configIn.loadFromString(out); + } catch (InvalidConfigurationException ex) { + throw new RuntimeException(out, ex); + } + + assertThat(out, configIn.getItemStack("provider"), allOf(equalTo(stack), sameHash(stack))); + assertThat(out, configIn.getItemStack("unequal"), allOf(equalTo(unequalStack), sameHash(unequalStack))); + assertThat(out, configIn.getItemStack("provider"), is(not(unequalStack))); + assertThat(out, configIn.getItemStack("provider"), is(not(configIn.getItemStack("unequal")))); + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/CraftItemStackTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/NMSCraftItemStackTest.java similarity index 85% rename from src/test/java/org/bukkit/craftbukkit/inventory/CraftItemStackTest.java rename to src/test/java/org/bukkit/craftbukkit/inventory/NMSCraftItemStackTest.java index fe2bc181aa..be1ffcf677 100644 --- a/src/test/java/org/bukkit/craftbukkit/inventory/CraftItemStackTest.java +++ b/src/test/java/org/bukkit/craftbukkit/inventory/NMSCraftItemStackTest.java @@ -9,13 +9,13 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.support.AbstractTestingBase; import org.junit.Test; -public class CraftItemStackTest extends AbstractTestingBase { +public class NMSCraftItemStackTest extends AbstractTestingBase { @Test public void testCloneEnchantedItem() throws Exception { net.minecraft.server.ItemStack nmsItemStack = new net.minecraft.server.ItemStack(net.minecraft.server.Item.POTION); nmsItemStack.addEnchantment(Enchantment.DAMAGE_ALL, 1); - ItemStack itemStack = new CraftItemStack(nmsItemStack); + ItemStack itemStack = CraftItemStack.asCraftMirror(nmsItemStack); ItemStack clone = itemStack.clone(); assertThat(clone.getType(), is(itemStack.getType())); assertThat(clone.getAmount(), is(itemStack.getAmount())); @@ -29,7 +29,7 @@ public class CraftItemStackTest extends AbstractTestingBase { @Test public void testCloneNullItem() throws Exception { net.minecraft.server.ItemStack nmsItemStack = null; - ItemStack itemStack = new CraftItemStack(nmsItemStack); + ItemStack itemStack = CraftItemStack.asCraftMirror(nmsItemStack); ItemStack clone = itemStack.clone(); assertThat(clone, is(itemStack)); } diff --git a/src/test/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterServiceTest.java b/src/test/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterServiceTest.java index 342949b78b..df7437c9b6 100644 --- a/src/test/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterServiceTest.java +++ b/src/test/java/org/bukkit/craftbukkit/updater/BukkitDLUpdaterServiceTest.java @@ -1,14 +1,13 @@ package org.bukkit.craftbukkit.updater; +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; + import java.io.FileNotFoundException; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import static org.junit.Assert.assertNotNull; -import org.junit.Ignore; import org.junit.Test; -@Ignore ("useful tests, but not necessary to run on each compile") public class BukkitDLUpdaterServiceTest { @Test(expected=IOException.class) public void testHostNotFound() throws IOException { @@ -28,6 +27,6 @@ public class BukkitDLUpdaterServiceTest { public void testArtifactExists() throws IOException { BukkitDLUpdaterService service = new BukkitDLUpdaterService("dl.bukkit.org"); - assertNotNull(service.fetchArtifact("latest-dev")); + assertThat(service.fetchArtifact("latest-dev"), is(not(nullValue()))); } } diff --git a/src/test/java/org/bukkit/potion/PotionTest.java b/src/test/java/org/bukkit/potion/PotionTest.java index 1040b6ad6b..a9df7d1996 100644 --- a/src/test/java/org/bukkit/potion/PotionTest.java +++ b/src/test/java/org/bukkit/potion/PotionTest.java @@ -6,21 +6,11 @@ import static org.hamcrest.Matchers.*; import java.util.EnumMap; import java.util.Map; -import org.bukkit.craftbukkit.potion.CraftPotionBrewer; +import org.bukkit.support.AbstractTestingBase; import org.bukkit.support.Util; -import org.junit.BeforeClass; import org.junit.Test; -import net.minecraft.server.MobEffectList; - -public class PotionTest { - - @BeforeClass - public static void setUp() { - Potion.setPotionBrewer(new CraftPotionBrewer()); - MobEffectList.BLINDNESS.getClass(); - PotionEffectType.stopAcceptingRegistrations(); - } +public class PotionTest extends AbstractTestingBase { @Test public void getEffects() { @@ -35,7 +25,7 @@ public class PotionTest { } @Test - public void testEffectCompleteness() throws SecurityException, IllegalAccessException, NoSuchFieldException { + public void testEffectCompleteness() throws Throwable { Map effectDurations = Util.getInternalState(net.minecraft.server.PotionBrewer.class, null, "effectDurations"); Map effects = new EnumMap(PotionType.class); @@ -46,7 +36,7 @@ public class PotionTest { PotionType enumType = PotionType.getByEffect(type); assertNotNull(type.getName(), enumType); - assertThat(enumType.name(), effects.put(enumType, enumType.name()), is((String)null)); + assertThat(enumType.name(), effects.put(enumType, enumType.name()), is(nullValue())); } assertThat(effects.entrySet(), hasSize(effectDurations.size())); diff --git a/src/test/java/org/bukkit/support/AbstractTestingBase.java b/src/test/java/org/bukkit/support/AbstractTestingBase.java index ca14db9bd8..e04158d6aa 100644 --- a/src/test/java/org/bukkit/support/AbstractTestingBase.java +++ b/src/test/java/org/bukkit/support/AbstractTestingBase.java @@ -17,5 +17,8 @@ public abstract class AbstractTestingBase { @BeforeClass public static void setup() { StatisticList.a(); + DummyServer.setup(); + DummyPotions.setup(); + DummyEnchantments.setup(); } } \ No newline at end of file diff --git a/src/test/java/org/bukkit/support/DummyEnchantments.java b/src/test/java/org/bukkit/support/DummyEnchantments.java new file mode 100644 index 0000000000..5ed00a72b0 --- /dev/null +++ b/src/test/java/org/bukkit/support/DummyEnchantments.java @@ -0,0 +1,12 @@ +package org.bukkit.support; + +import net.minecraft.server.Enchantment; + +public class DummyEnchantments { + static { + Enchantment.byId.getClass(); + org.bukkit.enchantments.Enchantment.stopAcceptingRegistrations(); + } + + public static void setup() {} +} diff --git a/src/test/java/org/bukkit/support/DummyPotions.java b/src/test/java/org/bukkit/support/DummyPotions.java new file mode 100644 index 0000000000..30666abde9 --- /dev/null +++ b/src/test/java/org/bukkit/support/DummyPotions.java @@ -0,0 +1,17 @@ +package org.bukkit.support; + +import net.minecraft.server.MobEffectList; + +import org.bukkit.craftbukkit.potion.CraftPotionBrewer; +import org.bukkit.potion.Potion; +import org.bukkit.potion.PotionEffectType; + +public class DummyPotions { + static { + Potion.setPotionBrewer(new CraftPotionBrewer()); + MobEffectList.BLINDNESS.getClass(); + PotionEffectType.stopAcceptingRegistrations(); + } + + public static void setup() {} +} diff --git a/src/test/java/org/bukkit/support/DummyServer.java b/src/test/java/org/bukkit/support/DummyServer.java new file mode 100644 index 0000000000..e5215bb4e5 --- /dev/null +++ b/src/test/java/org/bukkit/support/DummyServer.java @@ -0,0 +1,79 @@ +package org.bukkit.support; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.logging.Logger; + +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.craftbukkit.inventory.CraftItemFactory; +import org.bukkit.craftbukkit.util.Versioning; + +public class DummyServer implements InvocationHandler { + private static interface MethodHandler { + Object handle(DummyServer server, Object[] args); + } + private static final HashMap methods = new HashMap(); + static { + try { + methods.put( + Server.class.getMethod("getItemFactory"), + new MethodHandler() { + public Object handle(DummyServer server, Object[] args) { + return CraftItemFactory.instance(); + } + } + ); + methods.put( + Server.class.getMethod("getName"), + new MethodHandler() { + public Object handle(DummyServer server, Object[] args) { + return DummyServer.class.getName(); + } + } + ); + methods.put( + Server.class.getMethod("getVersion"), + new MethodHandler() { + public Object handle(DummyServer server, Object[] args) { + return DummyServer.class.getPackage().getImplementationVersion(); + } + } + ); + methods.put( + Server.class.getMethod("getBukkitVersion"), + new MethodHandler() { + public Object handle(DummyServer server, Object[] args) { + return Versioning.getBukkitVersion(); + } + } + ); + methods.put( + Server.class.getMethod("getLogger"), + new MethodHandler() { + final Logger logger = Logger.getLogger(DummyServer.class.getCanonicalName()); + public Object handle(DummyServer server, Object[] args) { + return logger; + } + } + ); + Bukkit.setServer(Proxy.getProxyClass(Server.class.getClassLoader(), Server.class).asSubclass(Server.class).getConstructor(InvocationHandler.class).newInstance(new DummyServer())); + } catch (Throwable t) { + throw new Error(t); + } + } + + public static void setup() {} + + private DummyServer() {}; + + public Object invoke(Object proxy, Method method, Object[] args) { + MethodHandler handler = methods.get(method); + if (handler != null) { + return handler.handle(this, args); + } + throw new UnsupportedOperationException(String.valueOf(method)); + } +} diff --git a/src/test/java/org/bukkit/support/Matchers.java b/src/test/java/org/bukkit/support/Matchers.java new file mode 100644 index 0000000000..b190c67369 --- /dev/null +++ b/src/test/java/org/bukkit/support/Matchers.java @@ -0,0 +1,30 @@ +package org.bukkit.support; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; + +public final class Matchers { + + private Matchers() {} + + public static Matcher sameHash(T value) { + return new SameHash(value); + } + + static class SameHash extends BaseMatcher { + private final int expected; + + SameHash(T object) { + expected = object.hashCode(); + } + + public boolean matches(Object item) { + return item.hashCode() == expected; + } + + public void describeTo(Description description) { + description.appendValue(expected); + } + } +}