diff --git a/src/main/java/com/Acrobot/ChestShop/ChestShop.java b/src/main/java/com/Acrobot/ChestShop/ChestShop.java index 0dbf97e..128ae42 100644 --- a/src/main/java/com/Acrobot/ChestShop/ChestShop.java +++ b/src/main/java/com/Acrobot/ChestShop/ChestShop.java @@ -3,6 +3,7 @@ package com.Acrobot.ChestShop; import com.Acrobot.Breeze.Configuration.Configuration; import com.Acrobot.ChestShop.Commands.Give; import com.Acrobot.ChestShop.Commands.ItemInfo; +import com.Acrobot.ChestShop.Commands.ShopInfo; import com.Acrobot.ChestShop.Commands.Toggle; import com.Acrobot.ChestShop.Commands.Version; import com.Acrobot.ChestShop.Commands.AccessToggle; @@ -23,6 +24,7 @@ import com.Acrobot.ChestShop.Listeners.ItemInfoListener; import com.Acrobot.ChestShop.Listeners.Modules.ItemAliasModule; import com.Acrobot.ChestShop.Listeners.Modules.MetricsModule; import com.Acrobot.ChestShop.Listeners.Modules.StockCounterModule; +import com.Acrobot.ChestShop.Listeners.ShopInfoListener; import com.Acrobot.ChestShop.Listeners.SignParseListener; import com.Acrobot.ChestShop.Listeners.Modules.DiscountModule; import com.Acrobot.ChestShop.Listeners.Modules.PriceRestrictionModule; @@ -130,6 +132,7 @@ public class ChestShop extends JavaPlugin { } registerCommand("iteminfo", new ItemInfo(), Permission.ITEMINFO); + registerCommand("shopinfo", new ShopInfo(), Permission.SHOPINFO); registerCommand("csVersion", new Version(), Permission.ADMIN); registerCommand("csMetrics", new com.Acrobot.ChestShop.Commands.Metrics(), Permission.ADMIN); registerCommand("csGive", new Give(), Permission.ADMIN); @@ -333,6 +336,7 @@ public class ChestShop extends JavaPlugin { registerEvent(new SignParseListener()); registerEvent(new ItemStringListener()); registerEvent(new ItemInfoListener()); + registerEvent(new ShopInfoListener()); registerEvent(new GarbageTextListener()); Plugin authMe = getServer().getPluginManager().getPlugin("AuthMe"); diff --git a/src/main/java/com/Acrobot/ChestShop/Commands/ItemInfo.java b/src/main/java/com/Acrobot/ChestShop/Commands/ItemInfo.java index a8d5b74..5841462 100644 --- a/src/main/java/com/Acrobot/ChestShop/Commands/ItemInfo.java +++ b/src/main/java/com/Acrobot/ChestShop/Commands/ItemInfo.java @@ -3,21 +3,25 @@ package com.Acrobot.ChestShop.Commands; import com.Acrobot.Breeze.Utils.MaterialUtil; import com.Acrobot.Breeze.Utils.StringUtil; import com.Acrobot.ChestShop.ChestShop; +import com.Acrobot.ChestShop.Configuration.Messages; +import com.Acrobot.ChestShop.Configuration.Properties; import com.Acrobot.ChestShop.Events.ItemInfoEvent; import com.Acrobot.ChestShop.Events.ItemParseEvent; import com.Acrobot.ChestShop.Utils.ItemUtil; +import com.google.common.collect.ImmutableMap; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import java.util.Map; import java.util.logging.Level; import static com.Acrobot.ChestShop.Configuration.Messages.iteminfo; -import static com.Acrobot.ChestShop.Configuration.Messages.iteminfo_fullname; import static com.Acrobot.ChestShop.Configuration.Messages.iteminfo_shopname; /** @@ -45,7 +49,11 @@ public class ItemInfo implements CommandExecutor { iteminfo.send(sender); try { - iteminfo_fullname.send(sender, "item", ItemUtil.getName(item)); + Map replacementMap = ImmutableMap.of("item", ItemUtil.getName(item)); + if (!Properties.SHOWITEM_MESSAGE || !(sender instanceof Player) + || !MaterialUtil.Show.sendMessage((Player) sender, Messages.iteminfo_fullname, new ItemStack[]{item}, replacementMap)) { + Messages.iteminfo_fullname.send(sender, replacementMap); + } } catch (IllegalArgumentException e) { sender.sendMessage(ChatColor.RED + "Error while generating full name. Please contact an admin or take a look at the console/log!"); ChestShop.getPlugin().getLogger().log(Level.SEVERE, "Error while generating full item name", e); diff --git a/src/main/java/com/Acrobot/ChestShop/Commands/ShopInfo.java b/src/main/java/com/Acrobot/ChestShop/Commands/ShopInfo.java new file mode 100644 index 0000000..ad4f6f9 --- /dev/null +++ b/src/main/java/com/Acrobot/ChestShop/Commands/ShopInfo.java @@ -0,0 +1,43 @@ +package com.Acrobot.ChestShop.Commands; + +import com.Acrobot.ChestShop.ChestShop; +import com.Acrobot.ChestShop.Configuration.Messages; +import com.Acrobot.ChestShop.Events.ShopInfoEvent; +import com.Acrobot.ChestShop.Signs.ChestShopSign; +import com.Acrobot.ChestShop.Utils.uBlock; +import org.bukkit.ChatColor; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +/** + * @author Phoenix616 + */ +public class ShopInfo implements CommandExecutor { + public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { + if (sender instanceof Player) { + Block target = ((Player) sender).getTargetBlock(5); + if (target != null) { + Sign sign = null; + if (ChestShopSign.isValid(target)) { + sign = (Sign) target.getState(); + } else if (uBlock.couldBeShopContainer(target)) { + sign = uBlock.getConnectedSign(target); + } + + if (sign != null) { + ShopInfoEvent event = new ShopInfoEvent((Player) sender, sign); + ChestShop.callEvent(event); + } else { + Messages.NO_SHOP_FOUND.sendWithPrefix(sender); + } + } + } else { + sender.sendMessage(ChatColor.RED + "Command must be run by a player!"); + } + return true; + } +} diff --git a/src/main/java/com/Acrobot/ChestShop/Configuration/Messages.java b/src/main/java/com/Acrobot/ChestShop/Configuration/Messages.java index dde244a..66d4c10 100644 --- a/src/main/java/com/Acrobot/ChestShop/Configuration/Messages.java +++ b/src/main/java/com/Acrobot/ChestShop/Configuration/Messages.java @@ -23,6 +23,11 @@ import java.util.logging.Level; */ public class Messages { public static Message prefix; + + public static Message shopinfo; + public static Message shopinfo_buy; + public static Message shopinfo_sell; + public static Message iteminfo; public static Message iteminfo_fullname; public static Message iteminfo_shopname; @@ -91,6 +96,7 @@ public class Messages { public static Message INCORRECT_ITEM_ID; public static Message INVALID_CLIENT_NAME; public static Message NOT_ENOUGH_PROTECTIONS; + public static Message NO_SHOP_FOUND; public static Message CANNOT_CREATE_SHOP_HERE; @@ -172,6 +178,10 @@ public class Messages { ChestShop.getAudiences().sender(sender).sendMessage(getComponent(sender, false, Collections.emptyMap(), replacements)); } + public void send(CommandSender sender, Map replacements) { + ChestShop.getAudiences().sender(sender).sendMessage(getComponent(sender, false, replacements)); + } + @Deprecated public BaseComponent[] getComponents(CommandSender sender, boolean prefixSuffix, Map replacementMap, String... replacements) { return BungeeComponentSerializer.get().serialize(getComponent(sender, prefixSuffix, replacementMap, replacements)); diff --git a/src/main/java/com/Acrobot/ChestShop/Events/ShopInfoEvent.java b/src/main/java/com/Acrobot/ChestShop/Events/ShopInfoEvent.java new file mode 100644 index 0000000..a9b171b --- /dev/null +++ b/src/main/java/com/Acrobot/ChestShop/Events/ShopInfoEvent.java @@ -0,0 +1,58 @@ +package com.Acrobot.ChestShop.Events; + +import org.bukkit.block.Sign; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * Represents a /shopinfo call or middle click on a sign + * + * @author Phoenix616 + */ +public class ShopInfoEvent extends Event implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + + private Player sender; + private Sign sign; + private boolean cancelled = false; + + public ShopInfoEvent(Player sender, Sign sign) { + this.sender = sender; + this.sign = sign; + } + + /** + * @return The Player who initiated the call + */ + public Player getSender() { + return sender; + } + + /** + * @return The shop sign + */ + public Sign getSign() { + return sign; + } + + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + cancelled = cancel; + } +} diff --git a/src/main/java/com/Acrobot/ChestShop/Listeners/ItemInfoListener.java b/src/main/java/com/Acrobot/ChestShop/Listeners/ItemInfoListener.java index 98d6a7c..6d07eca 100644 --- a/src/main/java/com/Acrobot/ChestShop/Listeners/ItemInfoListener.java +++ b/src/main/java/com/Acrobot/ChestShop/Listeners/ItemInfoListener.java @@ -1,7 +1,9 @@ package com.Acrobot.ChestShop.Listeners; import com.Acrobot.Breeze.Utils.StringUtil; +import com.Acrobot.ChestShop.ChestShop; import com.Acrobot.ChestShop.Events.ItemInfoEvent; +import com.Acrobot.ChestShop.Utils.ItemUtil; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.command.CommandSender; @@ -17,14 +19,18 @@ import org.bukkit.potion.Potion; import org.bukkit.potion.PotionEffect; import java.util.Map; +import java.util.logging.Level; import static com.Acrobot.Breeze.Utils.NumberUtil.toRoman; import static com.Acrobot.Breeze.Utils.NumberUtil.toTime; import static com.Acrobot.Breeze.Utils.StringUtil.capitalizeFirstLetter; +import static com.Acrobot.ChestShop.Configuration.Messages.iteminfo; import static com.Acrobot.ChestShop.Configuration.Messages.iteminfo_book; import static com.Acrobot.ChestShop.Configuration.Messages.iteminfo_book_generation; +import static com.Acrobot.ChestShop.Configuration.Messages.iteminfo_fullname; import static com.Acrobot.ChestShop.Configuration.Messages.iteminfo_lore; import static com.Acrobot.ChestShop.Configuration.Messages.iteminfo_repaircost; +import static com.Acrobot.ChestShop.Configuration.Messages.iteminfo_shopname; /** * @author Acrobot diff --git a/src/main/java/com/Acrobot/ChestShop/Listeners/Player/PlayerInteract.java b/src/main/java/com/Acrobot/ChestShop/Listeners/Player/PlayerInteract.java index d4a1123..060ea1e 100644 --- a/src/main/java/com/Acrobot/ChestShop/Listeners/Player/PlayerInteract.java +++ b/src/main/java/com/Acrobot/ChestShop/Listeners/Player/PlayerInteract.java @@ -1,6 +1,7 @@ package com.Acrobot.ChestShop.Listeners.Player; import com.Acrobot.Breeze.Utils.*; +import com.Acrobot.ChestShop.ChestShop; import com.Acrobot.ChestShop.Commands.AccessToggle; import com.Acrobot.ChestShop.Configuration.Messages; import com.Acrobot.ChestShop.Configuration.Properties; @@ -10,6 +11,7 @@ import com.Acrobot.ChestShop.Events.AccountQueryEvent; import com.Acrobot.ChestShop.Events.Economy.AccountCheckEvent; import com.Acrobot.ChestShop.Events.ItemParseEvent; import com.Acrobot.ChestShop.Events.PreTransactionEvent; +import com.Acrobot.ChestShop.Events.ShopInfoEvent; import com.Acrobot.ChestShop.Events.TransactionEvent; import com.Acrobot.ChestShop.Permission; import com.Acrobot.ChestShop.Security; @@ -61,17 +63,24 @@ public class PlayerInteract implements Listener { Action action = event.getAction(); Player player = event.getPlayer(); - if (Properties.USE_BUILT_IN_PROTECTION && isShopBlock(block)) { - if (Properties.TURN_OFF_DEFAULT_PROTECTION_WHEN_PROTECTED_EXTERNALLY) { + if (Properties.USE_BUILT_IN_PROTECTION && uBlock.couldBeShopContainer(block)) { + Sign sign = uBlock.getConnectedSign(block); + if (sign != null) { + if (Properties.TURN_OFF_DEFAULT_PROTECTION_WHEN_PROTECTED_EXTERNALLY) { + return; + } + + if (!Security.canAccess(player, block)) { + event.setCancelled(true); + if (Permission.has(player, Permission.SHOPINFO)) { + ChestShop.callEvent(new ShopInfoEvent(player, sign)); + } else { + Messages.ACCESS_DENIED.send(player); + } + } + return; } - - if (!Security.canAccess(player, block)) { - event.setCancelled(true); - Messages.ACCESS_DENIED.sendWithPrefix(player); - } - - return; } if (!isSign(block) || player.getInventory().getItemInMainHand().getType().name().contains("SIGN")) // Blocking accidental sign edition diff --git a/src/main/java/com/Acrobot/ChestShop/Listeners/Player/PlayerInventory.java b/src/main/java/com/Acrobot/ChestShop/Listeners/Player/PlayerInventory.java index 3678c54..7468139 100644 --- a/src/main/java/com/Acrobot/ChestShop/Listeners/Player/PlayerInventory.java +++ b/src/main/java/com/Acrobot/ChestShop/Listeners/Player/PlayerInventory.java @@ -1,12 +1,17 @@ package com.Acrobot.ChestShop.Listeners.Player; +import com.Acrobot.ChestShop.ChestShop; import com.Acrobot.ChestShop.Configuration.Messages; import com.Acrobot.ChestShop.Configuration.Properties; +import com.Acrobot.ChestShop.Events.ShopInfoEvent; +import com.Acrobot.ChestShop.Permission; import com.Acrobot.ChestShop.Security; import com.Acrobot.ChestShop.Signs.ChestShopSign; +import com.Acrobot.ChestShop.Utils.uBlock; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.DoubleChest; +import org.bukkit.block.Sign; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -59,7 +64,16 @@ public class PlayerInventory implements Listener { } if (!canAccess) { - Messages.ACCESS_DENIED.sendWithPrefix(player); + if (Permission.has(player, Permission.SHOPINFO)) { + for (Block container : containers) { + Sign sign = uBlock.getConnectedSign(container); + if (sign != null) { + ChestShop.callEvent(new ShopInfoEvent((Player) event.getPlayer(), sign)); + } + } + } else { + Messages.ACCESS_DENIED.sendWithPrefix(event.getPlayer()); + } event.setCancelled(true); } } diff --git a/src/main/java/com/Acrobot/ChestShop/Listeners/ShopInfoListener.java b/src/main/java/com/Acrobot/ChestShop/Listeners/ShopInfoListener.java new file mode 100644 index 0000000..5c4cc3d --- /dev/null +++ b/src/main/java/com/Acrobot/ChestShop/Listeners/ShopInfoListener.java @@ -0,0 +1,108 @@ +package com.Acrobot.ChestShop.Listeners; + +import com.Acrobot.Breeze.Utils.InventoryUtil; +import com.Acrobot.Breeze.Utils.MaterialUtil; +import com.Acrobot.Breeze.Utils.PriceUtil; +import com.Acrobot.Breeze.Utils.QuantityUtil; +import com.Acrobot.ChestShop.ChestShop; +import com.Acrobot.ChestShop.Configuration.Messages; +import com.Acrobot.ChestShop.Configuration.Properties; +import com.Acrobot.ChestShop.Economy.Economy; +import com.Acrobot.ChestShop.Events.AccountQueryEvent; +import com.Acrobot.ChestShop.Events.Economy.CurrencyFormatEvent; +import com.Acrobot.ChestShop.Events.ItemInfoEvent; +import com.Acrobot.ChestShop.Events.ItemParseEvent; +import com.Acrobot.ChestShop.Events.ShopInfoEvent; +import com.Acrobot.ChestShop.Signs.ChestShopSign; +import com.Acrobot.ChestShop.Utils.ItemUtil; +import com.Acrobot.ChestShop.Utils.uBlock; +import com.google.common.collect.ImmutableMap; +import org.bukkit.block.Container; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; + +import java.math.BigDecimal; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Acrobot + */ +public class ShopInfoListener implements Listener { + + @EventHandler(ignoreCancelled = true) + public static void showShopInfo(ShopInfoEvent event) { + if (ChestShopSign.isValid(event.getSign())) { + String nameLine = event.getSign().getLine(ChestShopSign.NAME_LINE); + int amount; + try { + amount = QuantityUtil.parseQuantity(event.getSign().getLine(ChestShopSign.QUANTITY_LINE)); + } catch (NumberFormatException notANumber) { + Messages.INVALID_SHOP_DETECTED.sendWithPrefix(event.getSender()); + return; + } + String pricesLine = event.getSign().getLine(ChestShopSign.PRICE_LINE); + + AccountQueryEvent queryEvent = new AccountQueryEvent(nameLine); + ChestShop.callEvent(queryEvent); + if (queryEvent.getAccount() == null) { + Messages.INVALID_SHOP_DETECTED.sendWithPrefix(event.getSender()); + return; + } + + String ownerName = queryEvent.getAccount().getName(); + ownerName = ownerName != null ? ownerName : nameLine; + + ItemParseEvent parseEvent = new ItemParseEvent(event.getSign().getLine(ChestShopSign.ITEM_LINE)); + ItemStack item = ChestShop.callEvent(parseEvent).getItem(); + if (item == null || amount < 1) { + Messages.INVALID_SHOP_DETECTED.sendWithPrefix(event.getSender()); + return; + } + + Container shopBlock = uBlock.findConnectedContainer(event.getSign()); + String stock; + if (shopBlock != null) { + stock = String.valueOf(InventoryUtil.getAmount(item, shopBlock.getInventory())); + } else { + stock = "\u221e"; // Infinity symbol + } + + Map replacementMap = ImmutableMap.of( + "item", ItemUtil.getName(item), + "stock", stock, + "owner", ownerName, + "prices", pricesLine, + "quantity", String.valueOf(amount) + ); + if (!Properties.SHOWITEM_MESSAGE + || !MaterialUtil.Show.sendMessage(event.getSender(), Messages.shopinfo, new ItemStack[]{item}, replacementMap)) { + Messages.shopinfo.send(event.getSender(), replacementMap); + } + + + BigDecimal buyPrice = PriceUtil.getExactBuyPrice(pricesLine); + BigDecimal sellPrice = PriceUtil.getExactSellPrice(pricesLine); + + ChestShop.callEvent(new ItemInfoEvent(event.getSender(), item)); + + if (!buyPrice.equals(PriceUtil.NO_PRICE)) { + CurrencyFormatEvent cfe = ChestShop.callEvent(new CurrencyFormatEvent(buyPrice)); + Messages.shopinfo_buy.send(event.getSender(), + "amount", String.valueOf(amount), + "price", cfe.getFormattedAmount() + ); + } + if (!sellPrice.equals(PriceUtil.NO_PRICE)) { + CurrencyFormatEvent cfe = ChestShop.callEvent(new CurrencyFormatEvent(sellPrice)); + Messages.shopinfo_sell.send(event.getSender(), + "amount", String.valueOf(amount), + "price", cfe.getFormattedAmount() + ); + } + } else { + Messages.INVALID_SHOP_DETECTED.sendWithPrefix(event.getSender()); + } + } +} diff --git a/src/main/java/com/Acrobot/ChestShop/Permission.java b/src/main/java/com/Acrobot/ChestShop/Permission.java index 6f16d37..5fc4ed1 100644 --- a/src/main/java/com/Acrobot/ChestShop/Permission.java +++ b/src/main/java/com/Acrobot/ChestShop/Permission.java @@ -42,7 +42,8 @@ public enum Permission { NOTIFY_TOGGLE("ChestShop.toggle"), ACCESS_TOGGLE("ChestShop.accesstoggle"), - ITEMINFO("ChestShop.iteminfo"); + ITEMINFO("ChestShop.iteminfo"), + SHOPINFO("ChestShop.shopinfo"); private final String permission; diff --git a/src/main/resources/languages/lang.en.yml b/src/main/resources/languages/lang.en.yml index b61cef4..d9f7de9 100644 --- a/src/main/resources/languages/lang.en.yml +++ b/src/main/resources/languages/lang.en.yml @@ -1,4 +1,13 @@ prefix: "&a[Shop] &r" + +shopinfo: |- + &aShop Information: + &fOwner: &7%owner + &fStock: &7%stock + &fItem: &7%item +shopinfo_buy: "&fBuy &7%amount &ffor &7%price" +shopinfo_sell: "&fSell &7%amount &ffor &7%price" + iteminfo: "&aItem Information: &r" iteminfo_fullname: "&fFull Name: &7%item" iteminfo_shopname: "&fShop Sign: &7%item" @@ -77,6 +86,7 @@ NO_PERMISSION: "You don't have permissions to do that!" INCORRECT_ITEM_ID: "You have specified an invalid item id!" INVALID_CLIENT_NAME: "Your username is not a valid Minecraft username!" NOT_ENOUGH_PROTECTIONS: "Could not create a protection!" +NO_SHOP_FOUND: "No shop found." CANNOT_CREATE_SHOP_HERE: "You can't create shop here!" diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 7aa3610..ed2921e 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -14,7 +14,10 @@ commands: usage: | / §2(what's the item in hand?) / §7log§f §2(what's the item ID of §7LOG§2?) - + shopinfo: + aliases: [sinfo,shop] + description: Shows information about the shop looked at + usage: / §2(information about the looked at shop) csGive: description: Gives an item to the appropriate player usage: / (amount) (player) @@ -84,6 +87,9 @@ permissions: ChestShop.iteminfo: description: Allows user to see item info with the command. default: true + ChestShop.shopinfo: + description: Allows user to see shop info with the command or middle click on shop sign/container. + default: true ChestShop.admin: description: Allows user to modify/destroy other stores and create an Admin Shops default: op