From 708252c020590de1c3a87ae628d56c05465a2167 Mon Sep 17 00:00:00 2001 From: Wesley Wolfe Date: Fri, 21 Dec 2012 07:37:53 -0600 Subject: [PATCH] Implement 1.4.6 ItemMeta. Adds BUKKIT-3236, BUKKIT-3237 Some meta functionality is refactored into common methods. CraftItemStack uses the ItemMetaKey identifiers for enchantments. Refactored unit test to include extra functionality; initially only checking the presence of the DelegateDeserialization annotation. --- pom.xml | 7 +- .../inventory/CraftItemFactory.java | 6 + .../craftbukkit/inventory/CraftItemStack.java | 44 +- .../inventory/CraftMetaCharge.java | 134 ++++++ .../inventory/CraftMetaEnchantedBook.java | 170 ++++++++ .../inventory/CraftMetaFirework.java | 392 ++++++++++++++++++ .../craftbukkit/inventory/CraftMetaItem.java | 156 +++++-- src/test/java/org/bukkit/DyeColorsTest.java | 8 + .../ItemMetaImplementationOverrideTest.java | 57 ++- .../craftbukkit/inventory/ItemMetaTest.java | 30 ++ .../inventory/ItemStackBookTest.java | 1 + .../ItemStackEnchantStorageTest.java | 108 +++++ .../ItemStackFireworkChargeTest.java | 128 ++++++ .../inventory/ItemStackFireworkTest.java | 184 ++++++++ .../inventory/ItemStackLeatherTest.java | 1 + .../ItemStackLoreEnchantmentTest.java | 1 + .../inventory/ItemStackPotionsTest.java | 1 + .../inventory/ItemStackSkullTest.java | 1 + .../craftbukkit/inventory/ItemStackTest.java | 1 + 19 files changed, 1341 insertions(+), 89 deletions(-) create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java create mode 100644 src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/ItemStackEnchantStorageTest.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/ItemStackFireworkChargeTest.java create mode 100644 src/test/java/org/bukkit/craftbukkit/inventory/ItemStackFireworkTest.java diff --git a/pom.xml b/pom.xml index 19a9175f92..82b2c20334 100644 --- a/pom.xml +++ b/pom.xml @@ -290,12 +290,7 @@ ${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 + org/bukkit/craftbukkit/inventory/ItemStack*Test.java diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java index b2bcf344a0..81c6b72d19 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java @@ -62,6 +62,12 @@ public final class CraftItemFactory implements ItemFactory { return meta instanceof CraftMetaPotion ? meta : new CraftMetaPotion(meta); case MAP: return meta instanceof CraftMetaMap ? meta : new CraftMetaMap(meta); + case FIREWORK: + return meta instanceof CraftMetaFirework ? meta : new CraftMetaFirework(meta); + case FIREWORK_CHARGE: + return meta instanceof CraftMetaCharge ? meta : new CraftMetaCharge(meta); + case ENCHANTED_BOOK: + return meta instanceof CraftMetaEnchantedBook ? meta : new CraftMetaEnchantedBook(meta); default: return new CraftMetaItem(meta); } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java index 7de7c1d00f..5f2a6bd15d 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java @@ -1,5 +1,9 @@ package org.bukkit.craftbukkit.inventory; +import static org.bukkit.craftbukkit.inventory.CraftMetaItem.ENCHANTMENTS; +import static org.bukkit.craftbukkit.inventory.CraftMetaItem.ENCHANTMENTS_ID; +import static org.bukkit.craftbukkit.inventory.CraftMetaItem.ENCHANTMENTS_LVL; + import java.util.Map; import net.minecraft.server.EnchantmentManager; @@ -7,10 +11,10 @@ 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.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import com.google.common.collect.ImmutableMap; @@ -162,24 +166,24 @@ public final class CraftItemStack extends ItemStack { if (!makeTag(handle)) { return; } - NBTTagList list = getEnchantmentList(handle), listCopy; + NBTTagList list = getEnchantmentList(handle); if (list == null) { - list = new NBTTagList("ench"); - handle.tag.set("ench", list); + list = new NBTTagList(ENCHANTMENTS.NBT); + handle.tag.set(ENCHANTMENTS.NBT, list); } int size = list.size(); for (int i = 0; i < size; i++) { NBTTagCompound tag = (NBTTagCompound) list.get(i); - short id = tag.getShort("id"); + short id = tag.getShort(ENCHANTMENTS_ID.NBT); if (id == ench.getId()) { - tag.setShort("lvl", (short) level); + tag.setShort(ENCHANTMENTS_LVL.NBT, (short) level); return; } } NBTTagCompound tag = new NBTTagCompound(); - tag.setShort("id", (short) ench.getId()); - tag.setShort("lvl", (short) level); + tag.setShort(ENCHANTMENTS_ID.NBT, (short) ench.getId()); + tag.setShort(ENCHANTMENTS_LVL.NBT, (short) level); list.add(tag); } @@ -219,7 +223,7 @@ public final class CraftItemStack extends ItemStack { int index = Integer.MIN_VALUE, size = list.size(), level; for (int i = 0; i < size; i++) { - short id = ((NBTTagCompound) list.get(i)).getShort("id"); + short id = ((NBTTagCompound) list.get(i)).getShort(ENCHANTMENTS_ID.NBT); if (id == ench.getId()) { index = i; break; @@ -230,22 +234,22 @@ public final class CraftItemStack extends ItemStack { return 0; } if (index == 0 && size == 0) { - handle.tag.o("ench"); + handle.tag.o(ENCHANTMENTS.NBT); if (handle.tag.d()) { handle.tag = null; } } - listCopy = new NBTTagList("ench"); + listCopy = new NBTTagList(ENCHANTMENTS.NBT); level = Integer.MAX_VALUE; for (int i = 0; i < size; i++) { if (i == index) { - level = ((NBTTagCompound) list.get(i)).getShort("id"); + level = ((NBTTagCompound) list.get(i)).getShort(ENCHANTMENTS_ID.NBT); continue; } listCopy.add(list.get(i)); } - handle.tag.set("ench", listCopy); + handle.tag.set(ENCHANTMENTS.NBT, listCopy); return level; } @@ -263,10 +267,10 @@ public final class CraftItemStack extends ItemStack { } for (int i = 0; i < list.size(); i++) { - short id = ((NBTTagCompound) list.get(i)).getShort("id"); - short level = ((NBTTagCompound) list.get(i)).getShort("lvl"); + int id = 0xffff & ((NBTTagCompound) list.get(i)).getShort(ENCHANTMENTS_ID.NBT); + int level = 0xffff & ((NBTTagCompound) list.get(i)).getShort(ENCHANTMENTS_LVL.NBT); - result.put(Enchantment.getById(id), (int) level); + result.put(Enchantment.getById(id), level); } return result.build(); @@ -309,6 +313,12 @@ public final class CraftItemStack extends ItemStack { return new CraftMetaPotion(item.tag); case MAP: return new CraftMetaMap(item.tag); + case FIREWORK: + return new CraftMetaFirework(item.tag); + case FIREWORK_CHARGE: + return new CraftMetaCharge(item.tag); + case ENCHANTED_BOOK: + return new CraftMetaEnchantedBook(item.tag); default: return new CraftMetaItem(item.tag); } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java new file mode 100644 index 0000000000..84ce4bbd41 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java @@ -0,0 +1,134 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.Map; + +import net.minecraft.server.NBTTagCompound; + +import org.bukkit.FireworkEffect; +import org.bukkit.Material; +import org.bukkit.configuration.serialization.DelegateDeserialization; +import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta; +import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta.Deserializers; +import org.bukkit.inventory.meta.FireworkEffectMeta; + +import com.google.common.collect.ImmutableMap.Builder; + +@DelegateDeserialization(SerializableMeta.class) +class CraftMetaCharge extends CraftMetaItem implements FireworkEffectMeta { + static final ItemMetaKey EXPLOSION = new ItemMetaKey("Explosion", "firework-effect"); + + private FireworkEffect effect; + + CraftMetaCharge(CraftMetaItem meta) { + super(meta); + + if (meta instanceof CraftMetaCharge) { + effect = ((CraftMetaCharge) meta).effect; + } + } + + CraftMetaCharge(Map map) { + super(map); + + effect = SerializableMeta.getObject(FireworkEffect.class, map, EXPLOSION.BUKKIT, true); + } + + CraftMetaCharge(NBTTagCompound tag) { + super(tag); + + if (tag.hasKey(EXPLOSION.NBT)) { + effect = CraftMetaFirework.getEffect(tag.getCompound(EXPLOSION.NBT)); + } + } + + public void setEffect(FireworkEffect effect) { + this.effect = effect; + } + + public boolean hasEffect() { + return effect != null; + } + + public FireworkEffect getEffect() { + return effect; + } + + @Override + void applyToItem(NBTTagCompound itemTag) { + super.applyToItem(itemTag); + + if (hasEffect()) { + itemTag.set(EXPLOSION.NBT, CraftMetaFirework.getExplosion(effect)); + } + } + + @Override + boolean applicableTo(Material type) { + switch (type) { + case FIREWORK_CHARGE: + return true; + default: + return false; + } + } + + @Override + boolean isEmpty() { + return super.isEmpty() && !hasChargeMeta(); + } + + boolean hasChargeMeta() { + return hasEffect(); + } + + @Override + boolean equalsCommon(CraftMetaItem meta) { + if (!super.equalsCommon(meta)) { + return false; + } + if (meta instanceof CraftMetaCharge) { + CraftMetaCharge that = (CraftMetaCharge) meta; + + return (hasEffect() ? that.hasEffect() && this.effect.equals(that.effect) : !that.hasEffect()); + } + return true; + } + + @Override + boolean notUncommon(CraftMetaItem meta) { + return super.notUncommon(meta) && (meta instanceof CraftMetaCharge || !hasChargeMeta()); + } + + @Override + int applyHash() { + final int original; + int hash = original = super.applyHash(); + + if (hasEffect()) { + hash = 61 * hash + effect.hashCode(); + } + + return hash != original ? CraftMetaCharge.class.hashCode() ^ hash : hash; + } + + @Override + public CraftMetaCharge clone() { + return (CraftMetaCharge) super.clone(); + } + + @Override + Builder serialize(Builder builder) { + super.serialize(builder); + + if (hasEffect()) { + builder.put(EXPLOSION.BUKKIT, effect); + } + + return builder; + } + + @Override + Deserializers deserializer() { + return Deserializers.FIREWORK_EFFECT; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java new file mode 100644 index 0000000000..4dd394442f --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java @@ -0,0 +1,170 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.HashMap; +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.craftbukkit.inventory.CraftMetaItem.SerializableMeta.Deserializers; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; + +@DelegateDeserialization(SerializableMeta.class) +class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorageMeta { + static final ItemMetaKey STORED_ENCHANTMENTS = new ItemMetaKey("StoredEnchantments", "stored-enchants"); + + private Map enchantments; + + CraftMetaEnchantedBook(CraftMetaItem meta) { + super(meta); + + if (!(meta instanceof CraftMetaEnchantedBook)) { + return; + } + + CraftMetaEnchantedBook that = (CraftMetaEnchantedBook) meta; + + if (that.hasEnchants()) { + this.enchantments = new HashMap(that.enchantments); + } + } + + CraftMetaEnchantedBook(NBTTagCompound tag) { + super(tag); + + if (!tag.hasKey(STORED_ENCHANTMENTS.NBT)) { + return; + } + + enchantments = buildEnchantments(tag, STORED_ENCHANTMENTS); + } + + CraftMetaEnchantedBook(Map map) { + super(map); + + enchantments = buildEnchantments(map, STORED_ENCHANTMENTS); + } + + @Override + void applyToItem(NBTTagCompound itemTag) { + super.applyToItem(itemTag); + + applyEnchantments(enchantments, itemTag, STORED_ENCHANTMENTS); + } + + @Override + boolean applicableTo(Material type) { + switch (type) { + case ENCHANTED_BOOK: + return true; + default: + return false; + } + } + + @Override + boolean isEmpty() { + return super.isEmpty() && isEnchantedEmpty(); + } + + @Override + boolean equalsCommon(CraftMetaItem meta) { + if (!super.equalsCommon(meta)) { + return false; + } + if (meta instanceof CraftMetaEnchantedBook) { + CraftMetaEnchantedBook that = (CraftMetaEnchantedBook) meta; + + return (hasStoredEnchants() ? that.hasStoredEnchants() && this.enchantments.equals(that.enchantments) : !that.hasStoredEnchants()); + } + return true; + } + + @Override + boolean notUncommon(CraftMetaItem meta) { + return super.notUncommon(meta) && (meta instanceof CraftMetaEnchantedBook || isEnchantedEmpty()); + } + + @Override + int applyHash() { + final int original; + int hash = original = super.applyHash(); + + if (hasStoredEnchants()) { + hash = 61 * hash + enchantments.hashCode(); + } + + return original != hash ? CraftMetaEnchantedBook.class.hashCode() ^ hash : hash; + } + + @Override + public CraftMetaEnchantedBook clone() { + CraftMetaEnchantedBook meta = (CraftMetaEnchantedBook) super.clone(); + + if (hasStoredEnchants()) { + meta.enchantments = new HashMap(enchantments); + } + + return meta; + } + + @Override + Builder serialize(Builder builder) { + super.serialize(builder); + + serializeEnchantments(enchantments, builder, STORED_ENCHANTMENTS); + + return builder; + } + + @Override + Deserializers deserializer() { + return Deserializers.ENCHANTED; + } + + boolean isEnchantedEmpty() { + return !hasStoredEnchants(); + } + + public boolean hasStoredEnchant(Enchantment ench) { + return hasStoredEnchants() ? enchantments.containsKey(ench) : false; + } + + public int getStoredEnchantLevel(Enchantment ench) { + Integer level = hasStoredEnchants() ? enchantments.get(ench) : null; + if (level == null) { + return 0; + } + return level; + } + + public Map getStoredEnchants() { + return hasStoredEnchants() ? ImmutableMap.copyOf(enchantments) : ImmutableMap.of(); + } + + public boolean addStoredEnchant(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 removeStoredEnchant(Enchantment ench) { + return hasStoredEnchants() ? enchantments.remove(ench) != null : false; + } + + public boolean hasStoredEnchants() { + return !(enchantments == null || enchantments.isEmpty()); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java new file mode 100644 index 0000000000..67cc8b1cc8 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java @@ -0,0 +1,392 @@ +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 org.apache.commons.lang.Validate; +import org.bukkit.Color; +import org.bukkit.FireworkEffect; +import org.bukkit.FireworkEffect.Type; +import org.bukkit.Material; +import org.bukkit.configuration.serialization.DelegateDeserialization; +import org.bukkit.craftbukkit.inventory.CraftMetaItem.ItemMetaKey.Specific; +import org.bukkit.craftbukkit.inventory.CraftMetaItem.ItemMetaKey.Specific.To; +import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta; +import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta.Deserializers; +import org.bukkit.inventory.meta.FireworkMeta; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap.Builder; + +@DelegateDeserialization(SerializableMeta.class) +class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + /* + "Fireworks", "Explosion", "Explosions", "Flight", "Type", "Trail", "Flicker", "Colors", "FadeColors"; + + Fireworks + - Compound: Fireworks + -- Byte: Flight + -- List: Explosions + --- Compound: Explosion + ---- IntArray: Colors + ---- Byte: Type + ---- Boolean: Trail + ---- Boolean: Flicker + ---- IntArray: FadeColors + */ + + @Specific(To.NBT) + static final ItemMetaKey FIREWORKS = new ItemMetaKey("Fireworks"); + static final ItemMetaKey FLIGHT = new ItemMetaKey("Flight", "power"); + static final ItemMetaKey EXPLOSIONS = new ItemMetaKey("Explosions", "firework-effects"); + @Specific(To.NBT) + static final ItemMetaKey EXPLOSION_COLORS = new ItemMetaKey("Colors"); + @Specific(To.NBT) + static final ItemMetaKey EXPLOSION_TYPE = new ItemMetaKey("Type"); + @Specific(To.NBT) + static final ItemMetaKey EXPLOSION_TRAIL = new ItemMetaKey("Trail"); + @Specific(To.NBT) + static final ItemMetaKey EXPLOSION_FLICKER = new ItemMetaKey("Flicker"); + @Specific(To.NBT) + static final ItemMetaKey EXPLOSION_FADE = new ItemMetaKey("FadeColors"); + + private List effects; + private int power; + + CraftMetaFirework(CraftMetaItem meta) { + super(meta); + + if (!(meta instanceof CraftMetaFirework)) { + return; + } + + CraftMetaFirework that = (CraftMetaFirework) meta; + + this.power = that.power; + + if (that.hasEffects()) { + this.effects = new ArrayList(that.effects); + } + } + + CraftMetaFirework(NBTTagCompound tag) { + super(tag); + + if (!tag.hasKey(FIREWORKS.NBT)) { + return; + } + + NBTTagCompound fireworks = tag.getCompound(FIREWORKS.NBT); + + power = 0xff & fireworks.getByte(FLIGHT.NBT); + + if (!fireworks.hasKey(EXPLOSIONS.NBT)) { + return; + } + + NBTTagList fireworkEffects = fireworks.getList(EXPLOSIONS.NBT); + List effects = this.effects = new ArrayList(fireworkEffects.size()); + + for (int i = 0; i < fireworkEffects.size(); i++) { + effects.add(getEffect((NBTTagCompound) fireworkEffects.get(i))); + } + } + + static FireworkEffect getEffect(NBTTagCompound explosion) { + FireworkEffect.Builder effect = FireworkEffect.builder() + .flicker(explosion.getBoolean(EXPLOSION_FLICKER.NBT)) + .trail(explosion.getBoolean(EXPLOSION_TRAIL.NBT)) + .with(getEffectType(0xff & explosion.getByte(EXPLOSION_TYPE.NBT))); + + for (int color : explosion.getIntArray(EXPLOSION_COLORS.NBT)) { + effect.withColor(Color.fromRGB(color)); + } + + for (int color : explosion.getIntArray(EXPLOSION_FADE.NBT)) { + effect.withFade(Color.fromRGB(color)); + } + + return effect.build(); + } + + static NBTTagCompound getExplosion(FireworkEffect effect) { + NBTTagCompound explosion = new NBTTagCompound(); + + if (effect.hasFlicker()) { + explosion.setBoolean(EXPLOSION_FLICKER.NBT, true); + } + + if (effect.hasTrail()) { + explosion.setBoolean(EXPLOSION_TRAIL.NBT, true); + } + + addColors(explosion, EXPLOSION_COLORS, effect.getColors()); + addColors(explosion, EXPLOSION_FADE, effect.getFadeColors()); + + explosion.setByte(EXPLOSION_TYPE.NBT, (byte) getNBT(effect.getType())); + + return explosion; + } + + static int getNBT(Type type) { + switch (type) { + case BALL: + return 0; + case BALL_LARGE: + return 1; + case STAR: + return 2; + case CREEPER: + return 3; + case BURST: + return 4; + default: + throw new AssertionError(type); + } + } + + static Type getEffectType(int nbt) { + switch (nbt) { + case 0: + return Type.BALL; + case 1: + return Type.BALL_LARGE; + case 2: + return Type.STAR; + case 3: + return Type.CREEPER; + case 4: + return Type.BURST; + default: + throw new AssertionError(nbt); + } + } + + CraftMetaFirework(Map map) { + super(map); + + Integer power = SerializableMeta.getObject(Integer.class, map, FLIGHT.BUKKIT, true); + if (power != null) { + this.power = power; + } + + Iterable effects = SerializableMeta.getObject(Iterable.class, map, EXPLOSIONS.BUKKIT, true); + safelyAddEffects(effects); + } + + public boolean hasEffects() { + return !(effects == null || effects.isEmpty()); + } + + void safelyAddEffects(Iterable collection) { + if (collection == null || (collection instanceof Collection && ((Collection) collection).isEmpty())) { + return; + } + + List effects = this.effects; + if (effects == null) { + effects = this.effects = new ArrayList(); + } + + for (Object obj : collection) { + if (obj instanceof FireworkEffect) { + effects.add((FireworkEffect) obj); + } else { + throw new IllegalArgumentException(obj + " in " + collection + " is not a FireworkEffect"); + } + } + } + + @Override + void applyToItem(NBTTagCompound itemTag) { + super.applyToItem(itemTag); + if (isFireworkEmpty()) { + return; + } + + NBTTagCompound fireworks = itemTag.getCompound(FIREWORKS.NBT); + itemTag.setCompound(FIREWORKS.NBT, fireworks); + + if (hasEffects()) { + NBTTagList effects = new NBTTagList(EXPLOSIONS.NBT); + for (FireworkEffect effect : this.effects) { + effects.add(getExplosion(effect)); + } + + if (effects.size() > 0) { + fireworks.set(EXPLOSIONS.NBT, effects); + } + } + + if (hasPower()) { + fireworks.setByte(FLIGHT.NBT, (byte) power); + } + } + + static void addColors(NBTTagCompound compound, ItemMetaKey key, List colors) { + if (colors.isEmpty()) { + return; + } + + final int[] colorArray = new int[colors.size()]; + int i = 0; + for (Color color : colors) { + colorArray[i++] = color.asRGB(); + } + + compound.setIntArray(key.NBT, colorArray); + } + + @Override + boolean applicableTo(Material type) { + switch(type) { + case FIREWORK: + return true; + default: + return false; + } + } + + @Override + boolean isEmpty() { + return super.isEmpty() && isFireworkEmpty(); + } + + boolean isFireworkEmpty() { + return !(hasEffects() || hasPower()); + } + + boolean hasPower() { + return power != 0; + } + + @Override + boolean equalsCommon(CraftMetaItem meta) { + if (!super.equalsCommon(meta)) { + return false; + } + + if (meta instanceof CraftMetaFirework) { + CraftMetaFirework that = (CraftMetaFirework) meta; + + return (hasPower() ? that.hasPower() && this.power == that.power : !that.hasPower()) + && (hasEffects() ? that.hasEffects() && this.effects.equals(that.effects) : !that.hasEffects()); + } + + return true; + } + + @Override + boolean notUncommon(CraftMetaItem meta) { + return super.notUncommon(meta) && (meta instanceof CraftMetaFirework || isFireworkEmpty()); + } + + @Override + int applyHash() { + final int original; + int hash = original = super.applyHash(); + if (hasPower()) { + hash = 61 * hash + power; + } + if (hasEffects()) { + hash = 61 * hash + 13 * effects.hashCode(); + } + return hash != original ? CraftMetaFirework.class.hashCode() ^ hash : hash; + } + + @Override + Builder serialize(Builder builder) { + super.serialize(builder); + + if (hasEffects()) { + builder.put(EXPLOSIONS.BUKKIT, ImmutableList.copyOf(effects)); + } + + if (hasPower()) { + builder.put(FLIGHT.BUKKIT, power); + } + + return builder; + } + + @Override + Deserializers deserializer() { + return Deserializers.FIREWORK; + } + + @Override + public CraftMetaFirework clone() { + CraftMetaFirework meta = (CraftMetaFirework) super.clone(); + + if (this.effects != null) { + meta.effects = new ArrayList(this.effects); + } + + return meta; + } + + public void addEffect(FireworkEffect effect) { + Validate.notNull(effect, "Effect cannot be null"); + if (this.effects == null) { + this.effects = new ArrayList(); + } + this.effects.add(effect); + } + + public void addEffects(FireworkEffect...effects) { + Validate.notNull(effects, "Effects cannot be null"); + if (effects.length == 0) { + return; + } + + List list = this.effects; + if (list == null) { + list = this.effects = new ArrayList(); + } + + for (FireworkEffect effect : effects) { + Validate.notNull(effect, "Effect cannot be null"); + list.add(effect); + } + } + + public void addEffects(Iterable effects) { + Validate.notNull(effects, "Effects cannot be null"); + safelyAddEffects(effects); + } + + public List getEffects() { + return this.effects == null ? ImmutableList.of() : ImmutableList.copyOf(this.effects); + } + + public int getEffectsSize() { + return this.effects == null ? 0 : this.effects.size(); + } + + public void removeEffect(int index) { + if (this.effects == null) { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: 0"); + } else { + this.effects.remove(index); + } + } + + public void clearEffects() { + this.effects = null; + } + + public int getPower() { + return this.power; + } + + public void setPower(int power) { + Validate.isTrue(power > 0, "Power cannot be less than zero: ", power); + Validate.isTrue(power < 0x80, "Power cannot be more than 127: ", power); + this.power = power; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java index 7c52e85389..f8f9f261fb 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java @@ -1,5 +1,9 @@ package org.bukkit.craftbukkit.inventory; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -18,6 +22,7 @@ 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.craftbukkit.inventory.CraftMetaItem.ItemMetaKey.Specific; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.Repairable; @@ -50,7 +55,20 @@ import com.google.common.collect.ImmutableMap; */ @DelegateDeserialization(CraftMetaItem.SerializableMeta.class) class CraftMetaItem implements ItemMeta, Repairable { + static class ItemMetaKey { + + @Retention(RetentionPolicy.SOURCE) + @Target(ElementType.FIELD) + @interface Specific { + enum To { + BUKKIT, + NBT, + ; + } + To value(); + } + final String BUKKIT; final String NBT; @@ -99,6 +117,24 @@ class CraftMetaItem implements ItemMeta, Repairable { return new CraftMetaPotion(map); } }, + ENCHANTED { + @Override + CraftMetaEnchantedBook deserialize(Map map) { + return new CraftMetaEnchantedBook(map); + } + }, + FIREWORK { + @Override + CraftMetaFirework deserialize(Map map) { + return new CraftMetaFirework(map); + } + }, + FIREWORK_EFFECT { + @Override + CraftMetaCharge deserialize(Map map) { + return new CraftMetaCharge(map); + } + }, UNSPECIFIC { @Override CraftMetaItem deserialize(Map map) { @@ -155,10 +191,13 @@ class CraftMetaItem implements ItemMeta, Repairable { } static final ItemMetaKey NAME = new ItemMetaKey("Name", "display-name"); + @Specific(Specific.To.NBT) static final ItemMetaKey DISPLAY = new ItemMetaKey("display"); static final ItemMetaKey LORE = new ItemMetaKey("Lore", "lore"); static final ItemMetaKey ENCHANTMENTS = new ItemMetaKey("ench", "enchants"); + @Specific(Specific.To.NBT) static final ItemMetaKey ENCHANTMENTS_ID = new ItemMetaKey("id"); + @Specific(Specific.To.NBT) static final ItemMetaKey ENCHANTMENTS_LVL = new ItemMetaKey("lvl"); static final ItemMetaKey REPAIR = new ItemMetaKey("RepairCost", "repair-cost"); @@ -204,23 +243,31 @@ class CraftMetaItem implements ItemMeta, Repairable { } } - 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); - } - } + this.enchantments = buildEnchantments(tag, ENCHANTMENTS); if (tag.hasKey(REPAIR.NBT)) { repairCost = tag.getInt(REPAIR.NBT); } } + static Map buildEnchantments(NBTTagCompound tag, ItemMetaKey key) { + if (!tag.hasKey(key.NBT)) { + return null; + } + + NBTTagList ench = tag.getList(key.NBT); + Map enchantments = new HashMap(ench.size()); + + for (int i = 0; i < ench.size(); i++) { + int id = 0xffff & ((NBTTagCompound) ench.get(i)).getShort(ENCHANTMENTS_ID.NBT); + int level = 0xffff & ((NBTTagCompound) ench.get(i)).getShort(ENCHANTMENTS_LVL.NBT); + + enchantments.put(Enchantment.getById(id), level); + } + + return enchantments; + } + CraftMetaItem(Map map) { setDisplayName(SerializableMeta.getString(map, NAME.BUKKIT, true)); @@ -228,23 +275,31 @@ class CraftMetaItem implements ItemMeta, Repairable { 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); - } - } - } + enchantments = buildEnchantments(map, ENCHANTMENTS); if (map.containsKey(REPAIR.BUKKIT)) { repairCost = (Integer) map.get(REPAIR.BUKKIT); } } + static Map buildEnchantments(Map map, ItemMetaKey key) { + Map ench = SerializableMeta.getObject(Map.class, map, key.BUKKIT, true); + if (ench == null) { + return null; + } + + Map 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)) { + enchantments.put(enchantment, (Integer) entry.getValue()); + } + } + + return enchantments; + } + @Overridden void applyToItem(NBTTagCompound itemTag) { if (hasDisplayName()) { @@ -259,26 +314,32 @@ class CraftMetaItem implements ItemMeta, Repairable { 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); - } + applyEnchantments(enchantments, itemTag, ENCHANTMENTS); if (hasRepairCost()) { itemTag.setInt(REPAIR.NBT, repairCost); } } + static void applyEnchantments(Map enchantments, NBTTagCompound tag, ItemMetaKey key) { + if (enchantments == null || enchantments.size() == 0) { + return; + } + + NBTTagList list = new NBTTagList(key.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, entry.getValue().shortValue()); + + list.add(subtag); + } + + tag.set(key.NBT, list); + } + void setDisplayTag(NBTTagCompound tag, String key, NBTBase value) { final NBTTagCompound display = tag.getCompound(DISPLAY.NBT); @@ -459,13 +520,7 @@ class CraftMetaItem implements ItemMeta, Repairable { 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()); - } + serializeEnchantments(enchantments, builder, ENCHANTMENTS); if (hasRepairCost()) { builder.put(REPAIR.BUKKIT, repairCost); @@ -474,6 +529,19 @@ class CraftMetaItem implements ItemMeta, Repairable { return builder; } + static void serializeEnchantments(Map enchantments, ImmutableMap.Builder builder, ItemMetaKey key) { + if (enchantments == null || enchantments.isEmpty()) { + return; + } + + ImmutableMap.Builder enchants = ImmutableMap.builder(); + for (Map.Entry enchant : enchantments.entrySet()) { + enchants.put(enchant.getKey().getName(), enchant.getValue()); + } + + builder.put(key.BUKKIT, enchants.build()); + } + @Overridden SerializableMeta.Deserializers deserializer() { return SerializableMeta.Deserializers.UNSPECIFIC; @@ -505,6 +573,6 @@ class CraftMetaItem implements ItemMeta, Repairable { @Override public final String toString() { - return serialize().toString(); // TODO: cry + return deserializer().toString() + "_META:" + serialize(); // TODO: cry } } diff --git a/src/test/java/org/bukkit/DyeColorsTest.java b/src/test/java/org/bukkit/DyeColorsTest.java index 296f49a48f..8b2e8a7c0c 100644 --- a/src/test/java/org/bukkit/DyeColorsTest.java +++ b/src/test/java/org/bukkit/DyeColorsTest.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.List; import net.minecraft.server.EntitySheep; +import net.minecraft.server.ItemDye; import org.bukkit.support.AbstractTestingBase; import org.junit.Test; @@ -36,4 +37,11 @@ public class DyeColorsTest extends AbstractTestingBase { Color nmsColor = Color.fromRGB((int) (nmsColorArray[0] * 255), (int) (nmsColorArray[1] * 255), (int) (nmsColorArray[2] * 255)); assertThat(color, is(nmsColor)); } + + @Test + public void checkFireworkColor() { + Color color = dye.getFireworkColor(); + int nmsColor = ItemDye.b[dye.getData()]; + assertThat(color, is(Color.fromRGB(nmsColor))); + } } diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaImplementationOverrideTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaImplementationOverrideTest.java index ac0702a21d..f1b4ec0da8 100644 --- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaImplementationOverrideTest.java +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaImplementationOverrideTest.java @@ -1,10 +1,15 @@ package org.bukkit.craftbukkit.inventory; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Callable; import org.bukkit.Material; +import org.bukkit.configuration.serialization.DelegateDeserialization; import org.bukkit.craftbukkit.Overridden; import org.junit.Test; import org.junit.runner.RunWith; @@ -15,14 +20,10 @@ 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 { + @Parameters(name="[{index}]:{1}") + public static List data() { + final List testData = new ArrayList(); List> classes = new ArrayList>(); for (Material material : ItemStackTest.COMPOUND_MATERIALS) { @@ -31,37 +32,49 @@ public class ItemMetaImplementationOverrideTest { classes.add(clazz); } } - subclasses = classes.toArray(new Class[0]); - List list = new ArrayList(); for (Method method: parent.getDeclaredMethods()) { - if (method.isAnnotationPresent(annotation)) { + if (method.isAnnotationPresent(Overridden.class)) { list.add(method); } } - for (Class clazz : subclasses) { - for (Method method : list) { - testData.add(new Object[]{clazz, method, clazz.getSimpleName() + " contains " + method.getName()}); + for (final Class clazz : classes) { + for (final Method method : list) { + testData.add( + new Object[] { + new Callable() { + public Method call() throws Exception { + return clazz.getDeclaredMethod(method.getName(), method.getParameterTypes()); + } + }, + clazz.getSimpleName() + " contains " + method.getName() + } + ); } + + testData.add( + new Object[] { + new Callable() { + public DelegateDeserialization call() throws Exception { + return clazz.getAnnotation(DelegateDeserialization.class); + } + }, + clazz.getSimpleName() + " contains annotation " + DelegateDeserialization.class + } + ); } - 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; + @Parameter(0) public Callable test; + @Parameter(1) public String name; @Test public void testClass() throws Throwable { - clazz.getDeclaredMethod(method.getName(), method.getParameterTypes()); + assertThat(name, test.call(), is(not(nullValue()))); } } diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java index c95f499f51..876cefc06d 100644 --- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java @@ -7,13 +7,19 @@ import java.util.Arrays; import java.util.List; import org.bukkit.Color; +import org.bukkit.FireworkEffect; import org.bukkit.Material; +import org.bukkit.FireworkEffect.Type; 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.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import org.bukkit.inventory.meta.FireworkEffectMeta; +import org.bukkit.inventory.meta.FireworkMeta; import org.bukkit.inventory.meta.LeatherArmorMeta; import org.bukkit.inventory.meta.MapMeta; import org.bukkit.inventory.meta.PotionMeta; @@ -77,6 +83,30 @@ public class ItemMetaTest extends AbstractTestingBase { cleanStack.setItemMeta(meta); return cleanStack; } + }, + new StackProvider(Material.FIREWORK) { + @Override ItemStack operate(final ItemStack cleanStack) { + final FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.addEffect(FireworkEffect.builder().withColor(Color.GREEN).withFade(Color.OLIVE).with(Type.BALL_LARGE).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new StackProvider(Material.ENCHANTED_BOOK) { + @Override ItemStack operate(final ItemStack cleanStack) { + final EnchantmentStorageMeta meta = (EnchantmentStorageMeta) cleanStack.getItemMeta(); + meta.addStoredEnchant(Enchantment.ARROW_FIRE, 1, true); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new StackProvider(Material.FIREWORK_CHARGE) { + @Override ItemStack operate(final ItemStack cleanStack) { + final FireworkEffectMeta meta = (FireworkEffectMeta) cleanStack.getItemMeta(); + meta.setEffect(FireworkEffect.builder().withColor(Color.MAROON, Color.BLACK).with(Type.CREEPER).withFlicker().build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } } ); diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackBookTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackBookTest.java index 8321eefe72..a7edc048b7 100644 --- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackBookTest.java +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackBookTest.java @@ -20,6 +20,7 @@ public class ItemStackBookTest extends ItemStackTest { return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, Material.WRITTEN_BOOK, Material.BOOK_AND_QUILL); } + @SuppressWarnings("unchecked") static List operators() { return CompoundOperator.compound( Joiner.on('+'), diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackEnchantStorageTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackEnchantStorageTest.java new file mode 100644 index 0000000000..a0499b8ad3 --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackEnchantStorageTest.java @@ -0,0 +1,108 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +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 ItemStackEnchantStorageTest extends ItemStackTest { + + @Parameters(name="[{index}]:{" + NAME_PARAMETER + "}") + public static List data() { + return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, Material.ENCHANTED_BOOK); + } + + @SuppressWarnings("unchecked") + 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) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) cleanStack.getItemMeta(); + meta.addStoredEnchant(Enchantment.DURABILITY, 1, true); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) cleanStack.getItemMeta(); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Enchantable vs Blank" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) cleanStack.getItemMeta(); + meta.addStoredEnchant(Enchantment.KNOCKBACK, 1, true); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Enchantable vs Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) cleanStack.getItemMeta(); + meta.addStoredEnchant(Enchantment.DAMAGE_UNDEAD, 1, true); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) cleanStack.getItemMeta(); + meta.addStoredEnchant(Enchantment.DAMAGE_UNDEAD, 1, true); + meta.addStoredEnchant(Enchantment.FIRE_ASPECT, 1, true); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Enchantable vs More" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) cleanStack.getItemMeta(); + meta.addStoredEnchant(Enchantment.PROTECTION_FIRE, 1, true); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) cleanStack.getItemMeta(); + meta.addEnchant(Enchantment.PROTECTION_FIRE, 2, true); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Enchantable vs Other" + } + ) + ); + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackFireworkChargeTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackFireworkChargeTest.java new file mode 100644 index 0000000000..cb38cd2747 --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackFireworkChargeTest.java @@ -0,0 +1,128 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Color; +import org.bukkit.FireworkEffect; +import org.bukkit.FireworkEffect.Type; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.FireworkEffectMeta; +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 ItemStackFireworkChargeTest extends ItemStackTest { + + @Parameters(name="[{index}]:{" + NAME_PARAMETER + "}") + public static List data() { + return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, Material.FIREWORK_CHARGE); + } + + @SuppressWarnings("unchecked") + 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) { + FireworkEffectMeta meta = (FireworkEffectMeta) cleanStack.getItemMeta(); + meta.setEffect(FireworkEffect.builder().withColor(Color.WHITE).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkEffectMeta meta = (FireworkEffectMeta) cleanStack.getItemMeta(); + meta.setEffect(FireworkEffect.builder().withColor(Color.BLACK).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Effect Color 1 vs. Effect Color 2" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkEffectMeta meta = (FireworkEffectMeta) cleanStack.getItemMeta(); + meta.setEffect(FireworkEffect.builder().withColor(Color.WHITE).with(Type.CREEPER).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkEffectMeta meta = (FireworkEffectMeta) cleanStack.getItemMeta(); + meta.setEffect(FireworkEffect.builder().withColor(Color.WHITE).with(Type.BURST).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Effect type 1 vs. Effect type 2" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkEffectMeta meta = (FireworkEffectMeta) cleanStack.getItemMeta(); + meta.setEffect(FireworkEffect.builder().withColor(Color.WHITE).withFade(Color.BLUE).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkEffectMeta meta = (FireworkEffectMeta) cleanStack.getItemMeta(); + meta.setEffect(FireworkEffect.builder().withColor(Color.WHITE).withFade(Color.RED).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Effect fade 1 vs. Effect fade 2" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkEffectMeta meta = (FireworkEffectMeta) cleanStack.getItemMeta(); + meta.setEffect(FireworkEffect.builder().withColor(Color.WHITE).withFlicker().build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkEffectMeta meta = (FireworkEffectMeta) cleanStack.getItemMeta(); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Effect vs. Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkEffectMeta meta = (FireworkEffectMeta) cleanStack.getItemMeta(); + meta.setEffect(FireworkEffect.builder().withColor(Color.WHITE).withTrail().build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Effect vs. None" + } + ) + ); + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackFireworkTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackFireworkTest.java new file mode 100644 index 0000000000..afacf3b7d4 --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackFireworkTest.java @@ -0,0 +1,184 @@ +package org.bukkit.craftbukkit.inventory; + +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Color; +import org.bukkit.FireworkEffect; +import org.bukkit.Material; +import org.bukkit.FireworkEffect.Type; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.FireworkMeta; +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 ItemStackFireworkTest extends ItemStackTest { + + @Parameters(name="[{index}]:{" + NAME_PARAMETER + "}") + public static List data() { + return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, Material.FIREWORK); + } + + @SuppressWarnings("unchecked") + static List operators() { + return CompoundOperator.compound( + Joiner.on('+'), + NAME_PARAMETER, + Long.parseLong("110", 2), + ItemStackLoreEnchantmentTest.operators(), + Arrays.asList( + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.addEffect(FireworkEffect.builder().withColor(Color.WHITE).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.addEffect(FireworkEffect.builder().withColor(Color.BLACK).build()); + meta.addEffect(FireworkEffect.builder().withColor(Color.GREEN).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Effect Color 1 vs. Effect Color 2" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.addEffect(FireworkEffect.builder().withColor(Color.WHITE).with(Type.CREEPER).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.addEffect(FireworkEffect.builder().withColor(Color.WHITE).with(Type.BURST).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Effect type 1 vs. Effect type 2" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.addEffect(FireworkEffect.builder().withColor(Color.WHITE).withFade(Color.BLUE).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.addEffect(FireworkEffect.builder().withColor(Color.WHITE).withFade(Color.RED).build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Effect fade 1 vs. Effect fade 2" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.addEffect(FireworkEffect.builder().withColor(Color.WHITE).withFlicker().build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Effect vs. Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.addEffect(FireworkEffect.builder().withColor(Color.WHITE).withTrail().build()); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Effect vs. None" + } + ), + Arrays.asList( + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.setPower(150); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.setPower(100); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Height vs. Other" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.setPower(200); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + "Height vs. Null" + }, + new Object[] { + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + FireworkMeta meta = (FireworkMeta) cleanStack.getItemMeta(); + meta.setPower(10); + cleanStack.setItemMeta(meta); + return cleanStack; + } + }, + new Operator() { + public ItemStack operate(ItemStack cleanStack) { + return cleanStack; + } + }, + "Height vs. None" + } + ) + ); + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLeatherTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLeatherTest.java index a6f958310e..6d68e1f468 100644 --- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLeatherTest.java +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLeatherTest.java @@ -22,6 +22,7 @@ public class ItemStackLeatherTest extends ItemStackTest { return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, Material.LEATHER_BOOTS, Material.LEATHER_CHESTPLATE, Material.LEATHER_HELMET, Material.LEATHER_LEGGINGS); } + @SuppressWarnings("unchecked") static List operators() { return CompoundOperator.compound( Joiner.on('+'), diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLoreEnchantmentTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLoreEnchantmentTest.java index d3604fbc5c..7de61aaa7f 100644 --- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLoreEnchantmentTest.java +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackLoreEnchantmentTest.java @@ -20,6 +20,7 @@ public class ItemStackLoreEnchantmentTest extends ItemStackTest { return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, ItemStackTest.COMPOUND_MATERIALS); } + @SuppressWarnings("unchecked") static List operators() { return CompoundOperator.compound( Joiner.on('+'), diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackPotionsTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackPotionsTest.java index e6aa2c46d7..c1f9fb745b 100644 --- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackPotionsTest.java +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackPotionsTest.java @@ -21,6 +21,7 @@ public class ItemStackPotionsTest extends ItemStackTest { return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, Material.POTION); } + @SuppressWarnings("unchecked") static List operators() { return CompoundOperator.compound( Joiner.on('+'), diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackSkullTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackSkullTest.java index ea6381fad0..a79d443e7d 100644 --- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackSkullTest.java +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackSkullTest.java @@ -20,6 +20,7 @@ public class ItemStackSkullTest extends ItemStackTest { return StackProvider.compound(operators(), "%s %s", NAME_PARAMETER, Material.SKULL_ITEM); } + @SuppressWarnings("unchecked") static List operators() { return CompoundOperator.compound( Joiner.on('+'), diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackTest.java index 4592e1dc19..5d174e20f2 100644 --- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackTest.java +++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemStackTest.java @@ -184,6 +184,7 @@ public class ItemStackTest extends AbstractTestingBase { out.addAll(primarySingleton); } + @SuppressWarnings("unchecked") final List[] lists = new List[notSingletons.size() + 1]; notSingletons.toArray(lists); lists[lists.length - 1] = out;