diff --git a/com/Acrobot/ChestShop/ChestShop.java b/com/Acrobot/ChestShop/ChestShop.java index 5a219cc..04edf19 100644 --- a/com/Acrobot/ChestShop/ChestShop.java +++ b/com/Acrobot/ChestShop/ChestShop.java @@ -10,7 +10,6 @@ import com.Acrobot.ChestShop.DB.Queue; import com.Acrobot.ChestShop.DB.Transaction; import com.Acrobot.ChestShop.Listeners.*; import com.Acrobot.ChestShop.Logging.FileWriterQueue; -import com.Acrobot.ChestShop.Protection.MaskChest; import com.avaje.ebean.EbeanServer; import com.lennardf1989.bukkitex.Database; import org.bukkit.Server; @@ -59,7 +58,8 @@ public class ChestShop extends JavaPlugin { if (Config.getBoolean(Property.LOG_TO_DATABASE) || Config.getBoolean(Property.GENERATE_STATISTICS_PAGE)) setupDB(); if (Config.getBoolean(Property.GENERATE_STATISTICS_PAGE)) scheduleTask(new Generator(), 300L, (long) Config.getDouble(Property.STATISTICS_PAGE_GENERATION_INTERVAL) * 20L); if (Config.getBoolean(Property.LOG_TO_FILE)) scheduleTask(new FileWriterQueue(), 201L, 201L); - if (Config.getBoolean(Property.MASK_CHESTS_AS_OTHER_BLOCKS)) scheduleTask(new MaskChest(), 40L, 40L); + //if (Config.getBoolean(Property.MASK_CHESTS_AS_OTHER_BLOCKS)) scheduleTask(new MaskChest(), 40L, 40L); //Disabled due to bug //TODO Fix that + playerInteract.interval = Config.getInteger(Property.SHOP_INTERACTION_INTERVAL); //Register our commands! getCommand("iteminfo").setExecutor(new ItemInfo()); diff --git a/com/Acrobot/ChestShop/Commands/ItemInfo.java b/com/Acrobot/ChestShop/Commands/ItemInfo.java index 6a86e0b..be7b81c 100644 --- a/com/Acrobot/ChestShop/Commands/ItemInfo.java +++ b/com/Acrobot/ChestShop/Commands/ItemInfo.java @@ -3,14 +3,19 @@ package com.Acrobot.ChestShop.Commands; import com.Acrobot.ChestShop.Config.Config; import com.Acrobot.ChestShop.Config.Language; import com.Acrobot.ChestShop.Items.Items; +import com.Acrobot.ChestShop.Utils.uEnchantment; +import com.Acrobot.ChestShop.Utils.uSign; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import java.util.Map; + /** * @author Acrobot */ @@ -21,14 +26,41 @@ public class ItemInfo implements CommandExecutor { if (!(sender instanceof Player)) return false; item = ((Player) sender).getItemInHand(); } else { - item = Items.getItemStack(args[0]); + item = Items.getItemStack(joinArray(args)); } if (item == null || item.getType() == Material.AIR) return false; + + String durability = (item.getDurability() != 0 ? ChatColor.DARK_GREEN + ":" + item.getDurability() : ""); + String ench = uEnchantment.getEnchantment(item); + String enchantment = (ench != null ? ChatColor.DARK_AQUA + "-" + ench : ""); sender.sendMessage(Config.getLocal(Language.iteminfo)); - sender.sendMessage(item.getTypeId() + (item.getDurability() != 0 ? " : " + item.getDurability() : "") + " - " + ChatColor.GRAY + item.getType().name()); + sender.sendMessage(ChatColor.GRAY + uSign.capitalizeFirst(item.getType().name()) + + ChatColor.WHITE + " " + item.getTypeId() + durability + enchantment + ChatColor.WHITE); + + Map map = item.getEnchantments(); + for (Map.Entry e : map.entrySet()) + sender.sendMessage(ChatColor.DARK_GRAY + uSign.capitalizeFirst(e.getKey().getName()) + ' ' + intToRoman(e.getValue())); + return true; } + + private static String intToRoman(int integer){ + if (integer == 1) return "I"; + if (integer == 2) return "II"; + if (integer == 3) return "III"; + if (integer == 4) return "IV"; + if (integer == 5) return "V"; + return null; + } + + + + private static String joinArray(String[] array){ + StringBuilder b = new StringBuilder(array.length); + for (String s : array) b.append(s).append(' '); + return b.toString(); + } } diff --git a/com/Acrobot/ChestShop/Config/Property.java b/com/Acrobot/ChestShop/Config/Property.java index edaf267..8628cd6 100644 --- a/com/Acrobot/ChestShop/Config/Property.java +++ b/com/Acrobot/ChestShop/Config/Property.java @@ -21,7 +21,8 @@ public enum Property { USE_BUILT_IN_PROTECTION(true, "Do you want to use built-in protection against chest destruction?"), PROTECT_CHEST_WITH_LWC(false, "Do you want to protect shop chests with LWC?"), PROTECT_SIGN_WITH_LWC(false, "Do you want to protect shop signs with LWC?"), - MASK_CHESTS_AS_OTHER_BLOCKS(false, "Do you want to mask shop chests as other blocks? HIGHLY EXPERIMENTAL, CAN LAG!"), + //MASK_CHESTS_AS_OTHER_BLOCKS(false, "Do you want to mask shop chests as other blocks? HIGHLY EXPERIMENTAL, CAN LAG!"), + IGNORE_CREATIVE_MODE(true, "Do you want to allow using shops to people in creative mode?"), SHOW_MESSAGE_OUT_OF_STOCK(true, "Do you want to show \"Out of stock\" messages?"), SHOW_TRANSACTION_INFORMATION_CLIENT(true, "Do you want to show \"You bought/sold... \" messages?"), SHOW_TRANSACTION_INFORMATION_OWNER(true, "Do you want to show \"Somebody bought/sold... \" messages?"), @@ -29,7 +30,8 @@ public enum Property { WORLDGUARD_INTEGRATION(false, "Do you want to only let people build inside plots?"), TAX_AMOUNT(0, "Percent of the price that should go to the server's account. (100 = 100 percent)"), SHOP_REFUND_PRICE(0, "How much money do you get back when destroying a sign?"), - ALLOW_MULTIPLE_SHOPS_AT_ONE_BLOCK(false, "Do you want to allow other players to build a shop on a block where there's one already?"); + ALLOW_MULTIPLE_SHOPS_AT_ONE_BLOCK(false, "Do you want to allow other players to build a shop on a block where there's one already?"), + SHOP_INTERACTION_INTERVAL(100, "(In 1/1000th of a second) How often can a player use a shop sign?"); private final Object value; diff --git a/com/Acrobot/ChestShop/Items/Items.java b/com/Acrobot/ChestShop/Items/Items.java index e5676ca..ff767b4 100644 --- a/com/Acrobot/ChestShop/Items/Items.java +++ b/com/Acrobot/ChestShop/Items/Items.java @@ -1,9 +1,13 @@ package com.Acrobot.ChestShop.Items; +import com.Acrobot.ChestShop.Utils.uEnchantment; import com.Acrobot.ChestShop.Utils.uNumber; import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; +import java.util.Map; + /** * @author Acrobot * Manages ItemStack names and ID's @@ -31,33 +35,42 @@ public class Items { public static ItemStack getItemStack(String itemName) { ItemStack toReturn = getFromOddItem(itemName); if (toReturn != null) return toReturn; + + String[] split = itemName.split(":|-"); - Material material = getMaterial(itemName); - if (material != null) return new ItemStack(material, 1); + String[] space = split[0].split(" "); + Material material = getMaterial(split[0]); - return getItemStackWithDataValue(itemName); + for (int i = (space.length > 1 ? 1 : 0); i >= 0 && material == null; i--) material = getMaterial(space[i]); + + if (material == null) return null; + + toReturn = new ItemStack(material, 1); + + for (int i = 1; i < split.length; i++){ + split[i] = split[i].trim(); + if (uNumber.isInteger(split[i])) toReturn.setDurability((short) Integer.parseInt(split[i])); + else { + try{ toReturn.addEnchantments(getEnchantment(split[i])); + } catch (Exception ignored){} + } + } + short data = getDataFromWord(space[0], material); + if (data != 0) toReturn.setDurability(data); + + return toReturn; + } + + private static Map getEnchantment(String itemName){ + return uEnchantment.decodeEnchantment(itemName); } private static ItemStack getFromOddItem(String itemName) { return !Odd.isInitialized() ? null : Odd.returnItemStack(itemName.replace(":", ";")); } - private static ItemStack getItemStackWithDataValue(String itemName) { - if (!itemName.contains(":")) return getItemStackWithDataValueFromWord(itemName); - - String[] word = itemName.split(":"); - if (word.length < 2 || !uNumber.isInteger(word[1])) return null; - - Material item = getMaterial(word[0]); - return item == null ? null : new ItemStack(item, 1, Short.parseShort(word[1])); - } - - private static ItemStack getItemStackWithDataValueFromWord(String itemName) { - int indexOfChar = itemName.indexOf(' '); - - if (indexOfChar == -1) return null; - Material item = getMaterial(itemName.substring(indexOfChar)); - return item == null ? null : new ItemStack(item, 1, DataValue.get(itemName.substring(0, indexOfChar), item)); + private static short getDataFromWord(String name, Material material) { + return DataValue.get(name, material); } } diff --git a/com/Acrobot/ChestShop/Listeners/playerInteract.java b/com/Acrobot/ChestShop/Listeners/playerInteract.java index c439251..910f651 100644 --- a/com/Acrobot/ChestShop/Listeners/playerInteract.java +++ b/com/Acrobot/ChestShop/Listeners/playerInteract.java @@ -12,6 +12,7 @@ import com.Acrobot.ChestShop.Utils.uLongName; import com.Acrobot.ChestShop.Utils.uSign; import net.minecraft.server.IInventory; import net.minecraft.server.InventoryLargeChest; +import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Chest; @@ -31,7 +32,7 @@ import java.util.HashMap; public class playerInteract extends PlayerListener { private static final HashMap lastTransactionTime = new HashMap(); //Last player's transaction - private static final int interval = 100;//Minimal interval between transactions + public static int interval = 100;//Minimal interval between transactions public void onPlayerInteract(PlayerInteractEvent event) { Action action = event.getAction(); @@ -54,6 +55,11 @@ public class playerInteract extends PlayerListener { if (!uSign.isValid(sign) || !enoughTimeHasPassed(player) || player.isSneaking()) return; + if (Config.getBoolean(Property.IGNORE_CREATIVE_MODE) && player.getGameMode() == GameMode.CREATIVE){ + event.setCancelled(true); + return; + } + lastTransactionTime.put(player, System.currentTimeMillis()); if (action == Action.RIGHT_CLICK_BLOCK) event.setCancelled(true); diff --git a/com/Acrobot/ChestShop/Listeners/signChange.java b/com/Acrobot/ChestShop/Listeners/signChange.java index b64b808..68cca94 100644 --- a/com/Acrobot/ChestShop/Listeners/signChange.java +++ b/com/Acrobot/ChestShop/Listeners/signChange.java @@ -94,7 +94,6 @@ public class signChange extends BlockListener { dropSign(event); return; } - boolean canAccess = !Security.isProtected(chestBlock) || Security.canAccess(player, chestBlock); if (!canAccess) { @@ -150,18 +149,17 @@ public class signChange extends BlockListener { } private static String formatFourthLine(String fourthLine, Material material) { - String[] split = fourthLine.split(":"); - if (uNumber.isInteger(split[0])) { - String materialLine = material.name(); - if (split.length == 2) { - int maxLength = (14 - split[1].length()); //15 - length - 1 - if (materialLine.length() > maxLength) materialLine = materialLine.substring(0, maxLength); - materialLine = materialLine + ':' + split[1]; - } - fourthLine = materialLine; - } - fourthLine = fourthLine.replace("_", " "); - return fourthLine; + int index = (fourthLine.indexOf(':') != -1 ? fourthLine.indexOf(':') : 9999); + if (fourthLine.indexOf('-') < index && fourthLine.indexOf('-') != -1) index = fourthLine.indexOf('-'); + + StringBuilder toReturn = new StringBuilder(3); + String matName = uSign.capitalizeFirst(material.name()); + if (index != 9999 && matName.length() > (15 - (fourthLine.length() - index))) matName = matName.substring(0, 15 - (fourthLine.length() - index)); + if (Items.getMaterial(matName) == material) toReturn.append(matName); + else toReturn.append(material.getId()); + + if (index != -1 && index != 9999) toReturn.append(fourthLine.substring(index)); + return toReturn.toString(); } private static boolean formatFirstLine(String line1, Player player) { diff --git a/com/Acrobot/ChestShop/Protection/Plugins/Default.java b/com/Acrobot/ChestShop/Protection/Plugins/Default.java index 5e021c0..7bba9b7 100644 --- a/com/Acrobot/ChestShop/Protection/Plugins/Default.java +++ b/com/Acrobot/ChestShop/Protection/Plugins/Default.java @@ -29,7 +29,7 @@ public class Default implements Protection { Chest neighborChest = uBlock.findNeighbor(block); Sign neighborSign = (neighborChest != null ? uBlock.findSign2(neighborChest.getBlock()) : null); - return neighborSign != null && uLongName.stripName(playerName).equals(neighborSign.getLine(0)); + return neighborSign == null || uLongName.stripName(playerName).equals(neighborSign.getLine(0)); } public boolean protect(String name, Block block) { diff --git a/com/Acrobot/ChestShop/Utils/uEnchantment.java b/com/Acrobot/ChestShop/Utils/uEnchantment.java new file mode 100644 index 0000000..3220856 --- /dev/null +++ b/com/Acrobot/ChestShop/Utils/uEnchantment.java @@ -0,0 +1,41 @@ +package com.Acrobot.ChestShop.Utils; + +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Acrobot + */ +public class uEnchantment { + public static String getEnchantment(ItemStack item){ + return encodeEnchantment(item.getEnchantments()); + } + + public static String encodeEnchantment(Map map){ + int integer = 0; + for (Map.Entry entry : map.entrySet()){ + integer = integer * 1000 + (entry.getKey().getId()) * 10 + entry.getValue(); + } + return (integer != 0 ? Integer.toString(integer, 32) : null); + } + + public static Map decodeEnchantment(String base32){ + if (base32 == null) return new HashMap(); + Map map = new HashMap(); + + String integer = String.valueOf(Integer.parseInt(base32, 32)); + + for (int i = 0; i < (integer.length() / 3); i++){ + String item = integer.substring(i * 3, i * 3 + 3); + Enchantment ench = Enchantment.getById(Integer.parseInt(item.substring(0, 2))); + if (ench == null) continue; + int level = Integer.parseInt(item.substring(2)); + if (ench.getMaxLevel() < level || level < ench.getStartLevel()) continue; + map.put(ench, level); + } + return map; + } +} diff --git a/com/Acrobot/ChestShop/Utils/uInventory.java b/com/Acrobot/ChestShop/Utils/uInventory.java index ad72a3b..b296ed3 100644 --- a/com/Acrobot/ChestShop/Utils/uInventory.java +++ b/com/Acrobot/ChestShop/Utils/uInventory.java @@ -6,8 +6,6 @@ import org.bukkit.Material; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import java.util.HashMap; - /** * @author Acrobot */ @@ -26,7 +24,7 @@ public class uInventory { ItemStack currentItem = inv.getItem(slot); if (currentItem == null || currentItem.getType() == Material.AIR) continue; - if (currentItem.getType() == itemMaterial && (durability == -1 || currentItem.getDurability() == durability)) { + if (equals(currentItem, item, durability)) { int currentAmount = currentItem.getAmount(); if (amount == currentAmount) { currentItem = null; @@ -41,36 +39,53 @@ public class uInventory { inv.setItem(slot, currentItem); } } - return amount; } public static int add(Inventory inv, ItemStack item, int amount) { amount = (amount > 0 ? amount : 1); if (Config.getBoolean(Property.STACK_UNSTACKABLES)) return addAndStackTo64(inv, item, amount); - HashMap items = inv.addItem(new ItemStack(item.getType(), amount, item.getDurability())); + /*ItemStack itemstack = new ItemStack(item.getType(), amount, item.getDurability()); + itemstack.addEnchantments(item.getEnchantments()); + HashMap items = inv.addItem(itemstack); amount = 0; for (ItemStack toAdd : items.values()) amount += toAdd.getAmount(); - return amount; + return amount;*/ //TODO: Fix this in CraftBukkit's code + + return addManually(inv, item, amount); + } + + private static int addManually(Inventory inv, ItemStack item, int amount) { + return addManually(inv, item, amount, item.getType().getMaxStackSize()); } public static int addAndStackTo64(Inventory inv, ItemStack item, int amount) { - Material type = item.getType(); - for (int slot = 0; slot < inv.getSize(); slot++) { - if (amount <= 0) return 0; + return addManually(inv, item, amount, 64); + } + + public static int addManually(Inventory inv, ItemStack item, int amount, int max){ + if (amount <= 0) return 0; + + for (int slot = 0; slot < inv.getSize() && amount > 0; slot++){ ItemStack curItem = inv.getItem(slot); + ItemStack dupe = item.clone(); + if (curItem == null || curItem.getType() == Material.AIR) { - item.setAmount((amount > 64 ? 64 : amount)); - amount -= item.getAmount(); - inv.setItem(slot, item); - } else if (curItem.getType() == type && curItem.getDurability() == item.getDurability() && curItem.getAmount() != 64) { - int toFill = (64 - curItem.getAmount()); - item.setAmount((amount > toFill ? 64 : curItem.getAmount() + amount)); - amount -= item.getAmount(); - inv.setItem(slot, item); + dupe.setAmount((amount > max ? max : amount)); + dupe.addEnchantments(item.getEnchantments()); + amount -= dupe.getAmount(); + inv.setItem(slot, dupe); + } else if (equals(item, curItem, item.getDurability()) && curItem.getAmount() != max) { + int cA = curItem.getAmount(); + int amountAdded = amount > max - cA ? max - cA : amount; + dupe.setAmount(cA + amountAdded); + amount -= amountAdded; + dupe.addEnchantments(item.getEnchantments()); + inv.setItem(slot, dupe); } } + return amount; } @@ -79,14 +94,13 @@ public class uInventory { int amount = 0; for (ItemStack i : inv.getContents()) { - if (i != null && i.getType() == item.getType() && (durability == -1 || i.getDurability() == durability)) amount += i.getAmount(); + if (equals(i, item, durability)) amount += i.getAmount(); } return amount; } public static int fits(Inventory inv, ItemStack item, int amount, short durability) { - Material itemMaterial = item.getType(); - int maxStackSize = (Config.getBoolean(Property.STACK_UNSTACKABLES) ? 64 : itemMaterial.getMaxStackSize()); + int maxStackSize = (Config.getBoolean(Property.STACK_UNSTACKABLES) ? 64 : item.getType().getMaxStackSize()); int amountLeft = amount; for (ItemStack currentItem : inv.getContents()) { @@ -99,11 +113,18 @@ public class uInventory { int currentAmount = currentItem.getAmount(); - if (currentAmount != maxStackSize && currentItem.getType() == itemMaterial && (durability == -1 || currentItem.getDurability() == durability)) { + if (currentAmount != maxStackSize && equals(currentItem, item, durability)) { amountLeft = currentAmount + amountLeft <= maxStackSize ? 0 : amountLeft - (maxStackSize - currentAmount); } } return amountLeft; } + + private static boolean equals(ItemStack i, ItemStack item, short durability){ + return i != null + && i.getType() == item.getType() + && i.getEnchantments().equals(item.getEnchantments()) + && (durability == -1 || i.getDurability() == durability); + } } diff --git a/com/Acrobot/ChestShop/Utils/uSign.java b/com/Acrobot/ChestShop/Utils/uSign.java index 6d3ec4d..9a96a03 100644 --- a/com/Acrobot/ChestShop/Utils/uSign.java +++ b/com/Acrobot/ChestShop/Utils/uSign.java @@ -16,7 +16,7 @@ public class uSign { Pattern.compile("^$|^\\w.+$"), Pattern.compile("[0-9]+"), Pattern.compile(".+"), - Pattern.compile("[\\w :]+") + Pattern.compile("[\\w : -]+") }; public static Towny towny; //Moved this here - somehow, java fails at try/catch @@ -82,4 +82,17 @@ public class uSign { return (amount >= 1 ? amount : 1); } else return 1; } + + public static String capitalizeFirst(String name){ + return capitalizeFirst(name, '_'); + } + + public static String capitalizeFirst(String name, char separator){ + name = name.toLowerCase(); + String[] split = name.split(Character.toString(separator)); + StringBuilder total = new StringBuilder(3); + for (String s : split) total.append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).append(' '); + + return total.toString().trim(); + } } diff --git a/plugin.yml b/plugin.yml index 4e3e148..eb451db 100644 --- a/plugin.yml +++ b/plugin.yml @@ -2,7 +2,7 @@ name: ChestShop main: com.Acrobot.ChestShop.ChestShop -version: 3.29 +version: 3.30 author: Acrobot