From aba0bbc70f156dda47a10a0bfcf56346ad682441 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sun, 27 Nov 2011 00:26:31 +0000 Subject: Added Enchantment API --- .../java/org/bukkit/enchantments/Enchantment.java | 229 +++++++++++++++++++++ .../org/bukkit/enchantments/EnchantmentTarget.java | 46 +++++ .../bukkit/enchantments/EnchantmentWrapper.java | 46 +++++ src/main/java/org/bukkit/inventory/ItemStack.java | 125 ++++++++++- 4 files changed, 437 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/bukkit/enchantments/Enchantment.java create mode 100644 src/main/java/org/bukkit/enchantments/EnchantmentTarget.java create mode 100644 src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java (limited to 'src') diff --git a/src/main/java/org/bukkit/enchantments/Enchantment.java b/src/main/java/org/bukkit/enchantments/Enchantment.java new file mode 100644 index 00000000..69615817 --- /dev/null +++ b/src/main/java/org/bukkit/enchantments/Enchantment.java @@ -0,0 +1,229 @@ +package org.bukkit.enchantments; + +import java.util.HashMap; +import java.util.Map; +import org.bukkit.inventory.ItemStack; + +/** + * The various type of enchantments that may be added to armour or weapons + */ +public abstract class Enchantment { + /** + * Provides protection against environmental damage + */ + public static final Enchantment PROTECTION_ENVIRONMENTAL = new EnchantmentWrapper(0); + + /** + * Provides protection against fire damage + */ + public static final Enchantment PROTECTION_FIRE = new EnchantmentWrapper(1); + + /** + * Provides protection against fall damage + */ + public static final Enchantment PROTECTION_FALL = new EnchantmentWrapper(2); + + /** + * Provides protection against explosive damage + */ + public static final Enchantment PROTECTION_EXPLOSIONS = new EnchantmentWrapper(3); + + /** + * Provides protection against projectile damage + */ + public static final Enchantment PROTECTION_PROJECTILE = new EnchantmentWrapper(4); + + /** + * Decreases the rate of air loss whilst underwater + */ + public static final Enchantment OXYGEN = new EnchantmentWrapper(5); + + /** + * Increases the speed at which a player may mine underwater + */ + public static final Enchantment WATER_WORKER = new EnchantmentWrapper(6); + + /** + * Increases damage against all targets + */ + public static final Enchantment DAMAGE_ALL = new EnchantmentWrapper(16); + + /** + * Increases damage against undead targets + */ + public static final Enchantment DAMAGE_UNDEAD = new EnchantmentWrapper(17); + + /** + * Increases damage against arthropod targets + */ + public static final Enchantment DAMAGE_ARTHROPODS = new EnchantmentWrapper(18); + + /** + * All damage to other targets will knock them back when hit + */ + public static final Enchantment KNOCKBACK = new EnchantmentWrapper(19); + + /** + * When attacking a target, has a chance to set them on fire + */ + public static final Enchantment FIRE_ASPECT = new EnchantmentWrapper(20); + + /** + * Provides a chance of gaining extra loot when killing monsters + */ + public static final Enchantment LOOT_BONUS_MOBS = new EnchantmentWrapper(21); + + /** + * Increases the rate at which you mine/dig + */ + public static final Enchantment DIG_SPEED = new EnchantmentWrapper(32); + + /** + * Allows blocks to drop themselves instead of fragments (for example, stone instead of cobblestone) + */ + public static final Enchantment SILK_TOUCH = new EnchantmentWrapper(33); + + /** + * Decreases the rate at which a tool looses durability + */ + public static final Enchantment DURABILITY = new EnchantmentWrapper(34); + + /** + * Provides a chance of gaining extra loot when destroying blocks + */ + public static final Enchantment LOOT_BONUS_BLOCKS = new EnchantmentWrapper(35); + + private static final Map byId = new HashMap(); + private static final Map byName = new HashMap(); + private static boolean acceptingNew = true; + private final int id; + + public Enchantment(int id) { + this.id = id; + } + + /** + * Gets the unique ID of this enchantment + * + * @return Unique ID + */ + public int getId() { + return id; + } + + /** + * Gets the unique name of this enchantment + * + * @return Unique name + */ + public abstract String getName(); + + /** + * Gets the maximum level that this Enchantment may become. + * + * @return Maximum level of the Enchantment + */ + public abstract int getMaxLevel(); + + /** + * Gets the level that this Enchantment should start at + * + * @return Starting level of the Enchantment + */ + public abstract int getStartLevel(); + + /** + * Gets the type of {@link ItemStack} that may fit this Enchantment. + * + * @return Target type of the Enchantment + */ + public abstract EnchantmentTarget getItemTarget(); + + /** + * Checks if this Enchantment may be applied to the given {@link ItemStack} + * + * @param item Item to test + * @return True if the enchantment may be applied, otherwise False + */ + public abstract boolean canEnchantItem(ItemStack item); + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!(obj instanceof Enchantment)) { + return false; + } + final Enchantment other = (Enchantment) obj; + if (this.id != other.id) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return id; + } + + @Override + public String toString() { + return "Enchantment[" + id + ", " + getName() + "]"; + } + + /** + * Registers an enchantment with the given ID and object. + *

+ * Generally not to be used from within a plugin. + * + * @param id ID of the enchantment + * @param enchantment Enchantment to register + */ + public static void registerEnchantment(Enchantment enchantment) { + if (byId.containsKey(enchantment.id) || byName.containsKey(enchantment.getName())) { + throw new IllegalArgumentException("Cannot set already-set enchantment"); + } else if (!isAcceptingRegistrations()) { + throw new IllegalStateException("No longer accepting new enchantments (can only be done by the server implementation)"); + } + + byId.put(enchantment.id, enchantment); + byName.put(enchantment.getName(), enchantment); + } + + /** + * Checks if this is accepting Enchantment registrations. + * + * @return True if the server Implementation may add enchantments + */ + public static boolean isAcceptingRegistrations() { + return acceptingNew; + } + + /** + * Stops accepting any enchantment registrations + */ + public static void stopAcceptingRegistrations() { + acceptingNew = false; + } + + /** + * Gets the Enchantment at the specified ID + * + * @param id ID to fetch + * @return Resulting Enchantment, or null if not found + */ + public static Enchantment getById(int id) { + return byId.get(id); + } + + /** + * Gets the Enchantment at the specified name + * + * @param name Name to fetch + * @return Resulting Enchantment, or null if not found + */ + public static Enchantment getByName(String name) { + return byName.get(name); + } +} diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java new file mode 100644 index 00000000..74d72234 --- /dev/null +++ b/src/main/java/org/bukkit/enchantments/EnchantmentTarget.java @@ -0,0 +1,46 @@ +package org.bukkit.enchantments; + +/** + * Represents the applicable target for a {@link Enchantment} + */ +public enum EnchantmentTarget { + /** + * Allows the Enchantment to be placed on all items + */ + ALL, + + /** + * Allows the Enchantment to be placed on armor + */ + ARMOR, + + /** + * Allows the Enchantment to be placed on feet slot armor + */ + ARMOR_FEET, + + /** + * Allows the Enchantment to be placed on leg slot armor + */ + ARMOR_LEGS, + + /** + * Allows the Enchantment to be placed on torso slot armor + */ + ARMOR_TORSO, + + /** + * Allows the Enchantment to be placed on head slot armor + */ + ARMOR_HEAD, + + /** + * Allows the Enchantment to be placed on weapons (swords) + */ + WEAPON, + + /** + * Allows the Enchantment to be placed on tools (spades, pickaxe, hoes, axes) + */ + TOOL; +} diff --git a/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java new file mode 100644 index 00000000..842d34a0 --- /dev/null +++ b/src/main/java/org/bukkit/enchantments/EnchantmentWrapper.java @@ -0,0 +1,46 @@ +package org.bukkit.enchantments; + +import org.bukkit.inventory.ItemStack; + +/** + * A simple wrapper for ease of selecting {@link Enchantment}s + */ +public class EnchantmentWrapper extends Enchantment { + public EnchantmentWrapper(int id) { + super(id); + } + + /** + * Gets the enchantment bound to this wrapper + * + * @return Enchantment + */ + public Enchantment getEnchantment() { + return Enchantment.getById(getId()); + } + + @Override + public int getMaxLevel() { + return getEnchantment().getMaxLevel(); + } + + @Override + public int getStartLevel() { + return getEnchantment().getStartLevel(); + } + + @Override + public EnchantmentTarget getItemTarget() { + return getEnchantment().getItemTarget(); + } + + @Override + public boolean canEnchantItem(ItemStack item) { + return getEnchantment().canEnchantItem(item); + } + + @Override + public String getName() { + return getEnchantment().getName(); + } +} diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java index b948ccdb..18df0b73 100644 --- a/src/main/java/org/bukkit/inventory/ItemStack.java +++ b/src/main/java/org/bukkit/inventory/ItemStack.java @@ -1,10 +1,13 @@ package org.bukkit.inventory; +import com.google.common.collect.ImmutableMap; import java.io.Serializable; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import org.bukkit.Material; import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.enchantments.Enchantment; import org.bukkit.material.MaterialData; /** @@ -15,6 +18,7 @@ public class ItemStack implements Serializable, ConfigurationSerializable { private int amount = 0; private MaterialData data = null; private short durability = 0; + private Map enchantments = new HashMap(); public ItemStack(final int type) { this(type, 0); @@ -213,35 +217,138 @@ public class ItemStack implements Serializable, ConfigurationSerializable { return hash; } + /** + * Checks if this ItemStack contains the given {@link Enchantment} + * + * @param ench Enchantment to test + * @return True if this has the given enchantment + */ + public boolean containsEnchantment(Enchantment ench) { + return enchantments.containsKey(ench); + } + + /** + * Gets the level of the specified enchantment on this item stack + * + * @param ench Enchantment to check + * @return Level of the enchantment, or 0 + */ + public int getEnchantmentLevel(Enchantment ench) { + return enchantments.get(ench); + } + + /** + * Gets a map containing all enchantments and their levels on this item. + * + * @return Map of enchantments. + */ + public Map getEnchantments() { + return ImmutableMap.copyOf(enchantments); + } + + /** + * Adds the specified {@link Enchantment} to this item stack. + *

+ * If this item stack already contained the given enchantment (at any level), it will be replaced. + * + * @param ench Enchantment to add + * @param level Level of the enchantment + */ + public void addEnchantment(Enchantment ench, int level) { + if ((level < ench.getStartLevel()) || (level > ench.getMaxLevel())) { + throw new IllegalArgumentException("Enchantment level is either too low or too high (given " + level + ", bounds are " + ench.getStartLevel() + " to " + ench.getMaxLevel()); + } else if (!ench.canEnchantItem(this)) { + throw new IllegalArgumentException("Specified enchantment cannot be applied to this itemstack"); + } + + addUnsafeEnchantment(ench, level); + } + + /** + * Adds the specified {@link Enchantment} to this item stack. + *

+ * If this item stack already contained the given enchantment (at any level), it will be replaced. + *

+ * This method is unsafe and will ignore level restrictions or item type. Use at your own + * discretion. + * + * @param ench Enchantment to add + * @param level Level of the enchantment + */ + public void addUnsafeEnchantment(Enchantment ench, int level) { + enchantments.put(ench, level); + } + + /** + * Removes the specified {@link Enchantment} if it exists on this item stack + * + * @param ench Enchantment to remove + * @return Previous level, or 0 + */ + public int removeEnchantment(Enchantment ench) { + Integer previous = enchantments.remove(ench); + return (previous == null) ? 0 : previous; + } + public Map serialize() { Map result = new LinkedHashMap(); - + result.put("type", getType()); - + if (durability != 0) { result.put("damage", durability); } - + if (amount != 1) { result.put("amount", amount); } - + + Map enchants = getEnchantments(); + + if (enchants.size() > 0) { + Map safeEnchants = new HashMap(); + + for (Map.Entry entry : enchants.entrySet()) { + safeEnchants.put(entry.getKey().getName(), entry.getValue()); + } + + result.put("enchantments", safeEnchants); + } + return result; } - + public static ItemStack deserialize(Map args) { Material type = Material.getMaterial((String)args.get("type")); short damage = 0; int amount = 1; - + if (args.containsKey("damage")) { damage = (Short)args.get("damage"); } - + if (args.containsKey("amount")) { amount = (Integer)args.get("amount"); } - - return new ItemStack(type, amount, damage); + + ItemStack result = new ItemStack(type, amount, damage); + + if (args.containsKey("enchantments")) { + Object raw = args.get("enchantments"); + + if (raw instanceof Map) { + Map map = (Map)raw; + + for (Map.Entry entry : map.entrySet()) { + Enchantment enchantment = Enchantment.getByName(entry.getKey().toString()); + + if ((enchantment != null) && (entry.getValue() instanceof Integer)) { + result.addEnchantment(enchantment, (Integer)entry.getValue()); + } + } + } + } + + return result; } } -- cgit v1.2.3