From dc1bf15bf20ea4504783fe6a871cb75d818a99fc Mon Sep 17 00:00:00 2001 From: BuildTools Date: Wed, 2 Sep 2015 13:06:48 +0200 Subject: [PATCH] First Commit --- de/epiceric/shopchest/Commands.java | 332 ++++++++ de/epiceric/shopchest/ShopChest.java | 230 +++++ de/epiceric/shopchest/config/Config.java | 126 +++ de/epiceric/shopchest/config/Regex.java | 17 + de/epiceric/shopchest/event/InteractShop.java | 426 ++++++++++ de/epiceric/shopchest/event/NotifyUpdate.java | 37 + de/epiceric/shopchest/event/ProtectChest.java | 22 + .../shopchest/event/RegenerateShopItem.java | 27 + .../shopchest/event/UpdateHolograms.java | 50 ++ de/epiceric/shopchest/shop/Hologram.java | 89 ++ de/epiceric/shopchest/shop/Shop.java | 176 ++++ de/epiceric/shopchest/utils/ClickType.java | 69 ++ .../shopchest/utils/EnchantmentNames.java | 84 ++ de/epiceric/shopchest/utils/ItemNames.java | 617 ++++++++++++++ de/epiceric/shopchest/utils/JsonBuilder.java | 106 +++ de/epiceric/shopchest/utils/Metrics.java | 785 ++++++++++++++++++ de/epiceric/shopchest/utils/ShopUtils.java | 107 +++ .../shopchest/utils/UpdateChecker.java | 50 ++ de/epiceric/shopchest/utils/Utils.java | 29 + 19 files changed, 3379 insertions(+) create mode 100644 de/epiceric/shopchest/Commands.java create mode 100644 de/epiceric/shopchest/ShopChest.java create mode 100644 de/epiceric/shopchest/config/Config.java create mode 100644 de/epiceric/shopchest/config/Regex.java create mode 100644 de/epiceric/shopchest/event/InteractShop.java create mode 100644 de/epiceric/shopchest/event/NotifyUpdate.java create mode 100644 de/epiceric/shopchest/event/ProtectChest.java create mode 100644 de/epiceric/shopchest/event/RegenerateShopItem.java create mode 100644 de/epiceric/shopchest/event/UpdateHolograms.java create mode 100644 de/epiceric/shopchest/shop/Hologram.java create mode 100644 de/epiceric/shopchest/shop/Shop.java create mode 100644 de/epiceric/shopchest/utils/ClickType.java create mode 100644 de/epiceric/shopchest/utils/EnchantmentNames.java create mode 100644 de/epiceric/shopchest/utils/ItemNames.java create mode 100644 de/epiceric/shopchest/utils/JsonBuilder.java create mode 100644 de/epiceric/shopchest/utils/Metrics.java create mode 100644 de/epiceric/shopchest/utils/ShopUtils.java create mode 100644 de/epiceric/shopchest/utils/UpdateChecker.java create mode 100644 de/epiceric/shopchest/utils/Utils.java diff --git a/de/epiceric/shopchest/Commands.java b/de/epiceric/shopchest/Commands.java new file mode 100644 index 0000000..6d39bc7 --- /dev/null +++ b/de/epiceric/shopchest/Commands.java @@ -0,0 +1,332 @@ +package de.epiceric.shopchest; + +import java.lang.reflect.Method; +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.defaults.BukkitCommand; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.inventory.ItemStack; + +import de.epiceric.shopchest.config.Config; +import de.epiceric.shopchest.shop.Hologram; +import de.epiceric.shopchest.shop.Shop; +import de.epiceric.shopchest.utils.ClickType; +import de.epiceric.shopchest.utils.JsonBuilder; +import de.epiceric.shopchest.utils.ClickType.EnumClickType; +import de.epiceric.shopchest.utils.JsonBuilder.ClickAction; +import de.epiceric.shopchest.utils.JsonBuilder.HoverAction; +import de.epiceric.shopchest.utils.ShopUtils; +import de.epiceric.shopchest.utils.UpdateChecker; + +import net.md_5.bungee.api.ChatColor; +import net.milkbowl.vault.permission.Permission; +import net.minecraft.server.v1_8_R3.EntityArmorStand; + +public class Commands extends BukkitCommand { + + private ShopChest plugin; + + private Permission perm = ShopChest.perm; + + public Commands(ShopChest plugin, String name, String description, String usageMessage, List aliases) { + super(name, description, usageMessage, aliases); + this.plugin = plugin; + } + + public static void registerCommand(Command command, ShopChest plugin) + throws ReflectiveOperationException { + Method commandMap = plugin.getServer().getClass().getMethod("getCommandMap"); + Object cmdmap = commandMap.invoke(plugin.getServer()); + Method register = cmdmap.getClass().getMethod("register", String.class,Command.class); + register.invoke(cmdmap, command.getName(),command); + } + + + @Override + public boolean execute(CommandSender sender, String label, String[] args) { + + if (sender instanceof Player) { + + Player p = (Player) sender; + + if (args.length == 0) { + + sendBasicHelpMessage(p); + return true; + + } else { + + if (args[0].equalsIgnoreCase("create")) { + + if (perm.has(p, "shopchest.create")) { + + if (args.length == 4) { + + create(args, false, p); + return true; + + + } else if (args.length == 5) { + + if (args[4].equalsIgnoreCase("infinite")) { + + if (perm.has(p, "shopchest.create.infinite")) { + + create(args, true, p); + return true; + + } else { + + p.sendMessage(Config.noPermission_createInfinite()); + return true; + + } + + } else if (args[4].equalsIgnoreCase("normal")){ + + create(args, false, p); + return true; + + } else { + + sendBasicHelpMessage(p); + return true; + + } + + } else { + + sendBasicHelpMessage(p); + return true; + + } + + } else { + + p.sendMessage(Config.noPermission_create()); + return true; + + } + + } else if (args[0].equalsIgnoreCase("remove")) { + + remove(p); + return true; + + } else if (args[0].equalsIgnoreCase("info")) { + + info(p); + return true; + + } else if (args[0].equalsIgnoreCase("reload")) { + + if (perm.has(p, "shopchest.reload")) { + reload(p); + return true; + } else { + p.sendMessage(Config.noPermission_reload()); + return true; + } + + } else if (args[0].equalsIgnoreCase("update")) { + + if (perm.has(p, "shopchest.update")) { + checkUpdates(p); + return true; + } else { + p.sendMessage(Config.noPermission_update()); + return true; + } + + } + + return true; + + } + + + } else { + + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "Only players can execute this command."); + return true; + + } + + } + + private void checkUpdates(Player player) { + + JsonBuilder jb = new JsonBuilder().parse(Config.checking_update()); + jb.sendJson(player); + + UpdateChecker uc = new UpdateChecker(ShopChest.getInstance(), ShopChest.getInstance().getDescription().getWebsite()); + if (uc.updateNeeded()) { + ShopChest.latestVersion = uc.getVersion(); + ShopChest.downloadLink = uc.getLink(); + ShopChest.isUpdateNeeded = true; + JsonBuilder jb2 = new JsonBuilder(Config.update_available(ShopChest.latestVersion)).withHoverEvent(HoverAction.SHOW_TEXT, Config.click_to_download()).withClickEvent(ClickAction.OPEN_URL, ShopChest.downloadLink); + jb2.sendJson(player); + } else { + ShopChest.latestVersion = ""; + ShopChest.downloadLink = ""; + ShopChest.isUpdateNeeded = false; + JsonBuilder jb3 = new JsonBuilder().parse(Config.no_new_update()); + jb3.sendJson(player); + } + + } + + private void reload(Player player) { + + for (Shop shop : ShopUtils.getShops()) { + Hologram hologram = shop.getHologram(); + + shop.getItem().remove(); + ShopUtils.removeShop(shop); + + for (Player p : ShopChest.getInstance().getServer().getOnlinePlayers()) { + hologram.hidePlayer(p); + } + + for (Object o : hologram.getEntities()) { + EntityArmorStand e = (EntityArmorStand) o; + e.getWorld().removeEntity(e); + } + + + } + + for (String key : ShopChest.getInstance().shopChests.getKeys(false)) { + + OfflinePlayer vendor = ShopChest.getInstance().shopChests.getOfflinePlayer(key + ".vendor"); + int locationX = ShopChest.getInstance().shopChests.getInt(key + ".location.x"); + int locationY = ShopChest.getInstance().shopChests.getInt(key + ".location.y"); + int locationZ = ShopChest.getInstance().shopChests.getInt(key + ".location.z"); + World locationWorld = ShopChest.getInstance().getServer().getWorld(ShopChest.getInstance().shopChests.getString(key + ".location.world")); + Location location = new Location(locationWorld, locationX, locationY, locationZ); + ItemStack product = ShopChest.getInstance().shopChests.getItemStack(key + ".product"); + double buyPrice = ShopChest.getInstance().shopChests.getDouble(key + ".price.buy"); + double sellPrice = ShopChest.getInstance().shopChests.getDouble(key + ".price.sell"); + boolean infinite = ShopChest.getInstance().shopChests.getBoolean(key + ".infinite"); + + ShopUtils.addShop(new Shop(ShopChest.getInstance(), vendor, product, location, buyPrice, sellPrice, infinite)); + + } + + for (Player p : Bukkit.getOnlinePlayers()) { + Bukkit.getPluginManager().callEvent(new PlayerMoveEvent(p, p.getLocation(), p.getLocation())); + } + + player.sendMessage(Config.reloaded_shops(ShopChest.getInstance().shopChests.getKeys(false).size())); + + } + + private void create(String[] args, boolean infinite, Player p) { + int amount; + double buyPrice, sellPrice; + + + try { + amount = Integer.parseInt(args[1]); + buyPrice = Double.parseDouble(args[2]); + sellPrice = Double.parseDouble(args[3]); + } catch (NumberFormatException e) { + p.sendMessage(Config.amount_and_price_not_number()); + return; + } + + boolean buyEnabled = !(buyPrice <= 0), sellEnabled = !(sellPrice <= 0); + + if (!buyEnabled && !sellEnabled) { + p.sendMessage(Config.buy_and_sell_disabled()); + return; + } + + if (p.getItemInHand().getType().equals(Material.AIR)) { + p.sendMessage(Config.no_item_in_hand()); + return; + } + + for (String key : Config.minimum_prices()) { + + ItemStack itemStack; + double price = plugin.getConfig().getDouble("minimum-prices." + key); + + if (key.contains(":")) { + itemStack = new ItemStack(Material.getMaterial(key.split(":")[0]), 1, Short.parseShort(key.split(":")[1])); + } else { + itemStack = new ItemStack(Material.getMaterial(key), 1); + } + + if (itemStack.getType().equals(p.getItemInHand().getType())) { + if (buyEnabled) { + if ((buyPrice <= amount * price) && (buyPrice > 0)) { + p.sendMessage(Config.buyPrice_too_low(amount * price)); + return; + } + } + + if (sellEnabled) { + if ((sellPrice <= amount * price) && (sellPrice > 0)) { + p.sendMessage(Config.sellPrice_too_low(amount * price)); + return; + } + } + } + } + + if (sellEnabled && buyEnabled) { + if (Config.buy_greater_or_equal_sell()) { + if (buyPrice < sellPrice) { + p.sendMessage(Config.buyPrice_too_low(sellPrice)); + return; + } + } + } + + + ItemStack itemStack = new ItemStack(p.getItemInHand().getType(), amount, p.getItemInHand().getDurability()); + itemStack.setItemMeta(p.getItemInHand().getItemMeta()); + + if (Enchantment.DURABILITY.canEnchantItem(itemStack)) { + if (itemStack.getDurability() > 0) { + p.sendMessage(Config.cannot_sell_broken_item()); + return; + } + } + + ClickType.addPlayerClickType(p, new ClickType(EnumClickType.CREATE, itemStack, buyPrice, sellPrice, infinite)); + p.sendMessage(Config.click_chest_to_create()); + + } + + private void remove(Player p) { + p.sendMessage(Config.click_chest_to_remove()); + ClickType.addPlayerClickType(p, new ClickType(EnumClickType.REMOVE)); + } + + private void info(Player p) { + p.sendMessage(Config.click_chest_for_info()); + ClickType.addPlayerClickType(p, new ClickType(EnumClickType.INFO)); + } + + private void sendBasicHelpMessage(Player player) { + + player.sendMessage(ChatColor.GREEN + "/" + Config.main_command_name() + " create [infinite|normal]- " + Config.cmdDesc_create()); + player.sendMessage(ChatColor.GREEN + "/" + Config.main_command_name() + " remove - " + Config.cmdDesc_remove()); + player.sendMessage(ChatColor.GREEN + "/" + Config.main_command_name() + " info - " + Config.cmdDesc_info()); + player.sendMessage(ChatColor.GREEN + "/" + Config.main_command_name() + " reload - " + Config.cmdDesc_reload()); + player.sendMessage(ChatColor.GREEN + "/" + Config.main_command_name() + " update - " + Config.cmdDesc_update()); + + } + +} diff --git a/de/epiceric/shopchest/ShopChest.java b/de/epiceric/shopchest/ShopChest.java new file mode 100644 index 0000000..4254686 --- /dev/null +++ b/de/epiceric/shopchest/ShopChest.java @@ -0,0 +1,230 @@ +package de.epiceric.shopchest; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.logging.Logger; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.java.JavaPlugin; + +import de.epiceric.shopchest.config.Config; +import de.epiceric.shopchest.event.InteractShop; +import de.epiceric.shopchest.event.NotifyUpdate; +import de.epiceric.shopchest.event.ProtectChest; +import de.epiceric.shopchest.event.RegenerateShopItem; +import de.epiceric.shopchest.event.UpdateHolograms; +import de.epiceric.shopchest.shop.Hologram; +import de.epiceric.shopchest.shop.Shop; +import de.epiceric.shopchest.utils.JsonBuilder; +import de.epiceric.shopchest.utils.JsonBuilder.ClickAction; +import de.epiceric.shopchest.utils.JsonBuilder.HoverAction; +import de.epiceric.shopchest.utils.Metrics; +import de.epiceric.shopchest.utils.ShopUtils; +import de.epiceric.shopchest.utils.UpdateChecker; +import de.epiceric.shopchest.utils.Utils; +import net.milkbowl.vault.economy.Economy; +import net.milkbowl.vault.permission.Permission; +import net.minecraft.server.v1_8_R3.EntityArmorStand; + +public class ShopChest extends JavaPlugin{ + + private static ShopChest instance; + + public File shopChestsFile; + public YamlConfiguration shopChests; + + public static Logger logger = Logger.getLogger("Minecraft"); + public static Economy econ = null; + public static Permission perm = null; + + public static boolean isUpdateNeeded = false; + public static String latestVersion = ""; + public static String downloadLink = ""; + + public static ShopChest getInstance() { + return instance; + } + + + private boolean setupEconomy() { + + RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(Economy.class); + if (rsp == null) { + return false; + } + econ = rsp.getProvider(); + return econ != null; + } + + + private boolean setupPermissions() { + RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(Permission.class); + perm = rsp.getProvider(); + return perm != null; + } + + + @Override + public void onLoad() { + getLogger().info(Utils.getVersion()); + } + + @Override + public void onEnable() { + + if (getServer().getPluginManager().getPlugin("Vault") == null) { + logger.severe("[ShopChest] Could not find plugin 'Vault'!"); + getServer().getPluginManager().disablePlugin(this); + return; + } + + if (!setupEconomy() ) { + logger.severe("[ShopChest] Could not find any Vault dependency!"); + getServer().getPluginManager().disablePlugin(this); + return; + } + + try { + Metrics metrics = new Metrics(this); + metrics.start(); + } catch (IOException e) { + logger.severe("[ShopChest] [PluginMetrics] Could not submit stats."); + } + + setupPermissions(); + + instance = this; + reloadConfig(); + saveDefaultConfig(); + + UpdateChecker uc = new UpdateChecker(this, getDescription().getWebsite()); + logger.info("[ShopChest] Checking for Updates"); + if(uc.updateNeeded()) { + latestVersion = uc.getVersion(); + downloadLink = uc.getLink(); + isUpdateNeeded = true; + Bukkit.getConsoleSender().sendMessage("[ShopChest] " + ChatColor.GOLD + "New version available: " + ChatColor.RED + latestVersion); + } else { + logger.info("[ShopChest] No new version available"); + isUpdateNeeded = false; + } + + if (isUpdateNeeded) { + for (Player p : getServer().getOnlinePlayers()) { + if (p.isOp() || perm.has(p, "shopchest.notification.update")) { + JsonBuilder jb = new JsonBuilder(Config.update_available(latestVersion)).withHoverEvent(HoverAction.SHOW_TEXT, Config.click_to_download()).withClickEvent(ClickAction.OPEN_URL, downloadLink); + jb.sendJson(p); + + } + } + } + + + File shopChestDataFolder = new File(getDataFolder(), "data"); + shopChestDataFolder.mkdirs(); + + shopChestsFile = new File(getDataFolder(), "/data/shops.yml"); + if (!shopChestsFile.exists()) + try {shopChestsFile.createNewFile();} catch (IOException e) {e.printStackTrace();} + + File itemNamesFile = new File(getDataFolder(), "item_names.txt"); + + if (!itemNamesFile.exists()) + try {itemNamesFile.createNewFile();} catch (IOException e) {e.printStackTrace();} + + copy(getResource("item_names"), itemNamesFile); + + shopChests = YamlConfiguration.loadConfiguration(shopChestsFile); + + + try { + Commands.registerCommand(new Commands(this, Config.main_command_name(), "Manage Shops.", "", new ArrayList()), this); + } catch (Exception e) { + e.printStackTrace(); + } + + initializeShops(); + + getServer().getPluginManager().registerEvents(new UpdateHolograms(), this); + getServer().getPluginManager().registerEvents(new RegenerateShopItem(), this); + getServer().getPluginManager().registerEvents(new InteractShop(this), this); + getServer().getPluginManager().registerEvents(new NotifyUpdate(), this); + getServer().getPluginManager().registerEvents(new ProtectChest(), this); + + + } + + + @Override + public void onDisable() { + + for (Shop shop : ShopUtils.getShops()) { + Hologram hologram = shop.getHologram(); + + for (Player p : getServer().getOnlinePlayers()) { + hologram.hidePlayer(p); + } + + for (Object o : hologram.getEntities()) { + EntityArmorStand e = (EntityArmorStand) o; + e.getWorld().removeEntity(e); + } + + + shop.getItem().remove(); + } + + } + + private void initializeShops() { + + Bukkit.getConsoleSender().sendMessage("[ShopChest] Found " + String.valueOf(shopChests.getKeys(false).size()) + " Shops"); + + for (String key : shopChests.getKeys(false)) { + + OfflinePlayer vendor = shopChests.getOfflinePlayer(key + ".vendor"); + int locationX = shopChests.getInt(key + ".location.x"); + int locationY = shopChests.getInt(key + ".location.y"); + int locationZ = shopChests.getInt(key + ".location.z"); + World locationWorld = getServer().getWorld(shopChests.getString(key + ".location.world")); + Location location = new Location(locationWorld, locationX, locationY, locationZ); + ItemStack product = shopChests.getItemStack(key + ".product"); + double buyPrice = shopChests.getDouble(key + ".price.buy"); + double sellPrice = shopChests.getDouble(key + ".price.sell"); + boolean infinite = shopChests.getBoolean(key + ".infinite"); + + ShopUtils.addShop(new Shop(this, vendor, product, location, buyPrice, sellPrice, infinite)); + + } + + } + + public static void copy(InputStream in, File file) { + try { + OutputStream out = new FileOutputStream(file); + byte[] buf = new byte[1024]; + int len; + while((len=in.read(buf))>0){ + out.write(buf,0,len); + } + out.close(); + in.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + +} diff --git a/de/epiceric/shopchest/config/Config.java b/de/epiceric/shopchest/config/Config.java new file mode 100644 index 0000000..a762dcd --- /dev/null +++ b/de/epiceric/shopchest/config/Config.java @@ -0,0 +1,126 @@ +package de.epiceric.shopchest.config; + +import java.util.HashSet; +import java.util.Set; + +import de.epiceric.shopchest.ShopChest; + +public class Config { + + private static ShopChest plugin = ShopChest.getInstance(); + + public static Set minimum_prices() {return (plugin.getConfig().getConfigurationSection("minimum-prices") == null) ? new HashSet() : plugin.getConfig().getConfigurationSection("minimum-prices").getKeys(true);} + public static boolean buy_greater_or_equal_sell() {return plugin.getConfig().getBoolean("buy-greater-or-equal-sell");} + public static double maximal_distance() {return plugin.getConfig().getDouble("maximal-distance");} + + public static String main_command_name() { return plugin.getConfig().getString("main-command-name");} + public static String currency_symbol() { return plugin.getConfig().getString("currency-symbol").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String shop_created() { return plugin.getConfig().getString("messages.shop-created").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String chest_already_shop() { return plugin.getConfig().getString("messages.chest-already-shop").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String shop_removed() { return plugin.getConfig().getString("messages.shop-removed").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String chest_no_shop() { return plugin.getConfig().getString("messages.chest-no-shop").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String block_no_chest() { return plugin.getConfig().getString("messages.block-no-chest").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String not_enough_inventory_space() { return plugin.getConfig().getString("messages.not-enough-inventory-space").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String chest_not_enough_inventory_space() { return plugin.getConfig().getString("messages.chest-not-enough-inventory-space").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String not_enough_money() { return plugin.getConfig().getString("messages.not-enough-money").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String not_enough_items() { return plugin.getConfig().getString("messages.not-enough-items").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String vendor_not_enough_money() { return plugin.getConfig().getString("messages.vendor-not-enough-money").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String out_of_stock() { return plugin.getConfig().getString("messages.out-of-stock").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String amount_and_price_not_number() { return plugin.getConfig().getString("messages.amount-and-price-not-number").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String no_item_in_hand() { return plugin.getConfig().getString("messages.no-item-in-hand").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String click_chest_to_create() { return plugin.getConfig().getString("messages.click-chest-to-create-shop").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String click_chest_to_remove() { return plugin.getConfig().getString("messages.click-chest-to-remove-shop").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String click_chest_for_info() { return plugin.getConfig().getString("messages.click-chest-for-info").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String cmdDesc_create() { return plugin.getConfig().getString("messages.command-description.create").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String cmdDesc_remove() { return plugin.getConfig().getString("messages.command-description.remove").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String cmdDesc_info() { return plugin.getConfig().getString("messages.command-description.info").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String cmdDesc_reload() { return plugin.getConfig().getString("messages.command-description.reload").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String cmdDesc_update() { return plugin.getConfig().getString("messages.command-description.update").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String shopInfo_isInfinite() { return plugin.getConfig().getString("messages.shop-info.is-infinite").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");}; + public static String shopInfo_isNormal() { return plugin.getConfig().getString("messages.shop-info.is-not-infinite").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");}; + public static String noPermission_create() { return plugin.getConfig().getString("messages.no-permission.create").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String noPermission_createInfinite() { return plugin.getConfig().getString("messages.no-permission.create-infinite").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String noPermission_openOthers() { return plugin.getConfig().getString("messages.no-permission.open-others").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String noPermission_removeOthers() { return plugin.getConfig().getString("messages.no-permission.remove-others").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String noPermission_buy() { return plugin.getConfig().getString("messages.no-permission.buy").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String noPermission_sell() { return plugin.getConfig().getString("messages.no-permission.sell").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String noPermission_reload() { return plugin.getConfig().getString("messages.no-permission.reload").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String noPermission_update() { return plugin.getConfig().getString("messages.no-permission.update").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String cannot_break_shop() { return plugin.getConfig().getString("messages.cannot-break-shop").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String cannot_sell_broken_item() { return plugin.getConfig().getString("messages.cannot-sell-broken-item").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String disabled() {return plugin.getConfig().getString("messages.shop-info.disabled").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String buy_and_sell_disabled() {return plugin.getConfig().getString("messages.buy-and-sell-disabled").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String selling_disabled() {return plugin.getConfig().getString("messages.selling-disabled").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String buying_disabled() {return plugin.getConfig().getString("messages.buying-disabled").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String checking_update() {return plugin.getConfig().getString("messages.update.checking").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String no_new_update() {return plugin.getConfig().getString("messages.update.no-update").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + public static String click_to_download() {return plugin.getConfig().getString("messages.update.click-to-download").replaceAll("(&([a-f0-9k-or]))", "\u00A7$2");} + + public static String reloaded_shops(int amount) { + return plugin.getConfig().getString("messages.reloaded-shops").replace(Regex.amount, String.valueOf(amount)).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + + public static String opened_shop(String vendor) { + return plugin.getConfig().getString("messages.opened-shop").replace(Regex.vendor, vendor).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + + public static String buyPrice_too_low(double minPrice) { + return plugin.getConfig().getString("messages.buy-price-too-low").replace(Regex.minPrice, String.valueOf(minPrice)).replace(Regex.currencySymbol, currency_symbol()).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + + public static String sellPrice_too_low(double minPrice) { + return plugin.getConfig().getString("messages.sell-price-too-low").replace(Regex.minPrice, String.valueOf(minPrice)).replace(Regex.currencySymbol, currency_symbol()).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + + public static String update_available(String version) { + return plugin.getConfig().getString("messages.update.update-available").replace(Regex.version, version); + } + + public static String hologram_buy_sell(double buyPrice, double sellPrice) { + return plugin.getConfig().getString("messages.hologram.buy-and-sell").replace(Regex.currencySymbol, currency_symbol()).replace(Regex.buyPrice, String.valueOf(buyPrice)).replace(Regex.sellPrice, String.valueOf(sellPrice)).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + + public static String hologram_buy(double buyPrice) { + return plugin.getConfig().getString("messages.hologram.only-buy").replace(Regex.currencySymbol, currency_symbol()).replace(Regex.buyPrice, String.valueOf(buyPrice)).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + + public static String hologram_sell(double sellPrice) { + return plugin.getConfig().getString("messages.hologram.only-sell").replace(Regex.currencySymbol, currency_symbol()).replace(Regex.sellPrice, String.valueOf(sellPrice)).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + + public static String error_occurred(String error) { + return plugin.getConfig().getString("messages.error-occurred").replace(Regex.error, error).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + + public static String shopInfo_vendor(String vendor) { + return plugin.getConfig().getString("messages.shop-info.vendor").replace(Regex.vendor, vendor).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + + public static String shopInfo_product(int amount, String itemName) { + return plugin.getConfig().getString("messages.shop-info.product").replace(Regex.amount, String.valueOf(amount)).replace(Regex.itemName, itemName).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + + public static String shopInfo_enchantment(String enchantment) { + return plugin.getConfig().getString("messages.shop-info.enchantments").replace(Regex.enchantment, enchantment).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + + public static String shopInfo_price(double buyPrice, double sellPrice) { + if ((buyPrice <= 0) && (sellPrice > 0)) { + return plugin.getConfig().getString("messages.shop-info.price").replace(Regex.currencySymbol, currency_symbol()).replace(Regex.buyPrice + currency_symbol(), disabled()).replace(Regex.sellPrice, String.valueOf(sellPrice)).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } else if ((sellPrice <= 0) && (buyPrice > 0)) { + return plugin.getConfig().getString("messages.shop-info.price").replace(Regex.currencySymbol, currency_symbol()).replace(Regex.buyPrice, String.valueOf(buyPrice)).replace(Regex.sellPrice + currency_symbol(), disabled()).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } else if ((sellPrice > 0) && (buyPrice > 0)) { + return plugin.getConfig().getString("messages.shop-info.price").replace(Regex.currencySymbol, currency_symbol()).replace(Regex.buyPrice, String.valueOf(buyPrice)).replace(Regex.sellPrice, String.valueOf(sellPrice)).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } else { + return plugin.getConfig().getString("messages.shop-info.price").replace(Regex.currencySymbol, currency_symbol()).replace(Regex.buyPrice + currency_symbol(), disabled()).replace(Regex.sellPrice + currency_symbol(), disabled()).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + } + + public static String buy_success(int amount, String itemName, double buyPrice, String vendor) { + return plugin.getConfig().getString("messages.buy-success").replace(Regex.currencySymbol, currency_symbol()).replace(Regex.amount, String.valueOf(amount)).replace(Regex.itemName, itemName).replace(Regex.buyPrice, String.valueOf(buyPrice)).replace(Regex.vendor, vendor).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } + + public static String sell_success(int amount, String itemName, double sellPrice, String vendor) { + return plugin.getConfig().getString("messages.sell-success").replace(Regex.currencySymbol, currency_symbol()).replace(Regex.amount, String.valueOf(amount)).replace(Regex.itemName, itemName).replace(Regex.sellPrice, String.valueOf(sellPrice)).replace(Regex.vendor, vendor).replaceAll("(&([a-f0-9k-or]))", "\u00A7$2"); + } +} diff --git a/de/epiceric/shopchest/config/Regex.java b/de/epiceric/shopchest/config/Regex.java new file mode 100644 index 0000000..b2abda1 --- /dev/null +++ b/de/epiceric/shopchest/config/Regex.java @@ -0,0 +1,17 @@ +package de.epiceric.shopchest.config; + +public class Regex { + + public static String vendor = "%VENDOR%"; + public static String amount = "%AMOUNT%"; + public static String itemName = "%ITEMNAME%"; + public static String price = "%PRICE%"; + public static String currencySymbol = "%CURRENCY-SYMBOL%"; + public static String error = "%ERROR%"; + public static String enchantment = "%ENCHANTMENT%"; + public static String minPrice = "%MIN-PRICE%"; + public static String version = "%VERSION%"; + public static String buyPrice = "%BUY-PRICE%"; + public static String sellPrice = "%SELL-PRICE%"; + +} diff --git a/de/epiceric/shopchest/event/InteractShop.java b/de/epiceric/shopchest/event/InteractShop.java new file mode 100644 index 0000000..36f745b --- /dev/null +++ b/de/epiceric/shopchest/event/InteractShop.java @@ -0,0 +1,426 @@ +package de.epiceric.shopchest.event; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import de.epiceric.shopchest.ShopChest; +import de.epiceric.shopchest.config.Config; +import de.epiceric.shopchest.shop.Shop; +import de.epiceric.shopchest.utils.ClickType; +import de.epiceric.shopchest.utils.EnchantmentNames; +import de.epiceric.shopchest.utils.ItemNames; +import de.epiceric.shopchest.utils.ShopUtils; +import de.epiceric.shopchest.utils.Utils; +import net.milkbowl.vault.economy.Economy; +import net.milkbowl.vault.economy.EconomyResponse; +import net.milkbowl.vault.permission.Permission; + +public class InteractShop implements Listener{ + + private ShopChest plugin; + private Permission perm = ShopChest.perm; + private Economy econ = ShopChest.econ; + private YamlConfiguration shopChests; + + public InteractShop(ShopChest plugin) { + this.plugin = plugin; + shopChests = plugin.shopChests; + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent e) { + + Block b = e.getClickedBlock(); + Player p = e.getPlayer(); + + if (e.getAction() == Action.RIGHT_CLICK_BLOCK || e.getAction() == Action.LEFT_CLICK_BLOCK) { + + if (b.getType().equals(Material.CHEST) || b.getType().equals(Material.TRAPPED_CHEST)) { + + if (e.getAction() == Action.RIGHT_CLICK_BLOCK) { + + if (ClickType.getPlayerClickType(p) != null) { + + switch (ClickType.getPlayerClickType(p).getClickType()) { + + case CREATE: + e.setCancelled(true); + + if (!ShopUtils.isShop(b.getLocation())) { + ClickType clickType = ClickType.getPlayerClickType(p); + ItemStack product = clickType.getProduct(); + double buyPrice = clickType.getBuyPrice(); + double sellPrice = clickType.getSellPrice(); + boolean infinite = clickType.isInfinite(); + + create(p, b.getLocation(), product, buyPrice, sellPrice, infinite); + } else { + p.sendMessage(Config.chest_already_shop()); + } + + ClickType.removePlayerClickType(p); + break; + + case INFO: + e.setCancelled(true); + + if (ShopUtils.isShop(b.getLocation())) { + + Shop shop = ShopUtils.getShop(b.getLocation()); + info(p, shop); + + } else { + p.sendMessage(Config.chest_no_shop()); + } + + ClickType.removePlayerClickType(p); + break; + + case REMOVE: + e.setCancelled(true); + + if (ShopUtils.isShop(b.getLocation())) { + + Shop shop = ShopUtils.getShop(b.getLocation()); + + if (shop.getVendor().equals(p) || perm.has(p, "shopchest.removeOther")) { + remove(p, shop); + } else { + p.sendMessage(Config.noPermission_removeOthers()); + } + + } else { + p.sendMessage(Config.chest_no_shop()); + } + + ClickType.removePlayerClickType(p); + break; + + } + + } else { + + if (ShopUtils.isShop(b.getLocation())) { + e.setCancelled(true); + Shop shop = ShopUtils.getShop(b.getLocation()); + + if (p.equals(shop.getVendor())) { + e.setCancelled(false); + return; + } else { + + if (p.isSneaking()) { + if (perm.has(p, "shopchest.openOther")) { + p.sendMessage(Config.opened_shop(shop.getVendor().getName())); + e.setCancelled(false); + + } else { + p.sendMessage(Config.noPermission_openOthers()); + e.setCancelled(true); + } + } else { + + if (shop.getBuyPrice() > 0) { + e.setCancelled(true); + + if (perm.has(p, "shopchest.buy")) { + if (shop.isInfinite()) { + buy(p, shop); + } else { + Chest c = (Chest) b.getState(); + if (Utils.getAmount(c.getInventory(), shop.getProduct().clone().getType(), shop.getProduct().clone().getDurability(), shop.getProduct().getItemMeta()) >= shop.getProduct().getAmount()) { + buy(p, shop); + } else { + p.sendMessage(Config.out_of_stock()); + } + } + } else { + p.sendMessage(Config.noPermission_buy()); + } + } else { + p.sendMessage(Config.buying_disabled()); + } + } + + } + + } + + } + + + + } else if (e.getAction() == Action.LEFT_CLICK_BLOCK) { + + if (ShopUtils.isShop(b.getLocation())) { + Shop shop = ShopUtils.getShop(b.getLocation()); + + if (!p.equals(shop.getVendor())) { + if (shop.getSellPrice() > 0) { + if (perm.has(p, "shopchest.sell")) { + if (Utils.getAmount(p.getInventory(), shop.getProduct().getType(), shop.getProduct().getDurability(), shop.getProduct().getItemMeta()) >= shop.getProduct().getAmount()) { + sell(p, shop); + } else { + p.sendMessage(Config.not_enough_items()); + } + } else { + p.sendMessage(Config.noPermission_sell()); + } + } else { + p.sendMessage(Config.selling_disabled()); + } + } + + } + + } + + } + + } else { + if (ClickType.getPlayerClickType(p) != null) ClickType.removePlayerClickType(p); + } + + } + + private void create(Player executor, Location location, ItemStack product, double buyPrice, double sellPrice, boolean infinite) { + + Shop shop = new Shop(plugin, executor, product, location, buyPrice, sellPrice, infinite); + + shopChests.set(ShopUtils.getConfigTitle(location) + ".vendor", executor); + shopChests.set(ShopUtils.getConfigTitle(location) + ".location.world", location.getWorld().getName()); + shopChests.set(ShopUtils.getConfigTitle(location) + ".location.x", location.getBlockX()); + shopChests.set(ShopUtils.getConfigTitle(location) + ".location.y", location.getBlockY()); + shopChests.set(ShopUtils.getConfigTitle(location) + ".location.z", location.getBlockZ()); + shopChests.set(ShopUtils.getConfigTitle(location) + ".product", product); + shopChests.set(ShopUtils.getConfigTitle(location) + ".price.buy", buyPrice); + shopChests.set(ShopUtils.getConfigTitle(location) + ".price.sell", sellPrice); + shopChests.set(ShopUtils.getConfigTitle(location) + ".infinite", infinite); + + try {shopChests.save(plugin.shopChestsFile);} catch (IOException ex) {ex.printStackTrace();} + + ShopUtils.addShop(shop); + executor.sendMessage(Config.shop_created()); + + for (Player p : Bukkit.getOnlinePlayers()) { + Bukkit.getPluginManager().callEvent(new PlayerMoveEvent(p, p.getLocation(), p.getLocation())); + } + + } + + private void remove(Player executor, Shop shop) { + + shop.getItem().remove(); + ShopUtils.removeShop(shop); + + shopChests.set(ShopUtils.getConfigTitle(shop.getLocation()), null); + try {shopChests.save(plugin.shopChestsFile);} catch (IOException ex) {ex.printStackTrace();} + + for (Player player : plugin.getServer().getOnlinePlayers()) { + shop.getHologram().hidePlayer(player); + } + + executor.sendMessage(Config.shop_removed()); + + } + + private void info(Player executor, Shop shop) { + + String vendor = Config.shopInfo_vendor(shop.getVendor().getName()); + String product = Config.shopInfo_product(shop.getProduct().getAmount(), ItemNames.lookup(shop.getProduct())); + String enchantmentString = ""; + String price = Config.shopInfo_price(shop.getBuyPrice(), shop.getSellPrice()); + String infinite = (shop.isInfinite() ? Config.shopInfo_isInfinite() : Config.shopInfo_isNormal()); + + + Map enchantmentMap = shop.getProduct().getItemMeta().getEnchants(); + Enchantment[] enchantments = enchantmentMap.keySet().toArray(new Enchantment[enchantmentMap.size()]); + + for (int i = 0; i < enchantments.length; i++) { + + Enchantment enchantment = enchantments[i]; + + if (i == enchantments.length - 1) { + enchantmentString += EnchantmentNames.lookup(enchantment, enchantmentMap.get(enchantment)); + } else { + enchantmentString += EnchantmentNames.lookup(enchantment, enchantmentMap.get(enchantment)) + ", "; + } + + } + + executor.sendMessage(" "); + executor.sendMessage(vendor); + executor.sendMessage(product); + if (enchantmentString.length() > 0) executor.sendMessage(Config.shopInfo_enchantment(enchantmentString)); + executor.sendMessage(price); + executor.sendMessage(infinite); + executor.sendMessage(" "); + + + } + + private void buy(Player executor, Shop shop) { + + if (econ.getBalance(executor) >= shop.getBuyPrice()) { + + Block b = shop.getLocation().getBlock(); + Chest c = (Chest) b.getState(); + + HashMap slotFree = new HashMap<>(); + ItemStack product = shop.getProduct().clone(); + Inventory inventory = executor.getInventory(); + + for (int i = 0; i < 36; i++) { + + ItemStack item = inventory.getItem(i); + if (item == null) { + slotFree.put(i, product.getMaxStackSize()); + } else { + if ((item.getType().equals(product.getType())) && (item.getDurability() == product.getDurability()) && (item.getItemMeta().equals(product.getItemMeta())) && (item.getData().equals(product.getData()))) { + int amountInSlot = item.getAmount(); + int amountToFullStack = product.getMaxStackSize() - amountInSlot; + slotFree.put(i, amountToFullStack); + } + } + + } + + int leftAmount = product.getAmount(); + + int freeAmount = 0; + for (int value : slotFree.values()) { + freeAmount += value; + } + + EconomyResponse r = econ.withdrawPlayer(executor, shop.getBuyPrice()); + EconomyResponse r2 = econ.depositPlayer(shop.getVendor(), shop.getBuyPrice()); + + if (r.transactionSuccess()) { + if (r2.transactionSuccess()) { + if (freeAmount >= leftAmount) { + for (int slot : slotFree.keySet()) { + if (leftAmount >= 0) { + int amountInSlot = -(slotFree.get(slot) - product.getMaxStackSize()); + if (amountInSlot == -0) amountInSlot = 0; + for (int i = amountInSlot; i < product.getMaxStackSize() + 1; i++) { + if (leftAmount > 0) { + ItemStack boughtProduct = new ItemStack(product.clone().getType(), 1, product.clone().getDurability()); + boughtProduct.setItemMeta(product.clone().getItemMeta()); + if (!shop.isInfinite()) c.getInventory().removeItem(boughtProduct); + inventory.addItem(boughtProduct); + executor.updateInventory(); + leftAmount--; + } else if (leftAmount == 0) { + executor.sendMessage(Config.buy_success(product.getAmount(), ItemNames.lookup(product), shop.getBuyPrice(), shop.getVendor().getName())); + return; + } + } + } + } + } else { + executor.sendMessage(Config.not_enough_inventory_space()); + } + } else { + executor.sendMessage(Config.error_occurred(r2.errorMessage)); + } + } else { + executor.sendMessage(Config.error_occurred(r.errorMessage)); + } + + } else { + executor.sendMessage(Config.not_enough_money()); + } + + } + + private void sell(Player executor, Shop shop) { + + if (econ.getBalance(shop.getVendor()) >= shop.getSellPrice()) { + + Block block = shop.getLocation().getBlock(); + Chest chest = (Chest) block.getState(); + + HashMap slotFree = new HashMap<>(); + ItemStack product = shop.getProduct().clone(); + Inventory inventory = chest.getInventory(); + + for (int i = 0; i < chest.getInventory().getSize(); i++) { + + ItemStack item = inventory.getItem(i); + if (item == null) { + slotFree.put(i, product.getMaxStackSize()); + } else { + if ((item.getType().equals(product.getType())) && (item.getDurability() == product.getDurability()) && (item.getItemMeta().equals(product.getItemMeta())) && (item.getData().equals(product.getData()))) { + int amountInSlot = item.getAmount(); + int amountToFullStack = product.getMaxStackSize() - amountInSlot; + slotFree.put(i, amountToFullStack); + } + } + + } + + int leftAmount = product.getAmount(); + + int freeAmount = 0; + for (int value : slotFree.values()) { + freeAmount += value; + } + + EconomyResponse r = econ.withdrawPlayer(shop.getVendor(), shop.getSellPrice()); + EconomyResponse r2 = econ.depositPlayer(executor, shop.getSellPrice()); + + if (r.transactionSuccess()) { + if (r2.transactionSuccess()) { + if (freeAmount >= leftAmount) { + for (int slot : slotFree.keySet()) { + if (leftAmount >= 0) { + int amountInSlot = -(slotFree.get(slot) - product.getMaxStackSize()); + if (amountInSlot == -0) amountInSlot = 0; + for (int i = amountInSlot; i < product.getMaxStackSize() + 1; i++) { + if (leftAmount > 0) { + ItemStack boughtProduct = new ItemStack(product.clone().getType(), 1, product.clone().getDurability()); + boughtProduct.setItemMeta(product.clone().getItemMeta()); + if (!shop.isInfinite()) inventory.addItem(boughtProduct); + executor.getInventory().removeItem(boughtProduct); + executor.updateInventory(); + leftAmount--; + } else if (leftAmount == 0) { + executor.sendMessage(Config.sell_success(product.getAmount(), ItemNames.lookup(product), shop.getSellPrice(), shop.getVendor().getName())); + return; + } + } + } + } + } else { + executor.sendMessage(Config.chest_not_enough_inventory_space()); + } + } else { + executor.sendMessage(Config.error_occurred(r2.errorMessage)); + } + } else { + executor.sendMessage(Config.error_occurred(r.errorMessage)); + } + } else { + executor.sendMessage(Config.vendor_not_enough_money()); + } + + } + +} diff --git a/de/epiceric/shopchest/event/NotifyUpdate.java b/de/epiceric/shopchest/event/NotifyUpdate.java new file mode 100644 index 0000000..5d90d74 --- /dev/null +++ b/de/epiceric/shopchest/event/NotifyUpdate.java @@ -0,0 +1,37 @@ +package de.epiceric.shopchest.event; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +import de.epiceric.shopchest.ShopChest; +import de.epiceric.shopchest.config.Config; +import de.epiceric.shopchest.utils.JsonBuilder; +import de.epiceric.shopchest.utils.JsonBuilder.ClickAction; +import de.epiceric.shopchest.utils.JsonBuilder.HoverAction; +import net.milkbowl.vault.permission.Permission; + +public class NotifyUpdate implements Listener { + + private Permission perm = ShopChest.perm; + + public NotifyUpdate() {} + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent e) { + + Player p = e.getPlayer(); + + if (ShopChest.isUpdateNeeded) { + if (p.isOp() || perm.has(p, "shopchest.notification.update")) { + String version = ShopChest.latestVersion; + String link = ShopChest.downloadLink; + JsonBuilder jb = new JsonBuilder(Config.update_available(version)).withHoverEvent(HoverAction.SHOW_TEXT, Config.click_to_download()).withClickEvent(ClickAction.OPEN_URL, link); + jb.sendJson(p); + } + } + + } + +} diff --git a/de/epiceric/shopchest/event/ProtectChest.java b/de/epiceric/shopchest/event/ProtectChest.java new file mode 100644 index 0000000..ae094a6 --- /dev/null +++ b/de/epiceric/shopchest/event/ProtectChest.java @@ -0,0 +1,22 @@ +package de.epiceric.shopchest.event; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; + +import de.epiceric.shopchest.config.Config; +import de.epiceric.shopchest.utils.ShopUtils; + +public class ProtectChest implements Listener { + + public ProtectChest() {} + + @EventHandler + public void onBlockBreak(BlockBreakEvent e) { + if (ShopUtils.isShop(e.getBlock().getLocation())) { + e.setCancelled(true); + e.getPlayer().sendMessage(Config.cannot_break_shop()); + } + } + +} diff --git a/de/epiceric/shopchest/event/RegenerateShopItem.java b/de/epiceric/shopchest/event/RegenerateShopItem.java new file mode 100644 index 0000000..ad4a738 --- /dev/null +++ b/de/epiceric/shopchest/event/RegenerateShopItem.java @@ -0,0 +1,27 @@ +package de.epiceric.shopchest.event; + + +import org.bukkit.entity.Item; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.ItemDespawnEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; + +public class RegenerateShopItem implements Listener{ + + public RegenerateShopItem() {} + + @EventHandler(priority = EventPriority.HIGH) + public void onItemDespawn(ItemDespawnEvent e) { + Item item = e.getEntity(); + if (item.hasMetadata("shopItem")) e.setCancelled(true); + } + + @EventHandler(priority = EventPriority.HIGH) + public void onPlayerPickUpItem(PlayerPickupItemEvent e) { + if (e.getItem().hasMetadata("shopItem")) e.setCancelled(true); + } + + +} diff --git a/de/epiceric/shopchest/event/UpdateHolograms.java b/de/epiceric/shopchest/event/UpdateHolograms.java new file mode 100644 index 0000000..241c6ba --- /dev/null +++ b/de/epiceric/shopchest/event/UpdateHolograms.java @@ -0,0 +1,50 @@ +package de.epiceric.shopchest.event; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerMoveEvent; + +import de.epiceric.shopchest.config.Config; +import de.epiceric.shopchest.shop.Shop; +import de.epiceric.shopchest.utils.ShopUtils; + +public class UpdateHolograms implements Listener{ + + public UpdateHolograms() {} + + @EventHandler + public void onPlayerMove(PlayerMoveEvent e) { + + Player p = e.getPlayer(); + Location playerLocation = p.getLocation(); + + for (Shop shop : ShopUtils.getShops()) { + + Location shopLocation = shop.getLocation(); + + if (playerLocation.getWorld().equals(shopLocation.getWorld())) { + + if (playerLocation.distance(shop.getHologram().getLocation()) <= Config.maximal_distance()) { + + if (!shop.getHologram().isVisible(p)) { + shop.getHologram().showPlayer(p); + } + + } else { + + if (shop.getHologram().isVisible(p)) { + shop.getHologram().hidePlayer(p); + } + + } + + } + + } + + + } + +} diff --git a/de/epiceric/shopchest/shop/Hologram.java b/de/epiceric/shopchest/shop/Hologram.java new file mode 100644 index 0000000..f9ed3d9 --- /dev/null +++ b/de/epiceric/shopchest/shop/Hologram.java @@ -0,0 +1,89 @@ +package de.epiceric.shopchest.shop; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; + +import net.minecraft.server.v1_8_R3.EntityArmorStand; +import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy; +import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving; + +public class Hologram { + + private List entitylist = new ArrayList(); + private String[] text; + private Location location; + private double DISTANCE = 0.25D; + int count; + + private HashMap visible = new HashMap(); + + public Hologram(String[] text, Location location) { + this.text = text; + this.location = location; + create(); + } + + public Hologram(String text, Location location) { + this.text = new String[] {text}; + this.location = location; + create(); + } + + public String getText(int line) { + return text[line]; + } + + public Location getLocation() { + return location; + } + + public List getEntities() { + return entitylist; + } + + public void showPlayer(OfflinePlayer p) { + for (EntityArmorStand armor : entitylist) { + PacketPlayOutSpawnEntityLiving packet = new PacketPlayOutSpawnEntityLiving(armor); + ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packet); + } + visible.put(p, true); + } + + public void hidePlayer(OfflinePlayer p) { + for (EntityArmorStand armor : entitylist) { + PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(armor.getId()); + ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packet); + + } + visible.put(p, false); + } + + public boolean isVisible(OfflinePlayer p) { + if (visible.containsKey(p)) return visible.get(p); else return false; + } + + private void create() { + for (String text : this.text) { + EntityArmorStand entity = new EntityArmorStand(((CraftWorld) this.location.getWorld()).getHandle(),this.location.getX(), this.location.getY(),this.location.getZ()); + entity.setCustomName(text); + entity.setCustomNameVisible(true); + entity.setInvisible(true); + entity.setGravity(false); + entitylist.add(entity); + this.location.subtract(0, this.DISTANCE, 0); + count++; + } + + for (int i = 0; i < count; i++) { + this.location.add(0, this.DISTANCE, 0); + } + this.count = 0; + } + +} diff --git a/de/epiceric/shopchest/shop/Shop.java b/de/epiceric/shopchest/shop/Shop.java new file mode 100644 index 0000000..582cbbd --- /dev/null +++ b/de/epiceric/shopchest/shop/Shop.java @@ -0,0 +1,176 @@ +package de.epiceric.shopchest.shop; + +import java.util.ArrayList; +import java.util.Random; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.block.DoubleChest; +import org.bukkit.entity.Item; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.util.Vector; + +import de.epiceric.shopchest.ShopChest; +import de.epiceric.shopchest.config.Config; +import de.epiceric.shopchest.utils.ItemNames; + +public class Shop { + + private ShopChest plugin; + private OfflinePlayer vendor; + private ItemStack product; + private Location location; + private Hologram hologram; + private Item item; + private double buyPrice; + private double sellPrice; + private boolean infinite; + + public Shop(ShopChest plugin, OfflinePlayer vendor, ItemStack product, Location location, double buyPrice, double sellPrice, boolean infinite) { + this.plugin = plugin; + this.vendor = vendor; + this.product = product; + this.location = location; + this.buyPrice = buyPrice; + this.sellPrice = sellPrice; + this.infinite = infinite; + this.hologram = createHologram(product, location, buyPrice, sellPrice); + this.item = createItem(product, location); + } + + public Item createItem(ItemStack product, Location location) { + + Item item; + Location itemLocation; + ItemStack itemStack; + + itemLocation = new Location(location.getWorld(), hologram.getLocation().getX(), location.getY() + 1, hologram.getLocation().getZ()); + itemStack = new ItemStack(product.getType(), 1, product.getDurability()); + itemStack.setItemMeta(product.getItemMeta()); + + ArrayList lore = new ArrayList(); + lore.add("This is an Item of ShopChest"); + lore.add("This text is just to prevent merging."); + lore.add("ID: " + String.valueOf(new Random().nextInt())); + + itemStack.getItemMeta().setLore(lore); + + item = location.getWorld().dropItem(itemLocation, itemStack); + item.setVelocity(new Vector(0, 0, 0)); + item.setMetadata("shopItem", new FixedMetadataValue(plugin, true)); + + return item; + + } + + public Hologram createHologram(ItemStack product, Location shopLocation, double buyPrice, double sellPrice) { + + boolean doubleChest; + + Hologram hologram; + + Chest[] chests = new Chest[2]; + + Block b = shopLocation.getBlock(); + + if (b.getType().equals(Material.CHEST)) { + + Chest c = (Chest) b.getState(); + InventoryHolder ih = c.getInventory().getHolder(); + + if (ih instanceof DoubleChest) { + DoubleChest dc = (DoubleChest) ih; + + Chest r = (Chest) dc.getRightSide(); + Chest l = (Chest) dc.getLeftSide(); + + chests[0] = r; + chests[1] = l; + + doubleChest = true; + + } else { + doubleChest = false; + chests[0] = c; + } + + } else { + return null; + } + + Location holoLocation; + String[] holoText = new String[2]; + + if (doubleChest) { + + Chest r = chests[0]; + Chest l = chests[1]; + + if (b.getLocation().equals(r.getLocation())) { + + if (r.getX() != l.getX()) holoLocation = new Location(b.getWorld(), b.getX(), b.getY() - 0.6, b.getZ() + 0.5); + else if (r.getZ() != l.getZ()) holoLocation = new Location(b.getWorld(), b.getX() + 0.5, b.getY() - 0.6, b.getZ()); + else holoLocation = new Location(b.getWorld(), b.getX() + 0.5, b.getY() - 0.6, b.getZ() + 0.5); + + } else { + + if (r.getX() != l.getX()) holoLocation = new Location(b.getWorld(), b.getX() + 1, b.getY() - 0.6, b.getZ() + 0.5); + else if (r.getZ() != l.getZ()) holoLocation = new Location(b.getWorld(), b.getX() + 0.5, b.getY() - 0.6, b.getZ() + 1); + else holoLocation = new Location(b.getWorld(), b.getX() + 0.5, b.getY() - 0.6, b.getZ() + 0.5); + + } + + } else holoLocation = new Location(b.getWorld(), b.getX() + 0.5, b.getY() - 0.6, b.getZ() + 0.5); + + + holoText[0] = String.valueOf(product.getAmount()) + " x " + ItemNames.lookup(product); + + if ((buyPrice <= 0) && (sellPrice > 0)) holoText[1] = Config.hologram_sell(sellPrice); + else if ((buyPrice > 0) && (sellPrice <= 0)) holoText[1] = Config.hologram_buy(buyPrice); + else if ((buyPrice > 0) && (sellPrice > 0)) holoText[1] = Config.hologram_buy_sell(buyPrice, sellPrice); + else holoText[1] = Config.hologram_buy_sell(buyPrice, sellPrice); + + hologram = new Hologram(holoText, holoLocation); + + return hologram; + + } + + public OfflinePlayer getVendor() { + return vendor; + } + + public ItemStack getProduct() { + return product; + } + + public Location getLocation() { + return location; + } + + public double getBuyPrice() { + return buyPrice; + } + + public double getSellPrice() { + return sellPrice; + } + + public boolean isInfinite() { + return infinite; + } + + public Hologram getHologram() { + return hologram; + } + + public Item getItem() { + return item; + } + +} diff --git a/de/epiceric/shopchest/utils/ClickType.java b/de/epiceric/shopchest/utils/ClickType.java new file mode 100644 index 0000000..066b32d --- /dev/null +++ b/de/epiceric/shopchest/utils/ClickType.java @@ -0,0 +1,69 @@ +package de.epiceric.shopchest.utils; + +import java.util.HashMap; + +import org.bukkit.OfflinePlayer; +import org.bukkit.inventory.ItemStack; + +public class ClickType { + + private static HashMap playerClickType = new HashMap<>(); + + public static ClickType getPlayerClickType(OfflinePlayer player) { + if (playerClickType.containsKey(player)) + return playerClickType.get(player); + else + return null; + } + + public static void removePlayerClickType(OfflinePlayer player) { + playerClickType.remove(player); + } + + public static void addPlayerClickType(OfflinePlayer player, ClickType clickType) { + playerClickType.put(player, clickType); + } + + public enum EnumClickType { + CREATE, REMOVE, INFO; + } + + private EnumClickType enumClickType; + private ItemStack product; + private double buyPrice; + private double sellPrice; + private boolean infinite; + + public ClickType(EnumClickType enumClickType) { + this.enumClickType = enumClickType; + } + + public ClickType(EnumClickType enumClickType, ItemStack product, double buyPrice, double sellPrice, boolean infinite) { + this.enumClickType = enumClickType; + this.product = product; + this.sellPrice = sellPrice; + this.buyPrice = buyPrice; + this.infinite = infinite; + } + + public EnumClickType getClickType() { + return enumClickType; + } + + public ItemStack getProduct() { + return product; + } + + public double getBuyPrice() { + return buyPrice; + } + + public double getSellPrice() { + return sellPrice; + } + + public boolean isInfinite() { + return infinite; + } + +} diff --git a/de/epiceric/shopchest/utils/EnchantmentNames.java b/de/epiceric/shopchest/utils/EnchantmentNames.java new file mode 100644 index 0000000..62b15b3 --- /dev/null +++ b/de/epiceric/shopchest/utils/EnchantmentNames.java @@ -0,0 +1,84 @@ +package de.epiceric.shopchest.utils; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.bukkit.enchantments.Enchantment; + +import com.google.common.collect.ImmutableMap; + +public class EnchantmentNames { + + private static final Map enchMap = ImmutableMap.builder() + .put("PROTECTION_ENVIRONMENTAL", "Protection") + .put("PROTECTION_FIRE", "Fire Protection") + .put("PROTECTION_FALL", "Feather Falling") + .put("PROTECTION_EXPLOSIONS", "Blast Protection") + .put("OXYGEN", "Respiration") + .put("WATER_WORKER", "Aqua Affinity") + .put("THORNS", "Thorns") + .put("DEPTH_STRIDER", "Depth Strider") + .put("DAMAGE_ALL", "Sharpness") + .put("DAMAGE_UNDEAD", "smite") + .put("DAMAGE_ARTHROPODS", "Bane of Arthropods") + .put("KNOCKBACK", "Knockback") + .put("FIRE_ASPECT", "Fire Aspect") + .put("LOOT_BONUS_MOBS", "Looting") + .put("DIG_SPEED", "Efficiency") + .put("SILK_TOUCH", "Silk Touch") + .put("DURABILITY", "Unbreaking") + .put("LOOT_BONUS_BLOCKS", "Fortune") + .put("ARROW_DAMAGE", "Power") + .put("ARROW_KNOCKBACK", "Punch") + .put("ARROW_FIRE", "Flame") + .put("ARROW_INFINITE", "Infinity") + .put("LUCK", "Luck of the Sea") + .put("LURE", "Lure") + .build(); + + public static String lookup(Enchantment enchantment, int level) { + String key = enchantment.getName(); + String name = enchMap.get(key); + + String levelString = getRomanNumber(level); + + return name + " " + levelString; + } + + public static String getRomanNumber(int Int) { + + LinkedHashMap roman_numerals = new LinkedHashMap(); + roman_numerals.put("M", 1000); + roman_numerals.put("CM", 900); + roman_numerals.put("D", 500); + roman_numerals.put("CD", 400); + roman_numerals.put("C", 100); + roman_numerals.put("XC", 90); + roman_numerals.put("L", 50); + roman_numerals.put("XL", 40); + roman_numerals.put("X", 10); + roman_numerals.put("IX", 9); + roman_numerals.put("V", 5); + roman_numerals.put("IV", 4); + roman_numerals.put("I", 1); + String res = ""; + for(Map.Entry entry : roman_numerals.entrySet()){ + int matches = Int/entry.getValue(); + res += repeat(entry.getKey(), matches); + Int = Int % entry.getValue(); + } + return res; + } + + public static String repeat(String s, int n) { + if(s == null) { + return null; + } + final StringBuilder sb = new StringBuilder(); + for(int i = 0; i < n; i++) { + sb.append(s); + } + return sb.toString(); + } + +} diff --git a/de/epiceric/shopchest/utils/ItemNames.java b/de/epiceric/shopchest/utils/ItemNames.java new file mode 100644 index 0000000..37ab444 --- /dev/null +++ b/de/epiceric/shopchest/utils/ItemNames.java @@ -0,0 +1,617 @@ +package de.epiceric.shopchest.utils; + +import java.util.Map; + +import org.apache.commons.lang.WordUtils; +import org.bukkit.DyeColor; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BookMeta; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; + +import com.google.common.collect.ImmutableMap; + +public class ItemNames { + + private static final Map map = ImmutableMap.builder() + .put("1", "Stone") + .put("1:1", "Granite") + .put("1:2", "Polished Granite") + .put("1:3", "Diorite") + .put("1:4", "Polished Diorite") + .put("1:5", "Andesite") + .put("1:6", "Polished Andesite") + .put("2", "Grass Block") + .put("3", "Dirt") + .put("3:1", "Coarse Dirt") + .put("3:2", "Podzol") + .put("4", "Cobblestone") + .put("5", "Oak Wood Planks") + .put("5:1", "Spruce Wood Planks") + .put("5:2", "Birch Wood Planks") + .put("5:3", "Jungle Wood Planks") + .put("5:4", "Acacia Wood Planks") + .put("5:5", "Dark Oak Wood Planks") + .put("6", "Oak Sapling") + .put("6:1", "Spruce Sapling") + .put("6:2", "Birch Sapling") + .put("6:3", "Jungle Sapling") + .put("6:4", "Acacia Sapling") + .put("6:5", "Dark Oak Sapling") + .put("7", "Bedrock") + .put("8", "Water (No Spread)") + .put("9", "Water") + .put("10", "Lava (No Spread)") + .put("11", "Lava") + .put("12", "Sand") + .put("12:1", "Red Sand") + .put("13", "Gravel") + .put("14", "Gold Ore") + .put("15", "Iron Ore") + .put("16", "Coal Ore") + .put("17", "Oak Wood") + .put("17:1", "Spruce Wood") + .put("17:2", "Birch Wood") + .put("17:3", "Jungle Wood") + .put("18", "Oak Leaves") + .put("18:1", "Spruce Leaves") + .put("18:2", "Birch Leaves") + .put("18:3", "Jungle Leaves") + .put("19", "Sponge") + .put("19:1", "Wet Sponge") + .put("20", "Glass") + .put("21", "Lapis Lazuli Ore") + .put("22", "Lapis Lazuli Block") + .put("23", "Dispenser") + .put("24", "Sandstone") + .put("24:1", "Chiseled Sandstone") + .put("24:2", "Smooth Sandstone") + .put("25", "Note Block") + .put("26", "Bed") + .put("27", "Powered Rail") + .put("28", "Detector Rail") + .put("29", "Sticky Piston") + .put("30", "Web") + .put("31", "Shrub") + .put("31:1", "Grass") + .put("31:2", "Fern") + .put("32", "Dead Bush") + .put("33", "Piston") + .put("34", "Piston (Head)") + .put("35", "Wool") + .put("35:1", "Orange Wool") + .put("35:2", "Magenta Wool") + .put("35:3", "Light Blue Wool") + .put("35:4", "Yellow Wool") + .put("35:5", "Lime Wool") + .put("35:6", "Pink Wool") + .put("35:7", "Gray Wool") + .put("35:8", "Light Gray Wool") + .put("35:9", "Cyan Wool") + .put("35:10", "Purple Wool") + .put("35:11", "Blue Wool") + .put("35:12", "Brown Wool") + .put("35:13", "Green Wool") + .put("35:14", "Red Wool") + .put("35:15", "Black Wool") + .put("37", "Dandelion") + .put("38", "Rose") + .put("38:1", "Blue Orchid") + .put("38:2", "Allium") + .put("38:3", "Azure Bluet") + .put("38:4", "Red Tulip") + .put("38:5", "Orange Tulip") + .put("38:6", "White Tulip") + .put("38:7", "Pink Tulip") + .put("38:8", "Oxeye Daisy") + .put("39", "Brown Mushroom") + .put("40", "Red Mushroom") + .put("41", "Gold Block") + .put("42", "Iron Block") + .put("43", "Stone Slab (Double)") + .put("43:1", "Sandstone Slab (Double)") + .put("43:2", "Wooden Slab (Double)") + .put("43:3", "Cobblestone Slab (Double)") + .put("43:4", "Brick Slab (Double)") + .put("43:5", "Stone Brick Slab (Double)") + .put("43:6", "Nether Brick Slab (Double)") + .put("43:7", "Quartz Slab (Double)") + .put("43:8", "Smooth Stone Slab (Double)") + .put("43:9", "Smooth Sandstone Slab (Double)") + .put("44", "Stone Slab") + .put("44:1", "Sandstone Slab") + .put("44:2", "Wooden Slab") + .put("44:3", "Cobblestone Slab") + .put("44:4", "Brick Slab") + .put("44:5", "Stone Brick Slab") + .put("44:6", "Nether Brick Slab") + .put("44:7", "Quartz Slab") + .put("45", "Brick") + .put("46", "TNT") + .put("47", "Bookcase") + .put("48", "Moss Stone") + .put("49", "Obsidian") + .put("50", "Torch") + .put("51", "Fire") + .put("52", "Mob Spawner") + .put("53", "Oak Wood Stairs") + .put("54", "Chest") + .put("55", "Redstone Wire") + .put("56", "Diamond Ore") + .put("57", "Diamond Block") + .put("58", "Crafting Table") + .put("59", "Wheat (Crop)") + .put("60", "Farmland") + .put("61", "Furnace") + .put("62", "Furnace (Smelting)") + .put("63", "Sign (Block)") + .put("64", "Wood Door (Block)") + .put("65", "Ladder") + .put("66", "Rails") + .put("67", "Stone Stairs") + .put("68", "Sign (Wall Block)") + .put("69", "Lever") + .put("70", "Pressure Plate") + .put("71", "Iron Door (Block)") + .put("72", "Pressure Plate") + .put("73", "Redstone Ore") + .put("74", "Redstone Ore (Glowing)") + .put("75", "Redstone Torch (Off)") + .put("76", "Redstone Torch") + .put("77", "Button") + .put("78", "Snow") + .put("79", "Ice") + .put("80", "Snow Block") + .put("81", "Cactus") + .put("82", "Clay Block") + .put("83", "Sugar Cane (Block)") + .put("84", "Jukebox") + .put("85", "Fence") + .put("86", "Pumpkin") + .put("87", "Netherrack") + .put("88", "Soul Sand") + .put("89", "Glowstone") + .put("90", "Portal") + .put("91", "Jack-O-Lantern") + .put("92", "Cake (Block)") + .put("93", "Redstone Repeater (Block Off)") + .put("94", "Redstone Repeater (Block On)") + .put("95", "Stained Glass") + .put("96", "Wooden Trapdoor") + .put("97", "Stone Monster Egg") + .put("97:1", "Cobblestone Monster Egg") + .put("97:2", "Stone Brick Monster Egg") + .put("97:3", "Mossy Stone Brick Monster Egg") + .put("97:4", "Cracked Stone Brick Monster Egg") + .put("97:5", "Chiseled Stone Brick Monster Egg") + .put("98", "Stone Bricks") + .put("98:1", "Mossy Stone Bricks") + .put("98:2", "Cracked Stone Bricks") + .put("98:3", "Chiseled Stone Bricks") + .put("99", "Brown Mushroom (Block)") + .put("100", "Red Mushroom (Block)") + .put("101", "Iron Bars") + .put("102", "Glass Pane") + .put("103", "Melon (Block)") + .put("104", "Pumpkin Vine") + .put("105", "Melon Vine") + .put("106", "Vines") + .put("107", "Fence Gate") + .put("108", "Brick Stairs") + .put("109", "Stone Brick Stairs") + .put("110", "Mycelium") + .put("111", "Lily Pad") + .put("112", "Nether Brick") + .put("113", "Nether Brick Fence") + .put("114", "Nether Brick Stairs") + .put("115", "Nether Wart") + .put("116", "Enchantment Table") + .put("117", "Brewing Stand (Block)") + .put("118", "Cauldron (Block)") + .put("119", "End Portal") + .put("120", "End Portal Frame") + .put("121", "End Stone") + .put("122", "Dragon Egg") + .put("123", "Redstone Lamp (Inactive)") + .put("124", "Redstone Lamp (Active)") + .put("125", "Double Wood Slab") + .put("126", "Oak Wood Slab") + .put("126:1", "Spruce Wood Slab") + .put("126:2", "Birch Slab") + .put("126:3", "Jungle Slab") + .put("126:4", "Acacia Wood Slab") + .put("126:5", "Dark Oak Wood Slab") + .put("127", "Cocoa Plant") + .put("128", "Sandstone Stairs") + .put("129", "Emerald Ore") + .put("130", "Ender Chest") + .put("131", "Tripwire Hook") + .put("132", "Tripwire") + .put("133", "Emerald Block") + .put("134", "Spruce Wood Stairs") + .put("135", "Birch Wood Stairs") + .put("136", "Jungle Wood Stairs") + .put("137", "Command Block") + .put("138", "Beacon Block") + .put("139", "Cobblestone Wall") + .put("139:1", "Mossy Cobblestone Wall") + .put("140", "Flower Pot") + .put("141", "Carrots") + .put("142", "Potatoes") + .put("143", "Button") + .put("144", "Head") + .put("145", "Anvil") + .put("146", "Trapped Chest") + .put("147", "Weighted Pressure Plate (Light)") + .put("148", "Weighted Pressure Plate (Heavy)") + .put("149", "Redstone Comparator (inactive)") + .put("150", "Redstone Comparator (active)") + .put("151", "Daylight Sensor") + .put("152", "Redstone Block") + .put("153", "Nether Quartz Ore") + .put("154", "Hopper") + .put("155", "Quartz Block") + .put("155:1", "Chiseled Quartz Block") + .put("155:2", "Pillar Quartz Block") + .put("156", "Quartz Stairs") + .put("157", "Activator Rail") + .put("158", "Dropper") + .put("159", "Stained Clay") + .put("160", "Stained Glass Pane") + .put("161", "Acacia Leaves") + .put("161:1", "Dark Oak Leaves") + .put("162", "Acacia Wood") + .put("162:1", "Dark Oak Wood") + .put("163", "Acacia Wood Stairs") + .put("164", "Dark Oak Wood Stairs") + .put("165", "Slime Block") + .put("166", "Barrier") + .put("167", "Iron Trapdoor") + .put("168", "Prismarine") + .put("168:1", "Prismarine Bricks") + .put("168:2", "Dark Prismarine") + .put("169", "Sea Lantern") + .put("170", "Hay Block") + .put("171", "Carpet") + .put("172", "Hardened Clay") + .put("173", "Block of Coal") + .put("174", "Packed Ice") + .put("175", "Sunflower") + .put("175:1", "Lilac") + .put("175:2", "Double Tallgrass") + .put("175:3", "Large Fern") + .put("175:4", "Rose Bush") + .put("175:5", "Peony") + .put("256", "Iron Shovel") + .put("257", "Iron Pickaxe") + .put("258", "Iron Axe") + .put("259", "Flint and Steel") + .put("260", "Apple") + .put("261", "Bow") + .put("262", "Arrow") + .put("263", "Coal") + .put("263:1", "Charcoal") + .put("264", "Diamond") + .put("265", "Iron Ingot") + .put("266", "Gold Ingot") + .put("267", "Iron Sword") + .put("268", "Wooden Sword") + .put("269", "Wooden Shovel") + .put("270", "Wooden Pickaxe") + .put("271", "Wooden Axe") + .put("272", "Stone Sword") + .put("273", "Stone Shovel") + .put("274", "Stone Pickaxe") + .put("275", "Stone Axe") + .put("276", "Diamond Sword") + .put("277", "Diamond Shovel") + .put("278", "Diamond Pickaxe") + .put("279", "Diamond Axe") + .put("280", "Stick") + .put("281", "Bowl") + .put("282", "Mushroom Stew") + .put("283", "Gold Sword") + .put("284", "Gold Shovel") + .put("285", "Gold Pickaxe") + .put("286", "Gold Axe") + .put("287", "String") + .put("288", "Feather") + .put("289", "Gunpowder") + .put("290", "Wooden Hoe") + .put("291", "Stone Hoe") + .put("292", "Iron Hoe") + .put("293", "Diamond Hoe") + .put("294", "Gold Hoe") + .put("295", "Seeds") + .put("296", "Wheat") + .put("297", "Bread") + .put("298", "Leather Helmet") + .put("299", "Leather Chestplate") + .put("300", "Leather Leggings") + .put("301", "Leather Boots") + .put("302", "Chainmail Helmet") + .put("303", "Chainmail Chestplate") + .put("304", "Chainmail Leggings") + .put("305", "Chainmail Boots") + .put("306", "Iron Helmet") + .put("307", "Iron Chestplate") + .put("308", "Iron Leggings") + .put("309", "Iron Boots") + .put("310", "Diamond Helmet") + .put("311", "Diamond Chestplate") + .put("312", "Diamond Leggings") + .put("313", "Diamond Boots") + .put("314", "Gold Helmet") + .put("315", "Gold Chestplate") + .put("316", "Gold Leggings") + .put("317", "Gold Boots") + .put("318", "Flint") + .put("319", "Raw Porkchop") + .put("320", "Cooked Porkchop") + .put("321", "Painting") + .put("322", "Gold Apple") + .put("322:1", "Gold Apple (Enchanted)") + .put("323", "Sign") + .put("324", "Wooden Door") + .put("325", "Bucket") + .put("326", "Water Bucket") + .put("327", "Lava Bucket") + .put("328", "Minecart") + .put("329", "Saddle") + .put("330", "Iron Door") + .put("331", "Redstone") + .put("332", "Snowball") + .put("333", "Boat") + .put("334", "Leather") + .put("335", "Milk Bucket") + .put("336", "Brick") + .put("337", "Clay") + .put("338", "Sugar Cane") + .put("339", "Paper") + .put("340", "Book") + .put("341", "Slime Ball") + .put("342", "Storage Minecart") + .put("343", "Powered Minecart") + .put("344", "Egg") + .put("345", "Compass") + .put("346", "Fishing Rod") + .put("347", "Watch") + .put("348", "Glowstone Dust") + .put("349", "Raw Fish") + .put("349:1", "Raw Salmon") + .put("349:2", "Clownfish") + .put("349:3", "Pufferfish") + .put("350", "Cooked Fish") + .put("350:1", "Cooked Salmon") + .put("351", "Ink Sack [Black Dye]") + .put("351:1", "Rose Red [Red Dye]") + .put("351:2", "Cactus Green [Green Dye]") + .put("351:3", "Cocoa Bean [Brown Dye]") + .put("351:4", "Lapis Lazuli [Blue Dye]") + .put("351:5", "Purple Dye") + .put("351:6", "Cyan Dye") + .put("351:7", "Light Gray Dye") + .put("351:8", "Gray Dye") + .put("351:9", "Pink Dye") + .put("351:10", "Lime Dye") + .put("351:11", "Dandelion Yellow [Yellow Dye]") + .put("351:12", "Light Blue Dye") + .put("351:13", "Magenta Dye") + .put("351:14", "Orange Dye") + .put("351:15", "Bone Meal [White Dye]") + .put("352", "Bone") + .put("353", "Sugar") + .put("354", "Cake") + .put("355", "Bed") + .put("356", "Redstone Repeater") + .put("357", "Cookie") + .put("358", "Map") + .put("359", "Shears") + .put("360", "Melon") + .put("361", "Pumpkin Seeds") + .put("362", "Melon Seeds") + .put("363", "Raw Beef") + .put("364", "Steak") + .put("365", "Raw Chicken") + .put("366", "Roast Chicken") + .put("367", "Rotten Flesh") + .put("368", "Ender Pearl") + .put("369", "Blaze Rod") + .put("370", "Ghast Tear") + .put("371", "Gold Nugget") + .put("372", "Nether Wart") + .put("373", "Water Bottle") + .put("373:16", "Awkward Potion") + .put("373:32", "Thick Potion") + .put("373:64", "Mundane Potion") + .put("373:8193", "Regeneration Potion (0:45)") + .put("373:8194", "Swiftness Potion (3:00)") + .put("373:8195", "Fire Resistance Potion (3:00)") + .put("373:8196", "Poison Potion (0:45)") + .put("373:8197", "Healing Potion") + .put("373:8200", "Weakness Potion (1:30)") + .put("373:8201", "Strength Potion (3:00)") + .put("373:8202", "Slowness Potion (1:30)") + .put("373:8203", "Potion of Leaping (3:00)") + .put("373:8204", "Harming Potion") + .put("373:8225", "Regeneration Potion II (0:22)") + .put("373:8226", "Swiftness Potion II (1:30)") + .put("373:8228", "Poison Potion II (0:22)") + .put("373:8229", "Healing Potion II") + .put("373:8230", "Night Vision Potion (3:00)") + .put("373:8233", "Strength Potion II (1:30)") + .put("373:8235", "Potion of Leaping (1:30)") + .put("373:8236", "Harming Potion II") + .put("373:8237", "Water Breathing Potion (3:00)") + .put("373:8238", "Invisibility Potion (3:00)") + .put("373:8257", "Regeneration Potion (2:00)") + .put("373:8258", "Swiftness Potion (8:00)") + .put("373:8259", "Fire Resistance Potion (8:00)") + .put("373:8260", "Poison Potion (2:00)") + .put("373:8262", "Night Vision Potion (8:00)") + .put("373:8264", "Weakness Potion (4:00)") + .put("373:8265", "Strength Potion (8:00)") + .put("373:8266", "Slowness Potion (4:00)") + .put("373:8269", "Water Breathing Potion (8:00)") + .put("373:8270", "Invisibility Potion (8:00)") + .put("373:16378", "Fire Resistance Splash (2:15)") + .put("373:16385", "Regeneration Splash (0:33)") + .put("373:16386", "Swiftness Splash (2:15)") + .put("373:16388", "Poison Splash (0:33)") + .put("373:16389", "Healing Splash") + .put("373:16392", "Weakness Splash (1:07)") + .put("373:16393", "Strength Splash (2:15)") + .put("373:16394", "Slowness Splash (1:07)") + .put("373:16396", "Harming Splash") + .put("373:16418", "Swiftness Splash II (1:07)") + .put("373:16420", "Poison Splash II (0:16)") + .put("373:16421", "Healing Splash II") + .put("373:16422", "Night Vision Splash (2:15)") + .put("373:16425", "Strength Splash II (1:07)") + .put("373:16428", "Harming Splash II") + .put("373:16429", "Water Breathing Splash (2:15)") + .put("373:16430", "Invisibility Splash (2:15)") + .put("373:16449", "Regeneration Splash (1:30)") + .put("373:16450", "Swiftness Splash (6:00)") + .put("373:16451", "Fire Resistance Splash (6:00)") + .put("373:16452", "Poison Splash (1:30)") + .put("373:16454", "Night Vision Splash (6:00)") + .put("373:16456", "Weakness Splash (3:00)") + .put("373:16457", "Strength Splash (6:00)") + .put("373:16458", "Slowness Splash (3:00)") + .put("373:16461", "Water Breathing Splash (6:00)") + .put("373:16462", "Invisibility Splash (6:00)") + .put("373:16471", "Regeneration Splash II (0:16)") + .put("374", "Glass Bottle") + .put("375", "Spider Eye") + .put("376", "Fermented Spider Eye") + .put("377", "Blaze Powder") + .put("378", "Magma Cream") + .put("379", "Brewing Stand") + .put("380", "Cauldron") + .put("381", "Eye of Ender") + .put("382", "Glistering Melon") + .put("383", "Spawn Egg") + .put("383:50", "Spawn Creeper") + .put("383:51", "Spawn Skeleton") + .put("383:52", "Spawn Spider") + .put("383:54", "Spawn Zombie") + .put("383:55", "Spawn Slime") + .put("383:56", "Spawn Ghast") + .put("383:57", "Spawn Pigman") + .put("383:58", "Spawn Enderman") + .put("383:59", "Spawn Cave Spider") + .put("383:60", "Spawn Silverfish") + .put("383:61", "Spawn Blaze") + .put("383:62", "Spawn Magma Cube") + .put("383:65", "Spawn Bat") + .put("383:66", "Spawn Witch") + .put("383:67", "Spawn Endermite") + .put("383:68", "Spawn Guardian") + .put("383:90", "Spawn Pig") + .put("383:91", "Spawn Sheep") + .put("383:92", "Spawn Cow") + .put("383:93", "Spawn Chicken") + .put("383:94", "Spawn Squid") + .put("383:95", "Spawn Wolf") + .put("383:96", "Spawn Mooshroom") + .put("383:98", "Spawn Ocelot") + .put("383:100", "Spawn Horse") + .put("383:101", "Spawn Rabbit") + .put("383:120", "Spawn Villager") + .put("384", "Bottle o' Enchanting") + .put("385", "Fire Charge") + .put("386", "Book and Quill") + .put("387", "Written Book") + .put("388", "Emerald") + .put("389", "Item Frame") + .put("390", "Flower Pot") + .put("391", "Carrot") + .put("392", "Potato") + .put("393", "Baked Potato") + .put("394", "Poisonous Potato") + .put("395", "Empty Map") + .put("396", "Golden Carrot") + .put("397", "Skull Item") + .put("397:0", "Skeleton Skull") + .put("397:1", "Wither Skeleton Skull") + .put("397:2", "Zombie Head") + .put("373:3", "Head") + .put("373:4", "Creeper Head") + .put("398", "Carrot on a Stick") + .put("399", "Nether Star") + .put("400", "Pumpkin Pie") + .put("401", "Firework Rocket") + .put("402", "Firework Star") + .put("403", "Enchanted Book") + .put("404", "Redstone Comparator") + .put("405", "Nether Brick") + .put("406", "Nether Quartz") + .put("407", "Minecart with TNT") + .put("408", "Minecart with Hopper") + .put("409", "Prismarine Shard") + .put("410", "Prismarine Crystals") + .put("411", "Raw Rabbit") + .put("412", "Cooked Rabbit") + .put("413", "Rabbit Stew") + .put("414", "Rabbit Foot") + .put("415", "Rabbit Hide") + .put("417", "Iron Horse Armor") + .put("418", "Gold Horse Armor") + .put("419", "Diamond Horse Armor") + .put("420", "Lead") + .put("421", "Name Tag") + .put("422", "Minecart with Command Block") + .put("423", "Raw Mutton") + .put("424", "Cooked Mutton") + .put("2256", "Music Disk (13)") + .put("2257", "Music Disk (Cat)") + .put("2258", "Music Disk (Blocks)") + .put("2259", "Music Disk (Chirp)") + .put("2260", "Music Disk (Far)") + .put("2261", "Music Disk (Mall)") + .put("2262", "Music Disk (Mellohi)") + .put("2263", "Music Disk (Stal)") + .put("2264", "Music Disk (Strad)") + .put("2265", "Music Disk (Ward)") + .put("2266", "Music Disk (11)") + .put("2267", "Music Disk (wait)") + .build(); + + public static String lookup(ItemStack stack) { + if (stack.hasItemMeta()) { + ItemMeta meta = stack.getItemMeta(); + if (meta.getDisplayName() != null) { + return meta.getDisplayName(); + } else if (meta instanceof BookMeta) { + return ((BookMeta)meta).getTitle(); + } + } + + String result; + String key = Integer.toString(stack.getTypeId()); + Material mat = stack.getType(); + if ((mat == Material.WOOL || mat == Material.CARPET) && stack.getDurability() == 0) { + // special case: white wool/carpet is just called "Wool" or "Carpet" + result = map.get(key); + } else if (mat == Material.WOOL || mat == Material.CARPET || mat == Material.STAINED_CLAY || mat == Material.STAINED_GLASS || mat == Material.STAINED_GLASS_PANE) { + DyeColor dc = DyeColor.getByWoolData((byte)stack.getDurability()); + result = dc == null ? map.get(key) : WordUtils.capitalizeFully(dc.toString().replace("_", " ")) + " " + map.get(key); + } else if (mat == Material.LEATHER_HELMET || mat == Material.LEATHER_CHESTPLATE || mat == Material.LEATHER_LEGGINGS || mat == Material.LEATHER_BOOTS) { + LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) stack.getItemMeta(); + DyeColor dc = DyeColor.getByColor(leatherArmorMeta.getColor()); + result = dc == null ? map.get(key) : WordUtils.capitalizeFully(dc.toString()).replace("_", " ") + " " + map.get(key); + } else if (stack.getDurability() != 0) { + result = map.get(key + ":" + stack.getDurability()); + if (result == null) { + result = map.get(key); + } + } else { + result = map.containsKey(key) ? map.get(key) : stack.getType().toString(); + } + + return result; + } + +} diff --git a/de/epiceric/shopchest/utils/JsonBuilder.java b/de/epiceric/shopchest/utils/JsonBuilder.java new file mode 100644 index 0000000..15dbe43 --- /dev/null +++ b/de/epiceric/shopchest/utils/JsonBuilder.java @@ -0,0 +1,106 @@ +package de.epiceric.shopchest.utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import org.bukkit.ChatColor; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import net.minecraft.server.v1_8_R3.IChatBaseComponent.ChatSerializer; +import net.minecraft.server.v1_8_R3.PacketPlayOutChat; + + +public class JsonBuilder { + + /* JsonBuilder by FisheyLP */ + + public enum ClickAction { + RUN_COMMAND, SUGGEST_COMMAND, OPEN_URL + } + public enum HoverAction { + SHOW_TEXT + } + + private List extras = new ArrayList(); + + public JsonBuilder(String... text) { + for(String extra : text) + parse(extra); + } + + public JsonBuilder parse(String text) { + String regex = "[&§]{1}([a-fA-Fl-oL-O0-9]){1}"; + text = text.replaceAll(regex, "§$1"); + if(!Pattern.compile(regex).matcher(text).find()) { + withText(text); + return this; + } + String[] words = text.split(regex); + + int index = words[0].length(); + for(String word : words) { + try { + if(index != words[0].length()) + withText(word).withColor("§"+text.charAt(index - 1)); + } catch(Exception e){} + index += word.length() + 2; + } + return this; + } + + public JsonBuilder withText(String text) { + extras.add("{text:\"" + text + "\"}"); + return this; + } + + public JsonBuilder withColor(ChatColor color) { + String c = color.name().toLowerCase(); + addSegment(color.isColor() ? "color:" + c : c + ":true"); + return this; + } + + public JsonBuilder withColor(String color) { + while(color.length() != 1) color = color.substring(1).trim(); + withColor(ChatColor.getByChar(color)); + return this; + } + + public JsonBuilder withClickEvent(ClickAction action, String value) { + addSegment("clickEvent:{action:" + action.toString().toLowerCase() + + ",value:\"" + value + "\"}"); + return this; + } + + public JsonBuilder withHoverEvent(HoverAction action, String value) { + addSegment("hoverEvent:{action:" + action.toString().toLowerCase() + + ",value:\"" + value + "\"}"); + return this; + } + + private void addSegment(String segment) { + String lastText = extras.get(extras.size() - 1); + lastText = lastText.substring(0, lastText.length() - 1) + + ","+segment+"}"; + extras.remove(extras.size() - 1); + extras.add(lastText); + } + + public String toString() { + if(extras.size() <= 1) return extras.size() == 0 ? "{text:\"\"}" : extras.get(0); + String text = extras.get(0).substring(0, extras.get(0).length() - 1) + ",extra:["; + extras.remove(0);; + for (String extra : extras) + text = text + extra + ","; + text = text.substring(0, text.length() - 1) + "]}"; + return text; + } + + public void sendJson(Player p) { + ((CraftPlayer) p).getHandle().playerConnection.sendPacket( + new PacketPlayOutChat(ChatSerializer.a(toString()))); + + + } + } \ No newline at end of file diff --git a/de/epiceric/shopchest/utils/Metrics.java b/de/epiceric/shopchest/utils/Metrics.java new file mode 100644 index 0000000..3766598 --- /dev/null +++ b/de/epiceric/shopchest/utils/Metrics.java @@ -0,0 +1,785 @@ +/* + * Copyright 2011-2013 Tyler Blair. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and contributors and should not be interpreted as representing official policies, + * either expressed or implied, of anybody else. + */ +package de.epiceric.shopchest.utils; + +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.scheduler.BukkitTask; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; +import java.util.logging.Level; +import java.util.zip.GZIPOutputStream; + +public class Metrics { + + /** + * The current revision number + */ + private final static int REVISION = 7; + + /** + * The base url of the metrics domain + */ + private static final String BASE_URL = "http://report.mcstats.org"; + + /** + * The url used to report a server's status + */ + private static final String REPORT_URL = "/plugin/%s"; + + /** + * Interval of time to ping (in minutes) + */ + private static final int PING_INTERVAL = 15; + + /** + * The plugin this metrics submits for + */ + private final Plugin plugin; + + /** + * All of the custom graphs to submit to metrics + */ + private final Set graphs = Collections.synchronizedSet(new HashSet()); + + /** + * The plugin configuration file + */ + private final YamlConfiguration configuration; + + /** + * The plugin configuration file + */ + private final File configurationFile; + + /** + * Unique server id + */ + private final String guid; + + /** + * Debug mode + */ + private final boolean debug; + + /** + * Lock for synchronization + */ + private final Object optOutLock = new Object(); + + /** + * The scheduled task + */ + private volatile BukkitTask task = null; + + public Metrics(final Plugin plugin) throws IOException { + if (plugin == null) { + throw new IllegalArgumentException("Plugin cannot be null"); + } + + this.plugin = plugin; + + // load the config + configurationFile = getConfigFile(); + configuration = YamlConfiguration.loadConfiguration(configurationFile); + + // add some defaults + configuration.addDefault("opt-out", false); + configuration.addDefault("guid", UUID.randomUUID().toString()); + configuration.addDefault("debug", false); + + // Do we need to create the file? + if (configuration.get("guid", null) == null) { + configuration.options().header("http://mcstats.org").copyDefaults(true); + configuration.save(configurationFile); + } + + // Load the guid then + guid = configuration.getString("guid"); + debug = configuration.getBoolean("debug", false); + } + + /** + * Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics + * website. Plotters can be added to the graph object returned. + * + * @param name The name of the graph + * @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given + */ + public Graph createGraph(final String name) { + if (name == null) { + throw new IllegalArgumentException("Graph name cannot be null"); + } + + // Construct the graph object + final Graph graph = new Graph(name); + + // Now we can add our graph + graphs.add(graph); + + // and return back + return graph; + } + + /** + * Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend + * + * @param graph The name of the graph + */ + public void addGraph(final Graph graph) { + if (graph == null) { + throw new IllegalArgumentException("Graph cannot be null"); + } + + graphs.add(graph); + } + + /** + * Start measuring statistics. This will immediately create an async repeating task as the plugin and send the + * initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200 + * ticks. + * + * @return True if statistics measuring is running, otherwise false. + */ + public boolean start() { + synchronized (optOutLock) { + // Did we opt out? + if (isOptOut()) { + return false; + } + + // Is metrics already running? + if (task != null) { + return true; + } + + // Begin hitting the server with glorious data + task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, new Runnable() { + + private boolean firstPost = true; + + public void run() { + try { + // This has to be synchronized or it can collide with the disable method. + synchronized (optOutLock) { + // Disable Task, if it is running and the server owner decided to opt-out + if (isOptOut() && task != null) { + task.cancel(); + task = null; + // Tell all plotters to stop gathering information. + for (Graph graph : graphs) { + graph.onOptOut(); + } + } + } + + // We use the inverse of firstPost because if it is the first time we are posting, + // it is not a interval ping, so it evaluates to FALSE + // Each time thereafter it will evaluate to TRUE, i.e PING! + postPlugin(!firstPost); + + // After the first post we set firstPost to false + // Each post thereafter will be a ping + firstPost = false; + } catch (IOException e) { + if (debug) { + Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage()); + } + } + } + }, 0, PING_INTERVAL * 1200); + + return true; + } + } + + /** + * Has the server owner denied plugin metrics? + * + * @return true if metrics should be opted out of it + */ + public boolean isOptOut() { + synchronized (optOutLock) { + try { + // Reload the metrics file + configuration.load(getConfigFile()); + } catch (IOException ex) { + if (debug) { + Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); + } + return true; + } catch (InvalidConfigurationException ex) { + if (debug) { + Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); + } + return true; + } + return configuration.getBoolean("opt-out", false); + } + } + + /** + * Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task. + * + * @throws java.io.IOException + */ + public void enable() throws IOException { + // This has to be synchronized or it can collide with the check in the task. + synchronized (optOutLock) { + // Check if the server owner has already set opt-out, if not, set it. + if (isOptOut()) { + configuration.set("opt-out", false); + configuration.save(configurationFile); + } + + // Enable Task, if it is not running + if (task == null) { + start(); + } + } + } + + /** + * Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task. + * + * @throws java.io.IOException + */ + public void disable() throws IOException { + // This has to be synchronized or it can collide with the check in the task. + synchronized (optOutLock) { + // Check if the server owner has already set opt-out, if not, set it. + if (!isOptOut()) { + configuration.set("opt-out", true); + configuration.save(configurationFile); + } + + // Disable Task, if it is running + if (task != null) { + task.cancel(); + task = null; + } + } + } + + /** + * Gets the File object of the config file that should be used to store data such as the GUID and opt-out status + * + * @return the File object for the config file + */ + public File getConfigFile() { + // I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use + // is to abuse the plugin object we already have + // plugin.getDataFolder() => base/plugins/PluginA/ + // pluginsFolder => base/plugins/ + // The base is not necessarily relative to the startup directory. + File pluginsFolder = plugin.getDataFolder().getParentFile(); + + // return => base/plugins/PluginMetrics/config.yml + return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml"); + } + + /** + * Gets the online player (backwards compatibility) + * + * @return online player amount + */ + private int getOnlinePlayers() { + try { + Method onlinePlayerMethod = Server.class.getMethod("getOnlinePlayers"); + if(onlinePlayerMethod.getReturnType().equals(Collection.class)) { + return ((Collection)onlinePlayerMethod.invoke(Bukkit.getServer())).size(); + } else { + return ((Player[])onlinePlayerMethod.invoke(Bukkit.getServer())).length; + } + } catch (Exception ex) { + if (debug) { + Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage()); + } + } + + return 0; + } + + /** + * Generic method that posts a plugin to the metrics website + */ + private void postPlugin(final boolean isPing) throws IOException { + // Server software specific section + PluginDescriptionFile description = plugin.getDescription(); + String pluginName = description.getName(); + boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled + String pluginVersion = description.getVersion(); + String serverVersion = Bukkit.getVersion(); + int playersOnline = this.getOnlinePlayers(); + + // END server software specific section -- all code below does not use any code outside of this class / Java + + // Construct the post data + StringBuilder json = new StringBuilder(1024); + json.append('{'); + + // The plugin's description file containg all of the plugin data such as name, version, author, etc + appendJSONPair(json, "guid", guid); + appendJSONPair(json, "plugin_version", pluginVersion); + appendJSONPair(json, "server_version", serverVersion); + appendJSONPair(json, "players_online", Integer.toString(playersOnline)); + + // New data as of R6 + String osname = System.getProperty("os.name"); + String osarch = System.getProperty("os.arch"); + String osversion = System.getProperty("os.version"); + String java_version = System.getProperty("java.version"); + int coreCount = Runtime.getRuntime().availableProcessors(); + + // normalize os arch .. amd64 -> x86_64 + if (osarch.equals("amd64")) { + osarch = "x86_64"; + } + + appendJSONPair(json, "osname", osname); + appendJSONPair(json, "osarch", osarch); + appendJSONPair(json, "osversion", osversion); + appendJSONPair(json, "cores", Integer.toString(coreCount)); + appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0"); + appendJSONPair(json, "java_version", java_version); + + // If we're pinging, append it + if (isPing) { + appendJSONPair(json, "ping", "1"); + } + + if (graphs.size() > 0) { + synchronized (graphs) { + json.append(','); + json.append('"'); + json.append("graphs"); + json.append('"'); + json.append(':'); + json.append('{'); + + boolean firstGraph = true; + + final Iterator iter = graphs.iterator(); + + while (iter.hasNext()) { + Graph graph = iter.next(); + + StringBuilder graphJson = new StringBuilder(); + graphJson.append('{'); + + for (Plotter plotter : graph.getPlotters()) { + appendJSONPair(graphJson, plotter.getColumnName(), Integer.toString(plotter.getValue())); + } + + graphJson.append('}'); + + if (!firstGraph) { + json.append(','); + } + + json.append(escapeJSON(graph.getName())); + json.append(':'); + json.append(graphJson); + + firstGraph = false; + } + + json.append('}'); + } + } + + // close json + json.append('}'); + + // Create the url + URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName))); + + // Connect to the website + URLConnection connection; + + // Mineshafter creates a socks proxy, so we can safely bypass it + // It does not reroute POST requests so we need to go around it + if (isMineshafterPresent()) { + connection = url.openConnection(Proxy.NO_PROXY); + } else { + connection = url.openConnection(); + } + + + byte[] uncompressed = json.toString().getBytes(); + byte[] compressed = gzip(json.toString()); + + // Headers + connection.addRequestProperty("User-Agent", "MCStats/" + REVISION); + connection.addRequestProperty("Content-Type", "application/json"); + connection.addRequestProperty("Content-Encoding", "gzip"); + connection.addRequestProperty("Content-Length", Integer.toString(compressed.length)); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + + connection.setDoOutput(true); + + if (debug) { + System.out.println("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length); + } + + // Write the data + OutputStream os = connection.getOutputStream(); + os.write(compressed); + os.flush(); + + // Now read the response + final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String response = reader.readLine(); + + // close resources + os.close(); + reader.close(); + + if (response == null || response.startsWith("ERR") || response.startsWith("7")) { + if (response == null) { + response = "null"; + } else if (response.startsWith("7")) { + response = response.substring(response.startsWith("7,") ? 2 : 1); + } + + throw new IOException(response); + } else { + // Is this the first update this hour? + if (response.equals("1") || response.contains("This is your first update this hour")) { + synchronized (graphs) { + final Iterator iter = graphs.iterator(); + + while (iter.hasNext()) { + final Graph graph = iter.next(); + + for (Plotter plotter : graph.getPlotters()) { + plotter.reset(); + } + } + } + } + } + } + + /** + * GZip compress a string of bytes + * + * @param input + * @return + */ + public static byte[] gzip(String input) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream gzos = null; + + try { + gzos = new GZIPOutputStream(baos); + gzos.write(input.getBytes("UTF-8")); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (gzos != null) try { + gzos.close(); + } catch (IOException ignore) { + } + } + + return baos.toByteArray(); + } + + /** + * Check if mineshafter is present. If it is, we need to bypass it to send POST requests + * + * @return true if mineshafter is installed on the server + */ + private boolean isMineshafterPresent() { + try { + Class.forName("mineshafter.MineServer"); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * Appends a json encoded key/value pair to the given string builder. + * + * @param json + * @param key + * @param value + * @throws UnsupportedEncodingException + */ + private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException { + boolean isValueNumeric = false; + + try { + if (value.equals("0") || !value.endsWith("0")) { + Double.parseDouble(value); + isValueNumeric = true; + } + } catch (NumberFormatException e) { + isValueNumeric = false; + } + + if (json.charAt(json.length() - 1) != '{') { + json.append(','); + } + + json.append(escapeJSON(key)); + json.append(':'); + + if (isValueNumeric) { + json.append(value); + } else { + json.append(escapeJSON(value)); + } + } + + /** + * Escape a string to create a valid JSON string + * + * @param text + * @return + */ + private static String escapeJSON(String text) { + StringBuilder builder = new StringBuilder(); + + builder.append('"'); + for (int index = 0; index < text.length(); index++) { + char chr = text.charAt(index); + + switch (chr) { + case '"': + case '\\': + builder.append('\\'); + builder.append(chr); + break; + case '\b': + builder.append("\\b"); + break; + case '\t': + builder.append("\\t"); + break; + case '\n': + builder.append("\\n"); + break; + case '\r': + builder.append("\\r"); + break; + default: + if (chr < ' ') { + String t = "000" + Integer.toHexString(chr); + builder.append("\\u" + t.substring(t.length() - 4)); + } else { + builder.append(chr); + } + break; + } + } + builder.append('"'); + + return builder.toString(); + } + + /** + * Encode text as UTF-8 + * + * @param text the text to encode + * @return the encoded text, as UTF-8 + */ + private static String urlEncode(final String text) throws UnsupportedEncodingException { + return URLEncoder.encode(text, "UTF-8"); + } + + /** + * Represents a custom graph on the website + */ + public static class Graph { + + /** + * The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is + * rejected + */ + private final String name; + + /** + * The set of plotters that are contained within this graph + */ + private final Set plotters = new LinkedHashSet(); + + private Graph(final String name) { + this.name = name; + } + + /** + * Gets the graph's name + * + * @return the Graph's name + */ + public String getName() { + return name; + } + + /** + * Add a plotter to the graph, which will be used to plot entries + * + * @param plotter the plotter to add to the graph + */ + public void addPlotter(final Plotter plotter) { + plotters.add(plotter); + } + + /** + * Remove a plotter from the graph + * + * @param plotter the plotter to remove from the graph + */ + public void removePlotter(final Plotter plotter) { + plotters.remove(plotter); + } + + /** + * Gets an unmodifiable set of the plotter objects in the graph + * + * @return an unmodifiable {@link java.util.Set} of the plotter objects + */ + public Set getPlotters() { + return Collections.unmodifiableSet(plotters); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(final Object object) { + if (!(object instanceof Graph)) { + return false; + } + + final Graph graph = (Graph) object; + return graph.name.equals(name); + } + + /** + * Called when the server owner decides to opt-out of BukkitMetrics while the server is running. + */ + protected void onOptOut() { + } + } + + /** + * Interface used to collect custom data for a plugin + */ + public static abstract class Plotter { + + /** + * The plot's name + */ + private final String name; + + /** + * Construct a plotter with the default plot name + */ + public Plotter() { + this("Default"); + } + + /** + * Construct a plotter with a specific plot name + * + * @param name the name of the plotter to use, which will show up on the website + */ + public Plotter(final String name) { + this.name = name; + } + + /** + * Get the current value for the plotted point. Since this function defers to an external function it may or may + * not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called + * from any thread so care should be taken when accessing resources that need to be synchronized. + * + * @return the current value for the point to be plotted. + */ + public abstract int getValue(); + + /** + * Get the column name for the plotted point + * + * @return the plotted point's column name + */ + public String getColumnName() { + return name; + } + + /** + * Called after the website graphs have been updated + */ + public void reset() { + } + + @Override + public int hashCode() { + return getColumnName().hashCode(); + } + + @Override + public boolean equals(final Object object) { + if (!(object instanceof Plotter)) { + return false; + } + + final Plotter plotter = (Plotter) object; + return plotter.name.equals(name) && plotter.getValue() == getValue(); + } + } +} diff --git a/de/epiceric/shopchest/utils/ShopUtils.java b/de/epiceric/shopchest/utils/ShopUtils.java new file mode 100644 index 0000000..efaa1a1 --- /dev/null +++ b/de/epiceric/shopchest/utils/ShopUtils.java @@ -0,0 +1,107 @@ +package de.epiceric.shopchest.utils; + +import java.util.ArrayList; +import java.util.HashMap; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.block.DoubleChest; +import org.bukkit.inventory.InventoryHolder; + +import de.epiceric.shopchest.shop.Shop; + +public class ShopUtils { + + private static HashMap shopLocation = new HashMap<>(); + + public static Shop getShop(Location location) { + + Location newLocation = new Location(location.getWorld(), location.getX(), location.getY(), location.getZ()); + + if (shopLocation.containsKey(newLocation)) { + return shopLocation.get(newLocation); + } else { + return null; + } + + } + + public static boolean isShop(Location location) { + + Location newLocation = new Location(location.getWorld(), location.getX(), location.getY(), location.getZ()); + + return shopLocation.containsKey(newLocation); + + } + + public static Shop[] getShops() { + + ArrayList shops = new ArrayList<>(); + + for (Shop shop : shopLocation.values()) { + shops.add(shop); + } + + return shops.toArray(new Shop[shops.size()]); + + } + + public static void addShop(Shop shop) { + + Location loc = shop.getLocation(); + Block b = loc.getBlock(); + if (b.getType().equals(Material.CHEST) || b.getType().equals(Material.TRAPPED_CHEST)) { + Chest c = (Chest) b.getState(); + InventoryHolder ih = c.getInventory().getHolder(); + if (ih instanceof DoubleChest) { + DoubleChest dc = (DoubleChest) ih; + Chest r = (Chest) dc.getRightSide(); + Chest l = (Chest) dc.getLeftSide(); + + shopLocation.put(r.getLocation(), shop); + shopLocation.put(l.getLocation(), shop); + return; + + } + } + + shopLocation.put(shop.getLocation(), shop); + + } + + public static void removeShop(Shop shop) { + + Location loc = shop.getLocation(); + Block b = loc.getBlock(); + if (b.getType().equals(Material.CHEST) || b.getType().equals(Material.TRAPPED_CHEST)) { + Chest c = (Chest) b.getState(); + InventoryHolder ih = c.getInventory().getHolder(); + if (ih instanceof DoubleChest) { + DoubleChest dc = (DoubleChest) ih; + Chest r = (Chest) dc.getRightSide(); + Chest l = (Chest) dc.getLeftSide(); + + shopLocation.remove(r.getLocation()); + shopLocation.remove(l.getLocation()); + return; + + } + } + + shopLocation.remove(shop.getLocation()); + + } + + public static String getConfigTitle(Location location) { + World w = location.getWorld(); + int x = location.getBlockX(); + int y = location.getBlockY(); + int z = location.getBlockZ(); + + return w.getName() + "_" + String.valueOf(x) + "_" + String.valueOf(y) + "_" + String.valueOf(z); + } + +} diff --git a/de/epiceric/shopchest/utils/UpdateChecker.java b/de/epiceric/shopchest/utils/UpdateChecker.java new file mode 100644 index 0000000..f161b33 --- /dev/null +++ b/de/epiceric/shopchest/utils/UpdateChecker.java @@ -0,0 +1,50 @@ +package de.epiceric.shopchest.utils; + +import org.bukkit.Bukkit; +import org.jsoup.Connection; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; + +import de.epiceric.shopchest.ShopChest; +import net.md_5.bungee.api.ChatColor; + +public class UpdateChecker { + + private ShopChest plugin; + private String url; + private String version; + private String link; + + public UpdateChecker(ShopChest plugin, String url) { + this.plugin = plugin; + this.url = url; + } + + public boolean updateNeeded() { + try { + Connection con = Jsoup.connect("http://textuploader.com/all1l/raw"); + con.userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0"); + + Document doc = con.get(); + + version = doc.text().split("\\|")[0]; + link = url + "download?version=" + doc.text().split("\\|")[1]; + + return !plugin.getDescription().getVersion().equals(version); + + + } catch (Exception | Error e) { + Bukkit.getConsoleSender().sendMessage("[ShopChest] " + ChatColor.RED + "Error while checking for updates"); + return false; + } + } + + public String getVersion() { + return version; + } + + public String getLink() { + return link; + } + +} diff --git a/de/epiceric/shopchest/utils/Utils.java b/de/epiceric/shopchest/utils/Utils.java new file mode 100644 index 0000000..d2766f3 --- /dev/null +++ b/de/epiceric/shopchest/utils/Utils.java @@ -0,0 +1,29 @@ +package de.epiceric.shopchest.utils; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public class Utils { + + + public static int getAmount(Inventory inventory, Material type, short damage, ItemMeta itemMeta) { + ItemStack[] items = inventory.getContents(); + int amount = 0; + for (ItemStack item : items) { + if ((item != null) && (item.getType().equals(type)) && (item.getDurability() == damage) && (item.getAmount() > 0) && (item.getItemMeta().equals(itemMeta))) { + amount += item.getAmount(); + } + } + return amount; + } + + public static String getVersion() { + + return Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; + + } + +}