diff --git a/pom.xml b/pom.xml index 176e028..8ac2ab4 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,10 @@ vault-repo http://nexus.hc.to/content/repositories/pub_releases/ + + sk89q-repo + http://maven.sk89q.com/artifactory/repo/ + @@ -57,6 +61,11 @@ 1.6 provided + + com.sk89q + worldguard + 6.1.1-SNAPSHOT + diff --git a/src/main/java/de/epiceric/shopchest/ShopChest.java b/src/main/java/de/epiceric/shopchest/ShopChest.java index 337ccfe..abfba73 100644 --- a/src/main/java/de/epiceric/shopchest/ShopChest.java +++ b/src/main/java/de/epiceric/shopchest/ShopChest.java @@ -1,5 +1,7 @@ package de.epiceric.shopchest; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.protection.managers.storage.StorageException; import de.epiceric.shopchest.config.Config; import de.epiceric.shopchest.config.Regex; import de.epiceric.shopchest.event.ShopReloadEvent; @@ -19,10 +21,13 @@ import de.epiceric.shopchest.utils.ShopUtils; import de.epiceric.shopchest.utils.UpdateChecker; import de.epiceric.shopchest.utils.UpdateChecker.UpdateCheckerResult; import de.epiceric.shopchest.utils.Utils; +import de.epiceric.shopchest.worldguard.ShopFlag; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; +import org.bukkit.World; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; @@ -45,6 +50,7 @@ public class ShopChest extends JavaPlugin { private ShopUtils shopUtils; private File debugLogFile; private FileWriter fw; + private WorldGuardPlugin worldGuard; /** * @return An instance of ShopChest @@ -138,6 +144,23 @@ public class ShopChest extends JavaPlugin { getLogger().warning("Plugin may still work, but more errors are expected!"); } + Plugin worldGuardPlugin = Bukkit.getServer().getPluginManager().getPlugin("WorldGuard"); + if (worldGuardPlugin instanceof WorldGuardPlugin) { + worldGuard = (WorldGuardPlugin) worldGuardPlugin; + ShopFlag.init(); + + try { + // Reload WorldGuard regions, so that custom flags are applied + for (World world : getServer().getWorlds()) { + worldGuard.getRegionManager(world).load(); + } + } catch (StorageException e) { + getLogger().severe("Failed to reload WorldGuard region manager. WorldGuard support will probably not work!"); + debug("Failed to load WorldGuard region manager"); + debug(e); + } + } + debug("Loading utils and extras..."); LanguageUtils.load(); @@ -298,6 +321,9 @@ public class ShopChest extends JavaPlugin { if (!Utils.getServerVersion().equals("v1_8_R1")) getServer().getPluginManager().registerEvents(new BlockExplodeListener(this), this); + if (hasWorldGuard()) + getServer().getPluginManager().registerEvents(new WorldGuardListener(this), this); + initializeShops(); } @@ -369,6 +395,20 @@ public class ShopChest extends JavaPlugin { debug("Initialized " + count + " Shops"); } + /** + * @return Whether the plugin 'WorldGuard' is enabled + */ + public boolean hasWorldGuard() { + return worldGuard != null; + } + + /** + * @return An instance of {@link WorldGuardPlugin} or {@code null} if WorldGuard is not enabled + */ + public WorldGuardPlugin getWorldGuard() { + return worldGuard; + } + /** * @return ShopChest's {@link ShopUtils} containing some important methods */ diff --git a/src/main/java/de/epiceric/shopchest/listeners/ShopInteractListener.java b/src/main/java/de/epiceric/shopchest/listeners/ShopInteractListener.java index 94786c1..e5c1958 100644 --- a/src/main/java/de/epiceric/shopchest/listeners/ShopInteractListener.java +++ b/src/main/java/de/epiceric/shopchest/listeners/ShopInteractListener.java @@ -1,5 +1,9 @@ package de.epiceric.shopchest.listeners; +import com.sk89q.worldguard.bukkit.RegionContainer; +import com.sk89q.worldguard.bukkit.RegionQuery; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.protection.flags.StateFlag; import de.epiceric.shopchest.ShopChest; import de.epiceric.shopchest.config.Config; import de.epiceric.shopchest.config.Regex; @@ -15,6 +19,7 @@ import de.epiceric.shopchest.sql.Database; import de.epiceric.shopchest.utils.ClickType; import de.epiceric.shopchest.utils.ShopUtils; import de.epiceric.shopchest.utils.Utils; +import de.epiceric.shopchest.worldguard.ShopFlag; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.EconomyResponse; import net.milkbowl.vault.permission.Permission; @@ -49,6 +54,7 @@ public class ShopInteractListener implements Listener { private Database database; private ShopUtils shopUtils; private Config config; + private WorldGuardPlugin worldGuard; public ShopInteractListener(ShopChest plugin) { this.plugin = plugin; @@ -57,6 +63,7 @@ public class ShopInteractListener implements Listener { this.database = plugin.getShopDatabase(); this.shopUtils = plugin.getShopUtils(); this.config = plugin.getShopChestConfig(); + this.worldGuard = plugin.getWorldGuard(); } @EventHandler(priority = EventPriority.HIGH) @@ -70,10 +77,20 @@ public class ShopInteractListener implements Listener { if (ClickType.getPlayerClickType(p) != null) { if (ClickType.getPlayerClickType(p).getClickType() == ClickType.EnumClickType.CREATE) { if (!shopUtils.isShop(b.getLocation())) { - if (e.isCancelled() && !perm.has(p, "shopchest.create.protected")) { + + boolean worldGuardAllowed = true; + + if (plugin.hasWorldGuard()) { + RegionContainer container = worldGuard.getRegionContainer(); + RegionQuery query = container.createQuery(); + worldGuardAllowed = query.testState(b.getLocation(), p, ShopFlag.CREATE_SHOP); + } + + if ((e.isCancelled() || !worldGuardAllowed) && !perm.has(p, "shopchest.create.protected")) { p.sendMessage(LanguageUtils.getMessage(LocalizedMessage.Message.NO_PERMISSION_CREATE_PROTECTED)); ClickType.removePlayerClickType(p); plugin.debug(p.getName() + " is not allowed to create a shop on the selected chest"); + e.setCancelled(true); return; } @@ -181,19 +198,41 @@ public class ShopInteractListener implements Listener { plugin.debug(p.getName() + " wants to buy"); if (shop.getBuyPrice() > 0) { if (perm.has(p, "shopchest.buy")) { + boolean worldGuardAllowed = true; + if (shop.getShopType() == ShopType.ADMIN) { - buy(p, shop); - } else { - Chest c = (Chest) b.getState(); - if (Utils.getAmount(c.getInventory(), shop.getProduct()) >= shop.getProduct().getAmount()) { + if (plugin.hasWorldGuard()) { + RegionContainer container = worldGuard.getRegionContainer(); + RegionQuery query = container.createQuery(); + worldGuardAllowed = query.testState(b.getLocation(), p, ShopFlag.USE_ADMIN_SHOP); + } + + if (worldGuardAllowed) { buy(p, shop); } else { - if (config.auto_calculate_item_amount && Utils.getAmount(c.getInventory(), shop.getProduct()) > 0) { + plugin.debug(p.getName() + " doesn't have worldguard permission"); + } + } else { + if (plugin.hasWorldGuard()) { + RegionContainer container = worldGuard.getRegionContainer(); + RegionQuery query = container.createQuery(); + worldGuardAllowed = query.testState(b.getLocation(), p, ShopFlag.USE_SHOP); + } + + if (worldGuardAllowed) { + Chest c = (Chest) b.getState(); + if (Utils.getAmount(c.getInventory(), shop.getProduct()) >= shop.getProduct().getAmount()) { buy(p, shop); } else { - p.sendMessage(LanguageUtils.getMessage(LocalizedMessage.Message.OUT_OF_STOCK)); - plugin.debug("Shop is out of stock"); + if (config.auto_calculate_item_amount && Utils.getAmount(c.getInventory(), shop.getProduct()) > 0) { + buy(p, shop); + } else { + p.sendMessage(LanguageUtils.getMessage(LocalizedMessage.Message.OUT_OF_STOCK)); + plugin.debug("Shop is out of stock"); + } } + } else { + plugin.debug(p.getName() + " doesn't have worldguard permission"); } } } else { @@ -226,15 +265,29 @@ public class ShopInteractListener implements Listener { plugin.debug(p.getName() + " wants to sell"); if (shop.getSellPrice() > 0) { if (perm.has(p, "shopchest.sell")) { - if (Utils.getAmount(p.getInventory(), shop.getProduct()) >= shop.getProduct().getAmount()) { - sell(p, shop); - } else { - if (config.auto_calculate_item_amount && Utils.getAmount(p.getInventory(), shop.getProduct()) > 0) { + boolean worldGuardAllowed = true; + + if (plugin.hasWorldGuard()) { + RegionContainer container = worldGuard.getRegionContainer(); + RegionQuery query = container.createQuery(); + + StateFlag flag = (shop.getShopType() == ShopType.ADMIN ? ShopFlag.USE_ADMIN_SHOP : ShopFlag.USE_SHOP); + worldGuardAllowed = query.testState(b.getLocation(), p, flag); + } + + if (worldGuardAllowed) { + if (Utils.getAmount(p.getInventory(), shop.getProduct()) >= shop.getProduct().getAmount()) { sell(p, shop); } else { - p.sendMessage(LanguageUtils.getMessage(LocalizedMessage.Message.NOT_ENOUGH_ITEMS)); - plugin.debug(p.getName() + " doesn't have enough items"); + if (config.auto_calculate_item_amount && Utils.getAmount(p.getInventory(), shop.getProduct()) > 0) { + sell(p, shop); + } else { + p.sendMessage(LanguageUtils.getMessage(LocalizedMessage.Message.NOT_ENOUGH_ITEMS)); + plugin.debug(p.getName() + " doesn't have enough items"); + } } + } else { + plugin.debug(p.getName() + " doesn't have worldguard permission"); } } else { p.sendMessage(LanguageUtils.getMessage(LocalizedMessage.Message.NO_PERMISSION_SELL)); diff --git a/src/main/java/de/epiceric/shopchest/listeners/WorldGuardListener.java b/src/main/java/de/epiceric/shopchest/listeners/WorldGuardListener.java new file mode 100644 index 0000000..c84fd16 --- /dev/null +++ b/src/main/java/de/epiceric/shopchest/listeners/WorldGuardListener.java @@ -0,0 +1,112 @@ +package de.epiceric.shopchest.listeners; + +import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.bukkit.RegionContainer; +import com.sk89q.worldguard.bukkit.RegionQuery; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.bukkit.event.block.UseBlockEvent; +import com.sk89q.worldguard.protection.flags.StateFlag; +import de.epiceric.shopchest.ShopChest; +import de.epiceric.shopchest.shop.Shop; +import de.epiceric.shopchest.utils.ClickType; +import de.epiceric.shopchest.worldguard.ShopFlag; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.player.PlayerInteractEvent; + +public class WorldGuardListener implements Listener { + + private ShopChest plugin; + private WorldGuardPlugin worldGuard; + + public WorldGuardListener(ShopChest plugin) { + this.plugin = plugin; + this.worldGuard = plugin.getWorldGuard(); + } + + + private boolean isAllowed(UseBlockEvent event, Location location, Action action) { + Player p = event.getCause().getFirstPlayer(); + + LocalPlayer localPlayer = worldGuard.wrapPlayer(p); + RegionContainer container = worldGuard.getRegionContainer(); + RegionQuery query = container.createQuery(); + + if (action == Action.RIGHT_CLICK_BLOCK) { + + if (ClickType.getPlayerClickType(p) != null) { + + switch (ClickType.getPlayerClickType(p).getClickType()) { + + case CREATE: + return query.testState(location, localPlayer, ShopFlag.CREATE_SHOP); + case REMOVE: + case INFO: + return true; + } + } else { + if (plugin.getShopUtils().isShop(location)) { + Shop shop = plugin.getShopUtils().getShop(location); + + if (shop.getVendor().getUniqueId().equals(p.getUniqueId()) && shop.getShopType() != Shop.ShopType.ADMIN) { + return true; + } + + if (!shop.getVendor().getUniqueId().equals(p.getUniqueId()) && p.isSneaking()) { + return p.hasPermission("shopchest.openOther"); + } + + StateFlag flag = (shop.getShopType() == Shop.ShopType.NORMAL ? ShopFlag.USE_SHOP : ShopFlag.USE_ADMIN_SHOP); + + return query.testState(location, localPlayer, flag); + } + } + } else if (action == Action.LEFT_CLICK_BLOCK) { + if (plugin.getShopUtils().isShop(location)) { + Shop shop = plugin.getShopUtils().getShop(location); + + StateFlag flag = (shop.getShopType() == Shop.ShopType.NORMAL ? ShopFlag.USE_SHOP : ShopFlag.USE_ADMIN_SHOP); + + return query.testState(location, localPlayer, flag); + } + } + + return false; + } + + @EventHandler(priority = EventPriority.LOW) + public void onUseBlock(UseBlockEvent event) { + if (event.getCause().getFirstPlayer() == null) return; + + if (event.getOriginalEvent() instanceof PlayerInteractEvent) { + PlayerInteractEvent orig = (PlayerInteractEvent) event.getOriginalEvent(); + + if (orig.hasBlock()) { + Material type = orig.getClickedBlock().getType(); + if (type == Material.CHEST || type == Material.TRAPPED_CHEST) { + if (isAllowed(event, orig.getClickedBlock().getLocation(), orig.getAction())) { + event.setAllowed(true); + orig.setCancelled(false); + } + } + } + } else if (event.getOriginalEvent() instanceof InventoryOpenEvent) { + InventoryOpenEvent orig = (InventoryOpenEvent) event.getOriginalEvent(); + + if (orig.getInventory().getType() == InventoryType.CHEST) { + if (isAllowed(event, orig.getInventory().getLocation(), Action.RIGHT_CLICK_BLOCK)) { + event.setAllowed(true); + orig.setCancelled(false); + } + } + } + } + +} diff --git a/src/main/java/de/epiceric/shopchest/worldguard/ShopFlag.java b/src/main/java/de/epiceric/shopchest/worldguard/ShopFlag.java new file mode 100644 index 0000000..f306771 --- /dev/null +++ b/src/main/java/de/epiceric/shopchest/worldguard/ShopFlag.java @@ -0,0 +1,46 @@ +package de.epiceric.shopchest.worldguard; + +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.flags.StateFlag; +import org.bukkit.Bukkit; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +public class ShopFlag { + + private static Flag[] customFlagList; + + public static final StateFlag CREATE_SHOP; + public static final StateFlag USE_SHOP; + public static final StateFlag USE_ADMIN_SHOP; + + static { + CREATE_SHOP = new StateFlag("create-shop", false); + USE_SHOP = new StateFlag("use-shop", false); + USE_ADMIN_SHOP = new StateFlag("use-admin-shop", false); + + customFlagList = new Flag[] {CREATE_SHOP, USE_SHOP, USE_ADMIN_SHOP}; + } + + public static void init() { + // Add custom flags to WorldGuard's flag list + try { + Field flagListField = DefaultFlag.class.getField("flagsList"); + + Flag[] flags = new Flag[DefaultFlag.flagsList.length + customFlagList.length]; + System.arraycopy(DefaultFlag.flagsList, 0, flags, 0, DefaultFlag.flagsList.length); + System.arraycopy(customFlagList, 0, flags, DefaultFlag.flagsList.length, customFlagList.length); + + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(flagListField, flagListField.getModifiers() & ~Modifier.FINAL); + + flagListField.set(null, flags); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index c1fc722..b537f59 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -5,6 +5,7 @@ main: de.epiceric.shopchest.ShopChest version: ${project.version} author: EpicEric website: ${project.url} +softdepend: [WorldGuard] depend: [Vault] permissions: @@ -55,7 +56,7 @@ permissions: description: Allows you to check for updates. default: op shopchest.limit.*: - default: op + default: true shopchest.config: description: Allows you to change configuration values per command. default: op