diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2e975ff --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/.classpath +/.project +/.settings +/target \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..1b88a99 --- /dev/null +++ b/pom.xml @@ -0,0 +1,53 @@ + + 4.0.0 + de.iani.cubeside + TreasureChest + 1.1 + + UTF-8 + DEV + + + + spigotmc-repo + https://hub.spigotmc.org/nexus/content/groups/public + + + vault-repo + http://nexus.hc.to/content/repositories/pub_releases + + + + + org.spigotmc + spigot-api + 1.12-R0.1-SNAPSHOT + provided + + + de.iani.cubeside + PlayerUUIDCache + 1.4.0 + provided + + + net.milkbowl.vault + VaultAPI + 1.6 + provided + + + + + + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/src/main/java/de/iani/treasurechest/ChestInventoryListener.java b/src/main/java/de/iani/treasurechest/ChestInventoryListener.java new file mode 100644 index 0000000..139e2a2 --- /dev/null +++ b/src/main/java/de/iani/treasurechest/ChestInventoryListener.java @@ -0,0 +1,214 @@ +package de.iani.treasurechest; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public class ChestInventoryListener implements Listener { + private TreasureChest plugin; + + HashMap openInventories = new HashMap(); + + public ChestInventoryListener(TreasureChest plugin) { + this.plugin = plugin; + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onChestOpen(PlayerInteractEvent e) { + if (plugin.getChestLocation() == null) { + return; + } + Block b = e.getClickedBlock(); + if (e.getAction() == Action.RIGHT_CLICK_BLOCK && b != null && b.getLocation().equals(plugin.getChestLocation())) { + e.setCancelled(true); + if (!e.getPlayer().hasPermission("pricechest.access")) { + plugin.sendMessage(e.getPlayer(), "Du hast keinen Zugriff auf die Schatztruhe!"); + return; + } + if (openInventories.containsKey(e.getPlayer())) { + return;// ist schon offen? + } + + PlayerTreasureChestContent content = plugin.getData().getChestContent(e.getPlayer().getUniqueId()); + if (content == null || content.isEmpty()) { + plugin.sendMessage(e.getPlayer(), "Deine Schatztruhe ist leer!"); + return; + } + Inventory inventory = plugin.getServer().createInventory(null, 9 * 6, "Schatztruhe"); + OpenInventoryData openInventory = new OpenInventoryData(b.getLocation(), inventory); + + int pos = 0; + for (TreasureChestItem item : content.getItems()) { + if (pos < 9 * 6) { + ItemStack di = item.getDisplayItem().clone(); + ItemMeta meta = di.getItemMeta(); + ItemStack[] priceList = item.getPriceItems(); + ArrayList lore = new ArrayList<>(); + if (priceList != null) { + for (ItemStack stack : priceList) { + StringBuilder t = new StringBuilder(); + if (stack.getAmount() > 1) { + t.append(stack.getAmount()).append(" "); + } + t.append(TreasureChest.capitalize(stack.getType().name(), true)); + if (stack.getDurability() > 0) { + t.append(':').append(stack.getDurability()); + } + if (stack.getItemMeta().hasDisplayName()) { + t.append(" (benanntes Item)"); + } + lore.add(t.toString()); + } + } + if (item.getPriceMoney() > 0) { + lore.add(plugin.formatMoney(item.getPriceMoney())); + } + meta.setLore(lore); + di.setItemMeta(meta); + inventory.setItem(pos, di); + openInventory.setItemAtPosition(pos, pos); + } + pos += 1; + } + + e.getPlayer().openInventory(inventory); + openInventories.put(e.getPlayer(), openInventory); + e.getPlayer().playSound(b.getLocation(), Sound.BLOCK_CHEST_OPEN, 0.5f, 0.9f); + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void onInventoryClick(InventoryClickEvent event) { + OpenInventoryData openInventory = openInventories.get(event.getWhoClicked()); + if (openInventory == null) { + return; + } + + InventoryAction action = event.getAction(); + switch (action) { + case PICKUP_ALL: + case PICKUP_HALF: + case PICKUP_SOME: + case PICKUP_ONE: { + event.setCancelled(true); + if (event.getRawSlot() < event.getView().getTopInventory().getSize() && event.getWhoClicked() instanceof Player) { + Player player = (Player) event.getWhoClicked(); + + ItemStack[] playerInv = player.getInventory().getContents(); + playerInv = Arrays.copyOf(playerInv, 36); + Inventory clonedPlayerInventory = Bukkit.createInventory(null, 36); + clonedPlayerInventory.setContents(playerInv); + + PlayerTreasureChestContent content = plugin.getData().getChestContent(player.getUniqueId()); + int entryId = openInventory.getEntryAtPosition(event.getRawSlot()); + TreasureChestItem selectedItem = content.getItem(entryId); + if (selectedItem != null) { + ItemStack[] priceList = selectedItem.getPriceItems(); + int priceCount = priceList == null ? 0 : priceList.length; + if (priceCount > 0) { + ItemStack[] temp = new ItemStack[priceCount]; + for (int i = 0; i < priceCount; i++) { + temp[i] = priceList[i].clone(); + } + if (!clonedPlayerInventory.addItem(temp).isEmpty()) { + plugin.sendMessage(player, "Du hast nicht genügend Platz in deinem Inventar!", true); + player.updateInventory(); + return; + } + } + plugin.sendMessage(player, ChatColor.GRAY + "Hole Preis ab:"); + + if (priceCount > 0) { + ItemStack[] temp = new ItemStack[priceCount]; + for (int i = 0; i < priceCount; i++) { + temp[i] = priceList[i].clone(); + } + player.getInventory().addItem(temp); + for (ItemStack stack : priceList) { + StringBuilder t = new StringBuilder(" "); + if (stack.getAmount() > 1) { + t.append(stack.getAmount()).append(" "); + } + t.append(TreasureChest.capitalize(stack.getType().name(), true)); + if (stack.getDurability() > 0) { + t.append(':').append(stack.getDurability()); + } + ItemMeta meta = stack.getItemMeta(); + if (meta.hasDisplayName()) { + t.append(" (").append(meta.getDisplayName()).append(ChatColor.YELLOW).append(")"); + } + plugin.sendMessage(player, t.toString()); + } + } + if (selectedItem.getPriceMoney() > 0) { + plugin.giveMoney(player, selectedItem.getPriceMoney()); + plugin.sendMessage(player, " " + plugin.formatMoney(selectedItem.getPriceMoney())); + } + + plugin.sendMessage(player, ChatColor.GRAY + "Du hast einen Preis abgeholt!"); + + player.playSound(event.getWhoClicked().getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1f, 1f); + content.removeItem(entryId); + openInventory.getInventory().setItem(event.getRawSlot(), null); + openInventory.removeEntryAtPositionAndShift(event.getRawSlot()); + player.updateInventory(); + } + } + } + case CLONE_STACK: + case COLLECT_TO_CURSOR: + case DROP_ALL_CURSOR: + case DROP_ALL_SLOT: + case DROP_ONE_CURSOR: + case DROP_ONE_SLOT: + case HOTBAR_MOVE_AND_READD: + case HOTBAR_SWAP: + case UNKNOWN: + default: { + Player player = (Player) event.getWhoClicked(); + player.updateInventory(); + event.setCancelled(true); + return; + } + } + } + + @EventHandler(priority = EventPriority.HIGH) + public void onInventoryDrag(InventoryDragEvent event) { + if (openInventories.containsKey(event.getWhoClicked())) { + event.setCancelled(true); + } + } + + @EventHandler + public void onInventoryClose(InventoryCloseEvent e) { + OpenInventoryData data = openInventories.remove(e.getPlayer()); + if (data != null) { + ((Player) e.getPlayer()).playSound(data.getLocation(), Sound.BLOCK_CHEST_CLOSE, 0.5f, 0.9f); + } + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + openInventories.remove(event.getPlayer()); + } +} diff --git a/src/main/java/de/iani/treasurechest/OpenInventoryData.java b/src/main/java/de/iani/treasurechest/OpenInventoryData.java new file mode 100644 index 0000000..2574f61 --- /dev/null +++ b/src/main/java/de/iani/treasurechest/OpenInventoryData.java @@ -0,0 +1,59 @@ +package de.iani.treasurechest; + +import org.bukkit.Location; +import org.bukkit.inventory.Inventory; + +public class OpenInventoryData { + private Location location; + + private Inventory inventory; + + private int[] itemAtLocation; + + public OpenInventoryData(Location location, Inventory inventory) { + this.location = location; + this.inventory = inventory; + } + + public Inventory getInventory() { + return inventory; + } + + public Location getLocation() { + return location; + } + + public void setItemAtPosition(int inventoryPosition, int itemListPosition) { + if (itemAtLocation == null) { + itemAtLocation = new int[inventoryPosition + 1]; + } else if (itemAtLocation.length <= inventoryPosition) { + int[] temp = itemAtLocation; + itemAtLocation = new int[inventoryPosition + 1]; + System.arraycopy(temp, 0, itemAtLocation, 0, temp.length); + } + itemAtLocation[inventoryPosition] = itemListPosition + 1; + } + + public int getEntryAtPosition(int inventoryPosition) { + if (itemAtLocation == null || itemAtLocation.length <= inventoryPosition || inventoryPosition < 0) { + return -1; + } + return itemAtLocation[inventoryPosition] - 1; + } + + public void removeEntryAtPositionAndShift(int inventoryPosition) { + if (itemAtLocation == null || itemAtLocation.length <= inventoryPosition || inventoryPosition < 0) { + return; + } + int old = itemAtLocation[inventoryPosition]; + if (old >= 0) { + itemAtLocation[inventoryPosition] = -1; + for (int i = 0; i < itemAtLocation.length; i++) { + int oldHere = itemAtLocation[i]; + if (oldHere > old) { + itemAtLocation[i] = oldHere - 1; + } + } + } + } +} diff --git a/src/main/java/de/iani/treasurechest/PlayerEventListener.java b/src/main/java/de/iani/treasurechest/PlayerEventListener.java new file mode 100644 index 0000000..c4a6be1 --- /dev/null +++ b/src/main/java/de/iani/treasurechest/PlayerEventListener.java @@ -0,0 +1,19 @@ +package de.iani.treasurechest; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +public class PlayerEventListener implements Listener { + private TreasureChest plugin; + + public PlayerEventListener(TreasureChest plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + plugin.getData().removeActiveItem(event.getPlayer().getUniqueId()); + } + +} diff --git a/src/main/java/de/iani/treasurechest/PlayerTreasureChestContent.java b/src/main/java/de/iani/treasurechest/PlayerTreasureChestContent.java new file mode 100644 index 0000000..0d9d715 --- /dev/null +++ b/src/main/java/de/iani/treasurechest/PlayerTreasureChestContent.java @@ -0,0 +1,137 @@ +package de.iani.treasurechest; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; + +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public class PlayerTreasureChestContent { + private TreasureChest plugin; + + private File file; + + private ArrayList items; + + private long online; + + public PlayerTreasureChestContent(TreasureChest plugin, File file) { + this.plugin = plugin; + this.file = file; + try { + if (file.exists()) { + YamlConfiguration conf = YamlConfiguration.loadConfiguration(file); + + ConfigurationSection prices = conf.getConfigurationSection("prices"); + if (prices != null) { + for (String e : prices.getKeys(false)) { + ConfigurationSection price = prices.getConfigurationSection(e); + if (price != null) { + ItemStack display = price.getItemStack("displayItem"); + if (display == null) { + display = new ItemStack(Material.BEDROCK); + ItemMeta meta = display.getItemMeta(); + meta.setDisplayName("Unset displayitem"); + display.setItemMeta(meta); + } + int priceMoney = price.getInt("priceMoney"); + ArrayList priceItems = new ArrayList<>(); + ConfigurationSection itemPricesSection = price.getConfigurationSection("itemPrices"); + if (itemPricesSection != null) { + for (String pricee : itemPricesSection.getKeys(false)) { + ItemStack priceItem = itemPricesSection.getItemStack(pricee); + if (priceItem != null) { + priceItems.add(priceItem); + } + } + } + if (items == null) { + items = new ArrayList<>(); + } + items.add(new TreasureChestItem(display, priceItems.toArray(new ItemStack[priceItems.size()]), priceMoney)); + } + } + } + } + } catch (Exception e) { + plugin.getLogger().log(Level.SEVERE, "Could not load user chest file: " + file.getName(), e); + } + } + + private void save() { + file.getParentFile().mkdirs(); + YamlConfiguration conf = new YamlConfiguration(); + ConfigurationSection prices = conf.createSection("prices"); + if (items != null) { + int nr = 0; + for (TreasureChestItem i : items) { + ConfigurationSection price = prices.createSection(Integer.toString(nr++)); + price.set("displayItem", i.getDisplayItem().clone()); + price.set("priceMoney", i.getPriceMoney()); + ConfigurationSection itemsSec = price.createSection("itemPrices"); + if (i.getPriceItems() != null) { + int nr2 = 0; + for (ItemStack st : i.getPriceItems()) { + itemsSec.set(Integer.toString(nr2++), st.clone()); + } + } + } + } + try { + conf.save(file); + } catch (IOException e) { + plugin.getLogger().log(Level.SEVERE, "Could not save user chest file: " + file.getName(), e); + } + } + + public void addItem(TreasureChestItem item) { + item = item.clone(); + if (items == null) { + items = new ArrayList<>(); + } + items.add(item); + save(); + } + + public boolean removeItem(int pos) { + if (items == null || items.size() <= pos || pos < 0) { + return false; + } + items.remove(pos); + if (items.size() == 0) { + items = null; + } + save(); + return true; + } + + public boolean isEmpty() { + return items == null || items.isEmpty(); + } + + public List getItems() { + return items == null ? Collections.EMPTY_LIST : Collections.unmodifiableList(items); + } + + public TreasureChestItem getItem(int pos) { + if (items == null || items.size() <= pos || pos < 0) { + return null; + } + return items.get(pos); + } + + public void setOnline(long t) { + online = t; + } + + public boolean isOnline(long t) { + return online == t; + } +} diff --git a/src/main/java/de/iani/treasurechest/PriceChestCommandExecutor.java b/src/main/java/de/iani/treasurechest/PriceChestCommandExecutor.java new file mode 100644 index 0000000..5e55480 --- /dev/null +++ b/src/main/java/de/iani/treasurechest/PriceChestCommandExecutor.java @@ -0,0 +1,261 @@ +package de.iani.treasurechest; + +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import org.bukkit.ChatColor; +import org.bukkit.Effect; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import de.iani.playerUUIDCache.CachedPlayer; + +public class PriceChestCommandExecutor implements CommandExecutor { + private TreasureChest plugin; + + public PriceChestCommandExecutor(TreasureChest plugin) { + this.plugin = plugin; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (args.length == 0) { + displayHelp(sender, label); + } else { + String subcommand = args[0].toLowerCase(); + if (subcommand.equals("setchest")) { + if (!checkPlayer(sender) || !checkPermission(sender, "pricechest.setchest")) { + return true; + } + Player player = ((Player) sender); + Block target = player.getTargetBlock((Set) null, 5); + plugin.setChestLocation(target.getLocation()); + player.playEffect(target.getLocation(), Effect.MOBSPAWNER_FLAMES, null); + player.playEffect(target.getLocation(), Effect.MOBSPAWNER_FLAMES, null); + player.playEffect(target.getLocation(), Effect.MOBSPAWNER_FLAMES, null); + plugin.sendMessage(sender, "Treasurechest location set!"); + } else if (subcommand.equals("create")) { + if (!checkPlayer(sender) || !checkPermission(sender, "pricechest.create")) { + return true; + } + Player player = ((Player) sender); + ItemStack inHand = player.getInventory().getItemInMainHand(); + if (inHand == null || inHand.getType() == Material.AIR || inHand.getAmount() == 0) { + plugin.sendMessage(sender, "You have to hold the display item in hand!", true); + return true; + } + TreasureChestItem newItem = new TreasureChestItem(inHand.clone(), null, 0); + plugin.getData().setActiveItem(player.getUniqueId(), newItem); + plugin.sendMessage(sender, "Created a new Treasurechest item!"); + } else if (subcommand.equals("addmoney")) { + if (!checkPlayer(sender) || !checkPermission(sender, "pricechest.create")) { + return true; + } + if (args.length < 2) { + plugin.sendMessage(sender, "/" + label + " addmoney ", true); + return true; + } + int amount = getIntArgument(args[1], 0); + Player player = ((Player) sender); + TreasureChestItem activeItem = plugin.getData().getActiveItem(player.getUniqueId()); + if (activeItem == null) { + plugin.sendMessage(sender, "You have no active item!", true); + return true; + } + activeItem.setPriceMoney(activeItem.getPriceMoney() + amount); + plugin.sendMessage(sender, "Set the money to " + activeItem.getPriceMoney()); + } else if (subcommand.equals("additem")) { + if (!checkPlayer(sender) || !checkPermission(sender, "pricechest.create")) { + return true; + } + Player player = ((Player) sender); + ItemStack inHand = player.getInventory().getItemInMainHand(); + if (inHand == null || inHand.getType() == Material.AIR || inHand.getAmount() == 0) { + plugin.sendMessage(sender, "You have to hold the item in hand!", true); + return true; + } + TreasureChestItem activeItem = plugin.getData().getActiveItem(player.getUniqueId()); + if (activeItem == null) { + plugin.sendMessage(sender, "You have no active item!", true); + return true; + } + activeItem.addPriceItem(inHand.clone()); + plugin.sendMessage(sender, "Item added: " + inHand.getAmount() + " " + TreasureChest.capitalize(inHand.getType().name(), true)); + } else if (subcommand.equals("give")) { + if (!checkPlayer(sender) || !checkPermission(sender, "pricechest.give")) { + return true; + } + if (args.length < 2) { + plugin.sendMessage(sender, "/" + label + " give ", true); + return true; + } + Player player = ((Player) sender); + TreasureChestItem activeItem = plugin.getData().getActiveItem(player.getUniqueId()); + if (activeItem == null) { + plugin.sendMessage(sender, "You have no active item!", true); + return true; + } + + for (int arg = 1; arg < args.length; arg++) { + String nameOrId = args[arg].replace(",", "").trim(); + UUID targetuuid = null; + try { + targetuuid = UUID.fromString(nameOrId); + } catch (Exception e) { + CachedPlayer target = plugin.getPlayerUUIDCache().getPlayerFromNameOrUUID(nameOrId, true); + if (target != null) { + targetuuid = target.getUUID(); + nameOrId = target.getName(); + } + } + if (targetuuid == null) { + plugin.sendMessage(sender, "Unknown player!", true); + } else { + PlayerTreasureChestContent content = plugin.getData().getChestContent(targetuuid); + content.addItem(activeItem); + plugin.sendMessage(sender, "Item given to: " + nameOrId + " (" + targetuuid.toString() + ")"); + } + } + return true; + } else if (subcommand.equals("list")) { + if (!checkPermission(sender, "pricechest.list")) { + return true; + } + if (args.length < 2) { + plugin.sendMessage(sender, "/" + label + " list ", true); + return true; + } + String nameOrId = args[1]; + UUID targetuuid = null; + try { + targetuuid = UUID.fromString(nameOrId); + } catch (Exception e) { + CachedPlayer target = plugin.getPlayerUUIDCache().getPlayerFromNameOrUUID(nameOrId, true); + if (target != null) { + targetuuid = target.getUUID(); + nameOrId = target.getName(); + } + } + if (targetuuid == null) { + plugin.sendMessage(sender, "Unknown player!", true); + return true; + } + + PlayerTreasureChestContent content = plugin.getData().getChestContent(targetuuid); + plugin.sendMessage(sender, ChatColor.GRAY + "Preise von " + nameOrId + " (" + targetuuid.toString() + "):"); + List items = content.getItems(); + if (items.isEmpty()) { + plugin.sendMessage(sender, "keine Preise vorhanden"); + } else { + int nr = 1; + for (TreasureChestItem i : items) { + plugin.sendMessage(sender, nr + ": " + i.getDisplayItem().getItemMeta().getDisplayName()); + nr++; + } + } + } else if (subcommand.equals("remove")) { + if (!checkPermission(sender, "pricechest.remove")) { + return true; + } + if (args.length < 3) { + plugin.sendMessage(sender, "/" + label + " remove ", true); + return true; + } + + String nameOrId = args[1]; + UUID targetuuid = null; + try { + targetuuid = UUID.fromString(nameOrId); + } catch (Exception e) { + CachedPlayer target = plugin.getPlayerUUIDCache().getPlayerFromNameOrUUID(nameOrId, true); + if (target != null) { + targetuuid = target.getUUID(); + nameOrId = target.getName(); + } + } + if (targetuuid == null) { + plugin.sendMessage(sender, "Unknown player!", true); + return true; + } + int nr = getIntArgument(args[2], -1); + PlayerTreasureChestContent content = plugin.getData().getChestContent(targetuuid); + if (!content.removeItem(nr - 1)) { + plugin.sendMessage(sender, "Ungültige ID", true); + return true; + } + plugin.sendMessage(sender, "Der Preis wurde entfernt!"); + } else { + plugin.sendMessage(sender, "Unknown subcommand!", true); + return true; + } + } + return true; + } + + private void displayHelp(CommandSender sender, String label) { + plugin.sendMessage(sender, ChatColor.GREEN + "Commands"); + if (checkPlayer(sender, true) && checkPermission(sender, "pricechest.setchest", true)) { + plugin.sendMessage(sender, "/" + label + " setchest"); + plugin.sendMessage(sender, ChatColor.GREEN + " Set the treasure chest location to the location you are looking at."); + } + if (checkPlayer(sender, true) && checkPermission(sender, "pricechest.create", true)) { + plugin.sendMessage(sender, "/" + label + " create"); + plugin.sendMessage(sender, ChatColor.GREEN + " Creates a price with the item in hand as display item."); + plugin.sendMessage(sender, "/" + label + " additem"); + plugin.sendMessage(sender, ChatColor.GREEN + " Adds the item in hand to the price."); + plugin.sendMessage(sender, "/" + label + " addmoney "); + plugin.sendMessage(sender, ChatColor.GREEN + " Adds money to a price."); + } + if (checkPlayer(sender, true) && checkPermission(sender, "pricechest.give", true)) { + plugin.sendMessage(sender, "/" + label + " give "); + plugin.sendMessage(sender, ChatColor.GREEN + " Gives a price to a player."); + } + if (checkPermission(sender, "pricechest.list")) { + plugin.sendMessage(sender, "/" + label + " list "); + plugin.sendMessage(sender, ChatColor.GREEN + " Gives price for a player."); + } + if (checkPermission(sender, "pricechest.remove")) { + plugin.sendMessage(sender, "/" + label + " remove "); + plugin.sendMessage(sender, ChatColor.GREEN + " Removes a price from a players chest."); + } + } + + private int getIntArgument(String value, int defaultValue) { + try { + return Integer.parseInt(value); + } catch (Exception e) { + // ignore - return default + } + return defaultValue; + } + + private boolean checkPermission(CommandSender sender, String perm) { + return checkPermission(sender, perm, false); + } + + private boolean checkPermission(CommandSender sender, String perm, boolean silent) { + boolean hasPermission = sender.hasPermission(perm); + if (!silent && !hasPermission) { + plugin.sendMessage(sender, "No permission!", true); + } + return hasPermission; + } + + private boolean checkPlayer(CommandSender sender) { + return checkPlayer(sender, false); + } + + private boolean checkPlayer(CommandSender sender, boolean silent) { + boolean isPlayer = sender instanceof Player; + if (!isPlayer && !silent) { + plugin.sendMessage(sender, "You must be a player!", true); + } + return isPlayer; + } +} diff --git a/src/main/java/de/iani/treasurechest/PriceChestData.java b/src/main/java/de/iani/treasurechest/PriceChestData.java new file mode 100644 index 0000000..1ba6432 --- /dev/null +++ b/src/main/java/de/iani/treasurechest/PriceChestData.java @@ -0,0 +1,84 @@ +package de.iani.treasurechest; + +import java.io.File; +import java.util.HashMap; +import java.util.Iterator; +import java.util.UUID; + +import org.bukkit.entity.Player; + +public class PriceChestData { + private HashMap namedItems; + + private HashMap activeItems; + + private HashMap loadedChests; + + private TreasureChest plugin; + + private File chestContentFolder; + + public PriceChestData(TreasureChest plugin) { + namedItems = new HashMap<>(); + activeItems = new HashMap<>(); + loadedChests = new HashMap<>(); + + this.plugin = plugin; + chestContentFolder = new File(this.plugin.getDataFolder(), "content"); + chestContentFolder.mkdirs(); + } + + public TreasureChestItem getNamedItem(String name) { + return namedItems.get(name.toLowerCase().trim()); + } + + public TreasureChestItem getActiveItem(UUID playerUUID) { + return activeItems.get(playerUUID); + } + + public TreasureChestItem setActiveItem(UUID playerUUID, TreasureChestItem item) { + if (item == null) { + return removeActiveItem(playerUUID); + } + return activeItems.put(playerUUID, item); + } + + public TreasureChestItem removeActiveItem(UUID playerUUID) { + return activeItems.remove(playerUUID); + } + + public PlayerTreasureChestContent getChestContentIfLoaded(UUID playerUUID) { + return loadedChests.get(playerUUID); + } + + public PlayerTreasureChestContent getChestContent(UUID playerUUID) { + PlayerTreasureChestContent loaded = getChestContentIfLoaded(playerUUID); + if (loaded != null) { + return loaded; + } + return loadOrCreateChestContent(playerUUID); + } + + private PlayerTreasureChestContent loadOrCreateChestContent(UUID playerUUID) { + File playerData = new File(chestContentFolder, playerUUID.toString() + ".yml"); + PlayerTreasureChestContent content = new PlayerTreasureChestContent(plugin, playerData); + loadedChests.put(playerUUID, content); + return content; + } + + public void doGC() { + long t = System.currentTimeMillis(); + for (Player player : plugin.getServer().getOnlinePlayers()) { + PlayerTreasureChestContent content = loadedChests.get(player.getUniqueId()); + if (content != null) { + content.setOnline(t); + } + } + Iterator it = loadedChests.values().iterator(); + while (it.hasNext()) { + if (!it.next().isOnline(t)) { + it.remove(); + } + } + } +} diff --git a/src/main/java/de/iani/treasurechest/TreasureChest.java b/src/main/java/de/iani/treasurechest/TreasureChest.java new file mode 100644 index 0000000..33a2401 --- /dev/null +++ b/src/main/java/de/iani/treasurechest/TreasureChest.java @@ -0,0 +1,258 @@ +package de.iani.treasurechest; + +import java.util.ArrayList; +import java.util.Random; +import java.util.UUID; +import java.util.logging.Level; + +import net.milkbowl.vault.economy.Economy; + +import org.bukkit.ChatColor; +import org.bukkit.Effect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.java.JavaPlugin; + +import de.iani.playerUUIDCache.CachedPlayer; +import de.iani.playerUUIDCache.PlayerUUIDCache; + +public class TreasureChest extends JavaPlugin implements TreasureChestAPI { + private PriceChestData data; + + private Location chestLocation; + + private Random random; + + // private PlayerUUIDTools uuidTools; + + private boolean hasEconomy; + + private Economy economy; + + private PlayerUUIDCache playerUUIDCache; + + @Override + public void onEnable() { + random = new Random(); + setupEconomy(); + // uuidTools = new PlayerUUIDTools(this); + playerUUIDCache = (PlayerUUIDCache) getServer().getPluginManager().getPlugin("PlayerUUIDCache"); + readConfig(); + // chestLocation = new Location(getServer().getWorlds().get(0), 308, 127, -879); + data = new PriceChestData(this); + getCommand("pricechest").setExecutor(new PriceChestCommandExecutor(this)); + + getServer().getPluginManager().registerEvents(new ChestInventoryListener(this), this); + getServer().getPluginManager().registerEvents(new PlayerEventListener(this), this); + getServer().getScheduler().runTaskTimer(this, new Runnable() { + @Override + public void run() { + createParticles(); + } + }, 1, 1); + + getServer().getScheduler().runTaskTimer(this, new Runnable() { + @Override + public void run() { + doGC(); + } + }, 8456, 140000); + } + + public PlayerUUIDCache getPlayerUUIDCache() { + return playerUUIDCache; + } + + @Override + public boolean addItem(String player, ItemStack displayItem, ItemStack[] items, int money) { + if (!getServer().isPrimaryThread()) { + return false; + } + CachedPlayer id = playerUUIDCache.getPlayerFromNameOrUUID(player, true); + if (id == null) { + return false; + } + return addItem(id.getUUID(), displayItem, items, money); + } + + @Override + public boolean addItem(OfflinePlayer player, ItemStack displayItem, ItemStack[] items, int money) { + if (!getServer().isPrimaryThread()) { + return false; + } + return addItem(player.getUniqueId(), displayItem, items, money); + } + + private boolean addItem(UUID player, ItemStack displayItem, ItemStack[] items, int money) { + if (displayItem == null || displayItem.getAmount() == 0 || displayItem.getType() == Material.AIR) { + return false; + } + ArrayList copied = new ArrayList<>(); + for (ItemStack is : items) { + if (is != null && is.getAmount() > 0 && is.getType() != Material.AIR) { + copied.add(is); + } + } + items = copied.toArray(new ItemStack[copied.size()]); + + PlayerTreasureChestContent content = getData().getChestContent(player); + content.addItem(new TreasureChestItem(displayItem, items, money)); + return true; + } + + protected void doGC() { + data.doGC(); + } + + private void readConfig() { + // saveDefaultConfig(); + FileConfiguration config = getConfig(); + ConfigurationSection section = config.getConfigurationSection("chestLocation"); + if (section != null) { + String worldName = section.getString("world"); + int x = section.getInt("x"); + int y = section.getInt("y"); + int z = section.getInt("z"); + if (worldName != null) { + World world = getServer().getWorld(worldName); + if (world != null) { + chestLocation = new Location(world, x, y, z); + } + } + } + } + + public void saveConfig() { + FileConfiguration config = getConfig(); + if (chestLocation == null || chestLocation.getWorld() == null) { + config.set("chestLocation", null); + } else { + ConfigurationSection section = config.getConfigurationSection("chestLocation"); + if (section == null) { + section = config.createSection("chestLocation"); + } + section.set("world", chestLocation.getWorld().getName()); + section.set("x", chestLocation.getBlockX()); + section.set("y", chestLocation.getBlockY()); + section.set("z", chestLocation.getBlockZ()); + } + super.saveConfig(); + } + + // public PlayerUUIDTools getUUIDTools() + // { + // return uuidTools; + // } + + public PriceChestData getData() { + return data; + } + + public Location getChestLocation() { + return chestLocation; + } + + protected void createParticles() { + if (random.nextInt(10) == 0 && chestLocation != null) { + Location playerLocation = new Location(null, 0, 0, 0); + for (Player player : getServer().getOnlinePlayers()) { + player.getLocation(playerLocation); + if (playerLocation.getWorld() == chestLocation.getWorld()) { + double dx = playerLocation.getX() - chestLocation.getX(); + double dy = playerLocation.getY() - chestLocation.getY(); + double dz = playerLocation.getZ() - chestLocation.getZ(); + double dsquared = dx * dx + dy * dy + dz * dz; + if (dsquared < 16 * 16) { + if (!data.getChestContent(player.getUniqueId()).isEmpty()) { + player.playEffect(chestLocation, Effect.MOBSPAWNER_FLAMES, null); + } + } + } + } + } + } + + public void sendMessage(CommandSender p, String text) { + sendMessage(p, text, false); + } + + public void sendMessage(CommandSender p, String text, boolean error) { + p.sendMessage(ChatColor.BLUE + "[TC] " + (error ? ChatColor.DARK_RED : ChatColor.YELLOW) + text); + } + + public void setChestLocation(Location location) { + chestLocation = location; + saveConfig(); + } + + private void setupEconomy() { + try { + RegisteredServiceProvider economyProvider = getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class); + if (economyProvider != null) { + economy = economyProvider.getProvider(); + hasEconomy = true; + } else { + getLogger().severe("Kein Economy-Plugin! Es können keine Preisgelder ausgezahlt werden!"); + } + } catch (Throwable e) { + getLogger().severe("Vault nicht gefunden! Es können keine Preisgelder ausgezahlt werden!"); + } + } + + public boolean hasEconomy() { + return hasEconomy; + } + + public void giveMoney(Player player, int amount) { + if (hasEconomy) { + try { + economy.depositPlayer(player, amount); + } catch (Throwable e) { + getLogger().log(Level.SEVERE, "Error paying money", e); + } + } + } + + public String formatMoney(int amount) { + if (hasEconomy) { + try { + return economy.format(amount); + } catch (Throwable e) { + getLogger().log(Level.SEVERE, "Error formating money", e); + } + } + return Integer.toString(amount); + } + + public static String capitalize(String s, boolean replaceUnderscores) { + char[] cap = s.toCharArray(); + boolean lastSpace = true; + for (int i = 0; i < cap.length; i++) { + if (cap[i] == '_') { + if (replaceUnderscores) { + cap[i] = ' '; + } + lastSpace = true; + } else if (cap[i] >= '0' && cap[i] <= '9') { + lastSpace = true; + } else { + if (lastSpace) { + cap[i] = Character.toUpperCase(cap[i]); + } else { + cap[i] = Character.toLowerCase(cap[i]); + } + lastSpace = false; + } + } + return new String(cap); + } + +} diff --git a/src/main/java/de/iani/treasurechest/TreasureChestAPI.java b/src/main/java/de/iani/treasurechest/TreasureChestAPI.java new file mode 100644 index 0000000..a41e45e --- /dev/null +++ b/src/main/java/de/iani/treasurechest/TreasureChestAPI.java @@ -0,0 +1,10 @@ +package de.iani.treasurechest; + +import org.bukkit.OfflinePlayer; +import org.bukkit.inventory.ItemStack; + +public interface TreasureChestAPI { + public abstract boolean addItem(OfflinePlayer player, ItemStack displayItem, ItemStack[] items, int money); + + public abstract boolean addItem(String player, ItemStack displayItem, ItemStack[] items, int money); +} diff --git a/src/main/java/de/iani/treasurechest/TreasureChestItem.java b/src/main/java/de/iani/treasurechest/TreasureChestItem.java new file mode 100644 index 0000000..04bb03c --- /dev/null +++ b/src/main/java/de/iani/treasurechest/TreasureChestItem.java @@ -0,0 +1,67 @@ +package de.iani.treasurechest; + +import org.bukkit.inventory.ItemStack; + +public class TreasureChestItem implements Cloneable { + private ItemStack displayItem; + + private ItemStack[] priceItems; + + private int priceMoney; + + public TreasureChestItem(ItemStack displayItem) { + this.displayItem = displayItem; + } + + public TreasureChestItem(ItemStack displayItem, ItemStack[] priceItems, int priceMoney) { + this.displayItem = displayItem; + this.priceItems = priceItems; + this.priceMoney = priceMoney; + } + + public ItemStack getDisplayItem() { + return displayItem; + } + + public ItemStack[] getPriceItems() { + return priceItems; + } + + public int getPriceMoney() { + return priceMoney; + } + + public void setPriceMoney(int amount) { + priceMoney = amount; + } + + public void addPriceItem(ItemStack item) { + if (priceItems == null) { + priceItems = new ItemStack[] { item }; + } else { + ItemStack[] temp = priceItems; + priceItems = new ItemStack[temp.length + 1]; + System.arraycopy(temp, 0, priceItems, 0, temp.length); + priceItems[temp.length] = item; + } + } + + @Override + public TreasureChestItem clone() { + try { + TreasureChestItem el = (TreasureChestItem) super.clone(); + if (displayItem != null) { + el.displayItem = displayItem.clone(); + } + if (priceItems != null) { + el.priceItems = new ItemStack[priceItems.length]; + for (int i = 0; i < priceItems.length; i++) { + el.priceItems[i] = priceItems[i] != null ? priceItems[i].clone() : null; + } + } + return el; + } catch (CloneNotSupportedException e) { + throw new Error(e); + } + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..d560ec3 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,44 @@ +name: ${project.artifactId} +main: de.iani.treasurechest.TreasureChest +version: ${project.version}-${build.number} +author: Brokkonaut +description: Treasure Chests for Events +softdepend: [Vault] +depend: [PlayerUUIDCache] + +commands: + prizechest: + description: Prizechest/Treasurechest + aliases: [prize, pc, treasurechest, tc] + +permissions: + treasurechest.admin: + description: Gives access to all commands + default: op + children: + treasurechest.setchest: true + treasurechest.create: true + treasurechest.give: true + treasurechest.list: true + treasurechest.remove: true + treasurechest.staff: + description: Gives access to most commands + default: op + children: + treasurechest.create: true + treasurechest.give: true + treasurechest.list: true + treasurechest.remove: true + treasurechest.access: + description: Access your treasure chest + default: true + treasurechest.setchest: + description: Change the chest location + treasurechest.create: + description: Creates a treasure + treasurechest.give: + description: Gives a treasure to a player + treasurechest.list: + description: Lists treasures for a player + treasurechest.remove: + description: Removes a treasure from a player \ No newline at end of file