relatedHistory;
+
+ if (isWildcard) {
+ relatedHistory = lwc.getPhysicalDatabase().loadHistory((page - 1) * ITEMS_PER_PAGE, ITEMS_PER_PAGE);
+ historyCount = lwc.getPhysicalDatabase().getHistoryCount();
+ } else {
+ relatedHistory = lwc.getPhysicalDatabase().loadHistory(playerName, (page - 1) * ITEMS_PER_PAGE, ITEMS_PER_PAGE);
+ historyCount = lwc.getPhysicalDatabase().getHistoryCount(playerName);
+ }
+
+ // Calculate page count
+ if (historyCount > 0) {
+ pageCount = (int) Math.floor(historyCount / (page * ITEMS_PER_PAGE));
+
+ // compensate for what's left
+ while ((pageCount * ITEMS_PER_PAGE) < historyCount) {
+ pageCount++;
+ }
+ }
+
+ // Were there any usable results?
+ if (relatedHistory.size() == 0) {
+ lwc.sendLocale(sender, "lwc.noresults");
+ return;
+ }
+
+ // Is it a valid page? (this normally will NOT happen, with the previous statement in place!)
+ if (page > pageCount) {
+ lwc.sendLocale(sender, "lwc.noresults");
+ return;
+ }
+
+ // Send it to them
+ sendHistoryList(sender, relatedHistory, page, pageCount, historyCount);
+ }
+
+ @Override
+ public void onCommand(LWCCommandEvent event) {
+ if (event.isCancelled()) {
+ return;
+ }
+
+ if (event.hasFlag("h", "history")) {
+ doHistoryCommand(event);
+ } else if (event.hasFlag("d", "details")) {
+ doDetailsCommand(event);
+ }
+ }
+
+}
diff --git a/core/src/main/java/com/griefcraft/modules/info/InfoModule.java b/core/src/main/java/com/griefcraft/modules/info/InfoModule.java
new file mode 100644
index 000000000..4630a83db
--- /dev/null
+++ b/core/src/main/java/com/griefcraft/modules/info/InfoModule.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2011 Tyler Blair. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and contributors and should not be interpreted as representing official policies,
+ * either expressed or implied, of anybody else.
+ */
+
+package com.griefcraft.modules.info;
+
+import com.griefcraft.lwc.LWC;
+import com.griefcraft.model.Action;
+import com.griefcraft.model.LWCPlayer;
+import com.griefcraft.model.Permission;
+import com.griefcraft.model.Protection;
+import com.griefcraft.scripting.JavaModule;
+import com.griefcraft.scripting.event.LWCBlockInteractEvent;
+import com.griefcraft.scripting.event.LWCCommandEvent;
+import com.griefcraft.scripting.event.LWCProtectionInteractEvent;
+import org.bukkit.block.Block;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class InfoModule extends JavaModule {
+
+ @Override
+ public void onProtectionInteract(LWCProtectionInteractEvent event) {
+ if (event.getResult() != Result.DEFAULT) {
+ return;
+ }
+
+ if (!event.hasAction("info")) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ Protection protection = event.getProtection();
+ Player player = event.getPlayer();
+ event.setResult(Result.CANCEL);
+
+ String type = lwc.getPlugin().getMessageParser().parseMessage(protection.typeToString().toLowerCase());
+
+ lwc.sendLocale(player, "lwc.info", "owner", protection.getFormattedOwnerPlayerName(), "type", type);
+
+ if (event.canAdmin()) {
+ if (protection.getType() == Protection.Type.PRIVATE || protection.getType() == Protection.Type.DONATION) {
+ lwc.sendLocale(player, "lwc.acl", "size", protection.getPermissions().size());
+ int index = 0;
+ for (Permission permission : protection.getPermissions()) {
+ if (index >= 9) {
+ break;
+ }
+
+ player.sendMessage(permission.toString());
+ index ++;
+ }
+
+ if (index == 0) {
+ lwc.sendLocale(player, "lwc.acl.empty");
+ } else if (index >= 9) {
+ lwc.sendLocale(player, "lwc.acl.limitreached");
+ }
+
+ player.sendMessage("");
+ }
+ }
+
+ if (lwc.isAdmin(player)) {
+ lwc.sendLocale(player, "protection.interact.info.raw", "raw", protection.toString());
+ }
+
+ lwc.removeModes(player);
+ }
+
+ @Override
+ public void onBlockInteract(LWCBlockInteractEvent event) {
+ if (event.getResult() != Result.DEFAULT) {
+ return;
+ }
+
+ if (!event.hasAction("info")) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ Block block = event.getBlock();
+ Player player = event.getPlayer();
+ event.setResult(Result.CANCEL);
+
+ lwc.sendLocale(player, "protection.interact.error.notregistered", "block", LWC.materialToString(block));
+ lwc.removeModes(player);
+ }
+
+ @Override
+ public void onCommand(LWCCommandEvent event) {
+ if (event.isCancelled()) {
+ return;
+ }
+
+ if (!event.hasFlag("i", "info")) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ CommandSender sender = event.getSender();
+ String[] args = event.getArgs();
+
+ if (!(sender instanceof Player)) {
+ return;
+ }
+
+ event.setCancelled(true);
+
+ if (!lwc.hasPlayerPermission(sender, "lwc.info")) {
+ lwc.sendLocale(sender, "protection.accessdenied");
+ return;
+ }
+
+ LWCPlayer player = lwc.wrapPlayer(sender);
+ String type = "info";
+
+ if (args.length > 0) {
+ type = args[0].toLowerCase();
+ }
+
+ if (type.equals("info")) {
+ Action action = new Action();
+ action.setName("info");
+ action.setPlayer(player);
+
+ player.removeAllActions();
+ player.addAction(action);
+
+ lwc.sendLocale(player, "protection.info.finalize");
+ } else if (type.equals("history")) {
+ Action action = new Action();
+ action.setName("history");
+ action.setData("0");
+ action.setPlayer(player);
+
+ player.removeAllActions();
+ player.addAction(action);
+
+ lwc.sendLocale(player, "protection.info.finalize");
+ }
+ }
+
+}
diff --git a/core/src/main/java/com/griefcraft/modules/limits/LimitsModule.java b/core/src/main/java/com/griefcraft/modules/limits/LimitsModule.java
new file mode 100644
index 000000000..4f305782b
--- /dev/null
+++ b/core/src/main/java/com/griefcraft/modules/limits/LimitsModule.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright 2011 Tyler Blair. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and contributors and should not be interpreted as representing official policies,
+ * either expressed or implied, of anybody else.
+ */
+
+package com.griefcraft.modules.limits;
+
+import com.griefcraft.lwc.LWC;
+import com.griefcraft.scripting.JavaModule;
+import com.griefcraft.scripting.event.LWCProtectionRegisterEvent;
+import com.griefcraft.util.config.Configuration;
+import org.apache.commons.lang.StringUtils;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.permissions.PermissionAttachmentInfo;
+
+public class LimitsModule extends JavaModule {
+
+ /**
+ * The permission node for type: default protections
+ */
+ public static final String PERMISSION_NODE_GLOBAL = "lwc.limit.";
+
+ /**
+ * NODE.BLOCK.limit
+ */
+ public static final String PERMISSION_NODE_BLOCK = "lwc.limit.block.";
+
+ /**
+ * Limits type
+ */
+ public enum Type {
+ /**
+ * Undefined type
+ */
+ NULL,
+
+ /**
+ * Combines all blocks together into one
+ * This type ignores chest:, furnace:, etc
+ */
+ DEFAULT,
+
+ /**
+ * Limits are defined per-block
+ */
+ CUSTOM;
+
+ public static Type resolve(String name) {
+ for (Type type : values()) {
+ if (type.toString().equalsIgnoreCase(name)) {
+ return type;
+ }
+ }
+
+ return NULL;
+ }
+ }
+
+ private Configuration configuration = Configuration.load("limits.yml", false);
+
+ /**
+ * Integer value that represents unlimited protections
+ */
+ private int UNLIMITED = Integer.MAX_VALUE;
+
+ /**
+ * If protection limits are enabled
+ */
+ private boolean enabled = true;
+
+ public LimitsModule() {
+ enabled = LWC.getInstance().getConfiguration().getBoolean("optional.useProtectionLimits", true);
+ }
+
+ /**
+ * Set a config value in the configuration
+ *
+ * @param path
+ * @param value
+ */
+ public void set(String path, Object value) {
+ configuration.setProperty(path, value);
+ }
+
+ /**
+ * Save the configuration
+ */
+ public boolean save() {
+ return configuration.save();
+ }
+
+ /**
+ * Check if a player has reached their protection limit for a specific block type
+ *
+ * @param player
+ * @param block
+ * @return true if the player reached their limit
+ */
+ public boolean hasReachedLimit(Player player, Block block) {
+ if (configuration == null) {
+ return false;
+ }
+
+ LWC lwc = LWC.getInstance();
+ int limit = mapProtectionLimit(player, block.getTypeId());
+
+ // if they're limit is unlimited, how could they get above it? :)
+ if (limit == UNLIMITED) {
+ return false;
+ }
+
+ Type type = Type.resolve(resolveString(player, "type"));
+ int protections; // 0 = *
+
+ switch (type) {
+ case CUSTOM:
+ protections = lwc.getPhysicalDatabase().getProtectionCount(player.getName(), block.getTypeId());
+ break;
+
+ case DEFAULT:
+ protections = lwc.getPhysicalDatabase().getProtectionCount(player.getName());
+ break;
+
+ default:
+ throw new UnsupportedOperationException("Limit type " + type.toString() + " is undefined in LimitsModule::hasReachedLimit");
+ }
+
+ return protections >= limit;
+ }
+
+ /**
+ * Search the player's permissions for a permission and return it
+ * Depending on this is used, this can become O(scary)
+ *
+ * @param player
+ * @param prefix
+ * @return
+ */
+ public PermissionAttachmentInfo searchPermissions(Player player, String prefix) {
+ for (PermissionAttachmentInfo attachment : player.getEffectivePermissions()) {
+ String permission = attachment.getPermission();
+
+ // check for the perm node
+ if (attachment.getValue() && permission.startsWith(prefix)) {
+ // Bingo!
+ return attachment;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Search permissions for an integer and if found, return it
+ *
+ * @param player
+ * @param prefix
+ * @return
+ */
+ public int searchPermissionsForInteger(Player player, String prefix) {
+ PermissionAttachmentInfo attachment = searchPermissions(player, prefix);
+
+ // Not found
+ if (attachment == null) {
+ return -1;
+ }
+
+ // Found
+ return Integer.parseInt(attachment.getPermission().substring(prefix.length()));
+ }
+
+ /**
+ * Get the protection limits for a player
+ *
+ * @param player
+ * @param blockId
+ * @return
+ */
+ public int mapProtectionLimit(Player player, int blockId) {
+ if (configuration == null) {
+ return 0;
+ }
+
+ int limit = -1;
+ Type type = Type.resolve(resolveString(player, "type"));
+
+ // Try permissions
+ int globalLimit = searchPermissionsForInteger(player, PERMISSION_NODE_GLOBAL);
+
+ // Was it found?
+ if (globalLimit >= 0) {
+ return globalLimit;
+ }
+
+ // Try the block id now
+ int blockLimit = searchPermissionsForInteger(player, PERMISSION_NODE_BLOCK + blockId + ".");
+
+ if (blockLimit != -1) {
+ return blockLimit;
+ }
+
+ switch (type) {
+
+ case DEFAULT:
+ limit = resolveInteger(player, "limit");
+ break;
+
+ case CUSTOM:
+ // first try the block id
+ limit = resolveInteger(player, blockId + "");
+
+ // and now try the name
+ if (limit == -1 && blockId > 0) {
+ String name = StringUtils.replace(Material.getMaterial(blockId).toString().toLowerCase(), "block", "");
+
+ if (name.endsWith("_")) {
+ name = name.substring(0, name.length() - 1);
+ }
+
+ limit = resolveInteger(player, name);
+ }
+
+ // if it's STILL null, fall back
+ if (limit == -1) {
+ limit = resolveInteger(player, "limit");
+ }
+ break;
+
+ }
+
+ return limit == -1 ? UNLIMITED : limit;
+ }
+
+ /**
+ * Resolve a configuration node for a player. Tries nodes in this order:
+ *
+ * players.PLAYERNAME.node
+ * groups.GROUPNAME.node
+ * master.node
+ *
+ *
+ * @param player
+ * @param node
+ * @return
+ */
+ private String resolveString(Player player, String node) {
+ LWC lwc = LWC.getInstance();
+
+ // resolve the limits type
+ String value;
+
+ // try the player
+ value = configuration.getString("players." + player.getName() + "." + node);
+
+ // try the player's groups
+ if (value == null) {
+ for (String groupName : lwc.getPermissions().getGroups(player)) {
+ if (groupName != null && !groupName.isEmpty() && value == null) {
+ value = map("groups." + groupName + "." + node);
+ }
+ }
+ }
+
+ // if all else fails, use master
+ if (value == null) {
+ value = map("master." + node);
+ }
+
+ return value != null && !value.isEmpty() ? value : null;
+ }
+
+ /**
+ * Resolve an integer for a player
+ *
+ * @param player
+ * @param node
+ * @return
+ */
+ private int resolveInteger(Player player, String node) {
+ LWC lwc = LWC.getInstance();
+
+ // resolve the limits type
+ int value = -1;
+
+ // try the player
+ String temp = configuration.getString("players." + player.getName() + "." + node);
+
+ if (temp != null && !temp.isEmpty()) {
+ value = parseInt(temp);
+ }
+
+ // try the player's groups
+ if (value == -1) {
+ for (String groupName : lwc.getPermissions().getGroups(player)) {
+ if (groupName != null && !groupName.isEmpty()) {
+ temp = map("groups." + groupName + "." + node);
+
+ if (temp != null && !temp.isEmpty()) {
+ int resolved = parseInt(temp);
+
+ // Is it higher than what we already have?
+ if (resolved > value) {
+ value = resolved;
+ }
+ }
+ }
+ }
+ }
+
+ // if all else fails, use master
+ if (value == -1) {
+ temp = map("master." + node);
+
+ if (temp != null && !temp.isEmpty()) {
+ value = parseInt(temp);
+ }
+ }
+
+ // Default to 0, not -1 if it is still -1
+ return value;
+ }
+
+ /**
+ * Parse an int
+ *
+ * @param input
+ * @return
+ */
+ private int parseInt(String input) {
+ if (input.equalsIgnoreCase("unlimited")) {
+ return UNLIMITED;
+ }
+
+ return Integer.parseInt(input);
+ }
+
+ /**
+ * Get the value from either the path or the master value if it's null
+ *
+ * @param path
+ * @return
+ */
+ private String map(String path) {
+ String value = configuration.getString(path);
+
+ if (value == null) {
+ int lastIndex = path.lastIndexOf(".");
+ String node = path.substring(lastIndex + 1);
+
+ value = configuration.getString("master." + node);
+ }
+
+ if (value == null) {
+ value = "";
+ }
+
+ return value;
+ }
+
+ @Override
+ public void onRegisterProtection(LWCProtectionRegisterEvent event) {
+ if (!enabled || event.isCancelled()) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ Player player = event.getPlayer();
+ Block block = event.getBlock();
+
+ if (hasReachedLimit(player, block)) {
+ lwc.sendLocale(player, "protection.exceeded");
+ event.setCancelled(true);
+ }
+ }
+
+}
diff --git a/core/src/main/java/com/griefcraft/modules/limits/LimitsV2.java b/core/src/main/java/com/griefcraft/modules/limits/LimitsV2.java
new file mode 100644
index 000000000..1d19b1da8
--- /dev/null
+++ b/core/src/main/java/com/griefcraft/modules/limits/LimitsV2.java
@@ -0,0 +1,673 @@
+/*
+ * Copyright 2011 Tyler Blair. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and contributors and should not be interpreted as representing official policies,
+ * either expressed or implied, of anybody else.
+ */
+
+package com.griefcraft.modules.limits;
+
+import com.griefcraft.lwc.LWC;
+import com.griefcraft.scripting.JavaModule;
+import com.griefcraft.scripting.event.LWCCommandEvent;
+import com.griefcraft.scripting.event.LWCProtectionRegisterEvent;
+import com.griefcraft.scripting.event.LWCReloadEvent;
+import com.griefcraft.util.Colors;
+import com.griefcraft.util.config.Configuration;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.permissions.PermissionAttachmentInfo;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class LimitsV2 extends JavaModule {
+
+ /**
+ * The limit represented by unlimited
+ */
+ public final static int UNLIMITED = Integer.MAX_VALUE;
+
+ /**
+ * If the limits module is enabled
+ */
+ private boolean enabled = true;
+
+ /**
+ * The limits configuration
+ */
+ private final Configuration configuration = Configuration.load("limitsv2.yml");
+
+ /**
+ * A map of the default limits
+ */
+ private final List defaultLimits = new LinkedList();
+
+ /**
+ * A map of all of the player limits
+ */
+ private final Map> playerLimits = new HashMap>();
+
+ /**
+ * A map of all of the group limits - downcasted to lowercase to simplify comparisons
+ */
+ private final Map> groupLimits = new HashMap>();
+
+ /**
+ * A map mapping string representations of materials to their Material counterpart
+ */
+ private final Map materialCache = new HashMap();
+
+ {
+ for (Material material : Material.values()) {
+ String materialName = LWC.normalizeMaterialName(material);
+
+ // add the name & the block id
+ materialCache.put(materialName, material);
+ materialCache.put(material.getId() + "", material);
+ materialCache.put(materialName, material);
+
+ if (!materialName.equals(material.toString().toLowerCase())) {
+ materialCache.put(material.toString().toLowerCase(), material);
+ }
+ }
+ }
+
+ public abstract class Limit {
+
+ /**
+ * The limit
+ */
+ private final int limit;
+
+ public Limit(int limit) {
+ this.limit = limit;
+ }
+
+ /**
+ * Get the player's protection count that should be used with this limit
+ *
+ * @param player
+ * @param material
+ * @return
+ */
+ public abstract int getProtectionCount(Player player, Material material);
+
+ /**
+ * @return
+ */
+ public int getLimit() {
+ return limit;
+ }
+ }
+
+ public final class DefaultLimit extends Limit {
+
+ public DefaultLimit(int limit) {
+ super(limit);
+ }
+
+ @Override
+ public int getProtectionCount(Player player, Material material) {
+ return LWC.getInstance().getPhysicalDatabase().getProtectionCount(player.getName());
+ }
+
+ }
+
+ public final class BlockLimit extends Limit {
+
+ /**
+ * The block material to limit
+ */
+ private final Material material;
+
+ public BlockLimit(Material material, int limit) {
+ super(limit);
+ this.material = material;
+ }
+
+ @Override
+ public int getProtectionCount(Player player, Material material) {
+ return LWC.getInstance().getPhysicalDatabase().getProtectionCount(player.getName(), material.getId());
+ }
+
+ /**
+ * @return
+ */
+ public Material getMaterial() {
+ return material;
+ }
+
+ }
+
+ public final class SignLimit extends Limit {
+
+ public SignLimit(int limit) {
+ super(limit);
+ }
+
+ @Override
+ public int getProtectionCount(Player player, Material material) {
+ LWC lwc = LWC.getInstance();
+ return lwc.getPhysicalDatabase().getProtectionCount(player.getName(), Material.SIGN_POST.getId())
+ + lwc.getPhysicalDatabase().getProtectionCount(player.getName(), Material.WALL_SIGN.getId());
+ }
+
+ }
+
+ public LimitsV2() {
+ enabled = LWC.getInstance().getConfiguration().getBoolean("optional.useProtectionLimits", true);
+
+ if (enabled) {
+ loadLimits();
+ }
+ }
+
+ @Override
+ public void onReload(LWCReloadEvent event) {
+ if (enabled) {
+ reload();
+ }
+ }
+
+ @Override
+ public void onRegisterProtection(LWCProtectionRegisterEvent event) {
+ if (!enabled || event.isCancelled()) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ Player player = event.getPlayer();
+ Block block = event.getBlock();
+
+ if (hasReachedLimit(player, block.getType())) {
+ lwc.sendLocale(player, "protection.exceeded");
+ event.setCancelled(true);
+ }
+ }
+
+ @Override
+ public void onCommand(LWCCommandEvent event) {
+ if (!enabled || event.isCancelled()) {
+ return;
+ }
+
+ if (!event.hasFlag("limits")) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ CommandSender sender = event.getSender();
+ String[] args = event.getArgs();
+ event.setCancelled(true);
+
+ String playerName;
+
+ if (args.length == 0) {
+ if (args.length == 0 && !(sender instanceof Player)) {
+ sender.sendMessage(Colors.Red + "You are not a player!");
+ return;
+ }
+
+ playerName = sender.getName();
+ } else {
+ if (lwc.isAdmin(sender)) {
+ playerName = args[0];
+ } else {
+ lwc.sendLocale(sender, "protection.accessdenied");
+ return;
+ }
+ }
+
+ Player player = lwc.getPlugin().getServer().getPlayer(playerName);
+
+ if (player == null) {
+ sender.sendMessage(Colors.Red + "That player is not online!");
+ return;
+ }
+
+ // send their limits to them
+ sendLimits(sender, player, getPlayerLimits(player));
+ }
+
+ /**
+ * Gets the raw limits configuration
+ *
+ * @return
+ */
+ public Configuration getConfiguration() {
+ return configuration;
+ }
+
+ /**
+ * Reload the limits
+ */
+ public void reload() {
+ loadLimits();
+ }
+
+ /**
+ * Sends the list of limits to the player
+ *
+ * @param sender the commandsender to send the limits to
+ * @param target the player limits are being shown for, can be null
+ * @param limits
+ */
+ public void sendLimits(CommandSender sender, Player target, List limits) {
+ LWC lwc = LWC.getInstance();
+
+ for (Limit limit : limits) {
+ if (limit == null) {
+ continue;
+ }
+
+ String stringLimit = limit.getLimit() == UNLIMITED ? "Unlimited" : Integer.toString(limit.getLimit());
+ String colour = Colors.Yellow;
+
+ if (target != null) {
+ Material material = null;
+
+ if (limit instanceof BlockLimit) {
+ material = ((BlockLimit) limit).getMaterial();
+ } else if (limit instanceof SignLimit) {
+ material = Material.SIGN_POST;
+ }
+
+ boolean reachedLimit = hasReachedLimit(target, material);
+ colour = reachedLimit ? Colors.Red : Colors.Green;
+ }
+
+ if (limit instanceof DefaultLimit) {
+ String currentProtected = target != null ? (Integer.toString(limit.getProtectionCount(target, null)) + "/") : "";
+ sender.sendMessage("Default: " + colour + currentProtected + stringLimit);
+ } else if (limit instanceof BlockLimit) {
+ BlockLimit blockLimit = (BlockLimit) limit;
+ String currentProtected = target != null ? (Integer.toString(limit.getProtectionCount(target, blockLimit.getMaterial())) + "/") : "";
+ sender.sendMessage(lwc.materialToString(blockLimit.getMaterial()) + ": " + colour + currentProtected + stringLimit);
+ } else if (limit instanceof SignLimit) {
+ String currentProtected = target != null ? (Integer.toString(limit.getProtectionCount(target, null)) + "/") : "";
+ sender.sendMessage("Sign: " + colour + currentProtected + stringLimit);
+ } else {
+ sender.sendMessage(limit.getClass().getSimpleName() + ": " + Colors.Yellow + stringLimit);
+ }
+
+ }
+ }
+
+ /**
+ * Checks if a player has reached their protection limit
+ *
+ * @param player
+ * @param material the material type the player has interacted with
+ * @return
+ */
+ public boolean hasReachedLimit(Player player, Material material) {
+ Limit limit = getEffectiveLimit(player, material);
+
+ // if they don't have a limit it's not possible to reach it ^^
+ // ... but if it's null, what the hell did the server owner do?
+ if (limit == null) {
+ return false;
+ }
+
+ // Get the effective limit placed upon them
+ int neverPassThisNumber = limit.getLimit();
+
+ // get the amount of protections the player has
+ int protections = limit.getProtectionCount(player, material);
+
+ return protections >= neverPassThisNumber;
+ }
+
+ /**
+ * Find limits that are attached to the player via permissions (e.g lwc.protect.*.10 = 10 of any protection)
+ *
+ * @param player
+ * @return
+ */
+ private List findLimitsViaPermissions(Player player) {
+ List limits = new LinkedList();
+
+ for (PermissionAttachmentInfo pai : player.getEffectivePermissions()) {
+ String permission = pai.getPermission();
+ boolean value = pai.getValue();
+
+ if (!value || !permission.startsWith("lwc.protect.")) {
+ continue;
+ }
+
+ String[] split = permission.substring("lwc.protect.".length()).split(".");
+
+ if (split.length != 2) {
+ continue;
+ }
+
+ String matchName = split[0];
+ String strCount = split[1];
+
+ int count;
+ try {
+ count = Integer.parseInt(strCount);
+ } catch (NumberFormatException e) {
+ continue;
+ }
+
+ if (matchName.equals("*")) {
+ limits.add(new DefaultLimit(count));
+ } else if (matchName.equals("sign")) {
+ limits.add(new SignLimit(count));
+ } else {
+ Material material = materialCache.get(matchName);
+
+ if (material == null) {
+ continue;
+ }
+
+ limits.add(new BlockLimit(material, count));
+ }
+ }
+
+ return limits;
+ }
+
+ /**
+ * Gets the list of limits that may apply to the player.
+ * For group limits, it uses the highest one found.
+ *
+ * @param player
+ * @return
+ */
+ public List getPlayerLimits(Player player) {
+ LWC lwc = LWC.getInstance();
+ List limits = new LinkedList();
+
+ // get all of their own limits
+ String playerName = player.getName().toLowerCase();
+ if (playerLimits.containsKey(playerName)) {
+ limits.addAll(playerLimits.get(playerName));
+ }
+
+ for (Limit limit : findLimitsViaPermissions(player)) {
+ Limit matched = findLimit(limits, limit);
+
+ if (matched != null) {
+ // Is our limit better?
+ if (limit.getLimit() > matched.getLimit()) {
+ limits.remove(matched);
+ limits.add(limit);
+ }
+ } else {
+ limits.add(limit);
+ }
+ }
+
+ // Look over the group limits
+ for (String group : lwc.getPermissions().getGroups(player)) {
+ if (groupLimits.containsKey(group.toLowerCase())) {
+ for (Limit limit : groupLimits.get(group.toLowerCase())) {
+ // try to match one already inside what we found
+ Limit matched = findLimit(limits, limit);
+
+ if (matched != null) {
+ // Is our limit better?
+ if (limit.getLimit() > matched.getLimit()) {
+ limits.remove(matched);
+ limits.add(limit);
+ }
+ } else {
+ limits.add(limit);
+ }
+ }
+ }
+ }
+
+ // Look at the default limits
+ for (Limit limit : defaultLimits) {
+ // try to match one already inside what we found
+ Limit matched = findLimit(limits, limit);
+
+ if (matched == null) {
+ limits.add(limit);
+ }
+ }
+
+ return limits;
+ }
+
+ /**
+ * Get the player's effective limit that should take precedence
+ *
+ * @param player
+ * @param material
+ * @return
+ */
+ public Limit getEffectiveLimit(Player player, Material material) {
+ return getEffectiveLimit(getPlayerLimits(player), material);
+ }
+
+ /**
+ * Gets an immutable list of the default limits
+ *
+ * @return
+ */
+ public List getDefaultLimits() {
+ return Collections.unmodifiableList(defaultLimits);
+ }
+
+ /**
+ * Gets an unmodiable map of the player limits
+ *
+ * @return
+ */
+ public Map> getPlayerLimits() {
+ return Collections.unmodifiableMap(playerLimits);
+ }
+
+ /**
+ * Gets an unmodiable map of the group limits
+ *
+ * @return
+ */
+ public Map> getGroupLimits() {
+ return Collections.unmodifiableMap(groupLimits);
+ }
+
+ /**
+ * Orders the limits, putting the default limit at the top of the list
+ *
+ * @param limits
+ * @return
+ */
+ private List orderLimits(List limits) {
+ Limit defaultLimit = null;
+
+ // Locate the default limit
+ for (Limit limit : limits) {
+ if (limit instanceof DefaultLimit) {
+ defaultLimit = limit;
+ break;
+ }
+ }
+
+ // remove it
+ limits.remove(defaultLimit);
+
+ // readd it at the head
+ limits.add(0, defaultLimit);
+
+ return limits;
+ }
+
+ /**
+ * Gets the material's effective limit that should take precedence
+ *
+ * @param limits
+ * @param material
+ * @return Limit object if one is found otherwise NULL
+ */
+ private Limit getEffectiveLimit(List limits, Material material) {
+ if (limits == null) {
+ return null;
+ }
+
+ // Temporary storage to use if the default is found so we save time if no override was found
+ Limit defaultLimit = null;
+
+ for (Limit limit : limits) {
+ // Record the default limit if found
+ if (limit instanceof DefaultLimit) {
+ defaultLimit = limit;
+ } else if (limit instanceof SignLimit) {
+ if (material == Material.WALL_SIGN || material == Material.SIGN_POST) {
+ return limit;
+ }
+ } else if (limit instanceof BlockLimit) {
+ BlockLimit blockLimit = (BlockLimit) limit;
+
+ // If it's the appropriate material we can return immediately
+ if (blockLimit.getMaterial() == material) {
+ return blockLimit;
+ }
+ }
+ }
+
+ return defaultLimit;
+ }
+
+ /**
+ * Load all of the limits
+ */
+ private void loadLimits() {
+ // make sure we're working on a clean slate
+ defaultLimits.clear();
+ playerLimits.clear();
+ groupLimits.clear();
+
+ // add the default limits
+ defaultLimits.addAll(findLimits("defaults"));
+
+ // add all of the player limits
+ try {
+ for (String player : configuration.getKeys("players")) {
+ playerLimits.put(player.toLowerCase(), findLimits("players." + player));
+ }
+ } catch (NullPointerException e) { }
+
+ // add all of the group limits
+ try {
+ for (String group : configuration.getKeys("groups")) {
+ groupLimits.put(group.toLowerCase(), findLimits("groups." + group));
+ }
+ } catch (NullPointerException e) { }
+ }
+
+ /**
+ * Find and match all of the limits in a given list of nodes for the config
+ *
+ * @param node
+ * @return
+ */
+ private List findLimits(String node) {
+ List limits = new LinkedList();
+ List keys = configuration.getKeys(node);
+
+ for (String key : keys) {
+ String value = configuration.getString(node + "." + key);
+
+ int limit;
+
+ if (value.equalsIgnoreCase("unlimited")) {
+ limit = UNLIMITED;
+ } else {
+ limit = Integer.parseInt(value);
+ }
+
+ // Match default
+ if (key.equalsIgnoreCase("default")) {
+ limits.add(new DefaultLimit(limit));
+ } else if (key.equalsIgnoreCase("sign")) {
+ limits.add(new SignLimit(limit));
+ } else {
+ // attempt to resolve it as a block id
+ int blockId = -1;
+
+ try {
+ blockId = Integer.parseInt(key);
+ } catch (NumberFormatException e) { }
+
+ // resolve the material
+ Material material;
+
+ if (blockId >= 0) {
+ material = Material.getMaterial(blockId);
+ } else {
+ material = Material.getMaterial(key.toUpperCase());
+ }
+
+ if (material != null) {
+ limits.add(new BlockLimit(material, limit));
+ }
+ }
+ }
+
+ // Order it
+ orderLimits(limits);
+
+ return limits;
+ }
+
+ /**
+ * Find a limit in the list of limits that equals the given limit in class;
+ * The LIMIT itself does not need to be equal; only the class & if it's a
+ * BlockLimit, the material must equal
+ *
+ * @param limits
+ * @param compare
+ * @return
+ */
+ private Limit findLimit(List limits, Limit compare) {
+ for (Limit limit : limits) {
+ if (limit != null && limit.getClass().isInstance(compare)) {
+ if (limit instanceof BlockLimit) {
+ BlockLimit cmp1 = (BlockLimit) limit;
+ BlockLimit cmp2 = (BlockLimit) compare;
+
+ if (cmp1.getMaterial() == cmp2.getMaterial()) {
+ return limit;
+ }
+ } else {
+ return limit;
+ }
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/core/src/main/java/com/griefcraft/modules/modes/BaseModeModule.java b/core/src/main/java/com/griefcraft/modules/modes/BaseModeModule.java
new file mode 100644
index 000000000..1420aa0cf
--- /dev/null
+++ b/core/src/main/java/com/griefcraft/modules/modes/BaseModeModule.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011 Tyler Blair. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and contributors and should not be interpreted as representing official policies,
+ * either expressed or implied, of anybody else.
+ */
+
+package com.griefcraft.modules.modes;
+
+import com.griefcraft.lwc.LWC;
+import com.griefcraft.scripting.JavaModule;
+import com.griefcraft.scripting.event.LWCCommandEvent;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class BaseModeModule extends JavaModule {
+
+ @Override
+ public void onCommand(LWCCommandEvent event) {
+ if (!event.hasFlag("p", "mode")) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ CommandSender sender = event.getSender();
+ String[] args = event.getArgs();
+
+ event.setCancelled(true);
+
+ if (args.length == 0) {
+ lwc.sendSimpleUsage(sender, "/lwc mode ");
+ return;
+ }
+
+ if (!(sender instanceof Player)) {
+ return;
+ }
+
+ String mode = args[0].toLowerCase();
+ Player player = (Player) sender;
+
+ if (!lwc.isModeWhitelisted(player, mode)) {
+ if (!lwc.isAdmin(sender) && !lwc.isModeEnabled(mode)) {
+ lwc.sendLocale(player, "protection.modes.disabled");
+ return;
+ }
+ }
+
+ event.setCancelled(false);
+ }
+
+}
diff --git a/core/src/main/java/com/griefcraft/modules/modes/DropTransferModule.java b/core/src/main/java/com/griefcraft/modules/modes/DropTransferModule.java
new file mode 100644
index 000000000..c8f270636
--- /dev/null
+++ b/core/src/main/java/com/griefcraft/modules/modes/DropTransferModule.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2011 Tyler Blair. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and contributors and should not be interpreted as representing official policies,
+ * either expressed or implied, of anybody else.
+ */
+
+package com.griefcraft.modules.modes;
+
+import com.griefcraft.lwc.LWC;
+import com.griefcraft.model.Action;
+import com.griefcraft.model.LWCPlayer;
+import com.griefcraft.model.Mode;
+import com.griefcraft.model.Protection;
+import com.griefcraft.scripting.JavaModule;
+import com.griefcraft.scripting.event.LWCBlockInteractEvent;
+import com.griefcraft.scripting.event.LWCCommandEvent;
+import com.griefcraft.scripting.event.LWCDropItemEvent;
+import com.griefcraft.scripting.event.LWCProtectionInteractEvent;
+import com.herocraftonline.heroes.Heroes;
+import com.herocraftonline.heroes.characters.Hero;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Item;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.plugin.Plugin;
+
+import java.util.Map;
+import java.util.Set;
+
+public class DropTransferModule extends JavaModule {
+
+ private LWC lwc;
+
+ @Override
+ public void load(LWC lwc) {
+ this.lwc = lwc;
+ }
+
+ /**
+ * Check if the player is currently drop transferring
+ *
+ * @param player
+ * @return
+ */
+ private boolean isPlayerDropTransferring(LWCPlayer player) {
+ return player.hasMode("+dropTransfer");
+ }
+
+ /**
+ * Get the drop transfer target for a player
+ *
+ * @param player
+ * @return
+ */
+ private int getPlayerDropTransferTarget(LWCPlayer player) {
+ Mode mode = player.getMode("dropTransfer");
+
+ if (mode == null) {
+ return -1;
+ }
+
+ String target = mode.getData();
+
+ try {
+ return Integer.parseInt(target);
+ } catch (NumberFormatException e) {
+ }
+
+ return -1;
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public void onDropItem(LWCDropItemEvent event) {
+ Player bPlayer = event.getPlayer();
+ Item item = event.getEvent().getItemDrop();
+ ItemStack itemStack = item.getItemStack();
+
+ // Heroes
+ try {
+ Plugin heroesPlugin = lwc.getPlugin().getServer().getPluginManager().getPlugin("Heroes");
+
+ if (heroesPlugin != null) {
+ Heroes heroes = (Heroes) heroesPlugin;
+ Hero hero = heroes.getCharacterManager().getHero(bPlayer);
+
+ if (hero != null && hero.isInCombat()) {
+ return;
+ }
+ }
+ } catch (Exception e) { }
+
+ // MobArena
+ try {
+ Plugin mobarenaPlugin = lwc.getPlugin().getServer().getPluginManager().getPlugin("MobArena");
+
+ if (mobarenaPlugin != null) {
+ com.garbagemule.MobArena.MobArena mobarena = (com.garbagemule.MobArena.MobArena) mobarenaPlugin;
+
+ if (mobarena.getArenaMaster().getArenaAtLocation(bPlayer.getLocation()) != null) {
+ return;
+ }
+ }
+ } catch (Exception e) { }
+
+ LWCPlayer player = lwc.wrapPlayer(bPlayer);
+ int protectionId = getPlayerDropTransferTarget(player);
+
+ if (protectionId == -1) {
+ return;
+ }
+
+ if (!isPlayerDropTransferring(player)) {
+ return;
+ }
+
+ Protection protection = lwc.getPhysicalDatabase().loadProtection(protectionId);
+
+ if (protection == null) {
+ lwc.sendLocale(player, "lwc.nolongerexists");
+ player.disableMode(player.getMode("dropTransfer"));
+ return;
+ }
+
+ // load the world and the inventory
+ World world = player.getServer().getWorld(protection.getWorld());
+
+ if (world == null) {
+ lwc.sendLocale(player, "lwc.invalidworld");
+ player.disableMode(player.getMode("dropTransfer"));
+ return;
+ }
+
+ // Don't allow them to transfer items across worlds
+ if (bPlayer.getWorld() != world && !lwc.getConfiguration().getBoolean("modes.droptransfer.crossWorld", false)) {
+ lwc.sendLocale(player, "lwc.dropxfer.acrossworlds");
+ player.disableMode(player.getMode("dropTransfer"));
+ return;
+ }
+
+ Block block = world.getBlockAt(protection.getX(), protection.getY(), protection.getZ());
+ Map remaining = lwc.depositItems(block, itemStack);
+
+ if (remaining.size() > 0) {
+ lwc.sendLocale(player, "lwc.dropxfer.chestfull");
+
+ for (ItemStack temp : remaining.values()) {
+ bPlayer.getInventory().addItem(temp);
+ }
+ }
+
+ bPlayer.updateInventory(); // if they're in the chest and dropping items, this is required
+ item.remove();
+ }
+
+ @Override
+ public void onProtectionInteract(LWCProtectionInteractEvent event) {
+ LWC lwc = event.getLWC();
+ Protection protection = event.getProtection();
+ Set actions = event.getActions();
+ boolean canAccess = event.canAccess();
+
+ Player bPlayer = event.getPlayer();
+ LWCPlayer player = lwc.wrapPlayer(bPlayer);
+
+ if (!actions.contains("dropTransferSelect")) {
+ return;
+ }
+
+ if (!canAccess) {
+ lwc.sendLocale(player, "protection.interact.dropxfer.noaccess");
+ } else {
+ int blockId = protection.getBlockId();
+ if (blockId != Material.CHEST.getId() && blockId != Material.TRAPPED_CHEST.getId()) {
+ lwc.sendLocale(player, "protection.interact.dropxfer.notchest");
+ player.removeAllActions();
+ event.setResult(Result.CANCEL);
+
+ return;
+ }
+
+ Mode mode = new Mode();
+ mode.setName("dropTransfer");
+ mode.setData(protection.getId() + "");
+ mode.setPlayer(bPlayer);
+ player.enableMode(mode);
+ mode = new Mode();
+ mode.setName("+dropTransfer");
+ mode.setPlayer(bPlayer);
+ player.enableMode(mode);
+
+ lwc.sendLocale(player, "protection.interact.dropxfer.finalize");
+ }
+
+ player.removeAllActions(); // ignore the persist mode
+ }
+
+ @Override
+ public void onBlockInteract(LWCBlockInteractEvent event) {
+ Player player = event.getPlayer();
+ Set actions = event.getActions();
+
+ if (!actions.contains("dropTransferSelect")) {
+ return;
+ }
+
+ lwc.sendLocale(player, "protection.interact.dropxfer.notprotected");
+ lwc.removeModes(player);
+ }
+
+ @Override
+ public void onCommand(LWCCommandEvent event) {
+ if (!event.hasFlag("p", "mode")) {
+ return;
+ }
+
+ if (event.isCancelled()) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ CommandSender sender = event.getSender();
+ String[] args = event.getArgs();
+
+ LWCPlayer player = lwc.wrapPlayer(sender);
+ String mode = args[0].toLowerCase();
+
+ if (!mode.equals("droptransfer")) {
+ return;
+ }
+
+ event.setCancelled(true);
+
+ // internal name
+ mode = "dropTransfer";
+
+ if (args.length < 2) {
+ lwc.sendLocale(player, "protection.modes.dropxfer.help");
+ return;
+ }
+
+ String action = args[1].toLowerCase();
+ String playerName = player.getName();
+
+ if (action.equals("select")) {
+ if (isPlayerDropTransferring(player)) {
+ lwc.sendLocale(player, "protection.modes.dropxfer.select.error");
+ return;
+ }
+
+ player.disableMode(player.getMode(mode));
+
+ Action temp = new Action();
+ temp.setName("dropTransferSelect");
+ temp.setPlayer(player);
+
+ player.addAction(temp);
+ lwc.sendLocale(player, "protection.modes.dropxfer.select.finalize");
+ } else if (action.equals("on")) {
+ int target = getPlayerDropTransferTarget(player);
+
+ if (target == -1) {
+ lwc.sendLocale(player, "protection.modes.dropxfer.selectchest");
+ return;
+ }
+
+ Mode temp = new Mode();
+ temp.setName("+dropTransfer");
+ temp.setPlayer(player.getBukkitPlayer());
+
+ player.enableMode(temp);
+ lwc.sendLocale(player, "protection.modes.dropxfer.on.finalize");
+ } else if (action.equals("off")) {
+ int target = getPlayerDropTransferTarget(player);
+
+ if (target == -1) {
+ lwc.sendLocale(player, "protection.modes.dropxfer.selectchest");
+ return;
+ }
+
+ player.disableMode(player.getMode("+dropTransfer"));
+ lwc.sendLocale(player, "protection.modes.dropxfer.off.finalize");
+ } else if (action.equals("status")) {
+ if (getPlayerDropTransferTarget(player) == -1) {
+ lwc.sendLocale(player, "protection.modes.dropxfer.status.off");
+ } else {
+ if (isPlayerDropTransferring(player)) {
+ lwc.sendLocale(player, "protection.modes.dropxfer.status.active");
+ } else {
+ lwc.sendLocale(player, "protection.modes.dropxfer.status.inactive");
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/core/src/main/java/com/griefcraft/modules/modes/NoSpamModule.java b/core/src/main/java/com/griefcraft/modules/modes/NoSpamModule.java
new file mode 100644
index 000000000..6eb67f085
--- /dev/null
+++ b/core/src/main/java/com/griefcraft/modules/modes/NoSpamModule.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2011 Tyler Blair. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and contributors and should not be interpreted as representing official policies,
+ * either expressed or implied, of anybody else.
+ */
+
+package com.griefcraft.modules.modes;
+
+import com.griefcraft.lwc.LWC;
+import com.griefcraft.model.LWCPlayer;
+import com.griefcraft.model.Mode;
+import com.griefcraft.scripting.JavaModule;
+import com.griefcraft.scripting.event.LWCCommandEvent;
+import com.griefcraft.scripting.event.LWCSendLocaleEvent;
+import org.bukkit.command.CommandSender;
+
+public class NoSpamModule extends JavaModule {
+
+ @Override
+ public void onCommand(LWCCommandEvent event) {
+ if (!event.hasFlag("p", "mode")) {
+ return;
+ }
+
+ if (event.isCancelled()) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ CommandSender sender = event.getSender();
+ String[] args = event.getArgs();
+
+ LWCPlayer player = lwc.wrapPlayer(sender);
+ String mode = args[0].toLowerCase();
+
+ if (!mode.equals("nospam")) {
+ return;
+ }
+
+ if (!player.hasMode(mode)) {
+ Mode temp = new Mode();
+ temp.setName(mode);
+ temp.setPlayer(player.getBukkitPlayer());
+
+ player.enableMode(temp);
+ lwc.sendLocale(player, "protection.modes.nospam.finalize");
+ } else {
+ player.disableMode(player.getMode(mode));
+ lwc.sendLocale(player, "protection.modes.nospam.off");
+ }
+
+ event.setCancelled(true);
+ }
+
+ @Override
+ public void onSendLocale(LWCSendLocaleEvent event) {
+ LWC lwc = event.getLWC();
+ LWCPlayer player = lwc.wrapPlayer(event.getPlayer());
+ String locale = event.getLocale();
+
+ // they don't intrigue us
+ if (!player.hasMode("nospam")) {
+ return;
+ }
+
+ // hide all of the creation messages
+ if ((locale.endsWith("create.finalize") && !locale.equals("protection.create.finalize")) || locale.endsWith("notice.protected")) {
+ event.setCancelled(true);
+ }
+ }
+
+}
diff --git a/core/src/main/java/com/griefcraft/modules/modes/PersistModule.java b/core/src/main/java/com/griefcraft/modules/modes/PersistModule.java
new file mode 100644
index 000000000..48b1fb5af
--- /dev/null
+++ b/core/src/main/java/com/griefcraft/modules/modes/PersistModule.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011 Tyler Blair. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and contributors and should not be interpreted as representing official policies,
+ * either expressed or implied, of anybody else.
+ */
+
+package com.griefcraft.modules.modes;
+
+import com.griefcraft.lwc.LWC;
+import com.griefcraft.model.LWCPlayer;
+import com.griefcraft.model.Mode;
+import com.griefcraft.scripting.JavaModule;
+import com.griefcraft.scripting.event.LWCCommandEvent;
+import org.bukkit.command.CommandSender;
+
+public class PersistModule extends JavaModule {
+
+ @Override
+ public void onCommand(LWCCommandEvent event) {
+ if (!event.hasFlag("p", "mode")) {
+ return;
+ }
+
+ if (event.isCancelled()) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ CommandSender sender = event.getSender();
+ String[] args = event.getArgs();
+
+ LWCPlayer player = lwc.wrapPlayer(sender);
+ String mode = args[0].toLowerCase();
+
+ if (!mode.equals("persist")) {
+ return;
+ }
+
+ if (!player.hasMode(mode)) {
+ Mode temp = new Mode();
+ temp.setName(mode);
+ temp.setPlayer(player.getBukkitPlayer());
+
+ player.enableMode(temp);
+ lwc.sendLocale(player, "protection.modes.persist.finalize");
+ } else {
+ player.disableMode(player.getMode(mode));
+ lwc.sendLocale(player, "protection.modes.persist.off");
+ }
+
+ event.setCancelled(true);
+ }
+
+}
diff --git a/core/src/main/java/com/griefcraft/modules/modify/ModifyModule.java b/core/src/main/java/com/griefcraft/modules/modify/ModifyModule.java
new file mode 100644
index 000000000..20db3cb60
--- /dev/null
+++ b/core/src/main/java/com/griefcraft/modules/modify/ModifyModule.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2011 Tyler Blair. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and contributors and should not be interpreted as representing official policies,
+ * either expressed or implied, of anybody else.
+ */
+
+package com.griefcraft.modules.modify;
+
+import com.griefcraft.lwc.LWC;
+import com.griefcraft.model.Action;
+import com.griefcraft.model.LWCPlayer;
+import com.griefcraft.model.Protection;
+import com.griefcraft.scripting.JavaModule;
+import com.griefcraft.scripting.event.LWCBlockInteractEvent;
+import com.griefcraft.scripting.event.LWCCommandEvent;
+import com.griefcraft.scripting.event.LWCProtectionInteractEvent;
+import org.bukkit.block.Block;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static com.griefcraft.util.StringUtil.join;
+
+public class ModifyModule extends JavaModule {
+
+ /**
+ * Used to match an id parameter in /cmodify id:##
+ */
+ private final Pattern ID_MATCHER = Pattern.compile(".*id:(\\d+).*");
+
+ @Override
+ public void onProtectionInteract(LWCProtectionInteractEvent event) {
+ if (event.getResult() != Result.DEFAULT) {
+ return;
+ }
+
+ if (!event.hasAction("modify")) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ Protection protection = event.getProtection();
+ LWCPlayer player = lwc.wrapPlayer(event.getPlayer());
+ Player bPlayer = event.getPlayer();
+ event.setResult(Result.CANCEL);
+
+ if (!lwc.isAdmin(bPlayer) && Boolean.parseBoolean(lwc.resolveProtectionConfiguration(protection.getBlock(), "readonly-modify"))) {
+ lwc.sendLocale(player, "protection.accessdenied");
+ return;
+ }
+
+ if (lwc.canAdminProtection(player.getBukkitPlayer(), protection)) {
+ Action action = player.getAction("modify");
+
+ String data = action.getData();
+ String[] rights = new String[0];
+
+ if (data.length() > 0) {
+ rights = data.split(" ");
+ }
+
+ lwc.removeModes(player);
+ lwc.processRightsModifications(player, protection, rights);
+ } else {
+ lwc.sendLocale(player, "protection.interact.error.notowner", "block", LWC.materialToString(protection.getBlockId()));
+ lwc.removeModes(player);
+ }
+
+ }
+
+ @Override
+ public void onBlockInteract(LWCBlockInteractEvent event) {
+ if (event.getResult() != Result.DEFAULT) {
+ return;
+ }
+
+ if (!event.hasAction("modify")) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ Block block = event.getBlock();
+ Player player = event.getPlayer();
+ event.setResult(Result.CANCEL);
+
+ lwc.sendLocale(player, "protection.interact.error.notregistered", "block", LWC.materialToString(block));
+ lwc.removeModes(player);
+ }
+
+ @Override
+ public void onCommand(LWCCommandEvent event) {
+ if (event.isCancelled()) {
+ return;
+ }
+
+ if (!event.hasFlag("m", "modify")) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ CommandSender sender = event.getSender();
+ String[] args = event.getArgs();
+ String full = join(args, 0).trim();
+ event.setCancelled(true);
+
+ if (!lwc.hasPlayerPermission(sender, "lwc.modify")) {
+ lwc.sendLocale(sender, "protection.accessdenied");
+ return;
+ }
+
+ if (args.length < 1) {
+ lwc.sendLocale(sender, "help.modify");
+ return;
+ }
+
+ // Check for ID parameter
+ Matcher matcher = ID_MATCHER.matcher(full);
+ if (matcher.matches()) {
+ int protectionId = Integer.parseInt(matcher.group(1));
+
+ // load the protection
+ Protection protection = lwc.getPhysicalDatabase().loadProtection(protectionId);
+
+ // Does it even exist?
+ if (protection == null) {
+ lwc.sendLocale(sender, "lwc.protectionnotfound");
+ return;
+ }
+
+ // Can they admin it? (if they're console, they can!)
+ if (sender instanceof Player) {
+ if (!lwc.canAdminProtection((Player) sender, protection)) {
+ lwc.sendLocale(sender, "protection.accessdenied");
+ return;
+ }
+ }
+
+ // process it
+ lwc.processRightsModifications(sender, protection, args);
+ return;
+ }
+
+ if (!(sender instanceof Player)) {
+ lwc.sendLocale(sender, "lwc.onlyrealplayers");
+ return;
+ }
+
+ LWCPlayer player = lwc.wrapPlayer(sender);
+
+ Action action = new Action();
+ action.setName("modify");
+ action.setPlayer(player);
+ action.setData(full);
+
+ player.removeAllActions();
+ player.addAction(action);
+
+ lwc.sendLocale(sender, "protection.modify.finalize");
+ }
+
+}
diff --git a/core/src/main/java/com/griefcraft/modules/owners/OwnersModule.java b/core/src/main/java/com/griefcraft/modules/owners/OwnersModule.java
new file mode 100644
index 000000000..b9e117f7c
--- /dev/null
+++ b/core/src/main/java/com/griefcraft/modules/owners/OwnersModule.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2011 Tyler Blair. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and contributors and should not be interpreted as representing official policies,
+ * either expressed or implied, of anybody else.
+ */
+
+package com.griefcraft.modules.owners;
+
+import com.griefcraft.lwc.LWC;
+import com.griefcraft.model.Action;
+import com.griefcraft.model.LWCPlayer;
+import com.griefcraft.model.Permission;
+import com.griefcraft.model.Protection;
+import com.griefcraft.scripting.JavaModule;
+import com.griefcraft.scripting.event.LWCBlockInteractEvent;
+import com.griefcraft.scripting.event.LWCCommandEvent;
+import com.griefcraft.scripting.event.LWCProtectionInteractEvent;
+import org.bukkit.block.Block;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+
+public class OwnersModule extends JavaModule {
+
+ /**
+ * How many results to show per page
+ */
+ public static final int RESULTS_PER_PAGE = 15;
+
+ @Override
+ public void onProtectionInteract(LWCProtectionInteractEvent event) {
+ if (event.getResult() != Result.DEFAULT) {
+ return;
+ }
+
+ if (!event.hasAction("owners")) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ Protection protection = event.getProtection();
+ LWCPlayer player = lwc.wrapPlayer(event.getPlayer());
+ event.setResult(Result.CANCEL);
+
+ Action action = player.getAction("owners");
+ int accessPage = Integer.parseInt(action.getData());
+
+ // Calculate range
+ int start = (accessPage - 1) * RESULTS_PER_PAGE;
+ int max = start + RESULTS_PER_PAGE;
+
+ List permissions = protection.getPermissions();
+ int numRights = permissions.size();
+
+ // May have only been 2 rows left, or something. Get the real max
+ int realMax = start + permissions.size();
+
+ lwc.sendLocale(player, "lwc.owners.results", "start", start, "max", realMax, "total", numRights);
+
+ for (int index = 0; index < max; index++) {
+ if ((start + index) >= numRights) {
+ break;
+ }
+
+ Permission permission = permissions.get(start + index);
+ player.sendMessage(permission.toString());
+ }
+
+ lwc.removeModes(player);
+ }
+
+ @Override
+ public void onBlockInteract(LWCBlockInteractEvent event) {
+ if (event.getResult() != Result.DEFAULT) {
+ return;
+ }
+
+ if (!event.hasAction("owners")) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ Player player = event.getPlayer();
+ Block block = event.getBlock();
+
+ lwc.sendLocale(player, "protection.interact.error.notregistered", "block", LWC.materialToString(block));
+ lwc.removeModes(player);
+ }
+
+ @Override
+ public void onCommand(LWCCommandEvent event) {
+ if (event.isCancelled()) {
+ return;
+ }
+
+ if (!event.hasFlag("o", "owner", "owners")) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ CommandSender sender = event.getSender();
+ String[] args = event.getArgs();
+
+ event.setCancelled(true);
+
+ if (!(sender instanceof Player)) {
+ lwc.sendLocale(sender, "lwc.onlyrealplayers");
+ return;
+ }
+
+ LWCPlayer player = lwc.wrapPlayer(sender);
+ int page = 1;
+
+ if (args.length > 0) {
+ try {
+ page = Integer.parseInt(args[0]);
+ } catch (Exception e) {
+ lwc.sendSimpleUsage(sender, "/lwc -owners [page]");
+ return;
+ }
+ }
+
+ Action action = new Action();
+ action.setName("owners");
+ action.setPlayer(player);
+ action.setData(page + "");
+
+ player.removeAllActions();
+ player.addAction(action);
+
+ lwc.sendLocale(sender, "protection.owners.finalize");
+ }
+
+}
diff --git a/core/src/main/java/com/griefcraft/modules/pluginsupport/Towny.java b/core/src/main/java/com/griefcraft/modules/pluginsupport/Towny.java
new file mode 100644
index 000000000..1bd8e72a8
--- /dev/null
+++ b/core/src/main/java/com/griefcraft/modules/pluginsupport/Towny.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2011 Tyler Blair. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and contributors and should not be interpreted as representing official policies,
+ * either expressed or implied, of anybody else.
+ */
+
+package com.griefcraft.modules.pluginsupport;
+
+import com.griefcraft.lwc.LWC;
+import com.griefcraft.model.Permission;
+import com.griefcraft.model.Protection;
+import com.griefcraft.scripting.JavaModule;
+import com.griefcraft.scripting.event.LWCAccessEvent;
+import com.griefcraft.scripting.event.LWCProtectionRegisterEvent;
+import com.palmergames.bukkit.towny.object.Coord;
+import com.palmergames.bukkit.towny.object.Town;
+import com.palmergames.bukkit.towny.object.TownBlock;
+import com.palmergames.bukkit.towny.object.TownyUniverse;
+import com.palmergames.bukkit.towny.object.TownyWorld;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+
+import java.lang.reflect.Method;
+
+public class Towny extends JavaModule {
+
+ /**
+ * If Towny borders are to be used
+ */
+ private boolean townyBorders;
+
+ /**
+ * The Towny plugin
+ */
+ private com.palmergames.bukkit.towny.Towny towny;
+
+ /**
+ * Load the module
+ */
+ @Override
+ public void load(LWC lwc) {
+ this.townyBorders = lwc.getConfiguration().getBoolean("core.townyBorders", false);
+
+ // check for Towny
+ Plugin townyPlugin = lwc.getPlugin().getServer().getPluginManager().getPlugin("Towny");
+
+ // abort !
+ if (townyPlugin == null) {
+ return;
+ }
+
+ this.towny = (com.palmergames.bukkit.towny.Towny) townyPlugin;
+ }
+
+ /**
+ * Cancel the event and inform the player that they cannot protect there
+ *
+ * @param event
+ */
+ private void trigger(LWCProtectionRegisterEvent event) {
+ event.getLWC().sendLocale(event.getPlayer(), "lwc.towny.blocked");
+ event.setCancelled(true);
+ }
+
+ @Override
+ public void onAccessRequest(LWCAccessEvent event) {
+ Player player = event.getPlayer();
+ Protection protection = event.getProtection();
+
+ if (event.getAccess() != Permission.Access.NONE) {
+ return;
+ }
+
+ if (protection.getType() != Protection.Type.PRIVATE) {
+ return;
+ }
+
+ if (towny == null) {
+ return;
+ }
+
+ for (Permission permission : protection.getPermissions()) {
+ if (permission.getType() != Permission.Type.TOWN) {
+ continue;
+ }
+
+ String townName = permission.getName();
+
+ // Does the town exist?
+ try {
+ Town town = towny.getTownyUniverse().getTown(townName);
+
+ if (town == null) {
+ return;
+ }
+
+ // check if the player is a resident of said town
+ if (!town.hasResident(player.getName())) {
+ // Uh-oh!
+ event.setAccess(Permission.Access.NONE);
+ } else {
+ // They're in the town :-)
+ event.setAccess(Permission.Access.PLAYER);
+ }
+
+ // If they're the major, let them admin the protection
+ if (town.getMayor().getName().equalsIgnoreCase(player.getName())) {
+ event.setAccess(Permission.Access.ADMIN);
+ }
+ } catch (Exception e) {
+
+ }
+ }
+ }
+
+ /**
+ * Just a note: catching NotRegisteredException (which where an Exception is caught is where its thrown)
+ * will throw a ClassNotFoundException when Towny is not installed.
+ */
+ @Override
+ public void onRegisterProtection(LWCProtectionRegisterEvent event) {
+ if (event.isCancelled()) {
+ return;
+ }
+
+ if (!townyBorders || towny == null) {
+ return;
+ }
+
+ // the block being protected
+ Block block = event.getBlock();
+
+ // Get the towny world
+ TownyWorld world = null;
+
+ try {
+ try {
+ world = towny.getTownyUniverse().getWorld(block.getWorld().getName());
+ } catch (IncompatibleClassChangeError e) {
+ // Towny Advanced
+ try {
+ // We need to use Reflection because of the two TownyUniverse instances
+ // loaded (to retain Towny: CE support)
+ Method method = TownyUniverse.class.getDeclaredMethod("getWorld", String.class);
+
+ // resolve the world
+ // the method is static!
+ world = (TownyWorld) method.invoke(null, block.getWorld().getName());
+ } catch (Exception ex) {
+ // no world or something bad happened
+ trigger(event);
+ return;
+ }
+ }
+ } catch (Exception e) {
+ // No world, don't let them protect it!
+ trigger(event);
+ return;
+ }
+
+ if (!world.isUsingTowny()) {
+ return;
+ }
+
+ // attempt to get the town block
+ TownBlock townBlock = null;
+
+ try {
+ townBlock = world.getTownBlock(Coord.parseCoord(block));
+ } catch (Exception e) {
+ // No world, don't let them protect it!
+ trigger(event);
+ }
+ }
+
+}
diff --git a/core/src/main/java/com/griefcraft/modules/pluginsupport/WorldGuard.java b/core/src/main/java/com/griefcraft/modules/pluginsupport/WorldGuard.java
new file mode 100644
index 000000000..8bb9fff86
--- /dev/null
+++ b/core/src/main/java/com/griefcraft/modules/pluginsupport/WorldGuard.java
@@ -0,0 +1,393 @@
+/*
+ * Copyright 2011 Tyler Blair. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and contributors and should not be interpreted as representing official policies,
+ * either expressed or implied, of anybody else.
+ */
+
+package com.griefcraft.modules.pluginsupport;
+
+import com.griefcraft.lwc.LWC;
+import com.griefcraft.model.Permission;
+import com.griefcraft.model.Protection;
+import com.griefcraft.scripting.JavaModule;
+import com.griefcraft.scripting.event.LWCAccessEvent;
+import com.griefcraft.scripting.event.LWCCommandEvent;
+import com.griefcraft.scripting.event.LWCProtectionRegisterEvent;
+import com.griefcraft.util.Colors;
+import com.griefcraft.util.config.Configuration;
+import com.sk89q.worldedit.BlockVector;
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldguard.LocalPlayer;
+import com.sk89q.worldguard.bukkit.BukkitUtil;
+import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
+import com.sk89q.worldguard.protection.GlobalRegionManager;
+import com.sk89q.worldguard.protection.managers.RegionManager;
+import com.sk89q.worldguard.protection.regions.ProtectedRegion;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class WorldGuard extends JavaModule {
+
+ /**
+ * The WorldGuard module configuration
+ */
+ private Configuration configuration = Configuration.load("worldguard.yml");
+
+ /**
+ * The world guard plugin if it is enabled
+ */
+ private WorldGuardPlugin worldGuard = null;
+
+ @Override
+ public void load(LWC lwc) {
+ Plugin plugin = lwc.getPlugin().getServer().getPluginManager().getPlugin("WorldGuard");
+
+ if (plugin != null) {
+ worldGuard = (WorldGuardPlugin) plugin;
+ }
+ }
+
+ @Override
+ public void onCommand(LWCCommandEvent event) {
+ if (event.isCancelled()) {
+ return;
+ }
+
+ if (!event.hasFlag("a", "admin")) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ CommandSender sender = event.getSender();
+ String[] args = event.getArgs();
+
+ if (!args[0].equals("purgeregion") && !args[0].equals("protectregion")) {
+ return;
+ }
+
+ // The command name to send to them
+ String commandName = args[0];
+
+ event.setCancelled(true);
+
+ // check for worldguard
+ if (worldGuard == null) {
+ sender.sendMessage(Colors.Red + "WorldGuard is not enabled.");
+ return;
+ }
+
+ if (args.length < 2) {
+ lwc.sendSimpleUsage(sender, "/lwc admin " + commandName + " [World]");
+ return;
+ }
+
+ if (!(sender instanceof Player) && args.length < 3) {
+ sender.sendMessage(Colors.Red + "You must specify the world name the region is in since you are not logged in as a player.");
+ return;
+ }
+
+ // the region
+ String regionName = args[1];
+
+ // the world the region is in
+ String worldName = args.length > 2 ? args[2] : "";
+
+ // get the world to use
+ World world;
+
+ if (!worldName.isEmpty()) {
+ world = lwc.getPlugin().getServer().getWorld(worldName);
+ } else {
+ world = ((Player) sender).getWorld();
+ }
+
+ // was the world found?
+ if (world == null) {
+ sender.sendMessage(Colors.Red + "Invalid world.");
+ return;
+ }
+
+ GlobalRegionManager regions = worldGuard.getGlobalRegionManager();
+
+ // get the region manager for the world
+ RegionManager regionManager = regions.get(world);
+
+ // try and get the region
+ ProtectedRegion region = regionManager.getRegion(regionName);
+
+ if (region == null) {
+ sender.sendMessage(Colors.Red + "Region not found. If you region is in a different world than you, please use: /lwc admin " + commandName + " " + regionName + " WorldName");
+ return;
+ }
+
+ BlockVector minimum = region.getMinimumPoint();
+ BlockVector maximum = region.getMaximumPoint();
+
+ // Min values
+ int minBlockX = minimum.getBlockX();
+ int minBlockY = minimum.getBlockY();
+ int minBlockZ = minimum.getBlockZ();
+
+ // Max values
+ int maxBlockX = maximum.getBlockX();
+ int maxBlockY = maximum.getBlockY();
+ int maxBlockZ = maximum.getBlockZ();
+
+ // Calculate the amount of the blocks in the region
+ int numBlocks = (maxBlockX - minBlockX + 1) * (maxBlockY - minBlockY + 1) * (maxBlockZ - minBlockZ + 1);
+
+ if (args[0].equals("purgeregion")) {
+ // get all of the protections inside of the region
+ List protections = lwc.getPhysicalDatabase().loadProtections(world.getName(), minBlockX, maxBlockX, minBlockY, maxBlockY, minBlockZ, maxBlockZ);
+
+ // remove all of them
+ for (Protection protection : protections) {
+ protection.remove();
+ }
+
+ sender.sendMessage(Colors.Green + "Removed " + protections.size() + " protections from the region " + regionName);
+ } else if (args[0].equals("protectregion")) {
+ // The owner to assign to the protections
+ String ownerName = "LWCWorldGuard";
+
+ // the number of blocks that were registered
+ int registered = 0;
+
+ for (int x = minBlockX; x <= maxBlockX; x++) {
+ for (int y = minBlockY; y <= maxBlockY; y++) {
+ for (int z = minBlockZ; z <= maxBlockZ; z++) {
+ // Get the block at that location
+ Block block = world.getBlockAt(x, y, z);
+
+ // Ensure it's protectable
+ if (!lwc.isProtectable(block)) {
+ continue;
+ }
+
+ // Check if it's already protected
+ if (lwc.findProtection(block.getLocation()) != null) {
+ continue;
+ }
+
+ // Protect it!
+ lwc.getPhysicalDatabase().registerProtection(block.getTypeId(), Protection.Type.PRIVATE, world.getName(),
+ ownerName, "", x, y, z);
+ registered ++;
+ }
+ }
+ }
+
+ sender.sendMessage("Registered " + registered + " blocks in the region " + regionName);
+ sender.sendMessage("Currently, the owner of these protections is \"" + ownerName + "\". To change this to someone else, run:");
+ sender.sendMessage("/lwc admin updateprotections set owner = 'NewOwner' where owner = '" + ownerName + "'");
+ }
+ }
+
+
+ @Override
+ public void onAccessRequest(LWCAccessEvent event) {
+ if (event.getAccess() != Permission.Access.NONE) {
+ // Player already has access.
+ return;
+ }
+
+ // WorldGuard must be running and LWC must be configured to interface with it.
+ if (worldGuard == null) {
+ return;
+ }
+ if (!configuration.getBoolean("worldguard.enabled", false)) {
+ return;
+ }
+ if (!configuration.getBoolean("worldguard.allowRegionPermissions", true)) {
+ return;
+ }
+
+ Protection protection = event.getProtection();
+ GlobalRegionManager globalRegionManager = worldGuard.getGlobalRegionManager();
+ LocalPlayer wgPlayer = worldGuard.wrapPlayer(event.getPlayer());
+ for (Permission permission : protection.getPermissions()) {
+ if (permission.getType() != Permission.Type.REGION) {
+ continue;
+ }
+ String regionName = permission.getName();
+ if (regionName.equalsIgnoreCase("#this")) {
+ // Handle the special value which tells us to not actually look up a region but
+ // check just the player's WG build permissions on the block. It may be in multiple
+ // regions or none; we don't care here. That's WorldGuard's domain.
+ if (!globalRegionManager.canBuild(event.getPlayer(), protection.getBlock())) {
+ continue;
+ }
+ } else if (regionName.startsWith("#")) {
+ // Silently disallow looking up regions by index, a newer WG feature.
+ // Iterating through potentially thousands of regions each time we check a block's
+ // ACL is not a good idea. It would be cleaner to use regionManager.getRegionExact()
+ // below, but that would break compatibility with older versions of WG.
+ continue;
+ } else {
+ // Region name specified, go look it up
+ World world;
+ int c = regionName.indexOf(':');
+ if (c < 0) {
+ // No world specified in ACL. Use the block's world.
+ world = protection.getBlock().getWorld();
+ } else {
+ // World specified. Partition the string and look up the world.
+ String worldName = regionName.substring(c + 1);
+ world = event.getLWC().getPlugin().getServer().getWorld(worldName);
+ regionName = regionName.substring(0, c);
+ }
+ if (world == null) {
+ continue;
+ }
+ RegionManager regionManager = globalRegionManager.get(world);
+ if (regionManager == null) {
+ continue;
+ }
+ ProtectedRegion region = regionManager.getRegion(regionName);
+ if (region == null) {
+ continue;
+ }
+ // Check the region (and its parents) to see if the player is a member (or an owner).
+ if (!region.isMember(wgPlayer)) {
+ continue;
+ }
+ }
+ // We match the region, so bump up our access level. Whether we get PLAYER access or
+ // ADMIN access depends solely on the LWC permission entry. (I.e., WG owner does not
+ // imply LWC admin.)
+ if (permission.getAccess().ordinal() > event.getAccess().ordinal()) {
+ event.setAccess(permission.getAccess());
+ if (event.getAccess().ordinal() >= Permission.Access.ADMIN.ordinal()) {
+ return;
+ }
+ // else we just have PLAYER access. Keep looking; maybe we match another region
+ // that grants us ADMIN.
+ }
+ }
+ }
+
+ @Override
+ public void onRegisterProtection(LWCProtectionRegisterEvent event) {
+ if (worldGuard == null) {
+ return;
+ }
+
+ if (!configuration.getBoolean("worldguard.enabled", false)) {
+ return;
+ }
+
+ LWC lwc = event.getLWC();
+ Player player = event.getPlayer();
+ Block block = event.getBlock();
+
+ // Load the region manager for the world
+ GlobalRegionManager globalRegionManager = worldGuard.getGlobalRegionManager();
+ RegionManager regionManager = globalRegionManager.get(block.getWorld());
+
+ // Are we enforcing building?
+ if (configuration.getBoolean("worldguard.requireBuildRights", true)) {
+ if (!globalRegionManager.canBuild(player, block)) {
+ lwc.sendLocale(player, "lwc.worldguard.needbuildrights");
+ event.setCancelled(true);
+ return;
+ }
+ }
+
+ // Create a vector for the region
+ Vector vector = BukkitUtil.toVector(block);
+
+ // Load the regions the block encompasses
+ List regions = regionManager.getApplicableRegionsIDs(vector);
+
+ // Are they not in a region, and it's blocked there?
+ if (regions.size() == 0) {
+ if (!configuration.getBoolean("worldguard.allowProtectionsOutsideRegions", true)) {
+ lwc.sendLocale(player, "lwc.worldguard.notallowed");
+ event.setCancelled(true);
+ }
+ } else {
+ // check each region
+ for (String region : regions) {
+ // Should we deny them?
+ // we don't need to explicitly call isRegionAllowed because isRegionBlacklisted checks that as well
+ if (isRegionBlacklisted(region)) {
+ lwc.sendLocale(player, "lwc.worldguard.blacklisted");
+ event.setCancelled(true);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if a region is blacklisted
+ *
+ * @param region
+ * @return
+ */
+ private boolean isRegionBlacklisted(String region) {
+ if (!isRegionAllowed(region)) {
+ return true;
+ }
+
+ List