From 34388de2947ec9f67dac3de5b91d66f113eab2da Mon Sep 17 00:00:00 2001 From: Beez0r Date: Tue, 4 Jan 2022 23:03:47 -0800 Subject: [PATCH 01/15] iShop 2.16 Update --- src/com/minedhype/ishop/CommandShop.java | 1 + src/com/minedhype/ishop/Shop.java | 18 ++++ src/com/minedhype/ishop/iShop.java | 8 +- .../ishop/inventories/InvCreateRow.java | 11 +- .../minedhype/ishop/inventories/InvStock.java | 102 ++++++++++-------- src/resources/config.yml | 5 +- 6 files changed, 92 insertions(+), 53 deletions(-) diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index 06f976a..e32d809 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -611,6 +611,7 @@ private void reloadShop(Player player) { InvAdminShop.stockGUIShop = iShop.config.getBoolean("enableStockAccessFromShopGUI"); InvCreateRow.disabledItemList = iShop.config.getStringList("disabledItemsList"); InvCreateRow.itemsDisabled = iShop.config.getBoolean("disabledItems"); + InvCreateRow.strictStock = iShop.config.getBoolean("strictStock"); InvShop.listAllShops = iShop.config.getBoolean("publicShopListCommand"); Shop.showOwnedShops = iShop.config.getBoolean("publicShopListShowsOwned"); Shop.shopEnabled = iShop.config.getBoolean("enableShopBlock"); diff --git a/src/com/minedhype/ishop/Shop.java b/src/com/minedhype/ishop/Shop.java index 9d8170a..86bc195 100644 --- a/src/com/minedhype/ishop/Shop.java +++ b/src/com/minedhype/ishop/Shop.java @@ -10,6 +10,7 @@ import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import com.minedhype.ishop.inventories.InvAdminShop; import org.bukkit.Bukkit; @@ -96,6 +97,23 @@ private Shop(int idTienda, UUID owner, Location loc, boolean admin) { public static boolean checkShopDistanceFromStockBlock(Location stockLocation, UUID shopOwner) { return shops.parallelStream().filter(s -> !s.admin && s.isOwner(shopOwner)).anyMatch(s -> s.getLocation().getWorld().equals(stockLocation.getWorld()) && s.location.distanceSquared(stockLocation) <= EventShop.stockRangeLimit*EventShop.stockRangeLimit); } public static int getNumShops(UUID owner) { return (int) shops.parallelStream().filter(t -> !t.admin && t.owner.equals(owner)).count(); } + public static boolean strictStockShopCheck(ItemStack item, UUID uuid) { + AtomicBoolean restricted = new AtomicBoolean(true); + shops.parallelStream().filter(s -> !s.admin && s.isOwner(uuid)).forEach(s -> { + if(restricted.get()) { + for(int i=0; i<5; i++) { + if(restricted.get()) { + Optional row = s.getRow(i); + if(row.isPresent()) + if(row.get().getItemOut().isSimilar(item) || row.get().getItemOut2().isSimilar(item)) + restricted.set(false); + } + } + } + }); + return restricted.get(); + } + public static void getPlayersShopList() { if(iShop.config.getBoolean("adminShopPublic")) shops.parallelStream().forEach(s -> shopList.putIfAbsent(s.idTienda, s.owner)); diff --git a/src/com/minedhype/ishop/iShop.java b/src/com/minedhype/ishop/iShop.java index fc49b47..a944483 100644 --- a/src/com/minedhype/ishop/iShop.java +++ b/src/com/minedhype/ishop/iShop.java @@ -85,6 +85,7 @@ public void onEnable() { public void onDisable() { tickTask.cancel(); expiredTask.cancel(); + getServer().getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Saving shops & stock items to database, please wait & do not kill server process..."); if(Bukkit.getScheduler().isCurrentlyRunning(saveTask.getTaskId())) { while(Bukkit.getScheduler().isCurrentlyRunning(saveTask.getTaskId())) ; @@ -94,6 +95,7 @@ public void onDisable() { saveTask.cancel(); Shop.saveData(); } + getServer().getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Saving complete!"); if(connection != null) { try { connection.close(); @@ -257,9 +259,11 @@ public void createConfig() { List exemptExpiredShops = Arrays.asList("00000000-0000-0000-0000-000000000000"); config.set("exemptExpiringShops", exemptExpiredShops); config.set("outsideRegion", "&cCannot create shop outside of ishop region!"); - config.set("configVersion", "3.1"); - config.save(configFile); case "3.1": + config.set("strictStock", false); + config.set("configVersion", "3.2"); + config.save(configFile); + case "3.2": break; } } catch(IOException | InvalidConfigurationException e) { e.printStackTrace(); } diff --git a/src/com/minedhype/ishop/inventories/InvCreateRow.java b/src/com/minedhype/ishop/inventories/InvCreateRow.java index 4b6c647..99c6b3f 100644 --- a/src/com/minedhype/ishop/inventories/InvCreateRow.java +++ b/src/com/minedhype/ishop/inventories/InvCreateRow.java @@ -25,6 +25,7 @@ public class InvCreateRow extends GUI { private ItemStack itemOut2; private final ItemStack airItem = new ItemStack(Material.AIR, 0); public static Boolean itemsDisabled = iShop.config.getBoolean("disabledItems"); + public static Boolean strictStock = iShop.config.getBoolean("strictStock"); public static List disabledItemList = iShop.config.getStringList("disabledItemsList"); public InvCreateRow(Shop shop, int index) { @@ -53,14 +54,14 @@ else if(i == 13) { return; if((itemOut == airItem && itemOut2 == airItem) || (itemIn == airItem && itemIn2 == airItem)) return; + ItemStack in1 = itemIn.clone(); + ItemStack in2 = itemIn2.clone(); + ItemStack out1 = itemOut.clone(); + ItemStack out2 = itemOut2.clone(); if(itemsDisabled) { for(String itemsList:disabledItemList) { Material disabledItemsList = Material.matchMaterial(itemsList); if(disabledItemsList != null) { - ItemStack in1 = itemIn.clone(); - ItemStack in2 = itemIn2.clone(); - ItemStack out1 = itemOut.clone(); - ItemStack out2 = itemOut2.clone(); if(in1.getType().equals(disabledItemsList) || in2.getType().equals(disabledItemsList) || out1.getType().equals(disabledItemsList) || out2.getType().equals(disabledItemsList)) return; if(in1.getType().toString().contains("SHULKER_BOX") && in1.getItemMeta() instanceof BlockStateMeta) { @@ -130,7 +131,7 @@ else if(out2.getType().equals(Material.BUNDLE)) { } } } - shop.getRows()[index] = new RowStore(itemOut, itemOut2, itemIn, itemIn2, false); + shop.getRows()[index] = new RowStore(out1, out2, in1, in2, false); InvAdminShop inv = new InvAdminShop(shop, p.getPlayer()); inv.open(p); }); diff --git a/src/com/minedhype/ishop/inventories/InvStock.java b/src/com/minedhype/ishop/inventories/InvStock.java index f386104..e7aab82 100644 --- a/src/com/minedhype/ishop/inventories/InvStock.java +++ b/src/com/minedhype/ishop/inventories/InvStock.java @@ -5,6 +5,12 @@ import java.util.Optional; import java.util.UUID; import java.util.HashMap; +import com.minedhype.ishop.Messages; +import com.minedhype.ishop.Permission; +import com.minedhype.ishop.Shop; +import com.minedhype.ishop.StockShop; +import com.minedhype.ishop.iShop; +import com.minedhype.ishop.gui.GUI; import org.bukkit.Material; import org.bukkit.block.ShulkerBox; import org.bukkit.entity.Player; @@ -12,10 +18,6 @@ import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import com.minedhype.ishop.Messages; -import com.minedhype.ishop.StockShop; -import com.minedhype.ishop.iShop; -import com.minedhype.ishop.gui.GUI; import org.bukkit.inventory.meta.BlockStateMeta; import org.bukkit.inventory.meta.BundleMeta; @@ -26,6 +28,7 @@ public class InvStock extends GUI { private final ItemStack airItem = new ItemStack(Material.AIR, 0); private final UUID owner; private int pag; + private Player player; private InvStock(UUID owner) { super(54, Messages.SHOP_TITLE_STOCK.toString()); @@ -41,51 +44,59 @@ public void onClick(InventoryClickEvent event) { super.onClick(event); if(event.getRawSlot() >= 45 && event.getRawSlot() < 54) return; - if(InvCreateRow.itemsDisabled && event.getRawSlot() >= 54) { - ItemStack item = event.getCurrentItem(); - ItemStack item2 = event.getCursor(); - for(String itemsList:InvCreateRow.disabledItemList) { - Material disabledItemsList = Material.matchMaterial(itemsList); - if(item == null) - item = airItem; - if(item2 == null) - item2 = airItem; - if(disabledItemsList != null) { - if(!item.isSimilar(airItem)) { - if(item.getType().equals(disabledItemsList)) - return; - if(item.getType().toString().contains("SHULKER_BOX") && item.getItemMeta() instanceof BlockStateMeta) { - BlockStateMeta itemMeta1 = (BlockStateMeta) item.getItemMeta(); - ShulkerBox shulkerBox1 = (ShulkerBox) itemMeta1.getBlockState(); - if(shulkerBox1.getInventory().contains(disabledItemsList)) + if(event.getRawSlot() >= 54 && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + if(InvCreateRow.strictStock) { + ItemStack item = event.getCurrentItem(); + ItemStack item2 = event.getCursor(); + if(Shop.strictStockShopCheck(item, owner) || Shop.strictStockShopCheck(item2, owner)) + return; + } + if(InvCreateRow.itemsDisabled) { + ItemStack item = event.getCurrentItem(); + ItemStack item2 = event.getCursor(); + for(String itemsList:InvCreateRow.disabledItemList) { + Material disabledItemsList = Material.matchMaterial(itemsList); + if(item == null) + item = airItem; + if(item2 == null) + item2 = airItem; + if(disabledItemsList != null) { + if(!item.isSimilar(airItem)) { + if(item.getType().equals(disabledItemsList)) return; - } else if(item.getType().equals(Material.BUNDLE)) { - BundleMeta bundleIn1 = (BundleMeta) item.getItemMeta(); - if(bundleIn1.hasItems()) { - ItemStack itemDisabledOut = new ItemStack(disabledItemsList); - List bundleIn1Items = bundleIn1.getItems(); - for(ItemStack bundleList : bundleIn1Items) - if(bundleList.isSimilar(itemDisabledOut)) - return; + if(item.getType().toString().contains("SHULKER_BOX") && item.getItemMeta() instanceof BlockStateMeta) { + BlockStateMeta itemMeta1 = (BlockStateMeta) item.getItemMeta(); + ShulkerBox shulkerBox1 = (ShulkerBox) itemMeta1.getBlockState(); + if(shulkerBox1.getInventory().contains(disabledItemsList)) + return; + } else if(item.getType().equals(Material.BUNDLE)) { + BundleMeta bundleIn1 = (BundleMeta) item.getItemMeta(); + if(bundleIn1.hasItems()) { + ItemStack itemDisabledOut = new ItemStack(disabledItemsList); + List bundleIn1Items = bundleIn1.getItems(); + for(ItemStack bundleList : bundleIn1Items) + if(bundleList.isSimilar(itemDisabledOut)) + return; + } } } - } - if(!item2.isSimilar(airItem)) { - if(item2.getType().equals(disabledItemsList)) - return; - if(item2.getType().toString().contains("SHULKER_BOX") && item2.getItemMeta() instanceof BlockStateMeta) { - BlockStateMeta itemMeta2 = (BlockStateMeta) item2.getItemMeta(); - ShulkerBox shulkerBox2 = (ShulkerBox) itemMeta2.getBlockState(); - if(shulkerBox2.getInventory().contains(disabledItemsList)) + if(!item2.isSimilar(airItem)) { + if(item2.getType().equals(disabledItemsList)) return; - } else if(item2.getType().equals(Material.BUNDLE)) { - BundleMeta bundleIn2 = (BundleMeta) item2.getItemMeta(); - if(bundleIn2.hasItems()) { - ItemStack itemDisabledOut = new ItemStack(disabledItemsList); - List bundleIn2Items = bundleIn2.getItems(); - for(ItemStack bundleList : bundleIn2Items) - if(bundleList.isSimilar(itemDisabledOut)) - return; + if(item2.getType().toString().contains("SHULKER_BOX") && item2.getItemMeta() instanceof BlockStateMeta) { + BlockStateMeta itemMeta2 = (BlockStateMeta) item2.getItemMeta(); + ShulkerBox shulkerBox2 = (ShulkerBox) itemMeta2.getBlockState(); + if(shulkerBox2.getInventory().contains(disabledItemsList)) + return; + } else if(item2.getType().equals(Material.BUNDLE)) { + BundleMeta bundleIn2 = (BundleMeta) item2.getItemMeta(); + if(bundleIn2.hasItems()) { + ItemStack itemDisabledOut = new ItemStack(disabledItemsList); + List bundleIn2Items = bundleIn2.getItems(); + for(ItemStack bundleList : bundleIn2Items) + if(bundleList.isSimilar(itemDisabledOut)) + return; + } } } } @@ -123,6 +134,7 @@ private void openPage(Player player, int pag) { @Override public void open(Player player) { + this.player = player; refreshItems(); super.open(player); } diff --git a/src/resources/config.yml b/src/resources/config.yml index f2366d2..cd15f79 100644 --- a/src/resources/config.yml +++ b/src/resources/config.yml @@ -157,6 +157,9 @@ stockRangeLimitFromShop: 0 # Set to true if you would like '/shop stock' command range limit to be enforced using stockRangeLimitFromShop distance stockRangeLimitUsingCommand: false +# This will only allow items that are in active shop trades to be added and stored in stock inventory +strictStock: false + # Customizable Messages adminShop: "Admin Shop #%id" adminShopDisabled: "&cAdmin shops have been disabled!" @@ -235,4 +238,4 @@ countError: "&cGiven item to search stock for does not exist!" outsideRegion: "&cCannot create shop outside of ishop region!" # Do not edit this! -configVersion: 3.1 \ No newline at end of file +configVersion: 3.2 \ No newline at end of file From 3c96a5f5a5fe94744940f4820b739e321ef46ab3 Mon Sep 17 00:00:00 2001 From: Beez0r Date: Mon, 21 Feb 2022 18:44:43 -0800 Subject: [PATCH 02/15] iShop 2.17-beta3 --- src/com/minedhype/ishop/CommandShop.java | 28 ++++++++++++++----- src/com/minedhype/ishop/Messages.java | 3 ++ src/com/minedhype/ishop/Permission.java | 4 +++ src/com/minedhype/ishop/Shop.java | 8 +++++- src/com/minedhype/ishop/iShop.java | 13 +++++++-- .../minedhype/ishop/inventories/InvStock.java | 9 ++++-- src/resources/config.yml | 5 +++- src/resources/plugin.yml | 2 +- 8 files changed, 58 insertions(+), 14 deletions(-) diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index e32d809..53f8fe8 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -28,6 +28,8 @@ import com.minedhype.ishop.inventories.InvAdminShop; import com.minedhype.ishop.inventories.InvShopList; import com.minedhype.ishop.inventories.InvStock; +import me.ryanhamshire.GriefPrevention.Claim; +import me.ryanhamshire.GriefPrevention.GriefPrevention; public class CommandShop implements CommandExecutor { @Override @@ -104,9 +106,9 @@ private void listSubCmd(Player player, String label) { player.sendMessage(ChatColor.GRAY + "/" + label + " delete"); player.sendMessage(ChatColor.GRAY + "/" + label + " deleteid "); player.sendMessage(ChatColor.GRAY + "/" + label + " list"); - if(iShop.config.getBoolean("publicListCommand") || player.hasPermission(Permission.SHOP_ADMIN.toString())) + if(iShop.config.getBoolean("publicListCommand") || player.hasPermission(Permission.SHOP_ADMIN.toString()) || player.hasPermission(Permission.SHOP_LIST.toString())) player.sendMessage(ChatColor.GRAY + "/" + label + " list "); - if(iShop.config.getBoolean("publicShopListCommand") || player.hasPermission(Permission.SHOP_ADMIN.toString())) + if(iShop.config.getBoolean("publicShopListCommand") || player.hasPermission(Permission.SHOP_ADMIN.toString()) || player.hasPermission(Permission.SHOP_SHOPS.toString())) player.sendMessage(ChatColor.GRAY + "/" + label + " shops"); player.sendMessage(ChatColor.GRAY + "/" + label + " manage "); player.sendMessage(ChatColor.GRAY + "/" + label + " out"); @@ -218,6 +220,18 @@ private void createStore(Player player) { player.sendMessage(Messages.WG_REGION.toString()); return; } + boolean allowShopCreateInClaim = false; + if(iShop.gpLoader != null) { + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(block.getLocation(), false, false, null); + if(claim == null || claim.allowAccess(player) == null || claim.allowEdit(player) == null || claim.allowContainers(player) == null) + allowShopCreateInClaim = true; + } + else + allowShopCreateInClaim = true; + if(!allowShopCreateInClaim) { + player.sendMessage(Messages.GP_CLAIM.toString()); + return; + } Optional shop = Shop.getShopByLocation(block.getLocation()); if(shop.isPresent()) { player.sendMessage(Messages.EXISTING_SHOP.toString()); @@ -503,7 +517,7 @@ private void deleteShopID(Player player, String shopId) { } private void listShops(Player player, String playerName) { - if(playerName != null && !iShop.config.getBoolean("publicListCommand") && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + if(playerName != null && !iShop.config.getBoolean("publicListCommand") && !player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_LIST.toString())) { player.sendMessage(Messages.NO_PERMISSION.toString()); return; } @@ -532,7 +546,7 @@ private void listAdminShops(Player player) { } private void listAllShops(Player player) { - if(!InvShop.listAllShops && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + if(!InvShop.listAllShops && !player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_SHOPS.toString())) { player.sendMessage(Messages.SHOP_LIST_DISABLED.toString()); return; } @@ -636,7 +650,7 @@ private static UUID getUUID(String name) throws Exception { } private static void shopManage(Player player, String shopID) { - if(!InvAdminShop.remoteManage && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + if(!InvAdminShop.remoteManage && !player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_REMOTEMANAGE.toString())) { player.sendMessage(Messages.SHOP_REMOTE.toString()); return; } @@ -672,7 +686,7 @@ private static void shopManage(Player player, String shopID) { } private static void viewShop(Player player, String shopId) { - if(!iShop.config.getBoolean("remoteShopping") && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + if(!iShop.config.getBoolean("remoteShopping") && !player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_REMOTESHOPPING.toString())) { player.sendMessage(Messages.SHOP_NO_REMOTE.toString()); return; } @@ -689,7 +703,7 @@ private static void viewShop(Player player, String shopId) { player.sendMessage(Messages.SHOP_NOT_FOUND.toString()); return; } - if(shop.get().getOwner().equals(player.getUniqueId()) && !InvAdminShop.remoteManage && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + if(shop.get().getOwner().equals(player.getUniqueId()) && !InvAdminShop.remoteManage && !player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_REMOTEMANAGE.toString())) { player.sendMessage(Messages.SHOP_REMOTE.toString()); return; } diff --git a/src/com/minedhype/ishop/Messages.java b/src/com/minedhype/ishop/Messages.java index 41641fa..f8a521c 100644 --- a/src/com/minedhype/ishop/Messages.java +++ b/src/com/minedhype/ishop/Messages.java @@ -7,6 +7,7 @@ public enum Messages { ADMIN_SHOP_NUMBER("adminShopNumber"), DISABLED_SHOP_BLOCK("disabledShopBlock"), EXISTING_SHOP("existingShop"), + GP_CLAIM("noClaimPermission"), NOT_A_PLAYER("notPlayer"), NO_PERMISSION("noPermissions"), NO_PLAYER_FOUND("noPlayerFound"), @@ -44,6 +45,8 @@ public enum Messages { SHOP_NUMBER("shopNumber"), SHOP_OUT("outOfStock"), SHOP_PAGE("page"), + SHOP_PAGE_SKIPAHEAD("pageSkipAhead"), + SHOP_PAGE_SKIPPREV("pageSkipPrev"), SHOP_PURCHASE("buy"), SHOP_RELOAD("reload"), SHOP_REMOTE("noRemoteManage"), diff --git a/src/com/minedhype/ishop/Permission.java b/src/com/minedhype/ishop/Permission.java index 1130828..300fd2e 100644 --- a/src/com/minedhype/ishop/Permission.java +++ b/src/com/minedhype/ishop/Permission.java @@ -5,6 +5,10 @@ public enum Permission { SHOP_CREATE("ishop.create"), SHOP_LIMIT_BYPASS("ishop.create.limit.bypass"), SHOP_LIMIT_PREFIX("ishop.create.limit."), + SHOP_LIST("ishop.list"), + SHOP_REMOTEMANAGE("ishop.remotemanage"), + SHOP_REMOTESHOPPING("ishop.remoteshopping"), + SHOP_SHOPS("ishop.shops"), SHOP_STOCK("ishop.stock"); private final String perm; diff --git a/src/com/minedhype/ishop/Shop.java b/src/com/minedhype/ishop/Shop.java index 86bc195..1793a50 100644 --- a/src/com/minedhype/ishop/Shop.java +++ b/src/com/minedhype/ishop/Shop.java @@ -466,13 +466,19 @@ public static void loadData() { loadShops = iShop.getConnection().prepareStatement("SELECT location, owner, itemIn, itemIn2, itemOut, itemOut2, idTienda, admin, broadcast FROM zooMercaTiendasFilas LEFT JOIN zooMercaTiendas ON id = idTienda ORDER BY idTienda;"); ResultSet dataStore = loadShops.executeQuery(); while(dataStore.next()) { + if(dataStore.getString(1) == null) { + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] Error: Skipped loading a shop with null location in database!"); + continue; + } String[] locationRaw = dataStore.getString(1).split(";"); int x = Integer.parseInt(locationRaw[0]); int y = Integer.parseInt(locationRaw[1]); int z = Integer.parseInt(locationRaw[2]); World world = Bukkit.getWorld(locationRaw[3]); - if(world == null) + if(world == null) { + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] Error: Skipped loading a shop with null world in database!"); continue; + } Location location = new Location(world, x, y, z); Optional shop = Shop.getShopByLocation(location); if(!shop.isPresent()) { diff --git a/src/com/minedhype/ishop/iShop.java b/src/com/minedhype/ishop/iShop.java index a944483..f857e12 100644 --- a/src/com/minedhype/ishop/iShop.java +++ b/src/com/minedhype/ishop/iShop.java @@ -22,11 +22,13 @@ import com.minedhype.ishop.MetricsLite; import net.milkbowl.vault.economy.Economy; import org.bukkit.scheduler.BukkitTask; +import me.ryanhamshire.GriefPrevention.GriefPrevention; public class iShop extends JavaPlugin { File configFile; public static FileConfiguration config; public static WorldGuardLoader wgLoader = null; + public static GriefPrevention gpLoader = null; private static BukkitTask expiredTask, saveTask, tickTask; private static Connection connection = null; private static Economy economy = null; @@ -34,6 +36,9 @@ public class iShop extends JavaPlugin { @Override public void onLoad() { + Plugin gpCheck = Bukkit.getPluginManager().getPlugin("GriefPrevention"); + if(gpCheck != null) + gpLoader = (GriefPrevention)gpCheck; Plugin wgCheck = Bukkit.getPluginManager().getPlugin("WorldGuard"); if(wgCheck != null) wgLoader = new WorldGuardLoader(); @@ -261,9 +266,13 @@ public void createConfig() { config.set("outsideRegion", "&cCannot create shop outside of ishop region!"); case "3.1": config.set("strictStock", false); - config.set("configVersion", "3.2"); - config.save(configFile); case "3.2": + config.set("noClaimPermission", "&cYou do not have permission in this claim to create a shop!"); + config.set("pageSkipAhead", "5 Pages >>"); + config.set("pageSkipPrev", "<< 5 Pages"); + config.set("configVersion", "3.3"); + config.save(configFile); + case "3.3": break; } } catch(IOException | InvalidConfigurationException e) { e.printStackTrace(); } diff --git a/src/com/minedhype/ishop/inventories/InvStock.java b/src/com/minedhype/ishop/inventories/InvStock.java index e7aab82..8122210 100644 --- a/src/com/minedhype/ishop/inventories/InvStock.java +++ b/src/com/minedhype/ishop/inventories/InvStock.java @@ -28,6 +28,7 @@ public class InvStock extends GUI { private final ItemStack airItem = new ItemStack(Material.AIR, 0); private final UUID owner; private int pag; + private int totalPages = iShop.config.getInt("stockPages"); private Player player; private InvStock(UUID owner) { @@ -115,10 +116,14 @@ public void refreshItems() { placeItem(i, inv.getItem(i)); for(int i=45; i<54; i++) { - if(i == 47 && pag > 0) + if(i == 46 && pag > 4 && totalPages >= 10) + placeItem(i, GUI.createItem(Material.SPECTRAL_ARROW, Messages.SHOP_PAGE_SKIPPREV.toString()), p -> openPage(p, pag-5)); + else if(i == 47 && pag > 0) placeItem(i, GUI.createItem(Material.ARROW, Messages.SHOP_PAGE + " " + (pag)), p -> openPage(p, pag-1)); - else if(i == 51 && pag < iShop.config.getInt("stockPages")-1) + else if(i == 51 && pag < totalPages-1) placeItem(i, GUI.createItem(Material.ARROW, Messages.SHOP_PAGE + " " + (pag+2)), p -> openPage(p, pag+1)); + else if(i == 52 && pag < totalPages-5 && totalPages >= 10) + placeItem(i, GUI.createItem(Material.SPECTRAL_ARROW, Messages.SHOP_PAGE_SKIPAHEAD.toString()), p -> openPage(p, pag+5)); else placeItem(i, GUI.createItem(Material.BLACK_STAINED_GLASS_PANE, "")); } diff --git a/src/resources/config.yml b/src/resources/config.yml index cd15f79..59a304e 100644 --- a/src/resources/config.yml +++ b/src/resources/config.yml @@ -236,6 +236,9 @@ countAmount: "&aTotal amount of %item found: %amount" countEmpty: "&cCannot find any %item in stock inventory!" countError: "&cGiven item to search stock for does not exist!" outsideRegion: "&cCannot create shop outside of ishop region!" +noClaimPermission: "&cYou do not have permission in this claim to create a shop!" +pageSkipAhead: "5 Pages >>" +pageSkipPrev: "<< 5 Pages" # Do not edit this! -configVersion: 3.2 \ No newline at end of file +configVersion: 3.3 \ No newline at end of file diff --git a/src/resources/plugin.yml b/src/resources/plugin.yml index a503688..f2f8264 100644 --- a/src/resources/plugin.yml +++ b/src/resources/plugin.yml @@ -5,7 +5,7 @@ author: Beez0r website: https://minedhype.com version: "${project.version}" api-version: "1.17" -softdepend: [Vault, WorldGuard] +softdepend: [GriefPrevention, Vault, WorldGuard] commands: ishop: description: "/shop" From cde7302c21679debf5f2a0bf654dd78d491913cc Mon Sep 17 00:00:00 2001 From: Beez0r Date: Tue, 22 Feb 2022 19:29:48 -0800 Subject: [PATCH 03/15] iShop 2.17-beta4. Closes #14 --- src/com/minedhype/ishop/CommandShop.java | 28 +++++++++++++++++++----- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index 53f8fe8..bb82792 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -39,6 +39,10 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String reloadShop(null); return true; } + else if(args[0].equalsIgnoreCase("deleteid") && args[1] != null) { + deleteShopID(null, args[1]); + return true; + } else { sender.sendMessage(Messages.NOT_A_PLAYER.toString()); return false; @@ -485,24 +489,33 @@ private void deleteShopID(Player player, String shopId) { sID = Integer.parseInt(shopId); } catch (Exception e) { sID = -1; } if(sID < 0) { - player.sendMessage(Messages.SHOP_ID_INTEGER.toString()); + if(player != null) + player.sendMessage(Messages.SHOP_ID_INTEGER.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_ID_INTEGER.toString()); return; } Optional shop = Shop.getShopById(sID); if(!shop.isPresent()) { - player.sendMessage(Messages.SHOP_NOT_FOUND.toString()); + if(player != null) + player.sendMessage(Messages.SHOP_NOT_FOUND.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_NOT_FOUND.toString()); return; } - if(!shop.get().isOwner(player.getUniqueId()) && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + if(player != null && !shop.get().isOwner(player.getUniqueId()) && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { player.sendMessage(Messages.SHOP_NO_SELF.toString()); return; } - if(shop.get().isAdmin() && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + if(shop.get().isAdmin() && player != null && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { player.sendMessage(Messages.NO_PERMISSION.toString()); return; } if(InvStock.inShopInv.containsValue(shop.get().getOwner())) { - player.sendMessage(Messages.SHOP_BUSY.toString()); + if(player != null) + player.sendMessage(Messages.SHOP_BUSY.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_BUSY.toString()); return; } double cost = iShop.config.getDouble("returnAmount"); @@ -513,7 +526,10 @@ private void deleteShopID(Player player, String shopId) { } Shop.shopList.remove(shop.get().shopId()); shop.get().deleteShop(); - player.sendMessage(Messages.SHOP_IDDELETED.toString().replaceAll("%id", shopId)); + if(player != null) + player.sendMessage(Messages.SHOP_IDDELETED.toString().replaceAll("%id", shopId)); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_IDDELETED.toString().replaceAll("%id", shopId)); } private void listShops(Player player, String playerName) { From a333db9c476b406fe068063254b5cdb2099830fe Mon Sep 17 00:00:00 2001 From: Beez0r Date: Thu, 24 Feb 2022 23:15:51 -0800 Subject: [PATCH 04/15] iShop 2.17 Update --- src/com/minedhype/ishop/Shop.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/minedhype/ishop/Shop.java b/src/com/minedhype/ishop/Shop.java index 1793a50..844b3e3 100644 --- a/src/com/minedhype/ishop/Shop.java +++ b/src/com/minedhype/ishop/Shop.java @@ -467,7 +467,7 @@ public static void loadData() { ResultSet dataStore = loadShops.executeQuery(); while(dataStore.next()) { if(dataStore.getString(1) == null) { - Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] Error: Skipped loading a shop with null location in database!"); + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] Error: Skipped loading a shop with null location found in database! Make backups!"); continue; } String[] locationRaw = dataStore.getString(1).split(";"); @@ -476,7 +476,7 @@ public static void loadData() { int z = Integer.parseInt(locationRaw[2]); World world = Bukkit.getWorld(locationRaw[3]); if(world == null) { - Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] Error: Skipped loading a shop with null world in database!"); + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] Error: Skipped loading a shop with null world found in database! Make backups!"); continue; } Location location = new Location(world, x, y, z); From dae495648d6962aafa465b38247dba06aeb7fe0e Mon Sep 17 00:00:00 2001 From: Beez0r Date: Tue, 17 May 2022 00:28:28 -0700 Subject: [PATCH 05/15] iShop 2.18 Update --- src/com/minedhype/ishop/CommandShop.java | 180 +++++++++++++++--- src/com/minedhype/ishop/EventShop.java | 41 ++++ src/com/minedhype/ishop/Messages.java | 1 + src/com/minedhype/ishop/Permission.java | 3 +- src/com/minedhype/ishop/Shop.java | 40 +++- src/com/minedhype/ishop/Utils.java | 85 +++++++-- src/com/minedhype/ishop/iShop.java | 7 +- .../ishop/inventories/InvAdminShop.java | 25 +++ .../ishop/inventories/InvCreateRow.java | 2 +- .../ishop/inventories/InvShopList.java | 2 +- .../minedhype/ishop/inventories/InvStock.java | 13 +- src/resources/config.yml | 8 +- 12 files changed, 349 insertions(+), 58 deletions(-) diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index bb82792..d5dd730 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -7,6 +7,7 @@ import java.util.UUID; import com.minedhype.ishop.inventories.InvCreateRow; import com.minedhype.ishop.inventories.InvShop; +import me.ryanhamshire.GriefPrevention.ClaimPermission; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.TextComponent; import net.milkbowl.vault.economy.Economy; @@ -85,6 +86,8 @@ else if(args[0].equalsIgnoreCase("out") && args.length >= 2) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> outOfStock(player, args[1])); else if(args[0].equalsIgnoreCase("reload")) reloadShop(player); + else if(args[0].equalsIgnoreCase("removeallshops") && args.length >= 2) + removeAllShops(player, args[1]); else if(args[0].equalsIgnoreCase("shops")) listAllShops(player); else if(args[0].equalsIgnoreCase("sold") && args.length == 1) @@ -128,6 +131,7 @@ private void listSubCmd(Player player, String label) { player.sendMessage(ChatColor.GRAY + "/" + label + " listadmin"); player.sendMessage(ChatColor.GRAY + "/" + label + " managestock "); player.sendMessage(ChatColor.GRAY + "/" + label + " reload"); + player.sendMessage(ChatColor.GRAY + "/" + label + " removeallshops "); } } @@ -147,7 +151,11 @@ private void count(Player player, String itemName) { } } ItemStack item = new ItemStack(material); - int max = iShop.config.getInt("stockPages"); + int max; + if(InvAdminShop.usePerms) + max = InvAdminShop.permissionMax; + else + max = InvAdminShop.maxPages; int itemAmountCount = 0; for(int i=0; i stockStore = StockShop.getStockShopByOwner(player.getUniqueId(),i); @@ -227,7 +235,7 @@ private void createStore(Player player) { boolean allowShopCreateInClaim = false; if(iShop.gpLoader != null) { Claim claim = GriefPrevention.instance.dataStore.getClaimAt(block.getLocation(), false, false, null); - if(claim == null || claim.allowAccess(player) == null || claim.allowEdit(player) == null || claim.allowContainers(player) == null) + if(claim == null || claim.checkPermission(player, ClaimPermission.Access, null) == null || claim.checkPermission(player, ClaimPermission.Build, null) == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null || claim.checkPermission(player, ClaimPermission.Manage, null) == null || claim.checkPermission(player, ClaimPermission.Inventory, null) == null) allowShopCreateInClaim = true; } else @@ -532,6 +540,43 @@ private void deleteShopID(Player player, String shopId) { Bukkit.getConsoleSender().sendMessage(Messages.SHOP_IDDELETED.toString().replaceAll("%id", shopId)); } + private void removeAllShops(Player player, String playerName) { + if(!player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.NO_PERMISSION.toString()); + return; + } + UUID sOwner; + Player playerInGame = Bukkit.getPlayer(playerName); + if(playerInGame != null && playerInGame.isOnline()) + sOwner = playerInGame.getUniqueId(); + else { + try { + sOwner = getUUID(playerName); + } catch (Exception e) { + UUID foundPlayerUUID = null; + boolean foundPlayer = false; + for(OfflinePlayer offlinePlayers : Bukkit.getOfflinePlayers()) + if(offlinePlayers.getName().equalsIgnoreCase(playerName)) { + foundPlayerUUID = offlinePlayers.getUniqueId(); + foundPlayer = true; + break; + } + if(!foundPlayer) { + player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] " + Messages.NO_PLAYER_FOUND); + return; + } + sOwner = foundPlayerUUID; + } + } + if(InvStock.inShopInv.containsValue(sOwner)) { + player.sendMessage(Messages.SHOP_BUSY.toString()); + return; + } + final UUID shopOwner = sOwner; + Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> Shop.removeAllPlayersShops(player, shopOwner, playerName)); + } + private void listShops(Player player, String playerName) { if(playerName != null && !iShop.config.getBoolean("publicListCommand") && !player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_LIST.toString())) { player.sendMessage(Messages.NO_PERMISSION.toString()); @@ -542,12 +587,28 @@ private void listShops(Player player, String playerName) { sOwner = player.getUniqueId(); playerName = player.getDisplayName(); } else { - try { - sOwner = getUUID(playerName); - } catch (Exception e) { - player.sendMessage(Messages.NO_PLAYER_SHOP.toString()); - Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] " + Messages.NO_PLAYER_SHOP); - return; + Player playerInGame = Bukkit.getPlayer(playerName); + if(playerInGame != null && playerInGame.isOnline()) + sOwner = playerInGame.getUniqueId(); + else { + try { + sOwner = getUUID(playerName); + } catch (Exception e) { + UUID foundPlayerUUID = null; + boolean foundPlayer = false; + for(OfflinePlayer offlinePlayers : Bukkit.getOfflinePlayers()) + if(offlinePlayers.getName().equalsIgnoreCase(playerName)) { + foundPlayerUUID = offlinePlayers.getUniqueId(); + foundPlayer = true; + break; + } + if(!foundPlayer) { + player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] " + Messages.NO_PLAYER_FOUND); + return; + } + sOwner = foundPlayerUUID; + } } } Shop.getShopList(player, sOwner, playerName); @@ -593,14 +654,33 @@ private void stockShop(Player player, String page) { return; } openPage--; - int stockPages = iShop.config.getInt("stockPages"); - if(openPage > 0 && openPage > stockPages-1) - openPage = stockPages-1; + int maxStockPages = InvAdminShop.maxPages; + if(InvAdminShop.usePerms) { + String permPrefix = Permission.SHOP_STOCK_PREFIX.toString(); + for(PermissionAttachmentInfo attInfo : player.getEffectivePermissions()) { + String perm = attInfo.getPermission(); + if(perm.startsWith(permPrefix)) { + int num; + try { + num = Integer.parseInt(perm.substring(perm.lastIndexOf(".")+1)); + } catch(Exception e) { num = InvAdminShop.maxPages; } + if(num > InvAdminShop.permissionMax) + maxStockPages = InvAdminShop.permissionMax; + else if(num > 0) + maxStockPages = num; + else + maxStockPages = InvAdminShop.maxPages; + } + } + } + if(openPage > 0 && openPage > maxStockPages-1) + openPage = maxStockPages-1; if(InvStock.inShopInv.containsValue(player.getUniqueId())) { player.sendMessage(Messages.SHOP_BUSY.toString()); return; } else { InvStock.inShopInv.put(player, player.getUniqueId()); } InvStock inv = InvStock.getInvStock(player.getUniqueId()); + inv.setMaxPages(maxStockPages); inv.setPag(openPage); inv.open(player); } @@ -637,8 +717,11 @@ private void reloadShop(Player player) { EventShop.multipleShopBlocks = iShop.config.getBoolean("multipleShopBlocks"); EventShop.multipleStockBlocks = iShop.config.getBoolean("multipleStockBlocks"); InvAdminShop.remoteManage = iShop.config.getBoolean("remoteManage"); + InvAdminShop.maxPages = iShop.config.getInt("stockPages"); + InvAdminShop.permissionMax = iShop.config.getInt("maxStockPages"); InvAdminShop.stockCommandEnabled = iShop.config.getBoolean("enableStockCommand"); InvAdminShop.stockGUIShop = iShop.config.getBoolean("enableStockAccessFromShopGUI"); + InvAdminShop.usePerms = iShop.config.getBoolean("usePermissions"); InvCreateRow.disabledItemList = iShop.config.getStringList("disabledItemsList"); InvCreateRow.itemsDisabled = iShop.config.getBoolean("disabledItems"); InvCreateRow.strictStock = iShop.config.getBoolean("strictStock"); @@ -750,12 +833,28 @@ private void manageStock(Player player, String stockOwner, String page) { player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); return; } else { - try { - sOwner = getUUID(stockOwner); - } catch (Exception e) { - player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); - Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] " + Messages.NO_PLAYER_FOUND); - return; + Player playerInGame = Bukkit.getPlayer(stockOwner); + if(playerInGame != null && playerInGame.isOnline()) + sOwner = playerInGame.getUniqueId(); + else { + try { + sOwner = getUUID(stockOwner); + } catch (Exception e) { + UUID foundPlayerUUID = null; + boolean foundPlayer = false; + for(OfflinePlayer offlinePlayers : Bukkit.getOfflinePlayers()) + if(offlinePlayers.getName().equalsIgnoreCase(stockOwner)) { + foundPlayerUUID = offlinePlayers.getUniqueId(); + foundPlayer = true; + break; + } + if(!foundPlayer) { + player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] " + Messages.NO_PLAYER_FOUND); + return; + } + sOwner = foundPlayerUUID; + } } } OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(sOwner); @@ -771,17 +870,24 @@ private void manageStock(Player player, String stockOwner, String page) { return; } pageNum--; - int stockPages = iShop.config.getInt("stockPages"); - if(pageNum > 0 && pageNum > stockPages-1) - pageNum = stockPages-1; + int maxStockPages; + if(InvAdminShop.usePerms) + maxStockPages = InvAdminShop.permissionMax; + else + maxStockPages = InvAdminShop.maxPages; + if(pageNum > 0 && pageNum > maxStockPages-1) + pageNum = maxStockPages-1; final int openPage = pageNum; + final int stockPage = maxStockPages; + final UUID shopOwner = sOwner; Bukkit.getScheduler().runTask(iShop.getPlugin(), () -> { - if(InvStock.inShopInv.containsValue(sOwner)) { + if(InvStock.inShopInv.containsValue(shopOwner)) { player.sendMessage(Messages.SHOP_BUSY.toString()); return; } else - InvStock.inShopInv.put(player, sOwner); - InvStock inv = InvStock.getInvStock(sOwner); + InvStock.inShopInv.put(player, shopOwner); + InvStock inv = InvStock.getInvStock(shopOwner); + inv.setMaxPages(stockPage); inv.setPag(openPage); inv.open(player); }); @@ -895,12 +1001,28 @@ private void outOfStock(Player player, String playerName) { sOwner = player.getUniqueId(); playerName = player.getDisplayName(); } else { - try { - sOwner = getUUID(playerName); - } catch (Exception e) { - player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); - Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] " + Messages.NO_PLAYER_FOUND); - return; + Player playerInGame = Bukkit.getPlayer(playerName); + if(playerInGame != null && playerInGame.isOnline()) + sOwner = playerInGame.getUniqueId(); + else { + try { + sOwner = getUUID(playerName); + } catch (Exception e) { + UUID foundPlayerUUID = null; + boolean foundPlayer = false; + for(OfflinePlayer offlinePlayers : Bukkit.getOfflinePlayers()) + if(offlinePlayers.getName().equalsIgnoreCase(playerName)) { + foundPlayerUUID = offlinePlayers.getUniqueId(); + foundPlayer = true; + break; + } + if(!foundPlayer) { + player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] " + Messages.NO_PLAYER_FOUND); + return; + } + sOwner = foundPlayerUUID; + } } } player.sendMessage(Messages.SHOP_LIST_OUT.toString()); diff --git a/src/com/minedhype/ishop/EventShop.java b/src/com/minedhype/ishop/EventShop.java index ceb2a7b..43b78ab 100644 --- a/src/com/minedhype/ishop/EventShop.java +++ b/src/com/minedhype/ishop/EventShop.java @@ -25,6 +25,7 @@ import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.permissions.PermissionAttachmentInfo; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -201,6 +202,26 @@ else if(event.getHand().equals(EquipmentSlot.OFF_HAND)) return; } else { InvStock.inShopInv.put(event.getPlayer(), event.getPlayer().getUniqueId()); } InvStock inv = InvStock.getInvStock(event.getPlayer().getUniqueId()); + int maxStockPages = InvAdminShop.maxPages; + if(InvAdminShop.usePerms) { + String permPrefix = Permission.SHOP_STOCK_PREFIX.toString(); + for(PermissionAttachmentInfo attInfo : event.getPlayer().getEffectivePermissions()) { + String perm = attInfo.getPermission(); + if(perm.startsWith(permPrefix)) { + int num; + try { + num = Integer.parseInt(perm.substring(perm.lastIndexOf(".")+1)); + } catch(Exception e) { num = InvAdminShop.maxPages; } + if(num > InvAdminShop.permissionMax) + maxStockPages = InvAdminShop.permissionMax; + else if(num > 0) + maxStockPages = num; + else + maxStockPages = InvAdminShop.maxPages; + } + } + } + inv.setMaxPages(maxStockPages); inv.setPag(0); inv.open(event.getPlayer()); } @@ -233,6 +254,26 @@ else if(event.getHand().equals(EquipmentSlot.OFF_HAND)) return; } else { InvStock.inShopInv.put(event.getPlayer(), event.getPlayer().getUniqueId()); } InvStock inv = InvStock.getInvStock(event.getPlayer().getUniqueId()); + int maxStockPages = InvAdminShop.maxPages; + if(InvAdminShop.usePerms) { + String permPrefix = Permission.SHOP_STOCK_PREFIX.toString(); + for(PermissionAttachmentInfo attInfo : event.getPlayer().getEffectivePermissions()) { + String perm = attInfo.getPermission(); + if(perm.startsWith(permPrefix)) { + int num; + try { + num = Integer.parseInt(perm.substring(perm.lastIndexOf(".")+1)); + } catch(Exception e) { num = InvAdminShop.maxPages; } + if(num > InvAdminShop.permissionMax) + maxStockPages = InvAdminShop.permissionMax; + else if(num > 0) + maxStockPages = num; + else + maxStockPages = InvAdminShop.maxPages; + } + } + } + inv.setMaxPages(maxStockPages); inv.setPag(0); inv.open(event.getPlayer()); } diff --git a/src/com/minedhype/ishop/Messages.java b/src/com/minedhype/ishop/Messages.java index f8a521c..b537836 100644 --- a/src/com/minedhype/ishop/Messages.java +++ b/src/com/minedhype/ishop/Messages.java @@ -50,6 +50,7 @@ public enum Messages { SHOP_PURCHASE("buy"), SHOP_RELOAD("reload"), SHOP_REMOTE("noRemoteManage"), + SHOP_REMOVED_ALL_PLAYER("removedAllPlayer"), SHOP_SELL("sell"), SHOP_TITLE_ADMIN_SHOP("adminShop"), SHOP_TITLE_BROADCAST_OFF("broadcastOff"), diff --git a/src/com/minedhype/ishop/Permission.java b/src/com/minedhype/ishop/Permission.java index 300fd2e..bfbbe03 100644 --- a/src/com/minedhype/ishop/Permission.java +++ b/src/com/minedhype/ishop/Permission.java @@ -9,7 +9,8 @@ public enum Permission { SHOP_REMOTEMANAGE("ishop.remotemanage"), SHOP_REMOTESHOPPING("ishop.remoteshopping"), SHOP_SHOPS("ishop.shops"), - SHOP_STOCK("ishop.stock"); + SHOP_STOCK("ishop.stock"), + SHOP_STOCK_PREFIX("ishop.pages."); private final String perm; Permission(String perms) { diff --git a/src/com/minedhype/ishop/Shop.java b/src/com/minedhype/ishop/Shop.java index 844b3e3..c28d258 100644 --- a/src/com/minedhype/ishop/Shop.java +++ b/src/com/minedhype/ishop/Shop.java @@ -34,6 +34,7 @@ import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.ClickEvent.Action; import net.md_5.bungee.api.chat.TextComponent; +import net.milkbowl.vault.economy.Economy; public class Shop { public static boolean deletePlayerShop = iShop.config.getBoolean("deleteBlock"); @@ -121,6 +122,33 @@ public static void getPlayersShopList() { shops.parallelStream().filter(s -> !s.admin).forEach(s -> shopList.putIfAbsent(s.idTienda, s.owner)); } + public static void removeAllPlayersShops(Player player, UUID sOwner, String pOwner) { + int deletedCount = 0; + List deleteShops = new ArrayList<>(); + for(Shop shop:shops) + if(!shop.admin && shop.isOwner(sOwner)) { + deleteShops.add(shop); + deletedCount++; + } + for(Shop shop:deleteShops) { + shopList.remove(shop.shopId()); + shop.deleteShop(); + } + Optional economy = iShop.getEconomy(); + if(economy.isPresent()) { + double cost = iShop.config.getDouble("returnAmount"); + if(deletedCount > 0 && cost > 0) { + OfflinePlayer offPlayer = Bukkit.getOfflinePlayer(sOwner); + double totalCost = cost * deletedCount; + economy.get().depositPlayer(offPlayer, totalCost); + } + } + if(deletedCount > 0) + player.sendMessage(Messages.SHOP_REMOVED_ALL_PLAYER.toString().replaceAll("%p", pOwner).replaceAll("%shops", String.valueOf(deletedCount))); + else + player.sendMessage(Messages.SHOP_NOT_FOUND.toString()); + } + public static void getShopList(Player player, UUID sOwner, String pOwner) { player.sendMessage(Messages.SHOP_FOUND.toString().replaceAll("%p", pOwner).replaceAll("%shops", String.valueOf(getNumShops(sOwner)))); shops.parallelStream().filter(s -> !s.admin && s.isOwner(sOwner)).forEach(s -> { @@ -748,7 +776,11 @@ public boolean hasExpired() { public void giveItem(ItemStack item) { ItemStack copy = item.clone(); - int max = iShop.config.getInt("stockPages"); + int max; + if(InvAdminShop.usePerms) + max = InvAdminShop.permissionMax; + else + max = InvAdminShop.maxPages; for(int i=0; i stock = StockShop.getStockShopByOwner(this.owner, i); if(!stock.isPresent()) @@ -764,7 +796,11 @@ public void giveItem(ItemStack item) { public void takeItem(ItemStack item) { ItemStack copy = item.clone(); - int max = iShop.config.getInt("stockPages"); + int max; + if(InvAdminShop.usePerms) + max = InvAdminShop.permissionMax; + else + max = InvAdminShop.maxPages; for(int i=0; i stock = StockShop.getStockShopByOwner(this.owner, i); if(!stock.isPresent()) diff --git a/src/com/minedhype/ishop/Utils.java b/src/com/minedhype/ishop/Utils.java index 1935905..3e5cf3c 100644 --- a/src/com/minedhype/ishop/Utils.java +++ b/src/com/minedhype/ishop/Utils.java @@ -4,18 +4,28 @@ import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import com.minedhype.ishop.inventories.InvAdminShop; public class Utils { public static boolean hasStock(Player player, ItemStack item) { if(item == null || item.getType().equals(Material.AIR)) return true; - return player.getInventory().containsAtLeast(item, item.getAmount()); + if(item.hasItemMeta()) { + ItemStack itemClone = item.clone(); + return (player.getInventory().containsAtLeast(item, item.getAmount()) || player.getInventory().containsAtLeast(itemClone, itemClone.getAmount())); + } + else + return player.getInventory().containsAtLeast(item, item.getAmount()); } public static boolean hasStock(Shop shop, ItemStack item) { if(shop.isAdmin() || item == null || item.getType().equals(Material.AIR)) return true; - int max = iShop.config.getInt("stockPages"); + int max; + if(InvAdminShop.usePerms) + max = InvAdminShop.permissionMax; + else + max = InvAdminShop.maxPages; int amount = item.getAmount(); int itemAmountCount = 0; for(int i=0; i= amount) return true; } @@ -40,7 +66,21 @@ public static boolean hasDoubleItemStock(Player player, ItemStack item, ItemStac if((item == null && item2 == null) || (item.getType().equals(Material.AIR) && item2.getType().equals(Material.AIR))) return true; int bothAmounts = item.getAmount() + item2.getAmount(); - return player.getInventory().containsAtLeast(item, bothAmounts); + if(!item.hasItemMeta() && !item2.hasItemMeta()) + return player.getInventory().containsAtLeast(item, bothAmounts); + else { + boolean hasItems = false; + boolean hasItems2 = false; + if(item.hasItemMeta()) { + ItemStack itemClone = item.clone(); + hasItems = player.getInventory().containsAtLeast(itemClone, bothAmounts); + } + if(item2.hasItemMeta()) { + ItemStack item2Clone = item2.clone(); + hasItems2 = player.getInventory().containsAtLeast(item2Clone, bothAmounts); + } + return (player.getInventory().containsAtLeast(item, bothAmounts) || player.getInventory().containsAtLeast(item2, bothAmounts) || hasItems || hasItems2); + } } public static boolean hasDoubleItemStock(Shop shop, ItemStack item, ItemStack item2) { @@ -50,7 +90,11 @@ public static boolean hasDoubleItemStock(Shop shop, ItemStack item, ItemStack it int item2Amount = 0; int item1Total = item.getAmount(); int item2Total = item2.getAmount(); - int max = iShop.config.getInt("stockPages"); + int max; + if(InvAdminShop.usePerms) + max = InvAdminShop.permissionMax; + else + max = InvAdminShop.maxPages; for(int i=0; i stockStore = StockShop.getStockShopByOwner(shop.getOwner(), i); if(!stockStore.isPresent()) @@ -58,15 +102,28 @@ public static boolean hasDoubleItemStock(Shop shop, ItemStack item, ItemStack it if(stockStore.get().getInventory().contains(item.getType()) || stockStore.get().getInventory().contains(item2.getType())) { for(int j=0; j item1Total && item.isSimilar(item2)) { - int difference = item1Amount - item1Total; - item2Amount += difference; - } + if(!item.hasItemMeta() && !item2.hasItemMeta()) { + if(item1Amount < item1Total && stockStore.get().getInventory().getItem(j).isSimilar(item)) { + item1Amount += stockStore.get().getInventory().getItem(j).getAmount(); + if(item1Amount > item1Total && item.isSimilar(item2)) { + int difference = item1Amount - item1Total; + item2Amount += difference; + } + } else if(item2Amount < item2Total && stockStore.get().getInventory().getItem(j).isSimilar(item2)) + item2Amount += stockStore.get().getInventory().getItem(j).getAmount(); + } + else { + ItemStack itemClone = item.clone(); + ItemStack item2Clone = item2.clone(); + if(item1Amount < item1Total && (stockStore.get().getInventory().getItem(j).isSimilar(item) || stockStore.get().getInventory().getItem(j).isSimilar(itemClone))) { + item1Amount += stockStore.get().getInventory().getItem(j).getAmount(); + if(item1Amount > item1Total && (item.isSimilar(item2) || item.isSimilar(item2Clone) || itemClone.isSimilar(item2) || itemClone.isSimilar(item2Clone))) { + int difference = item1Amount - item1Total; + item2Amount += difference; + } + } else if(item2Amount < item2Total && (stockStore.get().getInventory().getItem(j).isSimilar(item2) || stockStore.get().getInventory().getItem(j).isSimilar(item2Clone))) + item2Amount += stockStore.get().getInventory().getItem(j).getAmount(); } - else if(item2Amount < item2Total && stockStore.get().getInventory().getItem(j).isSimilar(item2)) - item2Amount += stockStore.get().getInventory().getItem(j).getAmount(); } if(item1Amount >= item1Total && item2Amount >= item2Total) return true; diff --git a/src/com/minedhype/ishop/iShop.java b/src/com/minedhype/ishop/iShop.java index f857e12..b17d926 100644 --- a/src/com/minedhype/ishop/iShop.java +++ b/src/com/minedhype/ishop/iShop.java @@ -270,9 +270,12 @@ public void createConfig() { config.set("noClaimPermission", "&cYou do not have permission in this claim to create a shop!"); config.set("pageSkipAhead", "5 Pages >>"); config.set("pageSkipPrev", "<< 5 Pages"); - config.set("configVersion", "3.3"); - config.save(configFile); case "3.3": + config.set("maxStockPages", 10); + config.set("removedAllPlayer", "&6Removed&c %shops &6shop(s) for player:&c %p"); + config.set("configVersion", "3.4"); + config.save(configFile); + case "3.4": break; } } catch(IOException | InvalidConfigurationException e) { e.printStackTrace(); } diff --git a/src/com/minedhype/ishop/inventories/InvAdminShop.java b/src/com/minedhype/ishop/inventories/InvAdminShop.java index 3caa95a..575eeae 100644 --- a/src/com/minedhype/ishop/inventories/InvAdminShop.java +++ b/src/com/minedhype/ishop/inventories/InvAdminShop.java @@ -3,6 +3,7 @@ import java.util.Optional; import com.minedhype.ishop.iShop; import com.minedhype.ishop.Messages; +import com.minedhype.ishop.Permission; import com.minedhype.ishop.RowStore; import com.minedhype.ishop.Shop; import com.minedhype.ishop.Utils; @@ -12,11 +13,15 @@ import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import com.minedhype.ishop.gui.GUI; +import org.bukkit.permissions.PermissionAttachmentInfo; public class InvAdminShop extends GUI { public static boolean remoteManage = iShop.config.getBoolean("remoteManage"); public static boolean stockGUIShop = iShop.config.getBoolean("enableStockAccessFromShopGUI"); public static boolean stockCommandEnabled = iShop.config.getBoolean("enableStockCommand"); + public static boolean usePerms = iShop.config.getBoolean("usePermissions"); + public static int maxPages = iShop.config.getInt("stockPages"); + public static int permissionMax = iShop.config.getInt("maxStockPages"); private final Shop shop; public InvAdminShop(Shop shop, Player player) { @@ -91,6 +96,26 @@ private void updateItems(Player player) { placeItem(y * 9 + x, GUI.createItem(Material.CHEST, Messages.SHOP_TITLE_STOCK.toString()), p -> { p.closeInventory(); InvStock inv = InvStock.getInvStock(player.getUniqueId()); + int maxStockPages = maxPages; + if(usePerms) { + String permPrefix = Permission.SHOP_STOCK_PREFIX.toString(); + for(PermissionAttachmentInfo attInfo : player.getEffectivePermissions()) { + String perm = attInfo.getPermission(); + if(perm.startsWith(permPrefix)) { + int num; + try { + num = Integer.parseInt(perm.substring(perm.lastIndexOf(".")+1)); + } catch(Exception e) { num = maxPages; } + if(num > permissionMax) + maxStockPages = permissionMax; + else if(num > 0) + maxStockPages = num; + else + maxStockPages = maxPages; + } + } + } + inv.setMaxPages(maxStockPages); inv.setPag(0); InvStock.inShopInv.put(player, player.getUniqueId()); inv.open(player); diff --git a/src/com/minedhype/ishop/inventories/InvCreateRow.java b/src/com/minedhype/ishop/inventories/InvCreateRow.java index 99c6b3f..97877cb 100644 --- a/src/com/minedhype/ishop/inventories/InvCreateRow.java +++ b/src/com/minedhype/ishop/inventories/InvCreateRow.java @@ -159,7 +159,7 @@ public void onClick(InventoryClickEvent event) { if(inv.getType().equals(InventoryType.CHEST) && event.getView().getTitle().contains(Messages.SHOP_TITLE_CREATESHOP.toString())) { event.setCancelled(true); if(event.getRawSlot() == 10 || event.getRawSlot() == 11 || event.getRawSlot() == 15 || event.getRawSlot() == 16) { - ItemStack item = event.getCursor().clone(); + ItemStack item = event.getCursor().clone(); if(event.getClick().isRightClick()) item.setAmount(1); placeItem(event.getRawSlot(), item); diff --git a/src/com/minedhype/ishop/inventories/InvShopList.java b/src/com/minedhype/ishop/inventories/InvShopList.java index de5d53c..287c37a 100644 --- a/src/com/minedhype/ishop/inventories/InvShopList.java +++ b/src/com/minedhype/ishop/inventories/InvShopList.java @@ -105,7 +105,7 @@ public void open(Player player) { shopslist.clear(); final UUID playerUUID = player.getUniqueId(); final Player openPlayer = player; - Bukkit.getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> { + Bukkit.getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> { getShopList(playerUUID); Bukkit.getScheduler().runTask(iShop.getPlugin(), () -> { PlayerShopList(); diff --git a/src/com/minedhype/ishop/inventories/InvStock.java b/src/com/minedhype/ishop/inventories/InvStock.java index 8122210..9ae2937 100644 --- a/src/com/minedhype/ishop/inventories/InvStock.java +++ b/src/com/minedhype/ishop/inventories/InvStock.java @@ -9,7 +9,6 @@ import com.minedhype.ishop.Permission; import com.minedhype.ishop.Shop; import com.minedhype.ishop.StockShop; -import com.minedhype.ishop.iShop; import com.minedhype.ishop.gui.GUI; import org.bukkit.Material; import org.bukkit.block.ShulkerBox; @@ -28,7 +27,7 @@ public class InvStock extends GUI { private final ItemStack airItem = new ItemStack(Material.AIR, 0); private final UUID owner; private int pag; - private int totalPages = iShop.config.getInt("stockPages"); + private int stockPages; private Player player; private InvStock(UUID owner) { @@ -114,15 +113,14 @@ public void refreshItems() { Inventory inv = stock.getInventory(); for(int i=0; i<45; i++) placeItem(i, inv.getItem(i)); - for(int i=45; i<54; i++) { - if(i == 46 && pag > 4 && totalPages >= 10) + if(i == 46 && pag > 4 && stockPages >= 10) placeItem(i, GUI.createItem(Material.SPECTRAL_ARROW, Messages.SHOP_PAGE_SKIPPREV.toString()), p -> openPage(p, pag-5)); else if(i == 47 && pag > 0) placeItem(i, GUI.createItem(Material.ARROW, Messages.SHOP_PAGE + " " + (pag)), p -> openPage(p, pag-1)); - else if(i == 51 && pag < totalPages-1) + else if(i == 51 && pag < stockPages-1) placeItem(i, GUI.createItem(Material.ARROW, Messages.SHOP_PAGE + " " + (pag+2)), p -> openPage(p, pag+1)); - else if(i == 52 && pag < totalPages-5 && totalPages >= 10) + else if(i == 52 && pag < stockPages-5 && stockPages >= 10) placeItem(i, GUI.createItem(Material.SPECTRAL_ARROW, Messages.SHOP_PAGE_SKIPAHEAD.toString()), p -> openPage(p, pag+5)); else placeItem(i, GUI.createItem(Material.BLACK_STAINED_GLASS_PANE, "")); @@ -156,4 +154,7 @@ public void onClose(InventoryCloseEvent event) { public void setPag(int pag) { this.pag = pag; } + public void setMaxPages(int maxPages) { + this.stockPages = maxPages; + } } diff --git a/src/resources/config.yml b/src/resources/config.yml index 59a304e..2aa064b 100644 --- a/src/resources/config.yml +++ b/src/resources/config.yml @@ -53,9 +53,12 @@ enableStockAccessFromShopGUI: true # Players with ishop.stock permission will bypass if disabled enableStockCommand: true -# Number of pages to have in the stock GUI +# Number of default stock pages to have in the stock GUI stockPages: 5 +# Maximum number of stock pages to have in the stock GUI if usePermissions is set to true +maxStockPages: 10 + # Enable sending of messages when players have purchased or sold item(s) from shops enableShopNotifications: true @@ -239,6 +242,7 @@ outsideRegion: "&cCannot create shop outside of ishop region!" noClaimPermission: "&cYou do not have permission in this claim to create a shop!" pageSkipAhead: "5 Pages >>" pageSkipPrev: "<< 5 Pages" +removedAllPlayer: "&6Removed&c %shops &6shop(s) for player:&c %p" # Do not edit this! -configVersion: 3.3 \ No newline at end of file +configVersion: 3.4 \ No newline at end of file From 7a99f4e5dc83cc66eecde95c5122f1f765dd7ed5 Mon Sep 17 00:00:00 2001 From: Beez0r Date: Fri, 19 Aug 2022 16:34:26 -0700 Subject: [PATCH 06/15] iShop 2.19 Update --- src/com/minedhype/ishop/CommandShop.java | 267 ++++++++++++++++++++++- src/com/minedhype/ishop/Messages.java | 4 + src/com/minedhype/ishop/iShop.java | 30 +-- src/resources/config.yml | 6 +- 4 files changed, 284 insertions(+), 23 deletions(-) diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index d5dd730..8a40b6b 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -20,10 +20,12 @@ import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.OfflinePlayer; import org.bukkit.inventory.ItemStack; import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.World; import org.json.simple.JSONObject; import org.json.simple.JSONValue; import com.minedhype.ishop.inventories.InvAdminShop; @@ -44,13 +46,33 @@ else if(args[0].equalsIgnoreCase("deleteid") && args[1] != null) { deleteShopID(null, args[1]); return true; } + else if(args[0].equalsIgnoreCase("createlocation") && args.length > 5) { + Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> createLocation(null, args[1], args[2], args[3], args[4], args[5])); + return true; + } + else if(args[0].equalsIgnoreCase("deletelocation") && args.length > 4) { + Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> deleteLocation(null, args[1], args[2], args[3], args[4])); + return true; + } else { - sender.sendMessage(Messages.NOT_A_PLAYER.toString()); + sender.sendMessage(ChatColor.GOLD + "iShop Console Commands:"); + sender.sendMessage(ChatColor.GRAY + label + " createlocation "); + sender.sendMessage(ChatColor.GRAY + label + " deletelocation "); + sender.sendMessage(ChatColor.GRAY + label + " deleteid "); + sender.sendMessage(ChatColor.GRAY + label + " reload"); return false; } } if(!(sender instanceof Player)) { - sender.sendMessage(Messages.NOT_A_PLAYER.toString()); + if(sender instanceof ConsoleCommandSender) { + sender.sendMessage(ChatColor.GOLD + "iShop Console Commands:"); + sender.sendMessage(ChatColor.GRAY + label + " createlocation "); + sender.sendMessage(ChatColor.GRAY + label + " deletelocation "); + sender.sendMessage(ChatColor.GRAY + label + " deleteid "); + sender.sendMessage(ChatColor.GRAY + label + " reload"); + } + else + sender.sendMessage(Messages.NOT_A_PLAYER.toString()); return false; } Player player = (Player) sender; @@ -64,10 +86,14 @@ else if(args[0].equalsIgnoreCase("create")) createStore(player); else if(args[0].equalsIgnoreCase("createshop") && args.length >= 2) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> createShop(player, args[1])); + else if(args[0].equalsIgnoreCase("createlocation") && args.length > 5) + Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> createLocation(player, args[1], args[2], args[3], args[4], args[5])); else if(args[0].equalsIgnoreCase("delete")) deleteShop(player); else if(args[0].equalsIgnoreCase("deleteid") && args.length >= 2) deleteShopID(player, args[1]); + else if(args[0].equalsIgnoreCase("deletelocation") && args.length > 4) + Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> deleteLocation(player, args[1], args[2], args[3], args[4])); else if(args[0].equalsIgnoreCase("list") && args.length == 1) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> listShops(player, null)); else if(args[0].equalsIgnoreCase("list") && args.length >= 2) @@ -128,6 +154,8 @@ private void listSubCmd(Player player, String label) { if(player.hasPermission(Permission.SHOP_ADMIN.toString())) { player.sendMessage(ChatColor.GRAY + "/" + label + " adminshop"); player.sendMessage(ChatColor.GRAY + "/" + label + " createshop "); + player.sendMessage(ChatColor.GRAY + "/" + label + " createlocation "); + player.sendMessage(ChatColor.GRAY + "/" + label + " deletelocation "); player.sendMessage(ChatColor.GRAY + "/" + label + " listadmin"); player.sendMessage(ChatColor.GRAY + "/" + label + " managestock "); player.sendMessage(ChatColor.GRAY + "/" + label + " reload"); @@ -394,6 +422,156 @@ private void createShop(Player player, String playerShop) { } else { player.sendMessage(Messages.EXISTING_SHOP.toString()); } } + private void createLocation(Player player, String playerShop, String x, String y, String z, String worldString) { + if(player != null && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.NO_PERMISSION.toString()); + return; + } + if(!iShop.config.getBoolean("enableShopBlock")) { + player.sendMessage(Messages.DISABLED_SHOP_BLOCK.toString()); + return; + } + String world; + if(worldString != null) + world = worldString; + else + world = "world"; + + int xLoc,yLoc,zLoc; + try { + xLoc = Integer.parseInt(x); + yLoc = Integer.parseInt(y); + zLoc = Integer.parseInt(z); + } + catch(Exception e) { + if(player != null) + player.sendMessage(Messages.SHOP_LOCATION_ERROR_NUM.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_LOCATION_ERROR_NUM.toString()); + return; + } + World worldLoc = Bukkit.getWorld(world); + Location blockLoc; + if(worldLoc != null) + blockLoc = new Location(worldLoc, xLoc, yLoc, zLoc); + else { + if(player != null) + player.sendMessage(Messages.SHOP_LOCATION_ERROR_WORLD.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_LOCATION_ERROR_WORLD.toString()); + return; + } + Block block = Bukkit.getWorld(world).getBlockAt(blockLoc); + if(iShop.config.getBoolean("disableShopInWorld")) { + List disabledWorldsList = iShop.config.getStringList("disabledWorldList"); + for(String disabledWorlds:disabledWorldsList) { + if(disabledWorlds != null && block.getWorld().getName().equals(disabledWorlds)) { + if(player != null) + player.sendMessage(Messages.SHOP_WORLD_DISABLED.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_WORLD_DISABLED.toString()); + return; + } + } + } + String shopBlock = iShop.config.getString("shopBlock"); + Material match = Material.matchMaterial(shopBlock); + if(match == null) { + try { + match = Material.matchMaterial(shopBlock.split("minecraft:")[1].toUpperCase()); + } catch(Exception ignored) { } + if(match == null) + match = Material.BARREL; + } + if(!EventShop.multipleShopBlocks) { + if(!block.getType().equals(match)) { + if(player != null) + player.sendMessage(Messages.TARGET_MISMATCH.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.TARGET_MISMATCH.toString()); + return; + } + } else { + boolean shopMatch = false; + for(String shopBlocks:EventShop.multipleShopBlock) { + Material shopListBlocks = Material.matchMaterial(shopBlocks); + if(shopListBlocks != null && block.getType().equals(shopListBlocks)) { + shopMatch = true; + break; + } + } + if(!block.getType().equals(match) && !shopMatch) { + if(player != null) + player.sendMessage(Messages.TARGET_MISMATCH.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.TARGET_MISMATCH.toString()); + return; + } + } + UUID shopOwner; + if(playerShop == null) { + if(player != null) + player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.NO_PLAYER_FOUND.toString()); + return; + } else { + Player playerInGame = Bukkit.getPlayer(playerShop); + if(playerInGame != null && playerInGame.isOnline()) + shopOwner = playerInGame.getUniqueId(); + else { + try { + shopOwner = getUUID(playerShop); + } catch (Exception e) { + UUID foundPlayerUUID = null; + boolean foundPlayer = false; + for(OfflinePlayer offlinePlayers : Bukkit.getOfflinePlayers()) + if(offlinePlayers.getName().equalsIgnoreCase(playerShop)) { + foundPlayerUUID = offlinePlayers.getUniqueId(); + foundPlayer = true; + break; + } + if(!foundPlayer) { + if(player != null) { + player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] " + Messages.NO_PLAYER_FOUND); + } + else + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] " + Messages.NO_PLAYER_FOUND); + return; + } + shopOwner = foundPlayerUUID; + } + } + } + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(shopOwner); + if(offlinePlayer == null || !offlinePlayer.hasPlayedBefore()) { + if(player != null) + player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.NO_PLAYER_FOUND.toString()); + return; + } + Optional shop = Shop.getShopByLocation(block.getLocation()); + if(!shop.isPresent()) { + Shop.createShop(block.getLocation(), shopOwner); + if(player != null) + player.sendMessage(Messages.SHOP_CREATED_LOC.toString().replaceAll("%p", playerShop).replaceAll("%w", world).replaceAll("%x", x).replaceAll("%y", y).replaceAll("%z", z)); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_CREATED_LOC.toString().replaceAll("%p", playerShop).replaceAll("%w", world).replaceAll("%x", x).replaceAll("%y", y).replaceAll("%z", z)); + final UUID shopOwnerFinal = shopOwner; + Bukkit.getServer().getScheduler().runTaskLaterAsynchronously(iShop.getPlugin(), () -> { + Optional shops = Shop.getShopByLocation(block.getLocation()); + Shop.shopList.put(shops.get().shopId(), shopOwnerFinal); + }, 10); + } else { + if(player != null) + player.sendMessage(Messages.EXISTING_SHOP.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.EXISTING_SHOP.toString().replaceAll("%p", playerShop)); + } + } + private void adminShop(Player player) { if(!player.hasPermission(Permission.SHOP_ADMIN.toString())) { player.sendMessage(Messages.NO_PERMISSION.toString()); @@ -540,6 +718,79 @@ private void deleteShopID(Player player, String shopId) { Bukkit.getConsoleSender().sendMessage(Messages.SHOP_IDDELETED.toString().replaceAll("%id", shopId)); } + private void deleteLocation(Player player, String x, String y, String z, String worldString) { + if(player != null && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.NO_PERMISSION.toString()); + return; + } + String world; + if(worldString != null) + world = worldString; + else + world = "world"; + + int xLoc,yLoc,zLoc; + try { + xLoc = Integer.parseInt(x); + yLoc = Integer.parseInt(y); + zLoc = Integer.parseInt(z); + } + catch(Exception e) { + if(player != null) + player.sendMessage(Messages.SHOP_LOCATION_ERROR_NUM.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_LOCATION_ERROR_NUM.toString()); + return; + } + World worldLoc = Bukkit.getWorld(world); + Location blockLoc; + if(worldLoc != null) + blockLoc = new Location(worldLoc, xLoc, yLoc, zLoc); + else { + if(player != null) + player.sendMessage(Messages.SHOP_LOCATION_ERROR_WORLD.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_LOCATION_ERROR_WORLD.toString()); + return; + } + + Optional shop = Shop.getShopByLocation(blockLoc); + if(!shop.isPresent()) { + if(player != null) + player.sendMessage(Messages.SHOP_NOT_FOUND.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_NOT_FOUND.toString()); + return; + } + if(player != null && !shop.get().isOwner(player.getUniqueId()) && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.SHOP_NO_SELF.toString()); + return; + } + if(player != null && shop.get().isAdmin() && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.NO_PERMISSION.toString()); + return; + } + if(InvStock.inShopInv.containsValue(shop.get().getOwner())) { + if(player != null) + player.sendMessage(Messages.SHOP_BUSY.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_BUSY.toString()); + return; + } + OfflinePlayer offPlayer = Bukkit.getOfflinePlayer(shop.get().getOwner()); + String shopOwner = offPlayer.getName(); + double cost = iShop.config.getDouble("returnAmount"); + Optional economy = iShop.getEconomy(); + if(cost > 0 && economy.isPresent()) + economy.get().depositPlayer(offPlayer, cost); + Shop.shopList.remove(shop.get().shopId()); + shop.get().deleteShop(); + if(player != null) + player.sendMessage(Messages.SHOP_DELETED_LOC.toString().replaceAll("%p", shopOwner).replaceAll("%w", world).replaceAll("%x", x).replaceAll("%y", y).replaceAll("%z", z)); + else + Bukkit.getConsoleSender().sendMessage(Messages.SHOP_DELETED_LOC.toString().replaceAll("%p", shopOwner).replaceAll("%w", world).replaceAll("%x", x).replaceAll("%y", y).replaceAll("%z", z)); + } + private void removeAllShops(Player player, String playerName) { if(!player.hasPermission(Permission.SHOP_ADMIN.toString())) { player.sendMessage(Messages.NO_PERMISSION.toString()); @@ -578,7 +829,7 @@ private void removeAllShops(Player player, String playerName) { } private void listShops(Player player, String playerName) { - if(playerName != null && !iShop.config.getBoolean("publicListCommand") && !player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_LIST.toString())) { + if(playerName != null && !iShop.config.getBoolean("publicListCommand") && (!player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_LIST.toString()))) { player.sendMessage(Messages.NO_PERMISSION.toString()); return; } @@ -623,7 +874,7 @@ private void listAdminShops(Player player) { } private void listAllShops(Player player) { - if(!InvShop.listAllShops && !player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_SHOPS.toString())) { + if(!InvShop.listAllShops && (!player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_SHOPS.toString()))) { player.sendMessage(Messages.SHOP_LIST_DISABLED.toString()); return; } @@ -749,7 +1000,7 @@ private static UUID getUUID(String name) throws Exception { } private static void shopManage(Player player, String shopID) { - if(!InvAdminShop.remoteManage && !player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_REMOTEMANAGE.toString())) { + if(!InvAdminShop.remoteManage && (!player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_REMOTEMANAGE.toString()))) { player.sendMessage(Messages.SHOP_REMOTE.toString()); return; } @@ -785,7 +1036,7 @@ private static void shopManage(Player player, String shopID) { } private static void viewShop(Player player, String shopId) { - if(!iShop.config.getBoolean("remoteShopping") && !player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_REMOTESHOPPING.toString())) { + if(!iShop.config.getBoolean("remoteShopping") && (!player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_REMOTESHOPPING.toString()))) { player.sendMessage(Messages.SHOP_NO_REMOTE.toString()); return; } @@ -802,7 +1053,7 @@ private static void viewShop(Player player, String shopId) { player.sendMessage(Messages.SHOP_NOT_FOUND.toString()); return; } - if(shop.get().getOwner().equals(player.getUniqueId()) && !InvAdminShop.remoteManage && !player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_REMOTEMANAGE.toString())) { + if(shop.get().getOwner().equals(player.getUniqueId()) && !InvAdminShop.remoteManage && (!player.hasPermission(Permission.SHOP_ADMIN.toString()) || !player.hasPermission(Permission.SHOP_REMOTEMANAGE.toString()))) { player.sendMessage(Messages.SHOP_REMOTE.toString()); return; } @@ -814,7 +1065,7 @@ private static void viewShop(Player player, String shopId) { player.sendMessage(Messages.SHOP_BUSY.toString()); return; } - if((shop.get().isAdmin() && player.hasPermission(Permission.SHOP_ADMIN.toString())) || shop.get().isOwner(player.getUniqueId())) { + if((shop.get().isAdmin() && (player.hasPermission(Permission.SHOP_ADMIN.toString())) || shop.get().isOwner(player.getUniqueId()))) { InvAdminShop inv = new InvAdminShop(shop.get(), player); inv.open(player, shop.get().getOwner()); } else { diff --git a/src/com/minedhype/ishop/Messages.java b/src/com/minedhype/ishop/Messages.java index b537836..3ac31bc 100644 --- a/src/com/minedhype/ishop/Messages.java +++ b/src/com/minedhype/ishop/Messages.java @@ -21,8 +21,10 @@ public enum Messages { SHOP_CLICK_MANAGE("clickManage"), SHOP_CLICK_SHOP("clickShop"), SHOP_CREATED("shopCreated"), + SHOP_CREATED_LOC("shopCreatedLoc"), SHOP_CREATE_NO_MONEY("noMoney"), SHOP_DELETED("shopDeleted"), + SHOP_DELETED_LOC("shopDeletedLoc"), SHOP_FAR("outOfStockRange"), SHOP_FOUND("foundShops"), SHOP_IDDELETED("shopIDDeleted"), @@ -32,6 +34,8 @@ public enum Messages { SHOP_LIST_DISABLED("shopListDisabled"), SHOP_LIST_OUT("listOutOfStock"), SHOP_LOCATION("location"), + SHOP_LOCATION_ERROR_NUM("shopLocationErrorNum"), + SHOP_LOCATION_ERROR_WORLD("shopLocationErrorWorld"), SHOP_MAX("shopLimit"), SHOP_NOT_FOUND("noShopFound"), SHOP_NOT_OUT("notOutOfStock"), diff --git a/src/com/minedhype/ishop/iShop.java b/src/com/minedhype/ishop/iShop.java index b17d926..b199f52 100644 --- a/src/com/minedhype/ishop/iShop.java +++ b/src/com/minedhype/ishop/iShop.java @@ -76,7 +76,11 @@ public void onEnable() { } catch(Exception e) { e.printStackTrace(); } }, delayTime); expiredTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, Shop::expiredShops, delayTime+20, 20000); - saveTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, Shop::saveData, delayTime+1200, 6000); + saveTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> { + try { + Shop.saveData(); + } catch (Exception e) { Bukkit.getConsoleSender().sendMessage(ChatColor.YELLOW + "[iShop] Warning: Tried saving to database while being modified at the same time. Saving will continue and try again later, but will also save to database safely upon server shutdown."); }; + }, delayTime+1200, 6000); tickTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, Shop::tickShops, delayTime+150, 50); Bukkit.getScheduler().runTaskLaterAsynchronously(this, Shop::getPlayersShopList, delayTime+100); MetricsLite metrics = new MetricsLite(this, 9189); @@ -88,18 +92,11 @@ public void onEnable() { @Override public void onDisable() { - tickTask.cancel(); expiredTask.cancel(); - getServer().getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Saving shops & stock items to database, please wait & do not kill server process..."); - if(Bukkit.getScheduler().isCurrentlyRunning(saveTask.getTaskId())) { - while(Bukkit.getScheduler().isCurrentlyRunning(saveTask.getTaskId())) - ; - saveTask.cancel(); - } - else { - saveTask.cancel(); - Shop.saveData(); - } + saveTask.cancel(); + tickTask.cancel(); + getServer().getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Safely saving shops & stock items to database, please wait & do not kill server process..."); + Shop.saveData(); getServer().getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Saving complete!"); if(connection != null) { try { @@ -273,9 +270,14 @@ public void createConfig() { case "3.3": config.set("maxStockPages", 10); config.set("removedAllPlayer", "&6Removed&c %shops &6shop(s) for player:&c %p"); - config.set("configVersion", "3.4"); - config.save(configFile); case "3.4": + config.set("shopCreatedLoc", "&7Shop has been &aCREATED&7 for&a %p &7at &a%x &7/&a %y &7/&a %z &7in &a%w&7!"); + config.set("shopDeletedLoc", "&7Shop has been &cDELETED&7 for&a %p &7at &a%x &7/&a %y &7/&a %z &7in &a%w&7!"); + config.set("shopLocationErrorNum", "&cLocation coordinates must be a positive or negative number!"); + config.set("shopLocationErrorWorld", "&cLocation coordinates must be in a valid world!"); + config.set("configVersion", "3.5"); + config.save(configFile); + case "3.5": break; } } catch(IOException | InvalidConfigurationException e) { e.printStackTrace(); } diff --git a/src/resources/config.yml b/src/resources/config.yml index 2aa064b..8acd377 100644 --- a/src/resources/config.yml +++ b/src/resources/config.yml @@ -243,6 +243,10 @@ noClaimPermission: "&cYou do not have permission in this claim to create a shop! pageSkipAhead: "5 Pages >>" pageSkipPrev: "<< 5 Pages" removedAllPlayer: "&6Removed&c %shops &6shop(s) for player:&c %p" +shopCreatedLoc: "&7Shop has been &aCREATED&7 for&a %p &7at &a%x &7/&a %y &7/&a %z &7in &a%w&7!" +shopDeletedLoc: "&7Shop has been &cDELETED&7 for&a %p &7at &a%x &7/&a %y &7/&a %z &7in &a%w&7!" +shopLocationErrorNum: "&cLocation coordinates must be a positive or negative number!" +shopLocationErrorWorld: "&cLocation coordinates must be in a valid world!" # Do not edit this! -configVersion: 3.4 \ No newline at end of file +configVersion: 3.5 \ No newline at end of file From 7fd9aae9ce0119b410bc63dd1c43a799b8f43908 Mon Sep 17 00:00:00 2001 From: Beez0r Date: Fri, 16 Sep 2022 00:19:57 -0700 Subject: [PATCH 07/15] iShop 2.20 Update --- src/com/minedhype/ishop/CommandShop.java | 8 +- src/com/minedhype/ishop/Shop.java | 94 ++++++++++++++++++- src/com/minedhype/ishop/iShop.java | 22 +++-- .../ishop/inventories/InvAdminShop.java | 2 +- .../ishop/inventories/InvCreateRow.java | 15 ++- src/resources/config.yml | 11 ++- 6 files changed, 136 insertions(+), 16 deletions(-) diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index 8a40b6b..ff17539 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -428,7 +428,10 @@ private void createLocation(Player player, String playerShop, String x, String y return; } if(!iShop.config.getBoolean("enableShopBlock")) { - player.sendMessage(Messages.DISABLED_SHOP_BLOCK.toString()); + if(player != null) + player.sendMessage(Messages.DISABLED_SHOP_BLOCK.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.DISABLED_SHOP_BLOCK.toString()); return; } String world; @@ -975,6 +978,8 @@ private void reloadShop(Player player) { InvAdminShop.usePerms = iShop.config.getBoolean("usePermissions"); InvCreateRow.disabledItemList = iShop.config.getStringList("disabledItemsList"); InvCreateRow.itemsDisabled = iShop.config.getBoolean("disabledItems"); + InvCreateRow.preventDupeTrades = iShop.config.getBoolean("preventDuplicates"); + InvCreateRow.preventAllDupeTrades = iShop.config.getBoolean("preventAllDuplicates"); InvCreateRow.strictStock = iShop.config.getBoolean("strictStock"); InvShop.listAllShops = iShop.config.getBoolean("publicShopListCommand"); Shop.showOwnedShops = iShop.config.getBoolean("publicShopListShowsOwned"); @@ -984,6 +989,7 @@ private void reloadShop(Player player) { Shop.particleEffects = iShop.config.getBoolean("showParticles"); Shop.maxDays = iShop.config.getInt("maxInactiveDays"); Shop.deletePlayerShop = iShop.config.getBoolean("deleteBlock"); + Shop.saveEmptyShops = iShop.config.getBoolean("saveEmptyShops"); Shop.stockMessages = iShop.config.getBoolean("enableShopSoldMessage"); Shop.exemptExpiringList = iShop.config.getStringList("exemptExpiringShops"); }); diff --git a/src/com/minedhype/ishop/Shop.java b/src/com/minedhype/ishop/Shop.java index c28d258..98b4744 100644 --- a/src/com/minedhype/ishop/Shop.java +++ b/src/com/minedhype/ishop/Shop.java @@ -39,6 +39,7 @@ public class Shop { public static boolean deletePlayerShop = iShop.config.getBoolean("deleteBlock"); public static boolean particleEffects = iShop.config.getBoolean("showParticles"); + public static boolean saveEmptyShops = iShop.config.getBoolean("saveEmptyShops"); public static boolean shopOutStock = iShop.config.getBoolean("enableOutOfStockMessages"); public static boolean shopEnabled = iShop.config.getBoolean("enableShopBlock"); public static boolean showOwnedShops = iShop.config.getBoolean("publicShopListShowsOwned"); @@ -568,7 +569,7 @@ public static void loadData() { } } - public static void saveData() { + public static void saveData(boolean shutDown) { StockShop.saveData(); PreparedStatement stmt = null; try { @@ -581,8 +582,18 @@ public static void saveData() { stmt.close(); } catch (Exception e) { e.printStackTrace(); } } - for(Shop shop : shops) - shop.saveDataShop(); + if(shutDown && saveEmptyShops) { + for(Shop shop : shops) + if(shop.saveDataShopEmpty()) { + ItemStack air = new ItemStack(Material.AIR, 0); + shop.getRows()[0] = new RowStore(air, air, air, air, false); + shop.saveEmptyShops(); + } + } + else { + for(Shop shop : shops) + shop.saveDataShop(); + } } public boolean hasItems() { @@ -598,6 +609,30 @@ private void saveDataShop() { row.saveData(idTienda); } + private boolean saveDataShopEmpty() { + boolean isEmpty = true; + for(RowStore row : rows) + if(row != null) { + row.saveData(idTienda); + if(isEmpty) + isEmpty = false; + } + return isEmpty; + } + + private void saveEmptyShops() { + RowStore row = rows[0]; + row.saveData(idTienda); + } + + public static void removeEmptyShopTrade() { + for(Shop shop : shops) { + Optional row = shop.getRow(0); + if(row.get().getItemIn().getType().isAir() && row.get().getItemIn2().getType().isAir() && row.get().getItemOut().getType().isAir() && row.get().getItemOut2().getType().isAir()) + shop.delete(0); + } + } + public void buy(Player player, int index) { Optional row = getRow(index); if(!row.isPresent()) @@ -814,7 +849,7 @@ public void takeItem(ItemStack item) { InvStock.getInvStock(this.owner).refreshItems(); } - public void delete(Player player, int index) { + public void delete(int index) { rows[index] = null; } public void deleteShop() { @@ -1129,6 +1164,57 @@ public void outOfStockItem(Player ownerPlayer, String itemString) { } } + public static boolean hasDuplicateTrades(ItemStack out1, ItemStack out2, ItemStack in1, ItemStack in2, int shopId) { + Optional shop = getShopById(shopId); + for(RowStore row:shop.get().getRows()) { + if(row != null) { + boolean row1, row2, row3, row4; + if(row.getItemIn().equals(in1) || (row.getItemIn().getType().isAir() && in1.getType().isAir())) + row1 = true; + else continue; + if(row.getItemIn2().equals(in2) || (row.getItemIn2().getType().isAir() && in2.getType().isAir())) + row2 = true; + else continue; + if(row.getItemOut().equals(out1) || (row.getItemOut().getType().isAir() && out1.getType().isAir())) + row3 = true; + else continue; + if(row.getItemOut2().equals(out2) || (row.getItemOut2().getType().isAir() && out2.getType().isAir())) + row4 = true; + else continue; + if(row1 && row2 && row3 && row4) + return true; + } + } + return false; + } + + public static boolean hasAnyDuplicateTrades(ItemStack out1, ItemStack out2, ItemStack in1, ItemStack in2, UUID shopOwner) { + for(Shop shop:shops) { + if(shop.isOwner(shopOwner) && !shop.isAdmin()) { + for(RowStore row:shop.getRows()) { + if(row != null) { + boolean row1, row2, row3, row4; + if(row.getItemIn().equals(in1) || (row.getItemIn().getType().isAir() && in1.getType().isAir())) + row1 = true; + else continue; + if(row.getItemIn2().equals(in2) || (row.getItemIn2().getType().isAir() && in2.getType().isAir())) + row2 = true; + else continue; + if(row.getItemOut().equals(out1) || (row.getItemOut().getType().isAir() && out1.getType().isAir())) + row3 = true; + else continue; + if(row.getItemOut2().equals(out2) || (row.getItemOut2().getType().isAir() && out2.getType().isAir())) + row4 = true; + else continue; + if(row1 && row2 && row3 && row4) + return true; + } + } + } + } + return false; + } + public Optional getRow(int index) { if(index < 0 || index > 4) return Optional.empty(); diff --git a/src/com/minedhype/ishop/iShop.java b/src/com/minedhype/ishop/iShop.java index b199f52..be74b3f 100644 --- a/src/com/minedhype/ishop/iShop.java +++ b/src/com/minedhype/ishop/iShop.java @@ -75,14 +75,16 @@ public void onEnable() { Shop.loadData(); } catch(Exception e) { e.printStackTrace(); } }, delayTime); - expiredTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, Shop::expiredShops, delayTime+20, 20000); + expiredTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, Shop::expiredShops, delayTime+9, 20000); saveTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> { try { - Shop.saveData(); - } catch (Exception e) { Bukkit.getConsoleSender().sendMessage(ChatColor.YELLOW + "[iShop] Warning: Tried saving to database while being modified at the same time. Saving will continue and try again later, but will also save to database safely upon server shutdown."); }; + Shop.saveData(false); + } catch (Exception e) { Bukkit.getConsoleSender().sendMessage(ChatColor.YELLOW + "[iShop] Warning: Tried saving to database while being modified at the same time. Saving will continue and try again later, but will also save to database safely upon server shutdown."); } }, delayTime+1200, 6000); - tickTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, Shop::tickShops, delayTime+150, 50); - Bukkit.getScheduler().runTaskLaterAsynchronously(this, Shop::getPlayersShopList, delayTime+100); + if(Shop.shopEnabled && Shop.particleEffects) + tickTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, Shop::tickShops, delayTime+250, 50); + Bukkit.getScheduler().runTaskLaterAsynchronously(this, Shop::getPlayersShopList, delayTime+160); + Bukkit.getScheduler().runTaskLaterAsynchronously(this, Shop::removeEmptyShopTrade, delayTime+100); MetricsLite metrics = new MetricsLite(this, 9189); new UpdateChecker(this, 84555).getVersion(version -> { if(!this.getDescription().getVersion().equalsIgnoreCase(version)) @@ -96,7 +98,7 @@ public void onDisable() { saveTask.cancel(); tickTask.cancel(); getServer().getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Safely saving shops & stock items to database, please wait & do not kill server process..."); - Shop.saveData(); + Shop.saveData(true); getServer().getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Saving complete!"); if(connection != null) { try { @@ -275,9 +277,13 @@ public void createConfig() { config.set("shopDeletedLoc", "&7Shop has been &cDELETED&7 for&a %p &7at &a%x &7/&a %y &7/&a %z &7in &a%w&7!"); config.set("shopLocationErrorNum", "&cLocation coordinates must be a positive or negative number!"); config.set("shopLocationErrorWorld", "&cLocation coordinates must be in a valid world!"); - config.set("configVersion", "3.5"); - config.save(configFile); case "3.5": + config.set("preventDuplicates", true); + config.set("preventAllDuplicates", false); + config.set("saveEmptyShops", true); + config.set("configVersion", "3.6"); + config.save(configFile); + case "3.6": break; } } catch(IOException | InvalidConfigurationException e) { e.printStackTrace(); } diff --git a/src/com/minedhype/ishop/inventories/InvAdminShop.java b/src/com/minedhype/ishop/inventories/InvAdminShop.java index 575eeae..fbe9d27 100644 --- a/src/com/minedhype/ishop/inventories/InvAdminShop.java +++ b/src/com/minedhype/ishop/inventories/InvAdminShop.java @@ -81,7 +81,7 @@ private void updateItems(Player player) { final int index = y-1; if(row.isPresent()) { placeItem(y*9+x, GUI.createItem(Material.TNT, ChatColor.BOLD+ Messages.SHOP_TITLE_DELETE.toString()), p -> { - shop.delete(p, index); + shop.delete(index); InvAdminShop inv = new InvAdminShop(shop, p.getPlayer()); inv.open(p); }); diff --git a/src/com/minedhype/ishop/inventories/InvCreateRow.java b/src/com/minedhype/ishop/inventories/InvCreateRow.java index 97877cb..e6db1b6 100644 --- a/src/com/minedhype/ishop/inventories/InvCreateRow.java +++ b/src/com/minedhype/ishop/inventories/InvCreateRow.java @@ -9,8 +9,9 @@ import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import com.minedhype.ishop.RowStore; import com.minedhype.ishop.Messages; +import com.minedhype.ishop.Permission; +import com.minedhype.ishop.RowStore; import com.minedhype.ishop.Shop; import com.minedhype.ishop.iShop; import com.minedhype.ishop.gui.GUI; @@ -25,6 +26,8 @@ public class InvCreateRow extends GUI { private ItemStack itemOut2; private final ItemStack airItem = new ItemStack(Material.AIR, 0); public static Boolean itemsDisabled = iShop.config.getBoolean("disabledItems"); + public static Boolean preventDupeTrades = iShop.config.getBoolean("preventDuplicates"); + public static Boolean preventAllDupeTrades = iShop.config.getBoolean("preventAllDuplicates"); public static Boolean strictStock = iShop.config.getBoolean("strictStock"); public static List disabledItemList = iShop.config.getStringList("disabledItemsList"); @@ -58,6 +61,16 @@ else if(i == 13) { ItemStack in2 = itemIn2.clone(); ItemStack out1 = itemOut.clone(); ItemStack out2 = itemOut2.clone(); + if(!p.hasPermission(Permission.SHOP_ADMIN.toString())) { + if(preventAllDupeTrades) { + if(Shop.hasAnyDuplicateTrades(out1, out2, in1, in2, p.getUniqueId())) + return; + } + else if(preventDupeTrades) { + if(Shop.hasDuplicateTrades(out1, out2, in1, in2, shop.shopId())) + return; + } + } if(itemsDisabled) { for(String itemsList:disabledItemList) { Material disabledItemsList = Material.matchMaterial(itemsList); diff --git a/src/resources/config.yml b/src/resources/config.yml index 8acd377..bf3a70b 100644 --- a/src/resources/config.yml +++ b/src/resources/config.yml @@ -163,6 +163,15 @@ stockRangeLimitUsingCommand: false # This will only allow items that are in active shop trades to be added and stored in stock inventory strictStock: false +# Prevent players from creating duplicate item trades within each shop they own +preventDuplicates: true + +# Prevent players from creating duplicate item trades from any shop they own +preventAllDuplicates: false + +# Save shops with no trades to database on server shutdown +saveEmptyShops: true + # Customizable Messages adminShop: "Admin Shop #%id" adminShopDisabled: "&cAdmin shops have been disabled!" @@ -249,4 +258,4 @@ shopLocationErrorNum: "&cLocation coordinates must be a positive or negative num shopLocationErrorWorld: "&cLocation coordinates must be in a valid world!" # Do not edit this! -configVersion: 3.5 \ No newline at end of file +configVersion: 3.6 \ No newline at end of file From 08a3db455307e43c7860399d31cfc72f79c64613 Mon Sep 17 00:00:00 2001 From: Beez0r Date: Thu, 29 Sep 2022 00:40:02 -0700 Subject: [PATCH 08/15] iShop 2.21 Update --- src/com/minedhype/ishop/iShop.java | 16 +++++++++++++--- src/resources/config.yml | 5 ++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/com/minedhype/ishop/iShop.java b/src/com/minedhype/ishop/iShop.java index be74b3f..2d48b2d 100644 --- a/src/com/minedhype/ishop/iShop.java +++ b/src/com/minedhype/ishop/iShop.java @@ -61,6 +61,7 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new GUIEvent(), this); getCommand("ishop").setExecutor(new CommandShop()); int delayTime; + int saveDatabaseTime; try { delayTime = config.getInt("shopsDatabaseLoadDelay"); } catch(Exception e) { delayTime = 0; } @@ -68,6 +69,13 @@ public void onEnable() { delayTime = 1; else delayTime*=20; + try { + saveDatabaseTime = config.getInt("saveDatabase"); + } catch(Exception e) { saveDatabaseTime = 15; } + if(saveDatabaseTime < 5) + saveDatabaseTime = 5; + (saveDatabaseTime)*=60; + (saveDatabaseTime)*=20; Bukkit.getScheduler().runTaskLater(this, () -> { try { connection = DriverManager.getConnection(chainConnect); @@ -80,7 +88,7 @@ public void onEnable() { try { Shop.saveData(false); } catch (Exception e) { Bukkit.getConsoleSender().sendMessage(ChatColor.YELLOW + "[iShop] Warning: Tried saving to database while being modified at the same time. Saving will continue and try again later, but will also save to database safely upon server shutdown."); } - }, delayTime+1200, 6000); + }, delayTime+1200, saveDatabaseTime); if(Shop.shopEnabled && Shop.particleEffects) tickTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, Shop::tickShops, delayTime+250, 50); Bukkit.getScheduler().runTaskLaterAsynchronously(this, Shop::getPlayersShopList, delayTime+160); @@ -281,9 +289,11 @@ public void createConfig() { config.set("preventDuplicates", true); config.set("preventAllDuplicates", false); config.set("saveEmptyShops", true); - config.set("configVersion", "3.6"); - config.save(configFile); case "3.6": + config.set("saveDatabase", 15); + config.set("configVersion", "3.7"); + config.save(configFile); + case "3.7": break; } } catch(IOException | InvalidConfigurationException e) { e.printStackTrace(); } diff --git a/src/resources/config.yml b/src/resources/config.yml index bf3a70b..71671d2 100644 --- a/src/resources/config.yml +++ b/src/resources/config.yml @@ -172,6 +172,9 @@ preventAllDuplicates: false # Save shops with no trades to database on server shutdown saveEmptyShops: true +# Save shops and stock to database interval in minutes. Database will auto save upon server shutdown. Default is every 15 minutes +saveDatabase: 15 + # Customizable Messages adminShop: "Admin Shop #%id" adminShopDisabled: "&cAdmin shops have been disabled!" @@ -258,4 +261,4 @@ shopLocationErrorNum: "&cLocation coordinates must be a positive or negative num shopLocationErrorWorld: "&cLocation coordinates must be in a valid world!" # Do not edit this! -configVersion: 3.6 \ No newline at end of file +configVersion: 3.7 \ No newline at end of file From c677d6863f590fdad9a60050a1ca9b2e69ae38b1 Mon Sep 17 00:00:00 2001 From: Beez0r Date: Thu, 23 Mar 2023 15:36:28 -0700 Subject: [PATCH 09/15] iShop 2.22 Update --- src/com/minedhype/ishop/CommandShop.java | 113 +++++++++++++++--- src/com/minedhype/ishop/EventShop.java | 47 +++----- src/com/minedhype/ishop/Messages.java | 1 + src/com/minedhype/ishop/iShop.java | 54 ++++++++- .../ishop/inventories/InvAdminShop.java | 24 ++-- src/resources/config.yml | 6 +- src/resources/plugin.yml | 2 +- 7 files changed, 182 insertions(+), 65 deletions(-) diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index ff17539..0a2263b 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -5,8 +5,15 @@ import java.util.Optional; import java.util.Scanner; import java.util.UUID; +import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.minedhype.ishop.inventories.InvCreateRow; import com.minedhype.ishop.inventories.InvShop; +import com.palmergames.bukkit.towny.utils.ShopPlotUtil; +import me.angeschossen.lands.api.flags.type.Flags; +import me.angeschossen.lands.api.land.LandWorld; import me.ryanhamshire.GriefPrevention.ClaimPermission; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.TextComponent; @@ -272,6 +279,36 @@ private void createStore(Player player) { player.sendMessage(Messages.GP_CLAIM.toString()); return; } + boolean allowShopCreateWithinLands = false; + if(iShop.lands != null) { + LandWorld world = iShop.lands.getWorld(player.getWorld()); + if(world != null) + if(world.hasRoleFlag(player.getUniqueId(), block.getLocation(), Flags.BLOCK_PLACE)) + allowShopCreateWithinLands = true; + } + else + allowShopCreateWithinLands = true; + if(!allowShopCreateWithinLands) { + player.sendMessage(Messages.NO_SHOP_CREATE_PERMISSION.toString()); + return; + } + if(iShop.superiorSkyblock2Check) { + Island island = SuperiorSkyblockAPI.getIslandAt(block.getLocation()); + if(island != null) { + IslandPrivilege islandPrivilege = IslandPrivilege.getByName("Build"); + SuperiorPlayer superiorPlayer = SuperiorSkyblockAPI.getPlayer(player.getUniqueId()); + if(!island.hasPermission(superiorPlayer, islandPrivilege)) { + player.sendMessage(Messages.NO_SHOP_CREATE_PERMISSION.toString()); + return; + } + } + } + if(iShop.townyCheck) { + if(!ShopPlotUtil.doesPlayerHaveAbilityToEditShopPlot(player, block.getLocation())) { + player.sendMessage(Messages.NO_SHOP_CREATE_PERMISSION.toString()); + return; + } + } Optional shop = Shop.getShopByLocation(block.getLocation()); if(shop.isPresent()) { player.sendMessage(Messages.EXISTING_SHOP.toString()); @@ -410,6 +447,59 @@ private void createShop(Player player, String playerShop) { player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); return; } + if(!player.isOp() && !iShop.config.getBoolean("skipPermsCheckForAdminCreateShop")) { + boolean isShopLoc; + if(iShop.wgLoader != null) + isShopLoc = iShop.wgLoader.checkRegion(block); + else + isShopLoc = true; + if(!isShopLoc) { + player.sendMessage(Messages.WG_REGION.toString()); + return; + } + boolean allowShopCreateInClaim = false; + if(iShop.gpLoader != null) { + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(block.getLocation(), false, false, null); + if(claim == null || claim.checkPermission(player, ClaimPermission.Access, null) == null || claim.checkPermission(player, ClaimPermission.Build, null) == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null || claim.checkPermission(player, ClaimPermission.Manage, null) == null || claim.checkPermission(player, ClaimPermission.Inventory, null) == null) + allowShopCreateInClaim = true; + } + else + allowShopCreateInClaim = true; + if(!allowShopCreateInClaim) { + player.sendMessage(Messages.GP_CLAIM.toString()); + return; + } + boolean allowShopCreateWithinLands = false; + if(iShop.lands != null) { + LandWorld world = iShop.lands.getWorld(player.getWorld()); + if(world != null) + if(world.hasRoleFlag(player.getUniqueId(), block.getLocation(), Flags.BLOCK_PLACE)) + allowShopCreateWithinLands = true; + } + else + allowShopCreateWithinLands = true; + if(!allowShopCreateWithinLands) { + player.sendMessage(Messages.NO_SHOP_CREATE_PERMISSION.toString()); + return; + } + if(iShop.superiorSkyblock2Check) { + Island island = SuperiorSkyblockAPI.getIslandAt(block.getLocation()); + if(island != null) { + IslandPrivilege islandPrivilege = IslandPrivilege.getByName("Build"); + SuperiorPlayer superiorPlayer = SuperiorSkyblockAPI.getPlayer(player.getUniqueId()); + if(!island.hasPermission(superiorPlayer, islandPrivilege)) { + player.sendMessage(Messages.NO_SHOP_CREATE_PERMISSION.toString()); + return; + } + } + } + if(iShop.townyCheck) { + if(!ShopPlotUtil.doesPlayerHaveAbilityToEditShopPlot(player, block.getLocation())) { + player.sendMessage(Messages.NO_SHOP_CREATE_PERMISSION.toString()); + return; + } + } + } Optional shop = Shop.getShopByLocation(block.getLocation()); if(!shop.isPresent()) { Shop.createShop(block.getLocation(), shopOwner); @@ -911,21 +1001,16 @@ private void stockShop(Player player, String page) { int maxStockPages = InvAdminShop.maxPages; if(InvAdminShop.usePerms) { String permPrefix = Permission.SHOP_STOCK_PREFIX.toString(); - for(PermissionAttachmentInfo attInfo : player.getEffectivePermissions()) { - String perm = attInfo.getPermission(); - if(perm.startsWith(permPrefix)) { - int num; - try { - num = Integer.parseInt(perm.substring(perm.lastIndexOf(".")+1)); - } catch(Exception e) { num = InvAdminShop.maxPages; } - if(num > InvAdminShop.permissionMax) - maxStockPages = InvAdminShop.permissionMax; - else if(num > 0) - maxStockPages = num; - else - maxStockPages = InvAdminShop.maxPages; + int maxPermPages = InvAdminShop.permissionMax; + boolean permissionFound = false; + for(int i=maxPermPages; i>0; i--) + if(player.hasPermission(permPrefix + i)) { + maxStockPages = i; + permissionFound = true; + break; } - } + if(!permissionFound) + maxStockPages = maxPermPages; } if(openPage > 0 && openPage > maxStockPages-1) openPage = maxStockPages-1; diff --git a/src/com/minedhype/ishop/EventShop.java b/src/com/minedhype/ishop/EventShop.java index 43b78ab..e206332 100644 --- a/src/com/minedhype/ishop/EventShop.java +++ b/src/com/minedhype/ishop/EventShop.java @@ -25,7 +25,6 @@ import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.inventory.EquipmentSlot; -import org.bukkit.permissions.PermissionAttachmentInfo; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -205,21 +204,16 @@ else if(event.getHand().equals(EquipmentSlot.OFF_HAND)) int maxStockPages = InvAdminShop.maxPages; if(InvAdminShop.usePerms) { String permPrefix = Permission.SHOP_STOCK_PREFIX.toString(); - for(PermissionAttachmentInfo attInfo : event.getPlayer().getEffectivePermissions()) { - String perm = attInfo.getPermission(); - if(perm.startsWith(permPrefix)) { - int num; - try { - num = Integer.parseInt(perm.substring(perm.lastIndexOf(".")+1)); - } catch(Exception e) { num = InvAdminShop.maxPages; } - if(num > InvAdminShop.permissionMax) - maxStockPages = InvAdminShop.permissionMax; - else if(num > 0) - maxStockPages = num; - else - maxStockPages = InvAdminShop.maxPages; + int maxPermPages = InvAdminShop.permissionMax; + boolean permissionFound = false; + for(int i=maxPermPages; i>0; i--) + if(event.getPlayer().hasPermission(permPrefix + i)) { + maxStockPages = i; + permissionFound = true; + break; } - } + if(!permissionFound) + maxStockPages = maxPermPages; } inv.setMaxPages(maxStockPages); inv.setPag(0); @@ -257,21 +251,16 @@ else if(num > 0) int maxStockPages = InvAdminShop.maxPages; if(InvAdminShop.usePerms) { String permPrefix = Permission.SHOP_STOCK_PREFIX.toString(); - for(PermissionAttachmentInfo attInfo : event.getPlayer().getEffectivePermissions()) { - String perm = attInfo.getPermission(); - if(perm.startsWith(permPrefix)) { - int num; - try { - num = Integer.parseInt(perm.substring(perm.lastIndexOf(".")+1)); - } catch(Exception e) { num = InvAdminShop.maxPages; } - if(num > InvAdminShop.permissionMax) - maxStockPages = InvAdminShop.permissionMax; - else if(num > 0) - maxStockPages = num; - else - maxStockPages = InvAdminShop.maxPages; + int maxPermPages = InvAdminShop.permissionMax; + boolean permissionFound = false; + for(int i=maxPermPages; i>0; i--) + if(event.getPlayer().hasPermission(permPrefix + i)) { + maxStockPages = i; + permissionFound = true; + break; } - } + if(!permissionFound) + maxStockPages = maxPermPages; } inv.setMaxPages(maxStockPages); inv.setPag(0); diff --git a/src/com/minedhype/ishop/Messages.java b/src/com/minedhype/ishop/Messages.java index 3ac31bc..ca75213 100644 --- a/src/com/minedhype/ishop/Messages.java +++ b/src/com/minedhype/ishop/Messages.java @@ -9,6 +9,7 @@ public enum Messages { EXISTING_SHOP("existingShop"), GP_CLAIM("noClaimPermission"), NOT_A_PLAYER("notPlayer"), + NO_SHOP_CREATE_PERMISSION("noPermissionToCreateShop"), NO_PERMISSION("noPermissions"), NO_PLAYER_FOUND("noPlayerFound"), NO_PLAYER_SHOP("noPlayerShop"), diff --git a/src/com/minedhype/ishop/iShop.java b/src/com/minedhype/ishop/iShop.java index 2d48b2d..36ed5fb 100644 --- a/src/com/minedhype/ishop/iShop.java +++ b/src/com/minedhype/ishop/iShop.java @@ -23,12 +23,16 @@ import net.milkbowl.vault.economy.Economy; import org.bukkit.scheduler.BukkitTask; import me.ryanhamshire.GriefPrevention.GriefPrevention; +import me.angeschossen.lands.api.LandsIntegration; public class iShop extends JavaPlugin { File configFile; public static FileConfiguration config; public static WorldGuardLoader wgLoader = null; public static GriefPrevention gpLoader = null; + public static LandsIntegration lands = null; + public static boolean superiorSkyblock2Check; + public static boolean townyCheck; private static BukkitTask expiredTask, saveTask, tickTask; private static Connection connection = null; private static Economy economy = null; @@ -42,6 +46,19 @@ public void onLoad() { Plugin wgCheck = Bukkit.getPluginManager().getPlugin("WorldGuard"); if(wgCheck != null) wgLoader = new WorldGuardLoader(); + Plugin landsCheck = Bukkit.getPluginManager().getPlugin("Lands"); + if(landsCheck != null) + lands = LandsIntegration.of(iShop.getPlugin()); + Plugin superiorSkyblock2Enabled = Bukkit.getPluginManager().getPlugin("SuperiorSkyblock2"); + if(superiorSkyblock2Enabled != null) + superiorSkyblock2Check = true; + else + superiorSkyblock2Check = false; + Plugin townyEnabled = Bukkit.getPluginManager().getPlugin("Towny"); + if(townyEnabled != null) + townyCheck = true; + else + townyCheck = false; } @Override @@ -102,9 +119,33 @@ public void onEnable() { @Override public void onDisable() { - expiredTask.cancel(); - saveTask.cancel(); - tickTask.cancel(); + if(Bukkit.getScheduler().isCurrentlyRunning(tickTask.getTaskId())) { + while(Bukkit.getScheduler().isCurrentlyRunning(tickTask.getTaskId())) + ; + tickTask.cancel(); + } + else + tickTask.cancel(); + if(Bukkit.getScheduler().isCurrentlyRunning(saveTask.getTaskId())) { + while(Bukkit.getScheduler().isCurrentlyRunning(saveTask.getTaskId())) + ; + saveTask.cancel(); + } + else + saveTask.cancel(); + if(Bukkit.getScheduler().isCurrentlyRunning(expiredTask.getTaskId())) { + while(Bukkit.getScheduler().isCurrentlyRunning(expiredTask.getTaskId())) + ; + expiredTask.cancel(); + } + else + expiredTask.cancel(); + if(!tickTask.isCancelled()) + tickTask.cancel(); + if(!saveTask.isCancelled()) + saveTask.cancel(); + if(!expiredTask.isCancelled()) + expiredTask.cancel(); getServer().getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Safely saving shops & stock items to database, please wait & do not kill server process..."); Shop.saveData(true); getServer().getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Saving complete!"); @@ -291,9 +332,12 @@ public void createConfig() { config.set("saveEmptyShops", true); case "3.6": config.set("saveDatabase", 15); - config.set("configVersion", "3.7"); - config.save(configFile); case "3.7": + config.set("skipPermsCheckForAdminCreateShop", true); + config.set("noPermissionToCreateShop", "&cYou do not have permission to create a shop at this location!"); + config.set("configVersion", "3.8"); + config.save(configFile); + case "3.8": break; } } catch(IOException | InvalidConfigurationException e) { e.printStackTrace(); } diff --git a/src/com/minedhype/ishop/inventories/InvAdminShop.java b/src/com/minedhype/ishop/inventories/InvAdminShop.java index fbe9d27..615a98c 100644 --- a/src/com/minedhype/ishop/inventories/InvAdminShop.java +++ b/src/com/minedhype/ishop/inventories/InvAdminShop.java @@ -13,7 +13,6 @@ import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import com.minedhype.ishop.gui.GUI; -import org.bukkit.permissions.PermissionAttachmentInfo; public class InvAdminShop extends GUI { public static boolean remoteManage = iShop.config.getBoolean("remoteManage"); @@ -99,21 +98,16 @@ private void updateItems(Player player) { int maxStockPages = maxPages; if(usePerms) { String permPrefix = Permission.SHOP_STOCK_PREFIX.toString(); - for(PermissionAttachmentInfo attInfo : player.getEffectivePermissions()) { - String perm = attInfo.getPermission(); - if(perm.startsWith(permPrefix)) { - int num; - try { - num = Integer.parseInt(perm.substring(perm.lastIndexOf(".")+1)); - } catch(Exception e) { num = maxPages; } - if(num > permissionMax) - maxStockPages = permissionMax; - else if(num > 0) - maxStockPages = num; - else - maxStockPages = maxPages; + int maxPermPages = InvAdminShop.permissionMax; + boolean permissionFound = false; + for(int i=maxPermPages; i>0; i--) + if(player.hasPermission(permPrefix + i)) { + maxStockPages = i; + permissionFound = true; + break; } - } + if(!permissionFound) + maxStockPages = maxPermPages; } inv.setMaxPages(maxStockPages); inv.setPag(0); diff --git a/src/resources/config.yml b/src/resources/config.yml index 71671d2..eeee80d 100644 --- a/src/resources/config.yml +++ b/src/resources/config.yml @@ -175,6 +175,9 @@ saveEmptyShops: true # Save shops and stock to database interval in minutes. Database will auto save upon server shutdown. Default is every 15 minutes saveDatabase: 15 +# When a player with iShop.admin permission uses command createshop and is not a server operator, skip checking for permission within GriefPrevention, Lands, SuperiorSkyblock2, Towny, and WorldGuard +skipPermsCheckForAdminCreateShop: true + # Customizable Messages adminShop: "Admin Shop #%id" adminShopDisabled: "&cAdmin shops have been disabled!" @@ -259,6 +262,7 @@ shopCreatedLoc: "&7Shop has been &aCREATED&7 for&a %p &7at &a%x &7/&a %y &7/&a % shopDeletedLoc: "&7Shop has been &cDELETED&7 for&a %p &7at &a%x &7/&a %y &7/&a %z &7in &a%w&7!" shopLocationErrorNum: "&cLocation coordinates must be a positive or negative number!" shopLocationErrorWorld: "&cLocation coordinates must be in a valid world!" +noPermissionToCreateShop: "&cYou do not have permission to create a shop at this location!" # Do not edit this! -configVersion: 3.7 \ No newline at end of file +configVersion: 3.8 \ No newline at end of file diff --git a/src/resources/plugin.yml b/src/resources/plugin.yml index f2f8264..873950d 100644 --- a/src/resources/plugin.yml +++ b/src/resources/plugin.yml @@ -5,7 +5,7 @@ author: Beez0r website: https://minedhype.com version: "${project.version}" api-version: "1.17" -softdepend: [GriefPrevention, Vault, WorldGuard] +softdepend: [GriefPrevention, Lands, SuperiorSkyblock2, Towny, Vault, WorldGuard] commands: ishop: description: "/shop" From 864a6507c50a37e638c05d27250b0e4fde779d52 Mon Sep 17 00:00:00 2001 From: Beez0r Date: Tue, 23 May 2023 14:30:57 -0700 Subject: [PATCH 10/15] iShop 2.23 Update --- src/com/minedhype/ishop/CommandShop.java | 203 +++++++++++++++++++++-- src/com/minedhype/ishop/Messages.java | 5 + src/com/minedhype/ishop/Permission.java | 3 + src/com/minedhype/ishop/Shop.java | 46 +++++ src/com/minedhype/ishop/TabComplete.java | 26 +++ src/com/minedhype/ishop/Utils.java | 12 +- src/com/minedhype/ishop/iShop.java | 14 +- src/resources/config.yml | 19 ++- 8 files changed, 303 insertions(+), 25 deletions(-) create mode 100644 src/com/minedhype/ishop/TabComplete.java diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index 0a2263b..040471a 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -1,7 +1,9 @@ package com.minedhype.ishop; import java.net.URL; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Scanner; import java.util.UUID; @@ -42,26 +44,28 @@ import me.ryanhamshire.GriefPrevention.GriefPrevention; public class CommandShop implements CommandExecutor { + + private final Map findCooldown = new HashMap<>(); + static boolean findCommandPublic = iShop.config.getBoolean("publicFindCommand"); + static boolean moveCommandPublic = iShop.config.getBoolean("publicMoveCommand"); + static int findCooldownTime = iShop.config.getInt("findCommandCooldown"); + @Override public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { if(sender instanceof ConsoleCommandSender && args.length > 0) { if(args[0].equalsIgnoreCase("reload")) { reloadShop(null); return true; - } - else if(args[0].equalsIgnoreCase("deleteid") && args[1] != null) { + } else if(args[0].equalsIgnoreCase("deleteid") && args[1] != null) { deleteShopID(null, args[1]); return true; - } - else if(args[0].equalsIgnoreCase("createlocation") && args.length > 5) { + } else if(args[0].equalsIgnoreCase("createlocation") && args.length > 5) { Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> createLocation(null, args[1], args[2], args[3], args[4], args[5])); return true; - } - else if(args[0].equalsIgnoreCase("deletelocation") && args.length > 4) { + } else if(args[0].equalsIgnoreCase("deletelocation") && args.length > 4) { Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> deleteLocation(null, args[1], args[2], args[3], args[4])); return true; - } - else { + } else { sender.sendMessage(ChatColor.GOLD + "iShop Console Commands:"); sender.sendMessage(ChatColor.GRAY + label + " createlocation "); sender.sendMessage(ChatColor.GRAY + label + " deletelocation "); @@ -101,6 +105,8 @@ else if(args[0].equalsIgnoreCase("deleteid") && args.length >= 2) deleteShopID(player, args[1]); else if(args[0].equalsIgnoreCase("deletelocation") && args.length > 4) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> deleteLocation(player, args[1], args[2], args[3], args[4])); + else if(args[0].equalsIgnoreCase("find") && args.length >= 2) + Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> find(player, args[1])); else if(args[0].equalsIgnoreCase("list") && args.length == 1) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> listShops(player, null)); else if(args[0].equalsIgnoreCase("list") && args.length >= 2) @@ -113,6 +119,8 @@ else if(args[0].equalsIgnoreCase("managestock") && args.length == 2) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> manageStock(player, args[1], "1")); else if(args[0].equalsIgnoreCase("managestock") && args.length >= 3) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> manageStock(player, args[1], args[2])); + else if(args[0].equalsIgnoreCase("move") && args.length >= 2) + Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> moveShop(player, args[1])); else if(args[0].equalsIgnoreCase("out") && args.length == 1) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> outOfStock(player, null)); else if(args[0].equalsIgnoreCase("out") && args.length >= 2) @@ -145,18 +153,23 @@ private void listSubCmd(Player player, String label) { player.sendMessage(ChatColor.GRAY + "/" + label + " create"); player.sendMessage(ChatColor.GRAY + "/" + label + " delete"); player.sendMessage(ChatColor.GRAY + "/" + label + " deleteid "); + if(findCommandPublic || player.hasPermission(Permission.SHOP_ADMIN.toString()) || player.hasPermission(Permission.SHOP_FIND.toString())) + player.sendMessage(ChatColor.GRAY + "/" + label + " find "); player.sendMessage(ChatColor.GRAY + "/" + label + " list"); if(iShop.config.getBoolean("publicListCommand") || player.hasPermission(Permission.SHOP_ADMIN.toString()) || player.hasPermission(Permission.SHOP_LIST.toString())) player.sendMessage(ChatColor.GRAY + "/" + label + " list "); - if(iShop.config.getBoolean("publicShopListCommand") || player.hasPermission(Permission.SHOP_ADMIN.toString()) || player.hasPermission(Permission.SHOP_SHOPS.toString())) - player.sendMessage(ChatColor.GRAY + "/" + label + " shops"); player.sendMessage(ChatColor.GRAY + "/" + label + " manage "); + if(moveCommandPublic || player.hasPermission(Permission.SHOP_ADMIN.toString()) || player.hasPermission(Permission.SHOP_MOVE.toString())) + player.sendMessage(ChatColor.GRAY + "/" + label + " move "); player.sendMessage(ChatColor.GRAY + "/" + label + " out"); if(player.hasPermission(Permission.SHOP_ADMIN.toString())) player.sendMessage(ChatColor.GRAY + "/" + label + " out "); - if(iShop.config.getBoolean("enableShopSoldMessage")); + if(iShop.config.getBoolean("publicShopListCommand") || player.hasPermission(Permission.SHOP_ADMIN.toString()) || player.hasPermission(Permission.SHOP_SHOPS.toString())) + player.sendMessage(ChatColor.GRAY + "/" + label + " shops"); + if(iShop.config.getBoolean("enableShopSoldMessage")) player.sendMessage(ChatColor.GRAY + "/" + label + " sold "); - player.sendMessage(ChatColor.GRAY + "/" + label + " stock "); + if(iShop.config.getBoolean("enableStockCommand") || player.hasPermission(Permission.SHOP_STOCK.toString()) || player.hasPermission(Permission.SHOP_ADMIN.toString())) + player.sendMessage(ChatColor.GRAY + "/" + label + " stock "); player.sendMessage(ChatColor.GRAY + "/" + label + " view "); if(player.hasPermission(Permission.SHOP_ADMIN.toString())) { player.sendMessage(ChatColor.GRAY + "/" + label + " adminshop"); @@ -884,6 +897,169 @@ private void deleteLocation(Player player, String x, String y, String z, String Bukkit.getConsoleSender().sendMessage(Messages.SHOP_DELETED_LOC.toString().replaceAll("%p", shopOwner).replaceAll("%w", world).replaceAll("%x", x).replaceAll("%y", y).replaceAll("%z", z)); } + private void find(Player player, String itemName) { + if(!findCommandPublic && !player.hasPermission(Permission.SHOP_FIND.toString()) && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.NO_PERMISSION.toString()); + return; + } + if(findCooldownTime > 0 && !player.hasPermission(Permission.SHOP_ADMIN.toString()) && !player.hasPermission(Permission.SHOP_BYPASS_FIND_CD.toString())) { + if(findCooldown.containsKey(player.getUniqueId())) { + long secondsLeft = (((findCooldown.get(player.getUniqueId()))/1000)+findCooldownTime) - (System.currentTimeMillis()/1000); + if(secondsLeft > 0) { + player.sendMessage(Messages.SHOP_FIND_COOLDOWN.toString().replaceAll("%time", String.valueOf(secondsLeft))); + return; + } + } + findCooldown.put(player.getUniqueId(), System.currentTimeMillis()); + } + Material material = Material.matchMaterial(itemName); + if(material == null) { + try { + material = Material.matchMaterial(itemName.split("minecraft:")[1].toUpperCase()); + } catch(Exception ignored) { } + if(material == null) { + player.sendMessage(Messages.SHOP_FIND_ERROR.toString()); + return; + } + } + ItemStack item = new ItemStack(material); + Shop.findItem(player, item, itemName); + } + + private void moveShop(Player player, String shopId) { + if(!moveCommandPublic && !player.hasPermission(Permission.SHOP_MOVE.toString()) && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.NO_PERMISSION.toString()); + return; + } + int sId; + try { + sId = Integer.parseInt(shopId); + } catch (Exception e) { sId = -1; } + if(sId < 1) { + if(player != null) + player.sendMessage(Messages.SHOP_ID_INTEGER.toString()); + return; + } + Block block = player.getTargetBlockExact(5); + if(block == null) { + player.sendMessage(Messages.TARGET_MISMATCH.toString()); + return; + } + if(iShop.config.getBoolean("disableShopInWorld")) { + List disabledWorldsList = iShop.config.getStringList("disabledWorldList"); + for(String disabledWorlds:disabledWorldsList) + if(disabledWorlds != null && block.getWorld().getName().equals(disabledWorlds)) { + player.sendMessage(Messages.SHOP_WORLD_DISABLED.toString()); + return; + } + } + String shopBlock = iShop.config.getString("shopBlock"); + Material match = Material.matchMaterial(shopBlock); + if(match == null) { + try { + match = Material.matchMaterial(shopBlock.split("minecraft:")[1].toUpperCase()); + } catch(Exception ignored) { } + if(match == null) + match = Material.BARREL; + } + if(!EventShop.multipleShopBlocks) { + if(!block.getType().equals(match)) { + player.sendMessage(Messages.TARGET_MISMATCH.toString()); + return; + } + } else { + boolean shopMatch = false; + for(String shopBlocks:EventShop.multipleShopBlock) { + Material shopListBlocks = Material.matchMaterial(shopBlocks); + if(shopListBlocks != null && block.getType().equals(shopListBlocks)) { + shopMatch = true; + break; + } + } + if(!block.getType().equals(match) && !shopMatch) { + player.sendMessage(Messages.TARGET_MISMATCH.toString()); + return; + } + } + if(!player.isOp()) { + boolean isShopLoc; + if(iShop.wgLoader != null) + isShopLoc = iShop.wgLoader.checkRegion(block); + else + isShopLoc = true; + if(!isShopLoc) { + player.sendMessage(Messages.WG_REGION.toString()); + return; + } + boolean allowShopCreateInClaim = false; + if(iShop.gpLoader != null) { + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(block.getLocation(), false, false, null); + if(claim == null || claim.checkPermission(player, ClaimPermission.Access, null) == null || claim.checkPermission(player, ClaimPermission.Build, null) == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null || claim.checkPermission(player, ClaimPermission.Manage, null) == null || claim.checkPermission(player, ClaimPermission.Inventory, null) == null) + allowShopCreateInClaim = true; + } else + allowShopCreateInClaim = true; + if(!allowShopCreateInClaim) { + player.sendMessage(Messages.GP_CLAIM.toString()); + return; + } + boolean allowShopCreateWithinLands = false; + if(iShop.lands != null) { + LandWorld world = iShop.lands.getWorld(player.getWorld()); + if(world != null) + if(world.hasRoleFlag(player.getUniqueId(), block.getLocation(), Flags.BLOCK_PLACE)) + allowShopCreateWithinLands = true; + } + else + allowShopCreateWithinLands = true; + if(!allowShopCreateWithinLands) { + player.sendMessage(Messages.NO_SHOP_CREATE_PERMISSION.toString()); + return; + } + if(iShop.superiorSkyblock2Check) { + Island island = SuperiorSkyblockAPI.getIslandAt(block.getLocation()); + if(island != null) { + IslandPrivilege islandPrivilege = IslandPrivilege.getByName("Build"); + SuperiorPlayer superiorPlayer = SuperiorSkyblockAPI.getPlayer(player.getUniqueId()); + if(!island.hasPermission(superiorPlayer, islandPrivilege)) { + player.sendMessage(Messages.NO_SHOP_CREATE_PERMISSION.toString()); + return; + } + } + } + if(iShop.townyCheck) + if(!ShopPlotUtil.doesPlayerHaveAbilityToEditShopPlot(player, block.getLocation())) { + player.sendMessage(Messages.NO_SHOP_CREATE_PERMISSION.toString()); + return; + } + } + Optional shopLocation = Shop.getShopByLocation(block.getLocation()); + if(shopLocation.isPresent()) { + player.sendMessage(Messages.EXISTING_SHOP.toString()); + return; + } + Optional shop = Shop.getShopById(sId); + if(!shop.isPresent()) { + player.sendMessage(Messages.SHOP_NOT_FOUND.toString()); + return; + } + if(!shop.get().isOwner(player.getUniqueId()) && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.SHOP_NO_SELF.toString()); + return; + } + if(shop.get().isAdmin() && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.NO_PERMISSION.toString()); + return; + } + if(InvStock.inShopInv.containsValue(shop.get().getOwner())) { + player.sendMessage(Messages.SHOP_BUSY.toString()); + return; + } + final Location oldShopBlock = shop.get().getLocation(); + final Location newShopBlock = block.getLocation(); + final int shopID = shop.get().shopId(); + Shop.moveShop(oldShopBlock, newShopBlock, player, shopID); + } + private void removeAllShops(Player player, String playerName) { if(!player.hasPermission(Permission.SHOP_ADMIN.toString())) { player.sendMessage(Messages.NO_PERMISSION.toString()); @@ -1077,6 +1253,9 @@ private void reloadShop(Player player) { Shop.saveEmptyShops = iShop.config.getBoolean("saveEmptyShops"); Shop.stockMessages = iShop.config.getBoolean("enableShopSoldMessage"); Shop.exemptExpiringList = iShop.config.getStringList("exemptExpiringShops"); + findCommandPublic = iShop.config.getBoolean("publicFindCommand"); + findCooldownTime = iShop.config.getInt("findCommandCooldown"); + moveCommandPublic = iShop.config.getBoolean("publicMoveCommand"); }); } diff --git a/src/com/minedhype/ishop/Messages.java b/src/com/minedhype/ishop/Messages.java index ca75213..01f50af 100644 --- a/src/com/minedhype/ishop/Messages.java +++ b/src/com/minedhype/ishop/Messages.java @@ -27,6 +27,10 @@ public enum Messages { SHOP_DELETED("shopDeleted"), SHOP_DELETED_LOC("shopDeletedLoc"), SHOP_FAR("outOfStockRange"), + SHOP_FIND("listFind"), + SHOP_FIND_COOLDOWN("cooldownMessageFind"), + SHOP_FIND_ERROR("findError"), + SHOP_FIND_NONE("nolistFind"), SHOP_FOUND("foundShops"), SHOP_IDDELETED("shopIDDeleted"), SHOP_ID_INTEGER("shopIntegerError"), @@ -38,6 +42,7 @@ public enum Messages { SHOP_LOCATION_ERROR_NUM("shopLocationErrorNum"), SHOP_LOCATION_ERROR_WORLD("shopLocationErrorWorld"), SHOP_MAX("shopLimit"), + SHOP_MOVED("shopMoved"), SHOP_NOT_FOUND("noShopFound"), SHOP_NOT_OUT("notOutOfStock"), SHOP_NO_ADMINSHOPS_FOUND("noAdminShopsFound"), diff --git a/src/com/minedhype/ishop/Permission.java b/src/com/minedhype/ishop/Permission.java index bfbbe03..0bc9d78 100644 --- a/src/com/minedhype/ishop/Permission.java +++ b/src/com/minedhype/ishop/Permission.java @@ -2,10 +2,13 @@ public enum Permission { SHOP_ADMIN("ishop.admin"), + SHOP_BYPASS_FIND_CD("ishop.bypassfindcooldown"), SHOP_CREATE("ishop.create"), + SHOP_FIND("ishop.find"), SHOP_LIMIT_BYPASS("ishop.create.limit.bypass"), SHOP_LIMIT_PREFIX("ishop.create.limit."), SHOP_LIST("ishop.list"), + SHOP_MOVE("ishop.move"), SHOP_REMOTEMANAGE("ishop.remotemanage"), SHOP_REMOTESHOPPING("ishop.remoteshopping"), SHOP_SHOPS("ishop.shops"), diff --git a/src/com/minedhype/ishop/Shop.java b/src/com/minedhype/ishop/Shop.java index 98b4744..820358a 100644 --- a/src/com/minedhype/ishop/Shop.java +++ b/src/com/minedhype/ishop/Shop.java @@ -123,6 +123,24 @@ public static void getPlayersShopList() { shops.parallelStream().filter(s -> !s.admin).forEach(s -> shopList.putIfAbsent(s.idTienda, s.owner)); } + public static void findItem(Player player, ItemStack item, String itemName) { + player.sendMessage(Messages.SHOP_FIND.toString().replaceAll("%item", itemName.toLowerCase())); + AtomicBoolean foundItem = new AtomicBoolean(false); + shops.parallelStream().forEach(s -> { + for(int i=0; i<5; i++) { + Optional row = s.getRow(i); + if(row.isPresent()) + if(row.get().getItemOut().isSimilar(item) || row.get().getItemOut2().isSimilar(item)) { + foundItem.set(true); + player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)) + ChatColor.GREEN + s.location.getBlockX() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockY() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockZ() + ChatColor.GOLD + " in " + ChatColor.GREEN + s.location.getWorld().getName()); + break; + } + } + }); + if(!foundItem.get()) + player.sendMessage(Messages.SHOP_FIND_NONE.toString()); + } + public static void removeAllPlayersShops(Player player, UUID sOwner, String pOwner) { int deletedCount = 0; List deleteShops = new ArrayList<>(); @@ -883,6 +901,34 @@ public void deleteShop(boolean removalOfArray) { }); } + public static void moveShop(Location oldLoc, Location newLoc, Player player, int shopID) { + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + PreparedStatement stmt = null; + try { + stmt = iShop.getConnection().prepareStatement("UPDATE zooMercaTiendas SET location = ? WHERE location = ?;"); + String oldLocationRaw = oldLoc.getBlockX()+";"+oldLoc.getBlockY()+";"+oldLoc.getBlockZ()+";"+oldLoc.getWorld().getName(); + String newLocationRaw = newLoc.getBlockX()+";"+newLoc.getBlockY()+";"+newLoc.getBlockZ()+";"+newLoc.getWorld().getName(); + stmt.setString(1, newLocationRaw); + stmt.setString(2, oldLocationRaw); + stmt.executeUpdate(); + Optional newShopLoc = Shop.getShopById(shopID); + newShopLoc.get().location.setX(newLoc.getX()); + newShopLoc.get().location.setY(newLoc.getY()); + newShopLoc.get().location.setZ(newLoc.getZ()); + newShopLoc.get().location.setWorld(newLoc.getWorld()); + } catch (Exception e) { e.printStackTrace(); } + finally { + try { + if(stmt != null) + stmt.close(); + } catch (Exception e) { e.printStackTrace(); } + } + player.sendMessage(Messages.SHOP_MOVED.toString().replaceAll("%id", String.valueOf(shopID))); + }); + if(deletePlayerShop) + Bukkit.getScheduler().runTask(iShop.getPlugin(), () -> oldLoc.getBlock().setType(Material.AIR)); + } + public void sendShopMessages(String i1, String i2, String o1, String o2, int inA1, int inA2, int outA1, int outA2, UUID shopOwner, Player player, boolean isAdminShop, boolean rowBroadcast) { OfflinePlayer ownerPlayer = Bukkit.getOfflinePlayer(shopOwner); if(!isAdminShop) { diff --git a/src/com/minedhype/ishop/TabComplete.java b/src/com/minedhype/ishop/TabComplete.java new file mode 100644 index 0000000..6d06e6e --- /dev/null +++ b/src/com/minedhype/ishop/TabComplete.java @@ -0,0 +1,26 @@ +package com.minedhype.ishop; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.bukkit.Material; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.util.StringUtil; + +public class TabComplete implements TabCompleter { + + private static final List items = Arrays.stream(Material.values()).filter(Material::isItem).map(material -> material.getKey().getKey()).toList(); + + @Override + public List onTabComplete(CommandSender sender, Command cmd, String label, String[] args) { + if(args[0].equalsIgnoreCase("find") || args[0].equalsIgnoreCase("count")) { + if(args.length == 2) + return StringUtil.copyPartialMatches(args[1].toLowerCase(), items, new ArrayList<>()); + return Collections.emptyList(); + } + return null; + } +} diff --git a/src/com/minedhype/ishop/Utils.java b/src/com/minedhype/ishop/Utils.java index 3e5cf3c..db30f7f 100644 --- a/src/com/minedhype/ishop/Utils.java +++ b/src/com/minedhype/ishop/Utils.java @@ -13,8 +13,7 @@ public static boolean hasStock(Player player, ItemStack item) { if(item.hasItemMeta()) { ItemStack itemClone = item.clone(); return (player.getInventory().containsAtLeast(item, item.getAmount()) || player.getInventory().containsAtLeast(itemClone, itemClone.getAmount())); - } - else + } else return player.getInventory().containsAtLeast(item, item.getAmount()); } @@ -38,8 +37,7 @@ public static boolean hasStock(Shop shop, ItemStack item) { ItemStack itemClone = item.clone(); if(stockStore.get().getInventory().containsAtLeast(item, amount) || stockStore.get().getInventory().containsAtLeast(itemClone, amount)) return true; - } - else { + } else { if(stockStore.get().getInventory().containsAtLeast(item, amount)) return true; } @@ -49,8 +47,7 @@ public static boolean hasStock(Shop shop, ItemStack item) { ItemStack itemClone = item.clone(); if(stockStore.get().getInventory().getItem(j) != null && (stockStore.get().getInventory().getItem(j).isSimilar(item) || stockStore.get().getInventory().getItem(j).isSimilar(itemClone))) itemAmountCount += stockStore.get().getInventory().getItem(j).getAmount(); - } - else { + } else { if(stockStore.get().getInventory().getItem(j) != null && stockStore.get().getInventory().getItem(j).isSimilar(item)) itemAmountCount += stockStore.get().getInventory().getItem(j).getAmount(); } @@ -111,8 +108,7 @@ public static boolean hasDoubleItemStock(Shop shop, ItemStack item, ItemStack it } } else if(item2Amount < item2Total && stockStore.get().getInventory().getItem(j).isSimilar(item2)) item2Amount += stockStore.get().getInventory().getItem(j).getAmount(); - } - else { + } else { ItemStack itemClone = item.clone(); ItemStack item2Clone = item2.clone(); if(item1Amount < item1Total && (stockStore.get().getInventory().getItem(j).isSimilar(item) || stockStore.get().getInventory().getItem(j).isSimilar(itemClone))) { diff --git a/src/com/minedhype/ishop/iShop.java b/src/com/minedhype/ishop/iShop.java index 36ed5fb..9175ad1 100644 --- a/src/com/minedhype/ishop/iShop.java +++ b/src/com/minedhype/ishop/iShop.java @@ -77,6 +77,7 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new EventShop(), this); getServer().getPluginManager().registerEvents(new GUIEvent(), this); getCommand("ishop").setExecutor(new CommandShop()); + getCommand("ishop").setTabCompleter(new TabComplete()); int delayTime; int saveDatabaseTime; try { @@ -335,9 +336,18 @@ public void createConfig() { case "3.7": config.set("skipPermsCheckForAdminCreateShop", true); config.set("noPermissionToCreateShop", "&cYou do not have permission to create a shop at this location!"); - config.set("configVersion", "3.8"); - config.save(configFile); case "3.8": + config.set("publicFindCommand", true); + config.set("findCommandCooldown", 5); + config.set("publicMoveCommand", true); + config.set("cooldownMessageFind","&6You must wait &c%time second(s) &6before using find command again!"); + config.set("findError", "&cGiven item to search shops for does not exist!"); + config.set("listFind", "&6Listing all found shop(s) trading &a%item&6:"); + config.set("nolistFind", "&cNo shop(s) have been found!"); + config.set("shopMoved", "&6Shop &a#%id &6has been moved to new targeted location!"); + config.set("configVersion", "3.9"); + config.save(configFile); + case "3.9": break; } } catch(IOException | InvalidConfigurationException e) { e.printStackTrace(); } diff --git a/src/resources/config.yml b/src/resources/config.yml index eeee80d..3128756 100644 --- a/src/resources/config.yml +++ b/src/resources/config.yml @@ -105,7 +105,7 @@ maxInactiveDays: 0 exemptExpiringShops: - 00000000-0000-0000-0000-000000000000 -# Delete block that the shop is located at when deleting a shop +# Remove block that the shop is located at when deleting or moving a shop deleteBlock: false # Show particle effects on active shop blocks @@ -178,6 +178,15 @@ saveDatabase: 15 # When a player with iShop.admin permission uses command createshop and is not a server operator, skip checking for permission within GriefPrevention, Lands, SuperiorSkyblock2, Towny, and WorldGuard skipPermsCheckForAdminCreateShop: true +# Allow everyone to use "/shop find " command to search all player shops that are selling given item +publicFindCommand: true + +# Time in seconds players must wait to use find command again. Set to 0 to disable +findCommandCooldown: 5 + +# Allow everyone to use '/shop move' command to move their shops to a new location +publicMoveCommand: true + # Customizable Messages adminShop: "Admin Shop #%id" adminShopDisabled: "&cAdmin shops have been disabled!" @@ -263,6 +272,10 @@ shopDeletedLoc: "&7Shop has been &cDELETED&7 for&a %p &7at &a%x &7/&a %y &7/&a % shopLocationErrorNum: "&cLocation coordinates must be a positive or negative number!" shopLocationErrorWorld: "&cLocation coordinates must be in a valid world!" noPermissionToCreateShop: "&cYou do not have permission to create a shop at this location!" - +cooldownMessageFind: "&6You must wait &c%time second(s) &6before using find command again!" +findError: "&cGiven item to search shops for does not exist!" +listFind: "&6Listing all found shop(s) trading &a%item&6:" +nolistFind: "&cNo shop(s) have been found!" +shopMoved: "&6Shop &a#%id &6has been moved to new targeted location!" # Do not edit this! -configVersion: 3.8 \ No newline at end of file +configVersion: 3.9 \ No newline at end of file From c511a80efcac20fe40435b3208108972c1af72ce Mon Sep 17 00:00:00 2001 From: Beez0r Date: Sun, 4 Jun 2023 15:00:43 -0700 Subject: [PATCH 11/15] iShop 2.24 Update --- src/com/minedhype/ishop/CommandShop.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index 040471a..3315341 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -365,14 +365,12 @@ private void createStore(Player player) { return; } } - Shop newShop = Shop.createShop(block.getLocation(), player.getUniqueId()); + Shop.createShop(block.getLocation(), player.getUniqueId()); player.sendMessage(Messages.SHOP_CREATED.toString()); Bukkit.getServer().getScheduler().runTaskLaterAsynchronously(iShop.getPlugin(), () -> { Optional shops = Shop.getShopByLocation(block.getLocation()); Shop.shopList.put(shops.get().shopId(), player.getUniqueId()); }, 10); - InvAdminShop inv = new InvAdminShop(newShop, player); - inv.open(player, newShop.getOwner()); } private void createShop(Player player, String playerShop) { From a51b6b2ce9ca4bf40ffe024617e020fdc196c38c Mon Sep 17 00:00:00 2001 From: Beez0r Date: Sun, 24 Dec 2023 15:01:00 -0800 Subject: [PATCH 12/15] iShop 2.25 Update --- src/com/minedhype/ishop/CommandShop.java | 34 ++++- src/com/minedhype/ishop/EventShop.java | 11 ++ src/com/minedhype/ishop/Shop.java | 163 +++++++++++++++++++++-- src/com/minedhype/ishop/TabComplete.java | 13 +- src/com/minedhype/ishop/Utils.java | 36 ++++- src/com/minedhype/ishop/iShop.java | 10 +- src/resources/config.yml | 4 +- 7 files changed, 253 insertions(+), 18 deletions(-) diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index 3315341..5df7ce2 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -52,6 +52,8 @@ public class CommandShop implements CommandExecutor { @Override public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { + if(EventShop.shuttingDown) + return true; if(sender instanceof ConsoleCommandSender && args.length > 0) { if(args[0].equalsIgnoreCase("reload")) { reloadShop(null); @@ -107,6 +109,8 @@ else if(args[0].equalsIgnoreCase("deletelocation") && args.length > 4) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> deleteLocation(player, args[1], args[2], args[3], args[4])); else if(args[0].equalsIgnoreCase("find") && args.length >= 2) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> find(player, args[1])); + else if(args[0].equalsIgnoreCase("findbook") && args.length >= 2) + Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> findBook(player, args[1])); else if(args[0].equalsIgnoreCase("list") && args.length == 1) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> listShops(player, null)); else if(args[0].equalsIgnoreCase("list") && args.length >= 2) @@ -153,8 +157,10 @@ private void listSubCmd(Player player, String label) { player.sendMessage(ChatColor.GRAY + "/" + label + " create"); player.sendMessage(ChatColor.GRAY + "/" + label + " delete"); player.sendMessage(ChatColor.GRAY + "/" + label + " deleteid "); - if(findCommandPublic || player.hasPermission(Permission.SHOP_ADMIN.toString()) || player.hasPermission(Permission.SHOP_FIND.toString())) + if(findCommandPublic || player.hasPermission(Permission.SHOP_ADMIN.toString()) || player.hasPermission(Permission.SHOP_FIND.toString())) { player.sendMessage(ChatColor.GRAY + "/" + label + " find "); + player.sendMessage(ChatColor.GRAY + "/" + label + " findbook "); + } player.sendMessage(ChatColor.GRAY + "/" + label + " list"); if(iShop.config.getBoolean("publicListCommand") || player.hasPermission(Permission.SHOP_ADMIN.toString()) || player.hasPermission(Permission.SHOP_LIST.toString())) player.sendMessage(ChatColor.GRAY + "/" + label + " list "); @@ -920,10 +926,36 @@ private void find(Player player, String itemName) { return; } } + if(material.isAir()) { + player.sendMessage(Messages.SHOP_FIND_ERROR.toString()); + return; + } ItemStack item = new ItemStack(material); Shop.findItem(player, item, itemName); } + private void findBook(Player player, String bookName) { + if(!findCommandPublic && !player.hasPermission(Permission.SHOP_FIND.toString()) && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.NO_PERMISSION.toString()); + return; + } + if(findCooldownTime > 0 && !player.hasPermission(Permission.SHOP_ADMIN.toString()) && !player.hasPermission(Permission.SHOP_BYPASS_FIND_CD.toString())) { + if(findCooldown.containsKey(player.getUniqueId())) { + long secondsLeft = (((findCooldown.get(player.getUniqueId()))/1000)+findCooldownTime) - (System.currentTimeMillis()/1000); + if(secondsLeft > 0) { + player.sendMessage(Messages.SHOP_FIND_COOLDOWN.toString().replaceAll("%time", String.valueOf(secondsLeft))); + return; + } + } + findCooldown.put(player.getUniqueId(), System.currentTimeMillis()); + } + if(!TabComplete.enchantments.contains(bookName)) { + player.sendMessage(Messages.SHOP_FIND_ERROR.toString()); + return; + } + Shop.findBook(player, bookName); + } + private void moveShop(Player player, String shopId) { if(!moveCommandPublic && !player.hasPermission(Permission.SHOP_MOVE.toString()) && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { player.sendMessage(Messages.NO_PERMISSION.toString()); diff --git a/src/com/minedhype/ishop/EventShop.java b/src/com/minedhype/ishop/EventShop.java index e206332..6d41318 100644 --- a/src/com/minedhype/ishop/EventShop.java +++ b/src/com/minedhype/ishop/EventShop.java @@ -41,6 +41,7 @@ public class EventShop implements Listener { public static boolean noShopNoStock = iShop.config.getBoolean("mustOwnShopForStock"); public static boolean placeFrameSign = iShop.config.getBoolean("placeItemFrameSigns"); public static boolean protectShopFromExplosion = iShop.config.getBoolean("protectShopBlocksFromExplosions"); + public static boolean shuttingDown = false; public static int soldMessageDelayTime = iShop.config.getInt("soldNotificationsDelayTime"); public static int stockRangeLimit = iShop.config.getInt("stockRangeLimitFromShop"); public static String shopBlock = iShop.config.getString("shopBlock"); @@ -88,6 +89,8 @@ public void onPlayerInteract(PlayerInteractEvent event) { return; } event.setCancelled(true); + if(shuttingDown) + return; if(InvStock.inShopInv.containsValue(shop.get().getOwner())) { if(event.getHand().equals(EquipmentSlot.HAND)) event.getPlayer().sendMessage(Messages.SHOP_BUSY.toString()); @@ -122,6 +125,8 @@ else if(event.getHand().equals(EquipmentSlot.OFF_HAND)) return; } event.setCancelled(true); + if(shuttingDown) + return; if(InvStock.inShopInv.containsValue(shop.get().getOwner())) { if(event.getHand().equals(EquipmentSlot.HAND)) event.getPlayer().sendMessage(Messages.SHOP_BUSY.toString()); @@ -159,6 +164,8 @@ else if(event.getHand().equals(EquipmentSlot.OFF_HAND)) return; } event.setCancelled(true); + if(shuttingDown) + return; if(InvStock.inShopInv.containsValue(shop.get().getOwner())) { if(event.getHand().equals(EquipmentSlot.HAND)) event.getPlayer().sendMessage(Messages.SHOP_BUSY.toString()); @@ -186,6 +193,8 @@ else if(event.getHand().equals(EquipmentSlot.OFF_HAND)) if(!isShopLoc || event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getPlayer().isSneaking()) return; event.setCancelled(true); + if(shuttingDown) + return; if(event.getAction() == Action.LEFT_CLICK_BLOCK) { if(Shop.getNumShops(event.getPlayer().getUniqueId()) < 1 && noShopNoStock) { event.getPlayer().sendMessage(Messages.NO_SHOP_STOCK.toString()); @@ -233,6 +242,8 @@ else if(event.getHand().equals(EquipmentSlot.OFF_HAND)) if(!isShopLoc || event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getPlayer().isSneaking()) return; event.setCancelled(true); + if(shuttingDown) + return; if(event.getAction() == Action.LEFT_CLICK_BLOCK) { if(Shop.getNumShops(event.getPlayer().getUniqueId()) < 1 && noShopNoStock) { event.getPlayer().sendMessage(Messages.NO_SHOP_STOCK.toString()); diff --git a/src/com/minedhype/ishop/Shop.java b/src/com/minedhype/ishop/Shop.java index 820358a..76273fd 100644 --- a/src/com/minedhype/ishop/Shop.java +++ b/src/com/minedhype/ishop/Shop.java @@ -20,11 +20,13 @@ import org.bukkit.OfflinePlayer; import org.bukkit.Particle; import org.bukkit.World; +import org.bukkit.block.ShulkerBox; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BlockStateMeta; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.plugin.Plugin; import com.google.gson.JsonArray; @@ -127,15 +129,156 @@ public static void findItem(Player player, ItemStack item, String itemName) { player.sendMessage(Messages.SHOP_FIND.toString().replaceAll("%item", itemName.toLowerCase())); AtomicBoolean foundItem = new AtomicBoolean(false); shops.parallelStream().forEach(s -> { - for(int i=0; i<5; i++) { - Optional row = s.getRow(i); - if(row.isPresent()) - if(row.get().getItemOut().isSimilar(item) || row.get().getItemOut2().isSimilar(item)) { + AtomicBoolean foundItemInShop = new AtomicBoolean(false); + for(int i=0; i<5; i++) { + Optional row = s.getRow(i); + if(row.isPresent() && !foundItemInShop.get()) { + boolean itemMatch = row.get().getItemOut().isSimilar(item); + boolean itemMatch2 = row.get().getItemOut2().isSimilar(item); + if(((itemMatch && itemMatch2) && Utils.hasDoubleItemStock(s, item, item)) || ((itemMatch && !itemMatch2) && Utils.hasStock(s, row.get().getItemOut2())) || ((!itemMatch && itemMatch2) && Utils.hasStock(s, row.get().getItemOut()))) { + foundItem.set(true); + foundItemInShop.set(true); + player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName())); + break; + } + if(row.get().getItemOut().getType().toString().contains("SHULKER_BOX") && row.get().getItemOut().getItemMeta() instanceof BlockStateMeta && Utils.hasStock(s, row.get().getItemOut())) { + BlockStateMeta itemMeta = (BlockStateMeta) row.get().getItemOut().getItemMeta(); + ShulkerBox shulkerBox = (ShulkerBox) itemMeta.getBlockState(); + if(shulkerBox.getInventory().contains(item.getType())) + for(ItemStack itemSearch:shulkerBox.getInventory().getContents()) { + if(itemSearch.isSimilar(item)) { + foundItem.set(true); + foundItemInShop.set(true); + player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName())); + break; + } + } + } + if(row.get().getItemOut2().getType().toString().contains("SHULKER_BOX") && row.get().getItemOut2().getItemMeta() instanceof BlockStateMeta && Utils.hasStock(s, row.get().getItemOut2())) { + BlockStateMeta itemMeta = (BlockStateMeta) row.get().getItemOut2().getItemMeta(); + ShulkerBox shulkerBox = (ShulkerBox) itemMeta.getBlockState(); + if(shulkerBox.getInventory().contains(item.getType())) + for(ItemStack itemSearch:shulkerBox.getInventory().getContents()) { + if(itemSearch.isSimilar(item)) { + foundItem.set(true); + foundItemInShop.set(true); + player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName())); + break; + } + } + } + } + } + }); + if(!foundItem.get()) + player.sendMessage(Messages.SHOP_FIND_NONE.toString()); + } + public static void findBook(Player player, String bookName) { + player.sendMessage(Messages.SHOP_FIND.toString().replaceAll("%item", bookName.toLowerCase())); + AtomicBoolean foundItem = new AtomicBoolean(false); + shops.parallelStream().forEach(s -> { + AtomicBoolean foundBookInShop = new AtomicBoolean(false); + for(int i=0; i<5; i++) { + Optional row = s.getRow(i); + if(!row.isPresent()) + continue; + if(!foundBookInShop.get() && (row.get().getItemOut().getType().equals(Material.ENCHANTED_BOOK) || row.get().getItemOut2().getType().equals(Material.ENCHANTED_BOOK))) { + if(row.get().getItemOut().equals(row.get().getItemOut2()) && row.get().getItemOut().getItemMeta() instanceof EnchantmentStorageMeta) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) row.get().getItemOut().getItemMeta(); + if(meta.getStoredEnchants().toString().contains(bookName)) { + if(!Utils.hasEnchantment(s, bookName, true)) + break; foundItem.set(true); - player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)) + ChatColor.GREEN + s.location.getBlockX() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockY() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockZ() + ChatColor.GOLD + " in " + ChatColor.GREEN + s.location.getWorld().getName()); + foundBookInShop.set(true); + player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName())); break; } + } + else { + if(row.get().getItemOut().getItemMeta() instanceof EnchantmentStorageMeta) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) row.get().getItemOut().getItemMeta(); + if(meta.getStoredEnchants().toString().contains(bookName)) { + if(!Utils.hasEnchantment(s, bookName, false) || !Utils.hasStock(s, row.get().getItemOut2())) + break; + foundItem.set(true); + foundBookInShop.set(true); + player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName())); + break; + } + } + if(row.get().getItemOut2().getItemMeta() instanceof EnchantmentStorageMeta) { + EnchantmentStorageMeta meta2 = (EnchantmentStorageMeta) row.get().getItemOut2().getItemMeta(); + if(meta2.getStoredEnchants().toString().contains(bookName)) { + if(!Utils.hasEnchantment(s, bookName, false) || !Utils.hasStock(s, row.get().getItemOut())) + break; + foundItem.set(true); + foundBookInShop.set(true); + player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName())); + break; + } + } + } + } + if(!foundBookInShop.get() && (row.get().getItemOut().getType().toString().contains("SHULKER_BOX") && row.get().getItemOut2().getType().toString().contains("SHULKER_BOX")) && (row.get().getItemOut().getItemMeta() instanceof BlockStateMeta && row.get().getItemOut2().getItemMeta() instanceof BlockStateMeta) && row.get().getItemOut().equals(row.get().getItemOut2())) { + BlockStateMeta itemMeta = (BlockStateMeta) row.get().getItemOut().getItemMeta(); + ShulkerBox shulkerBox = (ShulkerBox) itemMeta.getBlockState(); + if(shulkerBox.getInventory().contains(Material.ENCHANTED_BOOK)) { + for(ItemStack item:shulkerBox.getInventory().getContents()) { + if(item != null && item.getType().equals(Material.ENCHANTED_BOOK) && item.hasItemMeta() && item.getItemMeta() instanceof EnchantmentStorageMeta) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta(); + if(meta.getStoredEnchants().toString().contains(bookName)) { + if(!Utils.hasDoubleItemStock(s, row.get().getItemOut(), row.get().getItemOut2())) + break; + foundItem.set(true); + foundBookInShop.set(true); + player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName())); + break; + } + } + } + } } + else { + if(!foundBookInShop.get() && row.get().getItemOut().getType().toString().contains("SHULKER_BOX") && row.get().getItemOut().getItemMeta() instanceof BlockStateMeta) { + BlockStateMeta itemMeta = (BlockStateMeta) row.get().getItemOut().getItemMeta(); + ShulkerBox shulkerBox = (ShulkerBox) itemMeta.getBlockState(); + if(shulkerBox.getInventory().contains(Material.ENCHANTED_BOOK)) { + for(ItemStack item:shulkerBox.getInventory().getContents()) { + if(item != null && item.getType().equals(Material.ENCHANTED_BOOK) && item.hasItemMeta() && item.getItemMeta() instanceof EnchantmentStorageMeta) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta(); + if(meta.getStoredEnchants().toString().contains(bookName)) { + if(!Utils.hasStock(s, row.get().getItemOut())) + break; + foundItem.set(true); + foundBookInShop.set(true); + player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName())); + break; + } + } + } + } + } + if(!foundBookInShop.get() && row.get().getItemOut2().getType().toString().contains("SHULKER_BOX") && row.get().getItemOut2().getItemMeta() instanceof BlockStateMeta) { + BlockStateMeta itemMeta = (BlockStateMeta) row.get().getItemOut2().getItemMeta(); + ShulkerBox shulkerBox = (ShulkerBox) itemMeta.getBlockState(); + if(shulkerBox.getInventory().contains(Material.ENCHANTED_BOOK)) { + for(ItemStack item:shulkerBox.getInventory().getContents()) { + if(item != null && item.getType().equals(Material.ENCHANTED_BOOK) && item.hasItemMeta() && item.getItemMeta() instanceof EnchantmentStorageMeta) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta(); + if(meta.getStoredEnchants().toString().contains(bookName)) { + if(!Utils.hasStock(s, row.get().getItemOut2())) + break; + foundItem.set(true); + foundBookInShop.set(true); + player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName())); + break; + } + } + } + } + } + } + } }); if(!foundItem.get()) player.sendMessage(Messages.SHOP_FIND_NONE.toString()); @@ -172,14 +315,14 @@ public static void getShopList(Player player, UUID sOwner, String pOwner) { player.sendMessage(Messages.SHOP_FOUND.toString().replaceAll("%p", pOwner).replaceAll("%shops", String.valueOf(getNumShops(sOwner)))); shops.parallelStream().filter(s -> !s.admin && s.isOwner(sOwner)).forEach(s -> { if(s.isOwner(player.getUniqueId()) && InvAdminShop.remoteManage) { - String manageMessage = Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)) + ChatColor.GREEN + s.location.getBlockX() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockY() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockZ() + ChatColor.GOLD + " in " + ChatColor.GREEN + s.location.getWorld().getName(); + String manageMessage = Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName()); TextComponent manageMsg = new TextComponent(manageMessage); TextComponent manageText = new TextComponent(ChatColor.DARK_GRAY + " [" + Messages.SHOP_CLICK_MANAGE + ChatColor.DARK_GRAY + "]"); manageText.setClickEvent(new ClickEvent(Action.RUN_COMMAND, "/shop manage " + s.idTienda)); manageMsg.addExtra(manageText); player.spigot().sendMessage(manageMsg); } else if(player.hasPermission(Permission.SHOP_ADMIN.toString())) { - String manageMessage = Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)) + ChatColor.GREEN + s.location.getBlockX() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockY() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockZ() + ChatColor.GOLD + " in " + ChatColor.GREEN + s.location.getWorld().getName(); + String manageMessage = Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName()); TextComponent manageMsg = new TextComponent(manageMessage); TextComponent manageText = new TextComponent(ChatColor.DARK_GRAY + " [" + Messages.SHOP_CLICK_MANAGE + ChatColor.DARK_GRAY + "]"); manageText.setClickEvent(new ClickEvent(Action.RUN_COMMAND, "/shop manage " + s.idTienda)); @@ -194,14 +337,14 @@ public static void getShopList(Player player, UUID sOwner, String pOwner) { } else player.spigot().sendMessage(manageMsg); } else if(iShop.config.getBoolean("remoteShopping") && !s.isOwner(player.getUniqueId())) { - String shopMessage = Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)) + ChatColor.GREEN + s.location.getBlockX() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockY() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockZ() + ChatColor.GOLD + " in " + ChatColor.GREEN + s.location.getWorld().getName(); + String shopMessage = Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName()); TextComponent shopMsg = new TextComponent(shopMessage); TextComponent shopText = new TextComponent(ChatColor.DARK_GRAY + " [" + Messages.SHOP_CLICK_SHOP + ChatColor.DARK_GRAY + "]"); shopText.setClickEvent(new ClickEvent(Action.RUN_COMMAND, "/shop view " + s.idTienda)); shopMsg.addExtra(shopText); player.spigot().sendMessage(shopMsg); } else - player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)) + ChatColor.GREEN + s.location.getBlockX() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockY() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockZ() + ChatColor.GOLD + " in " + ChatColor.GREEN + s.location.getWorld().getName()); + player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName())); }); } @@ -209,7 +352,7 @@ public static void getAdminShopList(Player player) { player.sendMessage(Messages.SHOP_LIST_ADMINSHOPS.toString()); AtomicInteger shopCount = new AtomicInteger(0); shops.parallelStream().filter(s -> s.admin).forEach(s -> { - String manageMessage = Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)) + ChatColor.GREEN + s.location.getBlockX() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockY() + ChatColor.GOLD + " / " + ChatColor.GREEN + s.location.getBlockZ() + ChatColor.GOLD + " in " + ChatColor.GREEN + s.location.getWorld().getName(); + String manageMessage = Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName()); TextComponent manageMsg = new TextComponent(manageMessage); TextComponent manageText = new TextComponent(ChatColor.DARK_GRAY + " [" + Messages.SHOP_CLICK_MANAGE + ChatColor.DARK_GRAY + "]"); manageText.setClickEvent(new ClickEvent(Action.RUN_COMMAND, "/shop manage " + s.idTienda)); diff --git a/src/com/minedhype/ishop/TabComplete.java b/src/com/minedhype/ishop/TabComplete.java index 6d06e6e..dfa9a80 100644 --- a/src/com/minedhype/ishop/TabComplete.java +++ b/src/com/minedhype/ishop/TabComplete.java @@ -13,6 +13,8 @@ public class TabComplete implements TabCompleter { private static final List items = Arrays.stream(Material.values()).filter(Material::isItem).map(material -> material.getKey().getKey()).toList(); + private static final List findCommands = Arrays.asList("adminshop","count","create","createshop","createlocation","delete","deleteid","deletelocation","find","findbook","list","listadmin","manage","managestock","managestock","move","out","reload","removeallshops","shops","sold","stock","view"); + public static final List enchantments = Arrays.asList("aqua_affinity","bane_of_arthropods","blast_protection","channeling","curse_of_binding","curse_of_vanishing","depth_strider","efficiency","feather_falling","fire_aspect","fire_protection","flame","fortune","frost_walker","impaling","impaling","infinity","knockback","looting","loyalty","luck_of_the_sea","lure","mending","multishot","piercing","power","projectile_protection","protection","punch","quick_charge","respiration","riptide","sharpness","silk_touch","smite","soul_speed","sweeping_edge","swift_sneak","thorns","unbreaking"); @Override public List onTabComplete(CommandSender sender, Command cmd, String label, String[] args) { @@ -21,6 +23,13 @@ public List onTabComplete(CommandSender sender, Command cmd, String labe return StringUtil.copyPartialMatches(args[1].toLowerCase(), items, new ArrayList<>()); return Collections.emptyList(); } - return null; + else if(args[0].equalsIgnoreCase("findbook")) { + if(args.length == 2) + return StringUtil.copyPartialMatches(args[1].toUpperCase(), enchantments, new ArrayList<>()); + return Collections.emptyList(); + } + else { + return StringUtil.copyPartialMatches(args[0].toLowerCase(), findCommands, new ArrayList<>()); + } } -} +} \ No newline at end of file diff --git a/src/com/minedhype/ishop/Utils.java b/src/com/minedhype/ishop/Utils.java index db30f7f..221263d 100644 --- a/src/com/minedhype/ishop/Utils.java +++ b/src/com/minedhype/ishop/Utils.java @@ -5,6 +5,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import com.minedhype.ishop.inventories.InvAdminShop; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; public class Utils { public static boolean hasStock(Player player, ItemStack item) { @@ -97,7 +98,7 @@ public static boolean hasDoubleItemStock(Shop shop, ItemStack item, ItemStack it if(!stockStore.isPresent()) continue; if(stockStore.get().getInventory().contains(item.getType()) || stockStore.get().getInventory().contains(item2.getType())) { - for(int j=0; j stockStore = StockShop.getStockShopByOwner(shop.getOwner(), i); + if(!stockStore.isPresent()) + continue; + if(stockStore.get().getInventory().contains(Material.ENCHANTED_BOOK)) { + for(int j=0; j1) + return true; + } + else + return true; + } + } + } + } + } + return false; + } } diff --git a/src/com/minedhype/ishop/iShop.java b/src/com/minedhype/ishop/iShop.java index 9175ad1..ef1500a 100644 --- a/src/com/minedhype/ishop/iShop.java +++ b/src/com/minedhype/ishop/iShop.java @@ -12,6 +12,7 @@ import java.util.Optional; import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; @@ -120,6 +121,9 @@ public void onEnable() { @Override public void onDisable() { + EventShop.shuttingDown = true; + for(Player player:Bukkit.getServer().getOnlinePlayers()) + player.closeInventory(); if(Bukkit.getScheduler().isCurrentlyRunning(tickTask.getTaskId())) { while(Bukkit.getScheduler().isCurrentlyRunning(tickTask.getTaskId())) ; @@ -345,9 +349,11 @@ public void createConfig() { config.set("listFind", "&6Listing all found shop(s) trading &a%item&6:"); config.set("nolistFind", "&cNo shop(s) have been found!"); config.set("shopMoved", "&6Shop &a#%id &6has been moved to new targeted location!"); - config.set("configVersion", "3.9"); - config.save(configFile); case "3.9": + config.set("location", "&6Shop&a %id &6location XYZ:&a %x &6/&a %y &6/&a %z &6in&a %world"); + config.set("configVersion", "3.10"); + config.save(configFile); + case "3.10": break; } } catch(IOException | InvalidConfigurationException e) { e.printStackTrace(); } diff --git a/src/resources/config.yml b/src/resources/config.yml index 3128756..67a7a6b 100644 --- a/src/resources/config.yml +++ b/src/resources/config.yml @@ -202,7 +202,7 @@ deleteTitle: "DELETE" disabledShopBlock: "&cCannot create shop location when shop blocks are disabled!" existingShop: "&cCannot create shop where existing shop is already located!" foundShops: "&6Found&a %shops &6shop(s) for player:&a %p" -location: "&6Shop&a %id &6location XYZ: " +location: "&6Shop&a %id &6location XYZ:&a %x &6/&a %y &6/&a %z &6in&a %world" noItems: "&cYou do not have enough item(s) to buy from this shop!" noMoney: "&cYou do not have enough money to create a shop! You need at least &o$" noPermissions: "&cYou do not have permission for this command!" @@ -278,4 +278,4 @@ listFind: "&6Listing all found shop(s) trading &a%item&6:" nolistFind: "&cNo shop(s) have been found!" shopMoved: "&6Shop &a#%id &6has been moved to new targeted location!" # Do not edit this! -configVersion: 3.9 \ No newline at end of file +configVersion: 3.10 \ No newline at end of file From 9ca491df536775daf8d5629187d56720314ec844 Mon Sep 17 00:00:00 2001 From: Beez0r Date: Wed, 10 Jul 2024 21:40:29 -0700 Subject: [PATCH 13/15] iShop 2.26 Update --- src/com/minedhype/ishop/CommandShop.java | 170 +++++++++++++++++++++++ src/com/minedhype/ishop/RowStore.java | 74 +++++----- src/com/minedhype/ishop/Shop.java | 157 ++++++++++++++++++--- src/com/minedhype/ishop/StockShop.java | 18 +-- src/com/minedhype/ishop/TabComplete.java | 8 +- src/com/minedhype/ishop/iShop.java | 88 ++++++++++-- src/resources/config.yml | 5 +- 7 files changed, 434 insertions(+), 86 deletions(-) diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index 5df7ce2..f0dbb6a 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -67,9 +67,13 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String } else if(args[0].equalsIgnoreCase("deletelocation") && args.length > 4) { Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> deleteLocation(null, args[1], args[2], args[3], args[4])); return true; + } else if(args[0].equalsIgnoreCase("convertdatabase")) { + Shop.convertData(); + return true; } else { sender.sendMessage(ChatColor.GOLD + "iShop Console Commands:"); sender.sendMessage(ChatColor.GRAY + label + " createlocation "); + sender.sendMessage(ChatColor.GRAY + label + " convertdatabase"); sender.sendMessage(ChatColor.GRAY + label + " deletelocation "); sender.sendMessage(ChatColor.GRAY + label + " deleteid "); sender.sendMessage(ChatColor.GRAY + label + " reload"); @@ -80,6 +84,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String if(sender instanceof ConsoleCommandSender) { sender.sendMessage(ChatColor.GOLD + "iShop Console Commands:"); sender.sendMessage(ChatColor.GRAY + label + " createlocation "); + sender.sendMessage(ChatColor.GRAY + label + " convertdatabase"); sender.sendMessage(ChatColor.GRAY + label + " deletelocation "); sender.sendMessage(ChatColor.GRAY + label + " deleteid "); sender.sendMessage(ChatColor.GRAY + label + " reload"); @@ -93,6 +98,8 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> listSubCmd(player, label)); else if(args[0].equalsIgnoreCase("adminshop")) adminShop(player); + else if(args[0].equalsIgnoreCase("copy") && args.length >= 2) + Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> copyShop(player, args[1])); else if(args[0].equalsIgnoreCase("count") && args.length >= 2) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> count(player, args[1])); else if(args[0].equalsIgnoreCase("create")) @@ -153,6 +160,7 @@ else if(args[0].equalsIgnoreCase("view") && args.length >= 2) private void listSubCmd(Player player, String label) { player.sendMessage(ChatColor.GOLD + "iShop Commands:"); + player.sendMessage(ChatColor.GRAY + "/" + label + " copy "); player.sendMessage(ChatColor.GRAY + "/" + label + " count "); player.sendMessage(ChatColor.GRAY + "/" + label + " create"); player.sendMessage(ChatColor.GRAY + "/" + label + " delete"); @@ -529,6 +537,168 @@ private void createShop(Player player, String playerShop) { } else { player.sendMessage(Messages.EXISTING_SHOP.toString()); } } + private void copyShop(Player player, String shopId) { + if(iShop.config.getBoolean("usePermissions") && !player.hasPermission(Permission.SHOP_CREATE.toString())) { + player.sendMessage(Messages.NO_PERMISSION.toString()); + return; + } + if(!iShop.config.getBoolean("enableShopBlock")) { + player.sendMessage(Messages.DISABLED_SHOP_BLOCK.toString()); + return; + } + Block block = player.getTargetBlockExact(5); + if(block == null) { + player.sendMessage(Messages.TARGET_MISMATCH.toString()); + return; + } + if(iShop.config.getBoolean("disableShopInWorld")) { + List disabledWorldsList = iShop.config.getStringList("disabledWorldList"); + for(String disabledWorlds:disabledWorldsList) { + if(disabledWorlds != null && block.getWorld().getName().equals(disabledWorlds)) { + player.sendMessage(Messages.SHOP_WORLD_DISABLED.toString()); + return; + } + } + } + String shopBlock = iShop.config.getString("shopBlock"); + Material match = Material.matchMaterial(shopBlock); + if(match == null) { + try { + match = Material.matchMaterial(shopBlock.split("minecraft:")[1].toUpperCase()); + } catch(Exception ignored) { } + if(match == null) + match = Material.BARREL; + } + if(!EventShop.multipleShopBlocks) { + if(!block.getType().equals(match)) { + player.sendMessage(Messages.TARGET_MISMATCH.toString()); + return; + } + } else { + boolean shopMatch = false; + for(String shopBlocks:EventShop.multipleShopBlock) { + Material shopListBlocks = Material.matchMaterial(shopBlocks); + if(shopListBlocks != null && block.getType().equals(shopListBlocks)) { + shopMatch = true; + break; + } + } + if(!block.getType().equals(match) && !shopMatch) { + player.sendMessage(Messages.TARGET_MISMATCH.toString()); + return; + } + } + boolean isShopLoc; + if(iShop.wgLoader != null) + isShopLoc = iShop.wgLoader.checkRegion(block); + else + isShopLoc = true; + if(!isShopLoc) { + player.sendMessage(Messages.WG_REGION.toString()); + return; + } + boolean allowShopCreateInClaim = false; + if(iShop.gpLoader != null) { + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(block.getLocation(), false, false, null); + if(claim == null || claim.checkPermission(player, ClaimPermission.Access, null) == null || claim.checkPermission(player, ClaimPermission.Build, null) == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null || claim.checkPermission(player, ClaimPermission.Manage, null) == null || claim.checkPermission(player, ClaimPermission.Inventory, null) == null) + allowShopCreateInClaim = true; + } + else + allowShopCreateInClaim = true; + if(!allowShopCreateInClaim) { + player.sendMessage(Messages.GP_CLAIM.toString()); + return; + } + boolean allowShopCreateWithinLands = false; + if(iShop.lands != null) { + LandWorld world = iShop.lands.getWorld(player.getWorld()); + if(world != null) + if(world.hasRoleFlag(player.getUniqueId(), block.getLocation(), Flags.BLOCK_PLACE)) + allowShopCreateWithinLands = true; + } + else + allowShopCreateWithinLands = true; + if(!allowShopCreateWithinLands) { + player.sendMessage(Messages.NO_SHOP_CREATE_PERMISSION.toString()); + return; + } + if(iShop.superiorSkyblock2Check) { + Island island = SuperiorSkyblockAPI.getIslandAt(block.getLocation()); + if(island != null) { + IslandPrivilege islandPrivilege = IslandPrivilege.getByName("Build"); + SuperiorPlayer superiorPlayer = SuperiorSkyblockAPI.getPlayer(player.getUniqueId()); + if(!island.hasPermission(superiorPlayer, islandPrivilege)) { + player.sendMessage(Messages.NO_SHOP_CREATE_PERMISSION.toString()); + return; + } + } + } + if(iShop.townyCheck) { + if(!ShopPlotUtil.doesPlayerHaveAbilityToEditShopPlot(player, block.getLocation())) { + player.sendMessage(Messages.NO_SHOP_CREATE_PERMISSION.toString()); + return; + } + } + Optional shop = Shop.getShopByLocation(block.getLocation()); + if(shop.isPresent()) { + player.sendMessage(Messages.EXISTING_SHOP.toString()); + return; + } + boolean limitShops; + int numShops = Shop.getNumShops(player.getUniqueId()); + if(iShop.config.getBoolean("usePermissions")) { + int maxShops = 0; + String permPrefix = Permission.SHOP_LIMIT_PREFIX.toString(); + for(PermissionAttachmentInfo attInfo : player.getEffectivePermissions()) { + String perm = attInfo.getPermission(); + if(perm.startsWith(permPrefix)) { + int num; + try { + num = Integer.parseInt(perm.substring(perm.lastIndexOf(".")+1)); + } catch(Exception e) { num = 0; } + if(num > maxShops) + maxShops = num; + } + } + limitShops = numShops >= maxShops; + } + else { + int numConfig = iShop.config.getInt("defaultShopLimit"); + limitShops = numShops >= numConfig && numConfig >= 0; + } + if(player.hasPermission(Permission.SHOP_LIMIT_BYPASS.toString())) + limitShops = false; + if(limitShops) { + player.sendMessage(Messages.SHOP_MAX.toString()); + return; + } + double cost = iShop.config.getDouble("createCost"); + Optional economy = iShop.getEconomy(); + if(cost > 0 && economy.isPresent()) { + OfflinePlayer offPlayer = Bukkit.getOfflinePlayer(player.getUniqueId()); + EconomyResponse res = economy.get().withdrawPlayer(offPlayer, cost); + if(!res.transactionSuccess()) { + player.sendMessage(Messages.SHOP_CREATE_NO_MONEY.toString()+cost); + return; + } + } + int shopNumber = Integer.parseInt(shopId); + Optional copyShop = Shop.getShopById(shopNumber); + if(!copyShop.isPresent()) { + player.sendMessage(Messages.SHOP_NOT_FOUND.toString()); + return; + } + Optional shopCopy = Shop.getShopByLocation(block.getLocation()); + if(!shopCopy.isPresent()) { + Shop.duplicateShop(block.getLocation(),player.getUniqueId(), shopNumber); + player.sendMessage(Messages.SHOP_CREATED.toString()); + Bukkit.getServer().getScheduler().runTaskLaterAsynchronously(iShop.getPlugin(), () -> { + Optional shops = Shop.getShopByLocation(block.getLocation()); + Shop.shopList.put(shops.get().shopId(), player.getUniqueId()); + }, 10); + } else { player.sendMessage(Messages.EXISTING_SHOP.toString()); } + } + private void createLocation(Player player, String playerShop, String x, String y, String z, String worldString) { if(player != null && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { player.sendMessage(Messages.NO_PERMISSION.toString()); diff --git a/src/com/minedhype/ishop/RowStore.java b/src/com/minedhype/ishop/RowStore.java index c2cc624..3cea03a 100644 --- a/src/com/minedhype/ishop/RowStore.java +++ b/src/com/minedhype/ishop/RowStore.java @@ -1,8 +1,9 @@ package com.minedhype.ishop; import java.sql.PreparedStatement; +import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; public class RowStore { @@ -24,47 +25,36 @@ public RowStore(ItemStack itemOut, ItemStack itemOut2, ItemStack itemIn, ItemSta public void saveData(int idTienda) { PreparedStatement stmt = null; try { - stmt = iShop.getConnection().prepareStatement("INSERT INTO zooMercaTiendasFilas (itemIn, itemIn2, itemOut, itemOut2, idTienda, broadcast) VALUES (?,?,?,?,?,?);"); - YamlConfiguration configIn1 = new YamlConfiguration(); + stmt = iShop.getConnection().prepareStatement("INSERT INTO zooMercaTiendasFilas (itemInNew, itemIn2New, itemOutNew, itemOut2New, idTienda, broadcast) VALUES (?,?,?,?,?,?);"); + ItemStack[] saveAirItem = new ItemStack[]{airItem}; + final Inventory invIn = Bukkit.createInventory(null,9); + final Inventory invIn2 = Bukkit.createInventory(null,9); + final Inventory invOut = Bukkit.createInventory(null,9); + final Inventory invOut2 = Bukkit.createInventory(null,9); if(itemIn != null) { - itemIn.serialize().forEach(configIn1::set); - String itemInRaw = configIn1.saveToString(); - stmt.setString(1, itemInRaw); - } else { - airItem.serialize().forEach(configIn1::set); - String itemInRaw = configIn1.saveToString(); - stmt.setString(1, itemInRaw); - } - YamlConfiguration configIn2 = new YamlConfiguration(); + ItemStack[] item = new ItemStack[]{itemIn}; + invIn.addItem(item[0]); + } else + invIn.addItem(saveAirItem[0]); + stmt.setBytes(1, iShop.encodeByte(invIn.getContents())); if(itemIn2 != null) { - itemIn2.serialize().forEach(configIn2::set); - String itemIn2Raw = configIn2.saveToString(); - stmt.setString(2, itemIn2Raw); - } else { - airItem.serialize().forEach(configIn2::set); - String itemIn2Raw = configIn2.saveToString(); - stmt.setString(2, itemIn2Raw); - } - YamlConfiguration configOut1 = new YamlConfiguration(); + ItemStack[] item = new ItemStack[]{itemIn2}; + invIn2.addItem(item[0]); + } else + invIn2.addItem(saveAirItem[0]); + stmt.setBytes(2, iShop.encodeByte(invIn2.getContents())); if(itemOut != null) { - itemOut.serialize().forEach(configOut1::set); - String itemOutRaw = configOut1.saveToString(); - stmt.setString(3, itemOutRaw); - } else { - airItem.serialize().forEach(configOut1::set); - String itemOutRaw = configOut1.saveToString(); - stmt.setString(3, itemOutRaw); - } - YamlConfiguration configOut2 = new YamlConfiguration(); + ItemStack[] item = new ItemStack[]{itemOut}; + invOut.addItem(item[0]); + } else + invOut.addItem(saveAirItem[0]); + stmt.setBytes(3, iShop.encodeByte(invOut.getContents())); if(itemOut2 != null) { - itemOut2.serialize().forEach(configOut2::set); - String itemOut2Raw = configOut2.saveToString(); - stmt.setString(4, itemOut2Raw); - } else { - airItem.serialize().forEach(configOut2::set); - String itemOut2Raw = configOut2.saveToString(); - stmt.setString(4, itemOut2Raw); - } + ItemStack[] item = new ItemStack[]{itemOut2}; + invOut2.addItem(item[0]); + } else + invOut2.addItem(saveAirItem[0]); + stmt.setBytes(4, iShop.encodeByte(invOut2.getContents())); stmt.setInt(5, idTienda); stmt.setBoolean(6, broadcast); stmt.execute(); @@ -81,15 +71,23 @@ public void toggleBroadcast() { this.broadcast = !this.broadcast; } public ItemStack getItemIn() { + if(itemIn == null) + return airItem; return itemIn; } public ItemStack getItemIn2() { + if(itemIn2 == null) + return airItem; return itemIn2; } public ItemStack getItemOut() { + if(itemOut == null) + return airItem; return itemOut; } public ItemStack getItemOut2() { + if(itemOut2 == null) + return airItem; return itemOut2; } } diff --git a/src/com/minedhype/ishop/Shop.java b/src/com/minedhype/ishop/Shop.java index 76273fd..0045165 100644 --- a/src/com/minedhype/ishop/Shop.java +++ b/src/com/minedhype/ishop/Shop.java @@ -1,5 +1,6 @@ package com.minedhype.ishop; +import java.sql.Blob; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; @@ -12,6 +13,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import javax.sql.rowset.serial.SerialBlob; import com.minedhype.ishop.inventories.InvAdminShop; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -25,6 +27,7 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BlockStateMeta; import org.bukkit.inventory.meta.EnchantmentStorageMeta; @@ -37,6 +40,7 @@ import net.md_5.bungee.api.chat.ClickEvent.Action; import net.md_5.bungee.api.chat.TextComponent; import net.milkbowl.vault.economy.Economy; +import static com.minedhype.ishop.iShop.decodeByte; public class Shop { public static boolean deletePlayerShop = iShop.config.getBoolean("deleteBlock"); @@ -49,6 +53,7 @@ public class Shop { public static boolean stockMessages = iShop.config.getBoolean("enableShopSoldMessage"); public static boolean stockMessagesSaveAll = iShop.config.getBoolean("enableSavingAllShopSoldMessages"); public static List exemptExpiringList = iShop.config.getStringList("exemptExpiringShops"); + public static Particle shopParticles = Particle.valueOf(iShop.config.getString("shopParticles").toUpperCase()); public static int maxDays = iShop.config.getInt("maxInactiveDays"); public static final ConcurrentHashMap shopList = new ConcurrentHashMap<>(); public static final ConcurrentHashMap> shopMessages = new ConcurrentHashMap<>(); @@ -599,6 +604,20 @@ public static Shop createShop(Location loc, UUID owner, boolean admin) { return shop; } + public static Shop duplicateShop(Location loc, UUID owner, int shopId) { + Shop shop = new Shop(-1, owner, loc, false); + shops.add(shop); + Optional stockShop = StockShop.getStockShopByOwner(owner, 0); + if(!stockShop.isPresent()) + new StockShop(owner, 0); + Optional copyShop = Shop.getShopById(shopId); + for(int i=0;i<5;i++) { + if(copyShop.get().getRows()[i] != null) + shop.getRows()[i] = copyShop.get().getRows()[i]; + } + return shop; + } + public static void tickShops() { if(!shopEnabled) return; @@ -608,7 +627,11 @@ public static void tickShops() { double x = shop.location.getBlockX() + 0.5; double y = shop.location.getBlockY() + 1.25; double z = shop.location.getBlockZ() + 0.5; - shop.location.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, x, y, z, 10, 0.1, 0.1, 0.1); + try { + shop.location.getWorld().spawnParticle(shopParticles, x, y, z, 10, 0.1, 0.1, 0.1); + } catch(Exception e) { + shop.location.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, x, y, z, 10, 0.1, 0.1, 0.1); + } } } } @@ -632,8 +655,104 @@ public static void loadData() { PreparedStatement loadShops = null; try { - loadStocks = iShop.getConnection().prepareStatement("SELECT owner, items, pag FROM zooMercaStocks;"); + loadStocks = iShop.getConnection().prepareStatement("SELECT owner, itemsNew, pag FROM zooMercaStocks;"); ResultSet dataStocks = loadStocks.executeQuery(); + while(dataStocks.next()) { + String ownerRaw = dataStocks.getString(1); + UUID owner = UUID.fromString(ownerRaw); + int pag = dataStocks.getInt(3); + try { + Blob blob = new SerialBlob(dataStocks.getBytes(2)); + StockShop stock = new StockShop(owner, pag); + stock.getInventory().setContents(decodeByte(blob.getBinaryStream())); + } catch (Exception ignored) { } + } + loadShops = iShop.getConnection().prepareStatement("SELECT location, owner, itemInNew, itemIn2New, itemOutNew, itemOut2New, idTienda, admin, broadcast FROM zooMercaTiendasFilas LEFT JOIN zooMercaTiendas ON id = idTienda ORDER BY idTienda;"); + ResultSet dataStore = loadShops.executeQuery(); + while(dataStore.next()) { + if(dataStore.getString(1) == null) { + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] Error: Skipped loading a shop with null location found in database! Make backups!"); + continue; + } + String[] locationRaw = dataStore.getString(1).split(";"); + int x = Integer.parseInt(locationRaw[0]); + int y = Integer.parseInt(locationRaw[1]); + int z = Integer.parseInt(locationRaw[2]); + World world = Bukkit.getWorld(locationRaw[3]); + if(world == null) { + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] Error: Skipped loading a shop with null world found in database! Make backups!"); + continue; + } + Location location = new Location(world, x, y, z); + Optional shop = Shop.getShopByLocation(location); + if(!shop.isPresent()) { + String ownerRaw = dataStore.getString(2); + UUID owner = UUID.fromString(ownerRaw); + int idTienda = dataStore.getInt(7); + boolean admin = dataStore.getBoolean(8); + shops.add(new Shop(idTienda, owner, location, admin)); + shop = Shop.getShopByLocation(location); + } + RowStore[] rows = shop.get().getRows(); + int index = 0; + for(int len=rows.length; index= rows.length) + continue; + boolean broadcast = dataStore.getBoolean(9); + ItemStack airItem = new ItemStack(Material.AIR, 0); + final Inventory invIn = Bukkit.createInventory(null,9); + final Inventory invIn2 = Bukkit.createInventory(null,9); + final Inventory invOut = Bukkit.createInventory(null,9); + final Inventory invOut2 = Bukkit.createInventory(null,9); + try { + Blob blob = new SerialBlob(dataStore.getBytes(3)); + invIn.setContents(decodeByte(blob.getBinaryStream())); + } + catch(Exception e) { invIn.addItem(airItem); } + try { + Blob blob = new SerialBlob(dataStore.getBytes(4)); + invIn2.setContents(decodeByte(blob.getBinaryStream())); + } + catch(Exception e) { invIn2.addItem(airItem); } + try { + Blob blob = new SerialBlob(dataStore.getBytes(5)); + invOut.setContents(decodeByte(blob.getBinaryStream())); + } + catch(Exception e) { invOut.addItem(airItem); } + try { + Blob blob = new SerialBlob(dataStore.getBytes(6)); + invOut2.setContents(decodeByte(blob.getBinaryStream())); + } + catch(Exception e) { invOut2.addItem(airItem); } + rows[index] = new RowStore(invIn.getItem(0), invIn2.getItem(0), invOut.getItem(0), invOut2.getItem(0), broadcast); + } + } catch(Exception e) { + e.printStackTrace(); + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] Failed to load database properly! Shutting down to prevent data corruption."); + Bukkit.shutdown(); + } finally { + try { + if(loadStocks != null) + loadStocks.close(); + if(loadRows != null) + loadRows.close(); + if(loadShops != null) + loadShops.close(); + } catch (Exception e) { e.printStackTrace(); } + } + } + + public static void convertData() { + boolean failedToLoad = false; + PreparedStatement loadOldShops = null; + PreparedStatement loadOldStock = null; + try { + loadOldStock = iShop.getConnection().prepareStatement("SELECT owner, items, pag FROM zooMercaStocks;"); + ResultSet dataStocks = loadOldStock.executeQuery(); while(dataStocks.next()) { String ownerRaw = dataStocks.getString(1); UUID owner = UUID.fromString(ownerRaw); @@ -653,8 +772,8 @@ public static void loadData() { StockShop stock = new StockShop(owner, pag); stock.getInventory().setContents(itemsList.toArray(new ItemStack[0])); } - loadShops = iShop.getConnection().prepareStatement("SELECT location, owner, itemIn, itemIn2, itemOut, itemOut2, idTienda, admin, broadcast FROM zooMercaTiendasFilas LEFT JOIN zooMercaTiendas ON id = idTienda ORDER BY idTienda;"); - ResultSet dataStore = loadShops.executeQuery(); + loadOldShops = iShop.getConnection().prepareStatement("SELECT location, owner, itemIn, itemIn2, itemOut, itemOut2, idTienda, admin, broadcast FROM zooMercaTiendasFilas LEFT JOIN zooMercaTiendas ON id = idTienda ORDER BY idTienda;"); + ResultSet dataStore = loadOldShops.executeQuery(); while(dataStore.next()) { if(dataStore.getString(1) == null) { Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] Error: Skipped loading a shop with null location found in database! Make backups!"); @@ -683,7 +802,7 @@ public static void loadData() { int index = 0; for(int len=rows.length; index= rows.length) @@ -701,7 +820,7 @@ public static void loadData() { configIn2.loadFromString(itemInstack2Raw); configOut1.loadFromString(itemOutstack1Raw); configOut2.loadFromString(itemOutstack2Raw); - } catch (InvalidConfigurationException e) { e.printStackTrace(); } + } catch (Exception e) { e.printStackTrace(); } Map itemInRaw = configIn1.getValues(true); ItemStack itemIn = ItemStack.deserialize(itemInRaw); Map itemIn2Raw = configIn2.getValues(true); @@ -713,20 +832,24 @@ public static void loadData() { boolean broadcast = dataStore.getBoolean(9); rows[index] = new RowStore(itemOut, itemOut2, itemIn, itemIn2, broadcast); } - } catch(Exception e) { e.printStackTrace(); - Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] Failed to load database properly! Shutting down to prevent data corruption."); - Bukkit.shutdown(); - } finally { + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] Failed to convert/load database, keep multiple back-ups for safety!"); + failedToLoad = true; + } finally{ try { - if(loadStocks != null) - loadStocks.close(); - if(loadRows != null) - loadRows.close(); - if(loadShops != null) - loadShops.close(); - } catch (Exception e) { e.printStackTrace(); } + if(loadOldShops != null) + loadOldShops.close(); + if(loadOldStock != null) + loadOldStock.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + if(!failedToLoad) { + iShop.dropOldColumns(); + Bukkit.getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Successfully converted database!"); + Bukkit.getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] We STRONGLY recommend restarting your server now to prevent data corruption!"); } } diff --git a/src/com/minedhype/ishop/StockShop.java b/src/com/minedhype/ishop/StockShop.java index 5a63e69..014804d 100644 --- a/src/com/minedhype/ishop/StockShop.java +++ b/src/com/minedhype/ishop/StockShop.java @@ -8,11 +8,7 @@ import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.inventory.Inventory; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import org.bukkit.inventory.ItemStack; public class StockShop { private static final List stocks = new ArrayList<>(); @@ -54,19 +50,9 @@ public static void saveData() { private void saveStockData() { PreparedStatement stmt = null; try { - stmt = iShop.getConnection().prepareStatement("INSERT INTO zooMercaStocks (owner, items, pag) VALUES (?,?,?);"); - JsonArray items = new JsonArray(); - for(ItemStack item : inventory.getContents()) { - if(item == null) - continue; - YamlConfiguration config = new YamlConfiguration(); - item.serialize().forEach(config::set); - String itemRaw = config.saveToString(); - items.add(itemRaw); - } - String itemsJson = (new Gson()).toJson(items); + stmt = iShop.getConnection().prepareStatement("INSERT INTO zooMercaStocks (owner, itemsNew, pag) VALUES (?,?,?);"); stmt.setString(1, owner.toString()); - stmt.setString(2, itemsJson); + stmt.setBytes(2,iShop.encodeByte(inventory.getContents())); stmt.setInt(3, pag); stmt.execute(); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/com/minedhype/ishop/TabComplete.java b/src/com/minedhype/ishop/TabComplete.java index dfa9a80..9b7688b 100644 --- a/src/com/minedhype/ishop/TabComplete.java +++ b/src/com/minedhype/ishop/TabComplete.java @@ -13,8 +13,8 @@ public class TabComplete implements TabCompleter { private static final List items = Arrays.stream(Material.values()).filter(Material::isItem).map(material -> material.getKey().getKey()).toList(); - private static final List findCommands = Arrays.asList("adminshop","count","create","createshop","createlocation","delete","deleteid","deletelocation","find","findbook","list","listadmin","manage","managestock","managestock","move","out","reload","removeallshops","shops","sold","stock","view"); - public static final List enchantments = Arrays.asList("aqua_affinity","bane_of_arthropods","blast_protection","channeling","curse_of_binding","curse_of_vanishing","depth_strider","efficiency","feather_falling","fire_aspect","fire_protection","flame","fortune","frost_walker","impaling","impaling","infinity","knockback","looting","loyalty","luck_of_the_sea","lure","mending","multishot","piercing","power","projectile_protection","protection","punch","quick_charge","respiration","riptide","sharpness","silk_touch","smite","soul_speed","sweeping_edge","swift_sneak","thorns","unbreaking"); + private static final List shopCommands = Arrays.asList("adminshop","copy","count","create","createshop","createlocation","delete","deleteid","deletelocation","find","findbook","list","listadmin","manage","managestock","move","out","reload","removeallshops","shops","sold","stock","view"); + public static final List enchantments = Arrays.asList("aqua_affinity","bane_of_arthropods","binding_curse","blast_protection","breach","channeling","curse_of_binding","curse_of_vanishing","density","depth_strider","efficiency","feather_falling","fire_aspect","fire_protection","flame","fortune","frost_walker","impaling","infinity","knockback","looting","loyalty","luck_of_the_sea","lure","mending","multishot","piercing","power","projectile_protection","protection","punch","quick_charge","respiration","riptide","sharpness","silk_touch","smite","soul_speed","sweeping_edge","swift_sneak","thorns","unbreaking","vanishing_curse","wind_burst"); @Override public List onTabComplete(CommandSender sender, Command cmd, String label, String[] args) { @@ -29,7 +29,9 @@ else if(args[0].equalsIgnoreCase("findbook")) { return Collections.emptyList(); } else { - return StringUtil.copyPartialMatches(args[0].toLowerCase(), findCommands, new ArrayList<>()); + if(args.length < 2) + return StringUtil.copyPartialMatches(args[0].toLowerCase(), shopCommands, new ArrayList<>()); + return Collections.emptyList(); } } } \ No newline at end of file diff --git a/src/com/minedhype/ishop/iShop.java b/src/com/minedhype/ishop/iShop.java index ef1500a..616eff5 100644 --- a/src/com/minedhype/ishop/iShop.java +++ b/src/com/minedhype/ishop/iShop.java @@ -1,7 +1,9 @@ package com.minedhype.ishop; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; @@ -13,12 +15,15 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.util.io.BukkitObjectInputStream; +import org.bukkit.util.io.BukkitObjectOutputStream; import com.minedhype.ishop.gui.GUIEvent; import com.minedhype.ishop.MetricsLite; import net.milkbowl.vault.economy.Economy; @@ -79,6 +84,10 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new GUIEvent(), this); getCommand("ishop").setExecutor(new CommandShop()); getCommand("ishop").setTabCompleter(new TabComplete()); + try { + connection = DriverManager.getConnection(chainConnect); + this.createTables(); + } catch(Exception e) { e.printStackTrace(); } int delayTime; int saveDatabaseTime; try { @@ -97,8 +106,6 @@ public void onEnable() { (saveDatabaseTime)*=20; Bukkit.getScheduler().runTaskLater(this, () -> { try { - connection = DriverManager.getConnection(chainConnect); - this.createTables(); Shop.loadData(); } catch(Exception e) { e.printStackTrace(); } }, delayTime); @@ -168,8 +175,8 @@ private void createTables() { try { stmts = new PreparedStatement[] { connection.prepareStatement("CREATE TABLE IF NOT EXISTS zooMercaTiendas(id INTEGER PRIMARY KEY autoincrement, location varchar(64), owner varchar(64));"), - connection.prepareStatement("CREATE TABLE IF NOT EXISTS zooMercaTiendasFilas(itemIn text, itemOut text, idTienda INTEGER);"), - connection.prepareStatement("CREATE TABLE IF NOT EXISTS zooMercaStocks(owner varchar(64), items JSON);") + connection.prepareStatement("CREATE TABLE IF NOT EXISTS zooMercaTiendasFilas(itemInNew blob, itemIn2New blob, itemOutNew blob, itemOut2New blob, idTienda INTEGER);"), + connection.prepareStatement("CREATE TABLE IF NOT EXISTS zooMercaStocks(owner varchar(64), itemsNew blob);") }; } catch(Exception e) { e.printStackTrace(); } for(PreparedStatement stmt : stmts) { @@ -180,20 +187,77 @@ private void createTables() { } List stmtsPatches = new ArrayList<>(); try { - stmtsPatches.add(connection.prepareStatement("ALTER TABLE zooMercaTiendasFilas ADD COLUMN itemIn2 text NULL DEFAULT 'v: 2580\ntype: AIR\namount: 0' ")); - stmtsPatches.add(connection.prepareStatement("ALTER TABLE zooMercaTiendasFilas ADD COLUMN itemOut2 text NULL DEFAULT 'v: 2580\ntype: AIR\namount: 0' ")); - stmtsPatches.add(connection.prepareStatement("ALTER TABLE zooMercaTiendasFilas ADD COLUMN broadcast BOOLEAN DEFAULT 0")); - stmtsPatches.add(connection.prepareStatement("ALTER TABLE zooMercaStocks ADD COLUMN pag INTEGER DEFAULT 0")); + stmtsPatches.add(connection.prepareStatement("ALTER TABLE zooMercaTiendasFilas ADD COLUMN itemInNew blob;")); + } catch(Exception ignored) { } + try { + stmtsPatches.add(connection.prepareStatement("ALTER TABLE zooMercaTiendasFilas ADD COLUMN itemIn2New blob;")); + } catch(Exception ignored) { } + try { + stmtsPatches.add(connection.prepareStatement("ALTER TABLE zooMercaTiendasFilas ADD COLUMN itemOutNew blob;")); + } catch(Exception ignored) { } + try { + stmtsPatches.add(connection.prepareStatement("ALTER TABLE zooMercaTiendasFilas ADD COLUMN itemOut2New blob;")); + } catch(Exception ignored) { } + try { + stmtsPatches.add(connection.prepareStatement("ALTER TABLE zooMercaTiendasFilas ADD COLUMN broadcast BOOLEAN DEFAULT 0;")); + } catch(Exception ignored) { } + try { + stmtsPatches.add(connection.prepareStatement("ALTER TABLE zooMercaStocks ADD COLUMN pag INTEGER DEFAULT 0;")); + } catch(Exception ignored) { } + try { + stmtsPatches.add(connection.prepareStatement("ALTER TABLE zooMercaStocks ADD COLUMN itemsNew blob;")); + } catch(Exception ignored) { } + try { stmtsPatches.add(connection.prepareStatement("ALTER TABLE zooMercaTiendas ADD COLUMN admin BOOLEAN DEFAULT FALSE;")); } catch(Exception ignored) { } for(PreparedStatement stmtsPatch : stmtsPatches) { try { stmtsPatch.execute(); stmtsPatch.close(); - } catch (Exception ignored) { } + } catch(Exception ignored) { } } } + public static void dropOldColumns() { + PreparedStatement[] stmts = new PreparedStatement[] { }; + try { + stmts = new PreparedStatement[] { + connection.prepareStatement("ALTER TABLE zooMercaTiendasFilas DROP COLUMN itemIn;"), + connection.prepareStatement("ALTER TABLE zooMercaTiendasFilas DROP COLUMN itemIn2;"), + connection.prepareStatement("ALTER TABLE zooMercaTiendasFilas DROP COLUMN itemOut;"), + connection.prepareStatement("ALTER TABLE zooMercaTiendasFilas DROP COLUMN itemOut2;"), + connection.prepareStatement("ALTER TABLE zooMercaStocks DROP COLUMN items;") + }; + } catch(Exception e) { e.printStackTrace(); } + for(PreparedStatement stmt : stmts) { + try { + stmt.execute(); + stmt.close(); + } catch(Exception e) { e.printStackTrace(); } + } + } + + public static ItemStack[] decodeByte(InputStream inputStream) throws IOException, ClassNotFoundException { + if(inputStream == null || inputStream.available() == 0) + return new ItemStack[0]; + BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream); + ItemStack[] items = new ItemStack[dataInput.readInt()]; + for(int i=0; i Date: Fri, 12 Jul 2024 21:06:45 -0700 Subject: [PATCH 14/15] iShop 2.26 Update Part 2 --- src/com/minedhype/ishop/CommandShop.java | 2 +- src/com/minedhype/ishop/Shop.java | 4 ++-- src/com/minedhype/ishop/inventories/InvShopList.java | 7 ++++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index f0dbb6a..fec4a9b 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -160,7 +160,7 @@ else if(args[0].equalsIgnoreCase("view") && args.length >= 2) private void listSubCmd(Player player, String label) { player.sendMessage(ChatColor.GOLD + "iShop Commands:"); - player.sendMessage(ChatColor.GRAY + "/" + label + " copy "); + player.sendMessage(ChatColor.GRAY + "/" + label + " copy "); player.sendMessage(ChatColor.GRAY + "/" + label + " count "); player.sendMessage(ChatColor.GRAY + "/" + label + " create"); player.sendMessage(ChatColor.GRAY + "/" + label + " delete"); diff --git a/src/com/minedhype/ishop/Shop.java b/src/com/minedhype/ishop/Shop.java index 0045165..dbafa23 100644 --- a/src/com/minedhype/ishop/Shop.java +++ b/src/com/minedhype/ishop/Shop.java @@ -140,7 +140,7 @@ public static void findItem(Player player, ItemStack item, String itemName) { if(row.isPresent() && !foundItemInShop.get()) { boolean itemMatch = row.get().getItemOut().isSimilar(item); boolean itemMatch2 = row.get().getItemOut2().isSimilar(item); - if(((itemMatch && itemMatch2) && Utils.hasDoubleItemStock(s, item, item)) || ((itemMatch && !itemMatch2) && Utils.hasStock(s, row.get().getItemOut2())) || ((!itemMatch && itemMatch2) && Utils.hasStock(s, row.get().getItemOut()))) { + if(((itemMatch && itemMatch2) && Utils.hasDoubleItemStock(s, row.get().getItemOut(), row.get().getItemOut2())) || ((itemMatch && !itemMatch2) && Utils.hasStock(s, row.get().getItemOut())) || ((!itemMatch && itemMatch2) && Utils.hasStock(s, row.get().getItemOut2()))) { foundItem.set(true); foundItemInShop.set(true); player.sendMessage(Messages.SHOP_LOCATION.toString().replaceAll("%id", String.valueOf(s.idTienda)).replaceAll("%x", String.valueOf(s.location.getBlockX())).replaceAll("%y", String.valueOf(s.location.getBlockY())).replaceAll("%z", String.valueOf(s.location.getBlockZ())).replaceAll("%world", s.location.getWorld().getName())); @@ -728,7 +728,7 @@ public static void loadData() { invOut2.setContents(decodeByte(blob.getBinaryStream())); } catch(Exception e) { invOut2.addItem(airItem); } - rows[index] = new RowStore(invIn.getItem(0), invIn2.getItem(0), invOut.getItem(0), invOut2.getItem(0), broadcast); + rows[index] = new RowStore(invOut.getItem(0), invOut2.getItem(0), invIn.getItem(0), invIn2.getItem(0), broadcast); } } catch(Exception e) { e.printStackTrace(); diff --git a/src/com/minedhype/ishop/inventories/InvShopList.java b/src/com/minedhype/ishop/inventories/InvShopList.java index 287c37a..bcac599 100644 --- a/src/com/minedhype/ishop/inventories/InvShopList.java +++ b/src/com/minedhype/ishop/inventories/InvShopList.java @@ -77,9 +77,14 @@ private static void getShopList(UUID uuid) { ItemStack item = new ItemStack(playerHead); SkullMeta skullMeta = (SkullMeta) item.getItemMeta(); OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(Shop.shopList.get(id)); - skullMeta.setOwningPlayer(offlinePlayer); + boolean playerNotFound = false; + try { + skullMeta.setOwningPlayer(offlinePlayer); } + catch(Exception e) { playerNotFound = true; } if(Shop.getShopById(id).get().isAdmin()) skullMeta.setDisplayName(Messages.ADMIN_SHOP_NUMBER.toString().replaceAll("%id", id.toString())); + else if(playerNotFound) + skullMeta.setDisplayName(Messages.SHOP_NUMBER.toString().replaceAll("%player", "Unknown Player").replaceAll("%id", id.toString())); else skullMeta.setDisplayName(Messages.SHOP_NUMBER.toString().replaceAll("%player", offlinePlayer.getName()).replaceAll("%id", id.toString())); List skullLore = new ArrayList<>(); From d1bbb6a23881f780606be9e4f53a41cd2398af53 Mon Sep 17 00:00:00 2001 From: Beez0r Date: Thu, 28 May 2026 23:45:40 -0700 Subject: [PATCH 15/15] iShop 2.27 Update --- src/com/minedhype/ishop/CommandShop.java | 121 ++- src/com/minedhype/ishop/EventShop.java | 29 +- src/com/minedhype/ishop/Messages.java | 4 + src/com/minedhype/ishop/Metrics.java | 905 ++++++++++++++++++ src/com/minedhype/ishop/MetricsLite.java | 367 ------- src/com/minedhype/ishop/Shop.java | 41 +- src/com/minedhype/ishop/StockShop.java | 80 +- src/com/minedhype/ishop/TabComplete.java | 16 +- src/com/minedhype/ishop/gui/GUI.java | 19 +- src/com/minedhype/ishop/iShop.java | 53 +- .../ishop/inventories/InvShopList.java | 6 +- .../minedhype/ishop/inventories/InvStock.java | 25 +- .../ishop/inventories/InvStockList.java | 117 +++ src/resources/config.yml | 25 +- src/resources/plugin.yml | 2 +- 15 files changed, 1378 insertions(+), 432 deletions(-) create mode 100644 src/com/minedhype/ishop/Metrics.java delete mode 100644 src/com/minedhype/ishop/MetricsLite.java create mode 100644 src/com/minedhype/ishop/inventories/InvStockList.java diff --git a/src/com/minedhype/ishop/CommandShop.java b/src/com/minedhype/ishop/CommandShop.java index fec4a9b..2777881 100644 --- a/src/com/minedhype/ishop/CommandShop.java +++ b/src/com/minedhype/ishop/CommandShop.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Scanner; import java.util.UUID; @@ -39,6 +40,7 @@ import org.json.simple.JSONValue; import com.minedhype.ishop.inventories.InvAdminShop; import com.minedhype.ishop.inventories.InvShopList; +import com.minedhype.ishop.inventories.InvStockList; import com.minedhype.ishop.inventories.InvStock; import me.ryanhamshire.GriefPrevention.Claim; import me.ryanhamshire.GriefPrevention.GriefPrevention; @@ -70,12 +72,16 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String } else if(args[0].equalsIgnoreCase("convertdatabase")) { Shop.convertData(); return true; + } else if(args[0].equalsIgnoreCase("lockdown")) { + lockdownToggle(null); + return true; } else { sender.sendMessage(ChatColor.GOLD + "iShop Console Commands:"); sender.sendMessage(ChatColor.GRAY + label + " createlocation "); sender.sendMessage(ChatColor.GRAY + label + " convertdatabase"); sender.sendMessage(ChatColor.GRAY + label + " deletelocation "); sender.sendMessage(ChatColor.GRAY + label + " deleteid "); + sender.sendMessage(ChatColor.GRAY + label + " lockdown"); sender.sendMessage(ChatColor.GRAY + label + " reload"); return false; } @@ -87,6 +93,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String sender.sendMessage(ChatColor.GRAY + label + " convertdatabase"); sender.sendMessage(ChatColor.GRAY + label + " deletelocation "); sender.sendMessage(ChatColor.GRAY + label + " deleteid "); + sender.sendMessage(ChatColor.GRAY + label + " lockdown"); sender.sendMessage(ChatColor.GRAY + label + " reload"); } else @@ -94,6 +101,10 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String return false; } Player player = (Player) sender; + if(iShop.getPlugin().checkLockdown() && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.SHOP_LOCKDOWN.toString()); + return false; + } if(args.length == 0) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> listSubCmd(player, label)); else if(args[0].equalsIgnoreCase("adminshop")) @@ -124,6 +135,10 @@ else if(args[0].equalsIgnoreCase("list") && args.length >= 2) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> listShops(player, args[1])); else if(args[0].equalsIgnoreCase("listadmin")) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> listAdminShops(player)); + else if(args[0].equalsIgnoreCase("liststock")) + listAllStock(player); + else if(args[0].equalsIgnoreCase("lockdown")) + Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> lockdownToggle(player)); else if(args[0].equalsIgnoreCase("manage") && args.length >= 2) shopManage(player, args[1]); else if(args[0].equalsIgnoreCase("managestock") && args.length == 2) @@ -136,6 +151,8 @@ else if(args[0].equalsIgnoreCase("out") && args.length == 1) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> outOfStock(player, null)); else if(args[0].equalsIgnoreCase("out") && args.length >= 2) Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> outOfStock(player, args[1])); + else if(args[0].equalsIgnoreCase("purgestock") && args.length == 3 && args[2].equals("confirm")) + Bukkit.getServer().getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> purgePlayerStock(player, args[1])); else if(args[0].equalsIgnoreCase("reload")) reloadShop(player); else if(args[0].equalsIgnoreCase("removeallshops") && args.length >= 2) @@ -191,7 +208,10 @@ private void listSubCmd(Player player, String label) { player.sendMessage(ChatColor.GRAY + "/" + label + " createlocation "); player.sendMessage(ChatColor.GRAY + "/" + label + " deletelocation "); player.sendMessage(ChatColor.GRAY + "/" + label + " listadmin"); + player.sendMessage(ChatColor.GRAY + "/" + label + " liststock"); + player.sendMessage(ChatColor.GRAY + "/" + label + " lockdown"); player.sendMessage(ChatColor.GRAY + "/" + label + " managestock "); + player.sendMessage(ChatColor.GRAY + "/" + label + " purgestock confirm"); player.sendMessage(ChatColor.GRAY + "/" + label + " reload"); player.sendMessage(ChatColor.GRAY + "/" + label + " removeallshops "); } @@ -297,7 +317,7 @@ private void createStore(Player player) { boolean allowShopCreateInClaim = false; if(iShop.gpLoader != null) { Claim claim = GriefPrevention.instance.dataStore.getClaimAt(block.getLocation(), false, false, null); - if(claim == null || claim.checkPermission(player, ClaimPermission.Access, null) == null || claim.checkPermission(player, ClaimPermission.Build, null) == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null || claim.checkPermission(player, ClaimPermission.Manage, null) == null || claim.checkPermission(player, ClaimPermission.Inventory, null) == null) + if(claim == null || claim.checkPermission(player, ClaimPermission.Access, null) == null || claim.checkPermission(player, ClaimPermission.Build, null) == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null || claim.checkPermission(player, ClaimPermission.Manage, null) == null || claim.checkPermission(player, ClaimPermission.Container, null) == null) allowShopCreateInClaim = true; } else @@ -453,7 +473,7 @@ private void createShop(Player player, String playerShop) { UUID foundPlayerUUID = null; boolean foundPlayer = false; for(OfflinePlayer offlinePlayers : Bukkit.getOfflinePlayers()) - if(offlinePlayers.getName().equalsIgnoreCase(playerShop)) { + if(Objects.requireNonNull(offlinePlayers.getName()).equalsIgnoreCase(playerShop)) { foundPlayerUUID = offlinePlayers.getUniqueId(); foundPlayer = true; break; @@ -485,7 +505,7 @@ private void createShop(Player player, String playerShop) { boolean allowShopCreateInClaim = false; if(iShop.gpLoader != null) { Claim claim = GriefPrevention.instance.dataStore.getClaimAt(block.getLocation(), false, false, null); - if(claim == null || claim.checkPermission(player, ClaimPermission.Access, null) == null || claim.checkPermission(player, ClaimPermission.Build, null) == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null || claim.checkPermission(player, ClaimPermission.Manage, null) == null || claim.checkPermission(player, ClaimPermission.Inventory, null) == null) + if(claim == null || claim.checkPermission(player, ClaimPermission.Access, null) == null || claim.checkPermission(player, ClaimPermission.Build, null) == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null || claim.checkPermission(player, ClaimPermission.Manage, null) == null || claim.checkPermission(player, ClaimPermission.Container, null) == null) allowShopCreateInClaim = true; } else @@ -600,7 +620,7 @@ private void copyShop(Player player, String shopId) { boolean allowShopCreateInClaim = false; if(iShop.gpLoader != null) { Claim claim = GriefPrevention.instance.dataStore.getClaimAt(block.getLocation(), false, false, null); - if(claim == null || claim.checkPermission(player, ClaimPermission.Access, null) == null || claim.checkPermission(player, ClaimPermission.Build, null) == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null || claim.checkPermission(player, ClaimPermission.Manage, null) == null || claim.checkPermission(player, ClaimPermission.Inventory, null) == null) + if(claim == null || claim.checkPermission(player, ClaimPermission.Access, null) == null || claim.checkPermission(player, ClaimPermission.Build, null) == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null || claim.checkPermission(player, ClaimPermission.Manage, null) == null || claim.checkPermission(player, ClaimPermission.Container, null) == null) allowShopCreateInClaim = true; } else @@ -806,7 +826,7 @@ private void createLocation(Player player, String playerShop, String x, String y UUID foundPlayerUUID = null; boolean foundPlayer = false; for(OfflinePlayer offlinePlayers : Bukkit.getOfflinePlayers()) - if(offlinePlayers.getName().equalsIgnoreCase(playerShop)) { + if(Objects.requireNonNull(offlinePlayers.getName()).equalsIgnoreCase(playerShop)) { foundPlayerUUID = offlinePlayers.getUniqueId(); foundPlayer = true; break; @@ -1194,7 +1214,7 @@ private void moveShop(Player player, String shopId) { boolean allowShopCreateInClaim = false; if(iShop.gpLoader != null) { Claim claim = GriefPrevention.instance.dataStore.getClaimAt(block.getLocation(), false, false, null); - if(claim == null || claim.checkPermission(player, ClaimPermission.Access, null) == null || claim.checkPermission(player, ClaimPermission.Build, null) == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null || claim.checkPermission(player, ClaimPermission.Manage, null) == null || claim.checkPermission(player, ClaimPermission.Inventory, null) == null) + if(claim == null || claim.checkPermission(player, ClaimPermission.Access, null) == null || claim.checkPermission(player, ClaimPermission.Build, null) == null || claim.checkPermission(player, ClaimPermission.Edit, null) == null || claim.checkPermission(player, ClaimPermission.Manage, null) == null || claim.checkPermission(player, ClaimPermission.Container, null) == null) allowShopCreateInClaim = true; } else allowShopCreateInClaim = true; @@ -1276,7 +1296,7 @@ private void removeAllShops(Player player, String playerName) { UUID foundPlayerUUID = null; boolean foundPlayer = false; for(OfflinePlayer offlinePlayers : Bukkit.getOfflinePlayers()) - if(offlinePlayers.getName().equalsIgnoreCase(playerName)) { + if(Objects.requireNonNull(offlinePlayers.getName()).equalsIgnoreCase(playerName)) { foundPlayerUUID = offlinePlayers.getUniqueId(); foundPlayer = true; break; @@ -1317,7 +1337,7 @@ private void listShops(Player player, String playerName) { UUID foundPlayerUUID = null; boolean foundPlayer = false; for(OfflinePlayer offlinePlayers : Bukkit.getOfflinePlayers()) - if(offlinePlayers.getName().equalsIgnoreCase(playerName)) { + if(Objects.requireNonNull(offlinePlayers.getName()).equalsIgnoreCase(playerName)) { foundPlayerUUID = offlinePlayers.getUniqueId(); foundPlayer = true; break; @@ -1352,6 +1372,16 @@ private void listAllShops(Player player) { inv.open(player); } + private void listAllStock(Player player) { + if(!player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.NO_PERMISSION.toString()); + return; + } + InvStockList inv = InvStockList.setStockTitle("List of Players with Stock"); + inv.setPag(0); + inv.open(player); + } + private void stockShop(Player player, String page) { if(!InvAdminShop.stockCommandEnabled && !player.hasPermission(Permission.SHOP_ADMIN.toString()) && !player.hasPermission(Permission.SHOP_STOCK.toString())) { player.sendMessage(Messages.STOCK_COMMAND_DISABLED.toString()); @@ -1443,6 +1473,7 @@ private void reloadShop(Player player) { InvCreateRow.preventAllDupeTrades = iShop.config.getBoolean("preventAllDuplicates"); InvCreateRow.strictStock = iShop.config.getBoolean("strictStock"); InvShop.listAllShops = iShop.config.getBoolean("publicShopListCommand"); + InvStock.showStockListAdmin = iShop.config.getBoolean("showStockListItemForAdmin"); Shop.showOwnedShops = iShop.config.getBoolean("publicShopListShowsOwned"); Shop.shopEnabled = iShop.config.getBoolean("enableShopBlock"); Shop.shopNotifications = iShop.config.getBoolean("enableShopNotifications"); @@ -1453,6 +1484,9 @@ private void reloadShop(Player player) { Shop.saveEmptyShops = iShop.config.getBoolean("saveEmptyShops"); Shop.stockMessages = iShop.config.getBoolean("enableShopSoldMessage"); Shop.exemptExpiringList = iShop.config.getStringList("exemptExpiringShops"); + Shop.stockDeleteWhenShopsExpire = iShop.config.getBoolean("deleteStockWhenShopsExpire"); + StockShop.exemptStockExpiringList = iShop.config.getStringList("exemptExpiringStock"); + StockShop.maxStockDays = iShop.config.getInt("maxStockInactiveDays"); findCommandPublic = iShop.config.getBoolean("publicFindCommand"); findCooldownTime = iShop.config.getInt("findCommandCooldown"); moveCommandPublic = iShop.config.getBoolean("publicMoveCommand"); @@ -1564,7 +1598,7 @@ private void manageStock(Player player, String stockOwner, String page) { UUID foundPlayerUUID = null; boolean foundPlayer = false; for(OfflinePlayer offlinePlayers : Bukkit.getOfflinePlayers()) - if(offlinePlayers.getName().equalsIgnoreCase(stockOwner)) { + if(Objects.requireNonNull(offlinePlayers.getName()).equalsIgnoreCase(stockOwner)) { foundPlayerUUID = offlinePlayers.getUniqueId(); foundPlayer = true; break; @@ -1732,7 +1766,7 @@ private void outOfStock(Player player, String playerName) { UUID foundPlayerUUID = null; boolean foundPlayer = false; for(OfflinePlayer offlinePlayers : Bukkit.getOfflinePlayers()) - if(offlinePlayers.getName().equalsIgnoreCase(playerName)) { + if(Objects.requireNonNull(offlinePlayers.getName()).equalsIgnoreCase(playerName)) { foundPlayerUUID = offlinePlayers.getUniqueId(); foundPlayer = true; break; @@ -1749,4 +1783,71 @@ private void outOfStock(Player player, String playerName) { player.sendMessage(Messages.SHOP_LIST_OUT.toString()); Shop.getOutOfStock(player, sOwner, playerName); } + + private void purgePlayerStock(Player player, String stockOwner) { + if(!player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.NO_PERMISSION.toString()); + return; + } + UUID sOwner; + if(stockOwner == null) { + player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); + return; + } else { + Player playerInGame = Bukkit.getPlayer(stockOwner); + if(playerInGame != null && playerInGame.isOnline()) + sOwner = playerInGame.getUniqueId(); + else { + try { + sOwner = getUUID(stockOwner); + } catch (Exception e) { + UUID foundPlayerUUID = null; + boolean foundPlayer = false; + for(OfflinePlayer offlinePlayers : Bukkit.getOfflinePlayers()) + if(Objects.requireNonNull(offlinePlayers.getName()).equalsIgnoreCase(stockOwner)) { + foundPlayerUUID = offlinePlayers.getUniqueId(); + foundPlayer = true; + break; + } + if(!foundPlayer) { + player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "[iShop] " + Messages.NO_PLAYER_FOUND); + return; + } + sOwner = foundPlayerUUID; + } + } + } + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(sOwner); + if(offlinePlayer == null || !offlinePlayer.hasPlayedBefore()) { + player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); + return; + } + StockShop.purgePlayerStock(sOwner); + String playerName = offlinePlayer.getName(); + if(playerName != null) + player.sendMessage(Messages.PURGE_PLAYER_STOCK.toString().replaceAll("%p", playerName)); + else + player.sendMessage(Messages.NO_PLAYER_FOUND.toString()); + } + + private void lockdownToggle(Player player) { + if(player != null && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + player.sendMessage(Messages.NO_PERMISSION.toString()); + return; + } + if(iShop.getPlugin().checkLockdown()) { + iShop.getPlugin().setLockdown(false); + if(player != null) + player.sendMessage(Messages.STOCK_DISABLE_LOCKDOWN.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.STOCK_DISABLE_LOCKDOWN.toString()); + } else { + iShop.getPlugin().setLockdown(true); + if(player != null) + player.sendMessage(Messages.STOCK_ENABLE_LOCKDOWN.toString()); + else + Bukkit.getConsoleSender().sendMessage(Messages.STOCK_ENABLE_LOCKDOWN.toString()); + } + } } diff --git a/src/com/minedhype/ishop/EventShop.java b/src/com/minedhype/ishop/EventShop.java index 6d41318..b2ffff0 100644 --- a/src/com/minedhype/ishop/EventShop.java +++ b/src/com/minedhype/ishop/EventShop.java @@ -83,12 +83,15 @@ public void onPlayerInteract(PlayerInteractEvent event) { if(placeFrameSign) if(event.getPlayer().isSneaking() && event.getAction().equals(Action.RIGHT_CLICK_BLOCK) && (shop.get().isOwner(event.getPlayer().getUniqueId()) || event.getPlayer().hasPermission(Permission.SHOP_ADMIN.toString())) && (event.getPlayer().getInventory().getItemInMainHand().getType().toString().endsWith("_SIGN") || event.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.ITEM_FRAME))) return; + event.setCancelled(true); + if(iShop.getPlugin().checkLockdown() && !event.getPlayer().hasPermission(Permission.SHOP_ADMIN.toString())) { + event.getPlayer().sendMessage(Messages.SHOP_LOCKDOWN.toString()); + return; + } if(shop.get().isAdmin() && !adminShopEnabled) { - event.setCancelled(true); event.getPlayer().sendMessage(Messages.ADMIN_SHOP_DISABLED.toString()); return; } - event.setCancelled(true); if(shuttingDown) return; if(InvStock.inShopInv.containsValue(shop.get().getOwner())) { @@ -119,12 +122,15 @@ else if(event.getHand().equals(EquipmentSlot.OFF_HAND)) if(placeFrameSign) if(event.getPlayer().isSneaking() && event.getAction().equals(Action.RIGHT_CLICK_BLOCK) && (shop.get().isOwner(event.getPlayer().getUniqueId()) || event.getPlayer().hasPermission(Permission.SHOP_ADMIN.toString())) && (event.getPlayer().getInventory().getItemInMainHand().getType().toString().endsWith("_SIGN") || event.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.ITEM_FRAME))) return; + event.setCancelled(true); + if(iShop.getPlugin().checkLockdown() && !event.getPlayer().hasPermission(Permission.SHOP_ADMIN.toString())) { + event.getPlayer().sendMessage(Messages.SHOP_LOCKDOWN.toString()); + return; + } if(shop.get().isAdmin() && !adminShopEnabled) { - event.setCancelled(true); event.getPlayer().sendMessage(Messages.ADMIN_SHOP_DISABLED.toString()); return; } - event.setCancelled(true); if(shuttingDown) return; if(InvStock.inShopInv.containsValue(shop.get().getOwner())) { @@ -158,12 +164,15 @@ else if(event.getHand().equals(EquipmentSlot.OFF_HAND)) if(placeFrameSign) if(event.getPlayer().isSneaking() && event.getAction().equals(Action.RIGHT_CLICK_BLOCK) && (shop.get().isOwner(event.getPlayer().getUniqueId()) || event.getPlayer().hasPermission(Permission.SHOP_ADMIN.toString())) && (event.getPlayer().getInventory().getItemInMainHand().getType().toString().endsWith("_SIGN") || event.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.ITEM_FRAME))) return; + event.setCancelled(true); + if(iShop.getPlugin().checkLockdown() && !event.getPlayer().hasPermission(Permission.SHOP_ADMIN.toString())) { + event.getPlayer().sendMessage(Messages.SHOP_LOCKDOWN.toString()); + return; + } if(shop.get().isAdmin() && !adminShopEnabled) { - event.setCancelled(true); event.getPlayer().sendMessage(Messages.ADMIN_SHOP_DISABLED.toString()); return; } - event.setCancelled(true); if(shuttingDown) return; if(InvStock.inShopInv.containsValue(shop.get().getOwner())) { @@ -196,6 +205,10 @@ else if(event.getHand().equals(EquipmentSlot.OFF_HAND)) if(shuttingDown) return; if(event.getAction() == Action.LEFT_CLICK_BLOCK) { + if(iShop.getPlugin().checkLockdown() && !event.getPlayer().hasPermission(Permission.SHOP_ADMIN.toString())) { + event.getPlayer().sendMessage(Messages.SHOP_LOCKDOWN.toString()); + return; + } if(Shop.getNumShops(event.getPlayer().getUniqueId()) < 1 && noShopNoStock) { event.getPlayer().sendMessage(Messages.NO_SHOP_STOCK.toString()); return; @@ -245,6 +258,10 @@ else if(event.getHand().equals(EquipmentSlot.OFF_HAND)) if(shuttingDown) return; if(event.getAction() == Action.LEFT_CLICK_BLOCK) { + if(iShop.getPlugin().checkLockdown() && !event.getPlayer().hasPermission(Permission.SHOP_ADMIN.toString())) { + event.getPlayer().sendMessage(Messages.SHOP_LOCKDOWN.toString()); + return; + } if(Shop.getNumShops(event.getPlayer().getUniqueId()) < 1 && noShopNoStock) { event.getPlayer().sendMessage(Messages.NO_SHOP_STOCK.toString()); return; diff --git a/src/com/minedhype/ishop/Messages.java b/src/com/minedhype/ishop/Messages.java index 01f50af..203bf22 100644 --- a/src/com/minedhype/ishop/Messages.java +++ b/src/com/minedhype/ishop/Messages.java @@ -18,6 +18,7 @@ public enum Messages { NO_STOCK_BLOCK("noStockBlock"), PLAYER_INV_FULL("playerInventoryFull"), PLAYER_SHOP_CREATED("playerShopCreated"), + PURGE_PLAYER_STOCK("purgePlayersStock"), SHOP_BUSY("shopBusy"), SHOP_CLICK_MANAGE("clickManage"), SHOP_CLICK_SHOP("clickShop"), @@ -41,6 +42,7 @@ public enum Messages { SHOP_LOCATION("location"), SHOP_LOCATION_ERROR_NUM("shopLocationErrorNum"), SHOP_LOCATION_ERROR_WORLD("shopLocationErrorWorld"), + SHOP_LOCKDOWN("lockdown"), SHOP_MAX("shopLimit"), SHOP_MOVED("shopMoved"), SHOP_NOT_FOUND("noShopFound"), @@ -89,6 +91,8 @@ public enum Messages { STOCK_COUNT_AMOUNT("countAmount"), STOCK_COUNT_EMPTY("countEmpty"), STOCK_COUNT_ERROR("countError"), + STOCK_DISABLE_LOCKDOWN("disableLockdown"), + STOCK_ENABLE_LOCKDOWN("enableLockdown"), STOCK_INTEGER("stockIntegerError"), TARGET_MISMATCH("targetMismatch"), WG_REGION("outsideRegion"); diff --git a/src/com/minedhype/ishop/Metrics.java b/src/com/minedhype/ishop/Metrics.java new file mode 100644 index 0000000..2721af4 --- /dev/null +++ b/src/com/minedhype/ishop/Metrics.java @@ -0,0 +1,905 @@ +/* + * This Metrics class was auto-generated and can be copied into your project if you are + * not using a build tool like Gradle or Maven for dependency management. + * + * IMPORTANT: You are not allowed to modify this class, except changing the package. + * + * Disallowed modifications include but are not limited to: + * - Remove the option for users to opt-out + * - Change the frequency for data submission + * - Obfuscate the code (every obfuscator should allow you to make an exception for specific files) + * - Reformat the code (if you use a linter, add an exception) + * + * Violations will result in a ban of your plugin and account from bStats. + */ +package com.minedhype.ishop; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.zip.GZIPOutputStream; +import javax.net.ssl.HttpsURLConnection; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +public class Metrics { + + private final Plugin plugin; + + private final MetricsBase metricsBase; + + /** + * Creates a new Metrics instance. + * + * @param plugin Your plugin instance. + * @param serviceId The id of the service. It can be found at What is my plugin id? + */ + public Metrics(Plugin plugin, int serviceId) { + this.plugin = plugin; + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + if (!config.isSet("serverUuid")) { + config.addDefault("enabled", true); + config.addDefault("serverUuid", UUID.randomUUID().toString()); + config.addDefault("logFailedRequests", false); + config.addDefault("logSentData", false); + config.addDefault("logResponseStatusText", false); + // Inform the server owners about bStats + config + .options() + .header( + "bStats (https://bStats.org) collects some basic information for plugin authors, like how\n" + + "many people use their plugin and their total player count. It's recommended to keep bStats\n" + + "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n" + + "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n" + + "anonymous.\n" + + "Learn more here: https://bstats.org/docs/server-owners") + .copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { + } + } + // Load the data + boolean enabled = config.getBoolean("enabled", true); + String serverUUID = config.getString("serverUuid"); + boolean logErrors = config.getBoolean("logFailedRequests", false); + boolean logSentData = config.getBoolean("logSentData", false); + boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false); + boolean isFolia = false; + try { + isFolia = Class.forName("io.papermc.paper.threadedregions.RegionizedServer") != null; + } catch (Exception e) { + } + metricsBase = + new // See https://github.com/Bastian/bstats-metrics/pull/126 + // See https://github.com/Bastian/bstats-metrics/pull/126 + // See https://github.com/Bastian/bstats-metrics/pull/126 + // See https://github.com/Bastian/bstats-metrics/pull/126 + // See https://github.com/Bastian/bstats-metrics/pull/126 + // See https://github.com/Bastian/bstats-metrics/pull/126 + // See https://github.com/Bastian/bstats-metrics/pull/126 + MetricsBase( + "bukkit", + serverUUID, + serviceId, + enabled, + this::appendPlatformData, + this::appendServiceData, + isFolia + ? null + : submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask), + plugin::isEnabled, + (message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error), + (message) -> this.plugin.getLogger().log(Level.INFO, message), + logErrors, + logSentData, + logResponseStatusText, + false); + } + + /** Shuts down the underlying scheduler service. */ + public void shutdown() { + metricsBase.shutdown(); + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + metricsBase.addCustomChart(chart); + } + + private void appendPlatformData(JsonObjectBuilder builder) { + builder.appendField("playerAmount", getPlayerAmount()); + builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0); + builder.appendField("bukkitVersion", Bukkit.getVersion()); + builder.appendField("bukkitName", Bukkit.getName()); + builder.appendField("javaVersion", System.getProperty("java.version")); + builder.appendField("osName", System.getProperty("os.name")); + builder.appendField("osArch", System.getProperty("os.arch")); + builder.appendField("osVersion", System.getProperty("os.version")); + builder.appendField("coreCount", Runtime.getRuntime().availableProcessors()); + } + + private void appendServiceData(JsonObjectBuilder builder) { + builder.appendField("pluginVersion", plugin.getDescription().getVersion()); + } + + private int getPlayerAmount() { + try { + // Around MC 1.8 the return type was changed from an array to a collection, + // This fixes java.lang.NoSuchMethodError: + // org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + return onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + // Just use the new method if the reflection failed + return Bukkit.getOnlinePlayers().size(); + } + } + + public static class MetricsBase { + + /** The version of the Metrics class. */ + public static final String METRICS_VERSION = "3.2.1"; + + private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s"; + + private final ScheduledExecutorService scheduler; + + private final String platform; + + private final String serverUuid; + + private final int serviceId; + + private final Consumer appendPlatformDataConsumer; + + private final Consumer appendServiceDataConsumer; + + private final Consumer submitTaskConsumer; + + private final Supplier checkServiceEnabledSupplier; + + private final BiConsumer errorLogger; + + private final Consumer infoLogger; + + private final boolean logErrors; + + private final boolean logSentData; + + private final boolean logResponseStatusText; + + private final Set customCharts = new HashSet<>(); + + private final boolean enabled; + + /** + * Creates a new MetricsBase class instance. + * + * @param platform The platform of the service. + * @param serviceId The id of the service. + * @param serverUuid The server uuid. + * @param enabled Whether or not data sending is enabled. + * @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all platform-specific data. + * @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all service-specific data. + * @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be + * used to delegate the data collection to a another thread to prevent errors caused by + * concurrency. Can be {@code null}. + * @param checkServiceEnabledSupplier A supplier to check if the service is still enabled. + * @param errorLogger A consumer that accepts log message and an error. + * @param infoLogger A consumer that accepts info log messages. + * @param logErrors Whether or not errors should be logged. + * @param logSentData Whether or not the sent data should be logged. + * @param logResponseStatusText Whether or not the response status text should be logged. + * @param skipRelocateCheck Whether or not the relocate check should be skipped. + */ + public MetricsBase( + String platform, + String serverUuid, + int serviceId, + boolean enabled, + Consumer appendPlatformDataConsumer, + Consumer appendServiceDataConsumer, + Consumer submitTaskConsumer, + Supplier checkServiceEnabledSupplier, + BiConsumer errorLogger, + Consumer infoLogger, + boolean logErrors, + boolean logSentData, + boolean logResponseStatusText, + boolean skipRelocateCheck) { + ScheduledThreadPoolExecutor scheduler = + new ScheduledThreadPoolExecutor( + 1, + task -> { + Thread thread = new Thread(task, "bStats-Metrics"); + thread.setDaemon(true); + return thread; + }); + // We want delayed tasks (non-periodic) that will execute in the future to be + // cancelled when the scheduler is shutdown. + // Otherwise, we risk preventing the server from shutting down even when + // MetricsBase#shutdown() is called + scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + this.scheduler = scheduler; + this.platform = platform; + this.serverUuid = serverUuid; + this.serviceId = serviceId; + this.enabled = enabled; + this.appendPlatformDataConsumer = appendPlatformDataConsumer; + this.appendServiceDataConsumer = appendServiceDataConsumer; + this.submitTaskConsumer = submitTaskConsumer; + this.checkServiceEnabledSupplier = checkServiceEnabledSupplier; + this.errorLogger = errorLogger; + this.infoLogger = infoLogger; + this.logErrors = logErrors; + this.logSentData = logSentData; + this.logResponseStatusText = logResponseStatusText; + if (!skipRelocateCheck) { + checkRelocation(); + } + if (enabled) { + // WARNING: Removing the option to opt-out will get your plugin banned from + // bStats + startSubmitting(); + } + } + + public void addCustomChart(CustomChart chart) { + this.customCharts.add(chart); + } + + public void shutdown() { + scheduler.shutdown(); + } + + private void startSubmitting() { + final Runnable submitTask = + () -> { + if (!enabled || !checkServiceEnabledSupplier.get()) { + // Submitting data or service is disabled + scheduler.shutdown(); + return; + } + if (submitTaskConsumer != null) { + submitTaskConsumer.accept(this::submitData); + } else { + this.submitData(); + } + }; + // Many servers tend to restart at a fixed time at xx:00 which causes an uneven + // distribution of requests on the + // bStats backend. To circumvent this problem, we introduce some randomness into + // the initial and second delay. + // WARNING: You must not modify and part of this Metrics class, including the + // submit delay or frequency! + // WARNING: Modifying this code will get your plugin banned on bStats. Just + // don't do it! + long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3)); + long secondDelay = (long) (1000 * 60 * (Math.random() * 30)); + scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); + scheduler.scheduleAtFixedRate( + submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS); + } + + private void submitData() { + final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder(); + appendPlatformDataConsumer.accept(baseJsonBuilder); + final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder(); + appendServiceDataConsumer.accept(serviceJsonBuilder); + JsonObjectBuilder.JsonObject[] chartData = + customCharts.stream() + .map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors)) + .filter(Objects::nonNull) + .toArray(JsonObjectBuilder.JsonObject[]::new); + serviceJsonBuilder.appendField("id", serviceId); + serviceJsonBuilder.appendField("customCharts", chartData); + baseJsonBuilder.appendField("service", serviceJsonBuilder.build()); + baseJsonBuilder.appendField("serverUUID", serverUuid); + baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION); + JsonObjectBuilder.JsonObject data = baseJsonBuilder.build(); + scheduler.execute( + () -> { + try { + sendData(data); + } catch (Exception e) { + // Something went wrong! :( + if (logErrors) { + errorLogger.accept("Could not submit bStats metrics data", e); + } + } + }); + } + + private void sendData(JsonObjectBuilder.JsonObject data) throws Exception { + if (logSentData) { + infoLogger.accept("Sent bStats metrics data: " + data.toString()); + } + String url = String.format(REPORT_URL, platform); + HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(); + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("User-Agent", "Metrics-Service/1"); + connection.setDoOutput(true); + try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { + outputStream.write(compressedData); + } + StringBuilder builder = new StringBuilder(); + try (BufferedReader bufferedReader = + new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + } + if (logResponseStatusText) { + infoLogger.accept("Sent data to bStats and received response: " + builder); + } + } + + /** Checks that the class was properly relocated. */ + private void checkRelocation() { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null + || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this + // little "trick" ... :D + final String defaultPackage = + new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'}); + final String examplePackage = + new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure no one just copy & pastes the example and uses the wrong + // package names + if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage) + || MetricsBase.class.getPackage().getName().startsWith(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + /** + * Gzips the given string. + * + * @param str The string to gzip. + * @return The gzipped string. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + } + return outputStream.toByteArray(); + } + } + + public abstract static class CustomChart { + + private final String chartId; + + protected CustomChart(String chartId) { + if (chartId == null) { + throw new IllegalArgumentException("chartId must not be null"); + } + this.chartId = chartId; + } + + public JsonObjectBuilder.JsonObject getRequestJsonObject( + BiConsumer errorLogger, boolean logErrors) { + JsonObjectBuilder builder = new JsonObjectBuilder(); + builder.appendField("chartId", chartId); + try { + JsonObjectBuilder.JsonObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + builder.appendField("data", data); + } catch (Throwable t) { + if (logErrors) { + errorLogger.accept("Failed to get data for custom chart with id " + chartId, t); + } + return null; + } + return builder.build(); + } + + protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; + } + + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + public static class DrilldownPie extends CustomChart { + + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class AdvancedBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class AdvancedPie extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SimplePie extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + /** + * An extremely simple JSON builder. + * + *

While this class is neither feature-rich nor the most performant one, it's sufficient enough + * for its use-case. + */ + public static class JsonObjectBuilder { + + private StringBuilder builder = new StringBuilder(); + + private boolean hasAtLeastOneField = false; + + public JsonObjectBuilder() { + builder.append("{"); + } + + /** + * Appends a null field to the JSON. + * + * @param key The key of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendNull(String key) { + appendFieldUnescaped(key, "null"); + return this; + } + + /** + * Appends a string field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String value) { + if (value == null) { + throw new IllegalArgumentException("JSON value must not be null"); + } + appendFieldUnescaped(key, "\"" + escape(value) + "\""); + return this; + } + + /** + * Appends an integer field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int value) { + appendFieldUnescaped(key, String.valueOf(value)); + return this; + } + + /** + * Appends an object to the JSON. + * + * @param key The key of the field. + * @param object The object. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject object) { + if (object == null) { + throw new IllegalArgumentException("JSON object must not be null"); + } + appendFieldUnescaped(key, object.toString()); + return this; + } + + /** + * Appends a string array to the JSON. + * + * @param key The key of the field. + * @param values The string array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values) + .map(value -> "\"" + escape(value) + "\"") + .collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an integer array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an object array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends a field to the object. + * + * @param key The key of the field. + * @param escapedValue The escaped value of the field. + */ + private void appendFieldUnescaped(String key, String escapedValue) { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + if (key == null) { + throw new IllegalArgumentException("JSON key must not be null"); + } + if (hasAtLeastOneField) { + builder.append(","); + } + builder.append("\"").append(escape(key)).append("\":").append(escapedValue); + hasAtLeastOneField = true; + } + + /** + * Builds the JSON string and invalidates this builder. + * + * @return The built JSON string. + */ + public JsonObject build() { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + JsonObject object = new JsonObject(builder.append("}").toString()); + builder = null; + return object; + } + + /** + * Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt. + * + *

This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'. + * Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n"). + * + * @param value The value to escape. + * @return The escaped value. + */ + private static String escape(String value) { + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (c == '"') { + builder.append("\\\""); + } else if (c == '\\') { + builder.append("\\\\"); + } else if (c <= '\u000F') { + builder.append("\\u000").append(Integer.toHexString(c)); + } else if (c <= '\u001F') { + builder.append("\\u00").append(Integer.toHexString(c)); + } else { + builder.append(c); + } + } + return builder.toString(); + } + + /** + * A super simple representation of a JSON object. + * + *

This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not + * allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String, + * JsonObject)}. + */ + public static class JsonObject { + + private final String value; + + private JsonObject(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + } +} diff --git a/src/com/minedhype/ishop/MetricsLite.java b/src/com/minedhype/ishop/MetricsLite.java deleted file mode 100644 index e3ecb1d..0000000 --- a/src/com/minedhype/ishop/MetricsLite.java +++ /dev/null @@ -1,367 +0,0 @@ -package com.minedhype.ishop; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import org.bukkit.Bukkit; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.plugin.ServicePriority; - -import javax.net.ssl.HttpsURLConnection; -import java.io.*; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Collection; -import java.util.Timer; -import java.util.TimerTask; -import java.util.UUID; -import java.util.logging.Level; -import java.util.zip.GZIPOutputStream; - -/** - * bStats collects some data for plugin authors. - *

- * Check out https://bStats.org/ to learn more about bStats! - */ -@SuppressWarnings({"WeakerAccess", "unused"}) -public class MetricsLite { - - static { - // You can use the property to disable the check in your test environment - if (System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) { - // Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D - final String defaultPackage = new String( - new byte[]{'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); - final String examplePackage = new String(new byte[]{'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); - // We want to make sure nobody just copy & pastes the example and use the wrong package names - if (MetricsLite.class.getPackage().getName().equals(defaultPackage) || MetricsLite.class.getPackage().getName().equals(examplePackage)) { - throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); - } - } - } - - // The version of this bStats class - public static final int B_STATS_VERSION = 1; - - // The url to which the data is sent - private static final String URL = "https://bStats.org/submitData/bukkit"; - - // Is bStats enabled on this server? - private boolean enabled; - - // Should failed requests be logged? - private static boolean logFailedRequests; - - // Should the sent data be logged? - private static boolean logSentData; - - // Should the response text be logged? - private static boolean logResponseStatusText; - - // The uuid of the server - private static String serverUUID; - - // The plugin - private final Plugin plugin; - - // The plugin id - private final int pluginId; - - /** - * Class constructor. - * - * @param plugin The plugin which stats should be submitted. - * @param pluginId The id of the plugin. - * It can be found at What is my plugin id? - */ - public MetricsLite(Plugin plugin, int pluginId) { - if (plugin == null) { - throw new IllegalArgumentException("Plugin cannot be null!"); - } - this.plugin = plugin; - this.pluginId = pluginId; - - // Get the config file - File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); - File configFile = new File(bStatsFolder, "config.yml"); - YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); - - // Check if the config file exists - if (!config.isSet("serverUuid")) { - - // Add default values - config.addDefault("enabled", true); - // Every server gets it's unique random id. - config.addDefault("serverUuid", UUID.randomUUID().toString()); - // Should failed request be logged? - config.addDefault("logFailedRequests", false); - // Should the sent data be logged? - config.addDefault("logSentData", false); - // Should the response text be logged? - config.addDefault("logResponseStatusText", false); - - // Inform the server owners about bStats - config.options().header( - "bStats collects some data for plugin authors like how many servers are using their plugins.\n" + - "To honor their work, you should not disable it.\n" + - "This has nearly no effect on the server performance!\n" + - "Check out https://bStats.org/ to learn more :)" - ).copyDefaults(true); - try { - config.save(configFile); - } catch (IOException ignored) { } - } - - // Load the data - serverUUID = config.getString("serverUuid"); - logFailedRequests = config.getBoolean("logFailedRequests", false); - enabled = config.getBoolean("enabled", true); - logSentData = config.getBoolean("logSentData", false); - logResponseStatusText = config.getBoolean("logResponseStatusText", false); - if (enabled) { - boolean found = false; - // Search for all other bStats Metrics classes to see if we are the first one - for (Class service : Bukkit.getServicesManager().getKnownServices()) { - try { - service.getField("B_STATS_VERSION"); // Our identifier :) - found = true; // We aren't the first - break; - } catch (NoSuchFieldException ignored) { } - } - // Register our service - Bukkit.getServicesManager().register(MetricsLite.class, this, plugin, ServicePriority.Normal); - if (!found) { - // We are the first! - startSubmitting(); - } - } - } - - /** - * Checks if bStats is enabled. - * - * @return Whether bStats is enabled or not. - */ - public boolean isEnabled() { - return enabled; - } - - /** - * Starts the Scheduler which submits our data every 30 minutes. - */ - private void startSubmitting() { - final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags - timer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - if (!plugin.isEnabled()) { // Plugin was disabled - timer.cancel(); - return; - } - // Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler - // Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;) - Bukkit.getScheduler().runTask(plugin, () -> submitData()); - } - }, 1000 * 60 * 5, 1000 * 60 * 30); - // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start - // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted! - // WARNING: Just don't do it! - } - - /** - * Gets the plugin specific data. - * This method is called using Reflection. - * - * @return The plugin specific data. - */ - public JsonObject getPluginData() { - JsonObject data = new JsonObject(); - - String pluginName = plugin.getDescription().getName(); - String pluginVersion = plugin.getDescription().getVersion(); - - data.addProperty("pluginName", pluginName); // Append the name of the plugin - data.addProperty("id", pluginId); // Append the id of the plugin - data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin - data.add("customCharts", new JsonArray()); - - return data; - } - - /** - * Gets the server specific data. - * - * @return The server specific data. - */ - private JsonObject getServerData() { - // Minecraft specific data - int playerAmount; - try { - // Around MC 1.8 the return type was changed to a collection from an array, - // This fixes java.lang.NoSuchMethodError: org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; - Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); - playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) - ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() - : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; - } catch (Exception e) { - playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed - } - int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; - String bukkitVersion = Bukkit.getVersion(); - String bukkitName = Bukkit.getName(); - - // OS/Java specific data - String javaVersion = System.getProperty("java.version"); - String osName = System.getProperty("os.name"); - String osArch = System.getProperty("os.arch"); - String osVersion = System.getProperty("os.version"); - int coreCount = Runtime.getRuntime().availableProcessors(); - - JsonObject data = new JsonObject(); - - data.addProperty("serverUUID", serverUUID); - - data.addProperty("playerAmount", playerAmount); - data.addProperty("onlineMode", onlineMode); - data.addProperty("bukkitVersion", bukkitVersion); - data.addProperty("bukkitName", bukkitName); - - data.addProperty("javaVersion", javaVersion); - data.addProperty("osName", osName); - data.addProperty("osArch", osArch); - data.addProperty("osVersion", osVersion); - data.addProperty("coreCount", coreCount); - - return data; - } - - /** - * Collects the data and sends it afterwards. - */ - private void submitData() { - final JsonObject data = getServerData(); - - JsonArray pluginData = new JsonArray(); - // Search for all other bStats Metrics classes to get their plugin data - for (Class service : Bukkit.getServicesManager().getKnownServices()) { - try { - service.getField("B_STATS_VERSION"); // Our identifier :) - - for (RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) { - try { - Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider()); - if (plugin instanceof JsonObject) { - pluginData.add((JsonObject) plugin); - } else { // old bstats version compatibility - try { - Class jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject"); - if (plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) { - Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString"); - jsonStringGetter.setAccessible(true); - String jsonString = (String) jsonStringGetter.invoke(plugin); - JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject(); - pluginData.add(object); - } - } catch (ClassNotFoundException e) { - // minecraft version 1.14+ - if (logFailedRequests) { - this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception ", e); - } - } - } - } catch (NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) { - } - } - } catch (NoSuchFieldException ignored) { } - } - - data.add("plugins", pluginData); - - // Create a new thread for the connection to the bStats server - new Thread(() -> { - try { - // Send the data - sendData(plugin, data); - } catch (Exception e) { - // Something went wrong! :( - if (logFailedRequests) { - plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); - } - } - }).start(); - } - - /** - * Sends the data to the bStats server. - * - * @param plugin Any plugin. It's just used to get a logger instance. - * @param data The data to send. - * @throws Exception If the request failed. - */ - private static void sendData(Plugin plugin, JsonObject data) throws Exception { - if (data == null) { - throw new IllegalArgumentException("Data cannot be null!"); - } - if (Bukkit.isPrimaryThread()) { - throw new IllegalAccessException("This method must not be called from the main thread!"); - } - if (logSentData) { - plugin.getLogger().info("Sending data to bStats: " + data); - } - HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); - - // Compress the data to save bandwidth - byte[] compressedData = compress(data.toString()); - - // Add headers - connection.setRequestMethod("POST"); - connection.addRequestProperty("Accept", "application/json"); - connection.addRequestProperty("Connection", "close"); - connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request - connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); - connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format - connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); - - // Send data - connection.setDoOutput(true); - try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { - outputStream.write(compressedData); - } - - StringBuilder builder = new StringBuilder(); - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { - String line; - while ((line = bufferedReader.readLine()) != null) { - builder.append(line); - } - } - - if (logResponseStatusText) { - plugin.getLogger().info("Sent data to bStats and received response: " + builder); - } - } - - /** - * Gzips the given String. - * - * @param str The string to gzip. - * @return The gzipped String. - * @throws IOException If the compression failed. - */ - private static byte[] compress(final String str) throws IOException { - if (str == null) { - return null; - } - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - try(GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { - gzip.write(str.getBytes(StandardCharsets.UTF_8)); - } - return outputStream.toByteArray(); - } - -} diff --git a/src/com/minedhype/ishop/Shop.java b/src/com/minedhype/ishop/Shop.java index dbafa23..d91d5ca 100644 --- a/src/com/minedhype/ishop/Shop.java +++ b/src/com/minedhype/ishop/Shop.java @@ -41,6 +41,7 @@ import net.md_5.bungee.api.chat.TextComponent; import net.milkbowl.vault.economy.Economy; import static com.minedhype.ishop.iShop.decodeByte; +import static com.minedhype.ishop.StockShop.purgePlayerStock; public class Shop { public static boolean deletePlayerShop = iShop.config.getBoolean("deleteBlock"); @@ -52,6 +53,7 @@ public class Shop { public static boolean shopNotifications = iShop.config.getBoolean("enableShopNotifications"); public static boolean stockMessages = iShop.config.getBoolean("enableShopSoldMessage"); public static boolean stockMessagesSaveAll = iShop.config.getBoolean("enableSavingAllShopSoldMessages"); + public static boolean stockDeleteWhenShopsExpire = iShop.config.getBoolean("deleteStockWhenShopsExpire"); public static List exemptExpiringList = iShop.config.getStringList("exemptExpiringShops"); public static Particle shopParticles = Particle.valueOf(iShop.config.getString("shopParticles").toUpperCase()); public static int maxDays = iShop.config.getInt("maxInactiveDays"); @@ -106,16 +108,25 @@ private Shop(int idTienda, UUID owner, Location loc, boolean admin) { public static boolean checkShopDistanceFromStockBlock(Location stockLocation, UUID shopOwner) { return shops.parallelStream().filter(s -> !s.admin && s.isOwner(shopOwner)).anyMatch(s -> s.getLocation().getWorld().equals(stockLocation.getWorld()) && s.location.distanceSquared(stockLocation) <= EventShop.stockRangeLimit*EventShop.stockRangeLimit); } public static int getNumShops(UUID owner) { return (int) shops.parallelStream().filter(t -> !t.admin && t.owner.equals(owner)).count(); } - public static boolean strictStockShopCheck(ItemStack item, UUID uuid) { + public static boolean strictStockShopCheck(ItemStack item, ItemStack item2, UUID uuid) { AtomicBoolean restricted = new AtomicBoolean(true); shops.parallelStream().filter(s -> !s.admin && s.isOwner(uuid)).forEach(s -> { if(restricted.get()) { for(int i=0; i<5; i++) { if(restricted.get()) { Optional row = s.getRow(i); - if(row.isPresent()) - if(row.get().getItemOut().isSimilar(item) || row.get().getItemOut2().isSimilar(item)) - restricted.set(false); + if(row.isPresent()) { + if(!item.getType().isAir()) + if(row.get().getItemOut().isSimilar(item) || row.get().getItemOut2().isSimilar(item)) { + restricted.set(false); + break; + } + if(!item2.getType().isAir()) + if(row.get().getItemOut().isSimilar(item2) || row.get().getItemOut2().isSimilar(item2)) { + restricted.set(false); + break; + } + } } } } @@ -630,7 +641,7 @@ public static void tickShops() { try { shop.location.getWorld().spawnParticle(shopParticles, x, y, z, 10, 0.1, 0.1, 0.1); } catch(Exception e) { - shop.location.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, x, y, z, 10, 0.1, 0.1, 0.1); + shop.location.getWorld().spawnParticle(Particle.HAPPY_VILLAGER, x, y, z, 10, 0.1, 0.1, 0.1); } } } @@ -638,15 +649,31 @@ public static void tickShops() { public static void expiredShops() { exemptListInactive = exemptExpiringList.size() == 1 && exemptExpiringList.get(0).equals("00000000-0000-0000-0000-000000000000"); + int expiredCount = 0; List shopDelete = new ArrayList<>(); - for(Shop shop : shops) - if(shop.hasExpired() || shop.location.getWorld() == null) + List shopOwners = new ArrayList<>(); + for(Shop shop : shops) { + if(shop.hasExpired()) { shopDelete.add(shop); + expiredCount++; + if(stockDeleteWhenShopsExpire) { + purgePlayerStock(shop.getOwner()); + if(!shopOwners.contains(shop.getOwner())) + shopOwners.add(shop.getOwner()); + } + } + else if(shop.location.getWorld() == null) + shopDelete.add(shop); + } for(Shop shop : shopDelete) { shopList.remove(shop.shopId()); shop.deleteShop(); } + if(expiredCount > 0 && !stockDeleteWhenShopsExpire) + Bukkit.getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] " + expiredCount + " shops have expired."); + else if(!shopOwners.isEmpty()) + Bukkit.getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] " + expiredCount + " shops have expired. Stock has expired for " + shopOwners.size() + " players."); } public static void loadData() { diff --git a/src/com/minedhype/ishop/StockShop.java b/src/com/minedhype/ishop/StockShop.java index 014804d..1e320fb 100644 --- a/src/com/minedhype/ishop/StockShop.java +++ b/src/com/minedhype/ishop/StockShop.java @@ -6,8 +6,10 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; import org.bukkit.inventory.Inventory; public class StockShop { @@ -15,7 +17,15 @@ public class StockShop { private final UUID owner; private final Inventory inventory; private final int pag; - + private static boolean exemptStockListInactive; + private static final long millisecondsPerDay = 86400000; + public boolean isOwner(UUID owner) { return this.owner.equals(owner); } + public static List expiredStockOwners = new ArrayList<>(); + public static List exemptStockExpiringList = iShop.config.getStringList("exemptExpiringStock"); + public static Optional getStockShopByOwner(UUID owner, int pag) { return stocks.parallelStream().filter(t -> t.owner.equals(owner) && t.pag == pag).findFirst(); } + public static final ConcurrentHashMap stockList = new ConcurrentHashMap<>(); + public static int maxStockDays = iShop.config.getInt("maxStockInactiveDays"); + public static void getPlayersStockList() { stocks.parallelStream().filter(s -> !s.inventory.isEmpty()).forEach(s -> stockList.putIfAbsent(s.owner, "Owner")); } public StockShop(UUID owner, int pag) { this(owner, Bukkit.createInventory(null, 45, ChatColor.GREEN + Bukkit.getOfflinePlayer(owner).getName()+"'s shop"), pag); } public StockShop(UUID owner, Inventory inv, int pag) { @@ -25,7 +35,73 @@ public StockShop(UUID owner, Inventory inv, int pag) { stocks.add(this); } - public static Optional getStockShopByOwner(UUID owner, int pag) { return stocks.parallelStream().filter(t -> t.owner.equals(owner) && t.pag == pag).findFirst(); } + public static void purgePlayerStock(UUID stockOwner) { + List stockDelete = new ArrayList<>(); + for(StockShop stock : stocks) { + if(stock.isOwner(stockOwner)) + stockDelete.add(stock); + } + for(StockShop stock : stockDelete) + stock.deleteStock(true, !expiredStockOwners.contains(stock.getOwner())); + } + + public static void expiredStock() { + if(maxStockDays <= 0) + return; + exemptStockListInactive = exemptStockExpiringList.size() == 1 && exemptStockExpiringList.get(0).equals("00000000-0000-0000-0000-000000000000"); + List stockDelete = new ArrayList<>(); + List deleteCount = new ArrayList<>(); + for(StockShop stock : stocks) { + if(stock.hasStockExpired()) { + stockDelete.add(stock); + stock.getInventory().clear(); + if(!deleteCount.contains(stock.getOwner())) + deleteCount.add(stock.getOwner()); + } + } + for(StockShop stock : stockDelete) + stock.deleteStock(true, !expiredStockOwners.contains(stock.getOwner())); + if(!deleteCount.isEmpty()) + Bukkit.getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Stock has expired for " + deleteCount.size() + " players."); + } + + public boolean hasStockExpired() { + if(!exemptStockListInactive) + for(String exemptCheck : exemptStockExpiringList) { + if(exemptCheck != null && exemptCheck.equalsIgnoreCase(this.owner.toString())) + return false; + } + OfflinePlayer player = Bukkit.getOfflinePlayer(this.owner); + if(player.isOnline()) + return false; + return ((System.currentTimeMillis() - player.getLastPlayed()) / millisecondsPerDay) >= maxStockDays; + } + + public void deleteStock(boolean removalOfStock, boolean deleteFromDatabase) { + if(removalOfStock) { + stocks.remove(this); + if(deleteFromDatabase) { + expiredStockOwners.add(owner); + Bukkit.getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> { + PreparedStatement stmt1 = null; + try { + stmt1 = iShop.getConnection().prepareStatement("DELETE FROM zooMercaStocks WHERE owner = ?;"); + stmt1.setString(1, owner.toString()); + stmt1.execute(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (stmt1 != null) + stmt1.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } + } public static void saveData() { if(!hasStock()) diff --git a/src/com/minedhype/ishop/TabComplete.java b/src/com/minedhype/ishop/TabComplete.java index 9b7688b..ba55a19 100644 --- a/src/com/minedhype/ishop/TabComplete.java +++ b/src/com/minedhype/ishop/TabComplete.java @@ -4,17 +4,19 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; public class TabComplete implements TabCompleter { private static final List items = Arrays.stream(Material.values()).filter(Material::isItem).map(material -> material.getKey().getKey()).toList(); - private static final List shopCommands = Arrays.asList("adminshop","copy","count","create","createshop","createlocation","delete","deleteid","deletelocation","find","findbook","list","listadmin","manage","managestock","move","out","reload","removeallshops","shops","sold","stock","view"); - public static final List enchantments = Arrays.asList("aqua_affinity","bane_of_arthropods","binding_curse","blast_protection","breach","channeling","curse_of_binding","curse_of_vanishing","density","depth_strider","efficiency","feather_falling","fire_aspect","fire_protection","flame","fortune","frost_walker","impaling","infinity","knockback","looting","loyalty","luck_of_the_sea","lure","mending","multishot","piercing","power","projectile_protection","protection","punch","quick_charge","respiration","riptide","sharpness","silk_touch","smite","soul_speed","sweeping_edge","swift_sneak","thorns","unbreaking","vanishing_curse","wind_burst"); + private static final List shopCommands = Arrays.asList("adminshop","copy","count","create","createshop","createlocation","delete","deleteid","deletelocation","find","findbook","list","listadmin","liststock","lockdown","manage","managestock","move","out","purgestock","reload","removeallshops","shops","sold","stock","view"); + public static final List enchantments = Arrays.asList("aqua_affinity","bane_of_arthropods","binding_curse","blast_protection","breach","channeling","density","depth_strider","efficiency","feather_falling","fire_aspect","fire_protection","flame","fortune","frost_walker","impaling","infinity","knockback","looting","loyalty","luck_of_the_sea","lunge","lure","mending","multishot","piercing","power","projectile_protection","protection","punch","quick_charge","respiration","riptide","sharpness","silk_touch","smite","soul_speed","sweeping_edge","swift_sneak","thorns","unbreaking","vanishing_curse","wind_burst"); @Override public List onTabComplete(CommandSender sender, Command cmd, String label, String[] args) { @@ -28,6 +30,16 @@ else if(args[0].equalsIgnoreCase("findbook")) { return StringUtil.copyPartialMatches(args[1].toUpperCase(), enchantments, new ArrayList<>()); return Collections.emptyList(); } + if(args[0].equalsIgnoreCase("createlocation") || args[0].equalsIgnoreCase("createshop") || args[0].equalsIgnoreCase("list") || args[0].equalsIgnoreCase("managestock") || args[0].equalsIgnoreCase("out") || args[0].equalsIgnoreCase("purgestock") || args[0].equalsIgnoreCase("removeallshops")) { + if(args.length == 2) { + final List playersOnline = new ArrayList<>(); + for(Player player:Bukkit.getOnlinePlayers()) { + playersOnline.add(player.getName()); + } + return StringUtil.copyPartialMatches(args[1].toLowerCase(), playersOnline, new ArrayList<>()); + } + return Collections.emptyList(); + } else { if(args.length < 2) return StringUtil.copyPartialMatches(args[0].toLowerCase(), shopCommands, new ArrayList<>()); diff --git a/src/com/minedhype/ishop/gui/GUI.java b/src/com/minedhype/ishop/gui/GUI.java index 9041d20..7adce99 100644 --- a/src/com/minedhype/ishop/gui/GUI.java +++ b/src/com/minedhype/ishop/gui/GUI.java @@ -35,17 +35,16 @@ public void onClose(InventoryCloseEvent e) { } public static ItemStack createItem(Material material, String number, short data) { ItemStack item = new ItemStack(material); ItemMeta meta = item.getItemMeta(); - if(meta != null) + if(meta != null) { meta.setDisplayName(ChatColor.RESET + number); - else - meta.setDisplayName("unnamed"); - meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); - meta.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS); - meta.addItemFlags(ItemFlag.HIDE_DESTROYS); - meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); - meta.addItemFlags(ItemFlag.HIDE_PLACED_ON); - meta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); - item.setItemMeta(meta); + meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); + meta.addItemFlags(ItemFlag.HIDE_ADDITIONAL_TOOLTIP); + meta.addItemFlags(ItemFlag.HIDE_DESTROYS); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + meta.addItemFlags(ItemFlag.HIDE_PLACED_ON); + meta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); + item.setItemMeta(meta); + } return item; } diff --git a/src/com/minedhype/ishop/iShop.java b/src/com/minedhype/ishop/iShop.java index 616eff5..f584e8b 100644 --- a/src/com/minedhype/ishop/iShop.java +++ b/src/com/minedhype/ishop/iShop.java @@ -25,7 +25,7 @@ import org.bukkit.util.io.BukkitObjectInputStream; import org.bukkit.util.io.BukkitObjectOutputStream; import com.minedhype.ishop.gui.GUIEvent; -import com.minedhype.ishop.MetricsLite; +import com.minedhype.ishop.Metrics; import net.milkbowl.vault.economy.Economy; import org.bukkit.scheduler.BukkitTask; import me.ryanhamshire.GriefPrevention.GriefPrevention; @@ -39,10 +39,11 @@ public class iShop extends JavaPlugin { public static LandsIntegration lands = null; public static boolean superiorSkyblock2Check; public static boolean townyCheck; - private static BukkitTask expiredTask, saveTask, tickTask; + private static BukkitTask expiredShopTask, expiredStockTask, saveTask, tickTask; private static Connection connection = null; private static Economy economy = null; private static String chainConnect; + private boolean lockdown; @Override public void onLoad() { @@ -109,7 +110,9 @@ public void onEnable() { Shop.loadData(); } catch(Exception e) { e.printStackTrace(); } }, delayTime); - expiredTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, Shop::expiredShops, delayTime+9, 20000); + lockdown = config.getBoolean("lockdownEnabledOnStart"); + expiredShopTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, Shop::expiredShops, delayTime+9, 20000); + expiredStockTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, StockShop::expiredStock, delayTime+200, 35000); saveTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> { try { Shop.saveData(false); @@ -118,8 +121,9 @@ public void onEnable() { if(Shop.shopEnabled && Shop.particleEffects) tickTask = Bukkit.getScheduler().runTaskTimerAsynchronously(this, Shop::tickShops, delayTime+250, 50); Bukkit.getScheduler().runTaskLaterAsynchronously(this, Shop::getPlayersShopList, delayTime+160); + Bukkit.getScheduler().runTaskLaterAsynchronously(this, StockShop::getPlayersStockList, delayTime+300); Bukkit.getScheduler().runTaskLaterAsynchronously(this, Shop::removeEmptyShopTrade, delayTime+100); - MetricsLite metrics = new MetricsLite(this, 9189); + Metrics metrics = new Metrics(this, 9189); new UpdateChecker(this, 84555).getVersion(version -> { if(!this.getDescription().getVersion().equalsIgnoreCase(version)) getServer().getConsoleSender().sendMessage(ChatColor.RED + "[iShop] There is a new update available! - https://www.spigotmc.org/resources/ishop.84555/"); @@ -145,19 +149,28 @@ public void onDisable() { } else saveTask.cancel(); - if(Bukkit.getScheduler().isCurrentlyRunning(expiredTask.getTaskId())) { - while(Bukkit.getScheduler().isCurrentlyRunning(expiredTask.getTaskId())) + if(Bukkit.getScheduler().isCurrentlyRunning(expiredStockTask.getTaskId())) { + while(Bukkit.getScheduler().isCurrentlyRunning(expiredStockTask.getTaskId())) ; - expiredTask.cancel(); + expiredStockTask.cancel(); } else - expiredTask.cancel(); + expiredStockTask.cancel(); + if(Bukkit.getScheduler().isCurrentlyRunning(expiredShopTask.getTaskId())) { + while(Bukkit.getScheduler().isCurrentlyRunning(expiredShopTask.getTaskId())) + ; + expiredShopTask.cancel(); + } + else + expiredShopTask.cancel(); if(!tickTask.isCancelled()) tickTask.cancel(); if(!saveTask.isCancelled()) saveTask.cancel(); - if(!expiredTask.isCancelled()) - expiredTask.cancel(); + if(!expiredStockTask.isCancelled()) + expiredStockTask.cancel(); + if(!expiredShopTask.isCancelled()) + expiredShopTask.cancel(); getServer().getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Safely saving shops & stock items to database, please wait & do not kill server process..."); Shop.saveData(true); getServer().getConsoleSender().sendMessage(ChatColor.GREEN + "[iShop] Saving complete!"); @@ -416,10 +429,22 @@ public void createConfig() { case "3.9": config.set("location", "&6Shop&a %id &6location XYZ:&a %x &6/&a %y &6/&a %z &6in&a %world"); case "3.10": - config.set("shopParticles", "villager_happy"); - config.set("configVersion", "3.11"); - config.save(configFile); + config.set("shopParticles", "happy_villager"); case "3.11": + config.set("shopParticles", "happy_villager"); + config.set("maxStockInactiveDays", 0); + List exemptExpiredStock = Arrays.asList("00000000-0000-0000-0000-000000000000"); + config.set("exemptExpiringStock", exemptExpiredStock); + config.set("deleteStockWhenShopsExpire", false); + config.set("lockdownEnabledOnStart", false); + config.set("showStockListItemForAdmin", true); + config.set("purgePlayersStock", "&7Shop stock has been &cPURGED&7 for &c%p&7!"); + config.set("lockdown","&cShops and stock are currently on lockdown."); + config.set("enableLockdown", "&7Lockdown has been &aenabled&7. Only shop admins can access shops, stocks, and commands."); + config.set("disableLockdown", "&7Lockdown has been &cdisabled&7. Players can access shops, stocks, and commands."); + config.set("configVersion", "3.12"); + config.save(configFile); + case "3.12": break; } } catch(IOException | InvalidConfigurationException e) { e.printStackTrace(); } @@ -427,4 +452,6 @@ public void createConfig() { public static iShop getPlugin() { return iShop.getPlugin(iShop.class); } + public boolean checkLockdown() { return lockdown; } + public void setLockdown(boolean setLock) { lockdown = setLock; } } diff --git a/src/com/minedhype/ishop/inventories/InvShopList.java b/src/com/minedhype/ishop/inventories/InvShopList.java index bcac599..fa55439 100644 --- a/src/com/minedhype/ishop/inventories/InvShopList.java +++ b/src/com/minedhype/ishop/inventories/InvShopList.java @@ -18,10 +18,10 @@ import java.util.UUID; public class InvShopList extends GUI { - private final static ArrayList shopslist = new ArrayList<>(); + private int pag; private final ItemStack airItem = new ItemStack(Material.AIR, 0); + private static final ArrayList shopslist = new ArrayList<>(); private static final ItemStack playerHead = new ItemStack(Material.PLAYER_HEAD,1); - private int pag; private InvShopList(String shopTitle) { super(54, shopTitle); @@ -83,7 +83,7 @@ private static void getShopList(UUID uuid) { catch(Exception e) { playerNotFound = true; } if(Shop.getShopById(id).get().isAdmin()) skullMeta.setDisplayName(Messages.ADMIN_SHOP_NUMBER.toString().replaceAll("%id", id.toString())); - else if(playerNotFound) + else if(playerNotFound || offlinePlayer.getName() == null) skullMeta.setDisplayName(Messages.SHOP_NUMBER.toString().replaceAll("%player", "Unknown Player").replaceAll("%id", id.toString())); else skullMeta.setDisplayName(Messages.SHOP_NUMBER.toString().replaceAll("%player", offlinePlayer.getName()).replaceAll("%id", id.toString())); diff --git a/src/com/minedhype/ishop/inventories/InvStock.java b/src/com/minedhype/ishop/inventories/InvStock.java index 9ae2937..50140e5 100644 --- a/src/com/minedhype/ishop/inventories/InvStock.java +++ b/src/com/minedhype/ishop/inventories/InvStock.java @@ -10,6 +10,7 @@ import com.minedhype.ishop.Shop; import com.minedhype.ishop.StockShop; import com.minedhype.ishop.gui.GUI; +import com.minedhype.ishop.iShop; import org.bukkit.Material; import org.bukkit.block.ShulkerBox; import org.bukkit.entity.Player; @@ -22,6 +23,7 @@ public class InvStock extends GUI { + public static boolean showStockListAdmin = iShop.config.getBoolean("showStockListItemForAdmin"); public static final HashMap inShopInv = new HashMap<>(); private static final List inventories = new ArrayList<>(); private final ItemStack airItem = new ItemStack(Material.AIR, 0); @@ -45,21 +47,21 @@ public void onClick(InventoryClickEvent event) { if(event.getRawSlot() >= 45 && event.getRawSlot() < 54) return; if(event.getRawSlot() >= 54 && !player.hasPermission(Permission.SHOP_ADMIN.toString())) { + ItemStack item = event.getCurrentItem(); + ItemStack item2 = event.getCursor(); + if(item == null && item2 == null) + return; + if(item == null) + item = airItem; + if(item2 == null) + item2 = airItem; if(InvCreateRow.strictStock) { - ItemStack item = event.getCurrentItem(); - ItemStack item2 = event.getCursor(); - if(Shop.strictStockShopCheck(item, owner) || Shop.strictStockShopCheck(item2, owner)) + if(Shop.strictStockShopCheck(item,item2,owner)) return; } if(InvCreateRow.itemsDisabled) { - ItemStack item = event.getCurrentItem(); - ItemStack item2 = event.getCursor(); for(String itemsList:InvCreateRow.disabledItemList) { Material disabledItemsList = Material.matchMaterial(itemsList); - if(item == null) - item = airItem; - if(item2 == null) - item2 = airItem; if(disabledItemsList != null) { if(!item.isSimilar(airItem)) { if(item.getType().equals(disabledItemsList)) @@ -118,6 +120,11 @@ public void refreshItems() { placeItem(i, GUI.createItem(Material.SPECTRAL_ARROW, Messages.SHOP_PAGE_SKIPPREV.toString()), p -> openPage(p, pag-5)); else if(i == 47 && pag > 0) placeItem(i, GUI.createItem(Material.ARROW, Messages.SHOP_PAGE + " " + (pag)), p -> openPage(p, pag-1)); + else if(i == 49 && showStockListAdmin && player != null && player.hasPermission(Permission.SHOP_ADMIN.toString())) + placeItem(i, GUI.createItem(Material.END_CRYSTAL,"List of Players with Stock"), p -> { + p.closeInventory(); + p.performCommand("shop liststock"); + }); else if(i == 51 && pag < stockPages-1) placeItem(i, GUI.createItem(Material.ARROW, Messages.SHOP_PAGE + " " + (pag+2)), p -> openPage(p, pag+1)); else if(i == 52 && pag < stockPages-5 && stockPages >= 10) diff --git a/src/com/minedhype/ishop/inventories/InvStockList.java b/src/com/minedhype/ishop/inventories/InvStockList.java new file mode 100644 index 0000000..d006573 --- /dev/null +++ b/src/com/minedhype/ishop/inventories/InvStockList.java @@ -0,0 +1,117 @@ +package com.minedhype.ishop.inventories; + +import com.minedhype.ishop.iShop; +import com.minedhype.ishop.StockShop; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; +import com.minedhype.ishop.Messages; +import com.minedhype.ishop.gui.GUI; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +public class InvStockList extends GUI { + + private int pag; + private final ItemStack airItem = new ItemStack(Material.AIR, 0); + private static final ArrayList stocklist = new ArrayList<>(); + private static final ItemStack playerHead = new ItemStack(Material.PLAYER_HEAD,1); + private InvStockList(String stockTitle) { super(54, stockTitle); } + public static InvStockList setStockTitle(String stockTitle) { return new InvStockList(stockTitle); } + public void setPag(int pag) { this.pag = pag; } + + @Override + public void onClick(InventoryClickEvent event) { + super.onClick(event); + if(event.getRawSlot() >= 45 && event.getRawSlot() < 54) + return; + if(!event.getAction().equals(InventoryAction.PLACE_ALL) && !event.getAction().equals(InventoryAction.PICKUP_ALL)) + return; + if(event.getCurrentItem() == null || event.getCurrentItem().getType().isAir()) + return; + if(event.isLeftClick() && Objects.requireNonNull(event.getCurrentItem().getItemMeta()).hasLore() && event.getCurrentItem().getType().equals(Material.PLAYER_HEAD)) { + event.setCancelled(true); + Player player = (Player) event.getWhoClicked(); + player.closeInventory(); + player.performCommand("shop managestock " + event.getCurrentItem().getItemMeta().getDisplayName()); + } + } + + private void PlayerStockList() { + int index = pag * 45; + for(int i = 0; i < 45; i++) { + if(index <= stocklist.size()-1) { + placeItem(i, stocklist.get(index)); + index++; + } else + placeItem(i, airItem); + } + int stockListPages = (int)Math.ceil(stocklist.size()-1)/44; + for(int i=45; i<54; i++) { + if(i == 47 && pag > 0) + placeItem(i, GUI.createItem(Material.ARROW, Messages.SHOP_PAGE + " " + (pag)), p -> openPage(p, pag-1)); + else if(i == 51 && pag < stockListPages) + placeItem(i, GUI.createItem(Material.ARROW, Messages.SHOP_PAGE + " " + (pag+2)), p -> openPage(p, pag+1)); + else + placeItem(i, GUI.createItem(Material.BLACK_STAINED_GLASS_PANE, "")); + } + } + + private static void getStockList() { + for(UUID uuid : StockShop.stockList.keySet()) { + if(uuid != null) { + ItemStack item = new ItemStack(playerHead); + SkullMeta skullMeta = (SkullMeta) item.getItemMeta(); + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); + boolean playerNotFound = false; + try { + skullMeta.setOwningPlayer(offlinePlayer); + } catch (Exception e) { + playerNotFound = true; + } + if(offlinePlayer.getName() != null && !playerNotFound) + skullMeta.setDisplayName(offlinePlayer.getName()); + List skullLore = new ArrayList<>(); + skullLore.add(uuid.toString()); + skullMeta.setLore(skullLore); + item.setItemMeta(skullMeta); + stocklist.add(item); + } + } + } + + private void openPage(Player player, int pag) { + for(int i=45; i<54; i++) + placeItem(i, new ItemStack(airItem)); + player.closeInventory(); + this.pag = pag; + this.open(player); + } + + @Override + public void open(Player player) { + stocklist.clear(); + final Player openPlayer = player; + Bukkit.getScheduler().runTaskAsynchronously(iShop.getPlugin(), () -> { + getStockList(); + Bukkit.getScheduler().runTask(iShop.getPlugin(), () -> { + PlayerStockList(); + super.open(openPlayer); + }); + }); + } + + @Override + public void onDrag(InventoryDragEvent event) { + super.onDrag(event); + event.setCancelled(true); + } +} \ No newline at end of file diff --git a/src/resources/config.yml b/src/resources/config.yml index cdd2bf8..57077e7 100644 --- a/src/resources/config.yml +++ b/src/resources/config.yml @@ -105,6 +105,14 @@ maxInactiveDays: 0 exemptExpiringShops: - 00000000-0000-0000-0000-000000000000 +# Amount of days a player is inactive before deleting their stock inventory +# Set to 0 to disable +maxStockInactiveDays: 0 + +# List of player UUID's that will be exempt from stock expiring if maxStockInactiveDays is set above 0 +exemptExpiringStock: + - 00000000-0000-0000-0000-000000000000 + # Remove block that the shop is located at when deleting or moving a shop deleteBlock: false @@ -188,7 +196,16 @@ findCommandCooldown: 5 publicMoveCommand: true # Change the particle effect (requires server restart) for shops to any Enum Constant Particle found at https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Particle.html -shopParticles: "villager_happy" +shopParticles: "happy_villager" + +# Delete player stock inventory when their shops expire +deleteStockWhenShopsExpire: false + +# Setting to true will enable lockdown mode on start up. Only players with the ishop.admin permission can access shops, stocks, and commands during lockdown mode. Can toggle on/off using lockdown command. +lockdownEnabledOnStart: false + +# Enable players with ishop.admin permission to see clickable End Crystal item for player stock list while in stock inventory +showStockListItemForAdmin: true # Customizable Messages adminShop: "Admin Shop #%id" @@ -280,5 +297,9 @@ findError: "&cGiven item to search shops for does not exist!" listFind: "&6Listing all found shop(s) trading &a%item&6:" nolistFind: "&cNo shop(s) have been found!" shopMoved: "&6Shop &a#%id &6has been moved to new targeted location!" +purgePlayersStock: "&7Shop stock has been &cPURGED&7 for &c%p&7!" +lockdown: "&cShops and stock are currently on lockdown." +enableLockdown: "&7Lockdown has been &aenabled&7. Only shop admins can access shops, stocks, and commands." +disableLockdown: "&7Lockdown has been &cdisabled&7. Players can access shops, stocks, and commands." # Do not edit this! -configVersion: 3.11 \ No newline at end of file +configVersion: 3.12 \ No newline at end of file diff --git a/src/resources/plugin.yml b/src/resources/plugin.yml index 873950d..7d569cb 100644 --- a/src/resources/plugin.yml +++ b/src/resources/plugin.yml @@ -4,7 +4,7 @@ description: Item trading shops with unique GUI! author: Beez0r website: https://minedhype.com version: "${project.version}" -api-version: "1.17" +api-version: "26.1" softdepend: [GriefPrevention, Lands, SuperiorSkyblock2, Towny, Vault, WorldGuard] commands: ishop: