diff --git a/plugin.yml b/plugin.yml index 8e360014..ee8d91a7 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,3 +1,24 @@ name: WorldGuard main: com.sk89q.worldguard.bukkit.WorldGuardPlugin -version: WGVERSIONMACRO \ No newline at end of file +version: WGVERSIONMACRO +commands: + stopfire: + description: Halts all fire spread until it is disabled or the server is restarted + usage: / + allowfire: + description: Re-enables fire spread if he has been disabled with /stopfire + usage: / + god: + description: Toggles god mode + usage: / [other player] + stack: + description: Stacks items in the player's inventory + usage: / + aliases: ; + region: + description: Adjust protected regions + usage: / ... + aliases: rg, regions + reloadwg: + description: Reload WorldGuard's configuration + usage: / \ No newline at end of file diff --git a/src/com/sk89q/worldguard/bukkit/WorldGuardPlayerListener.java b/src/com/sk89q/worldguard/bukkit/WorldGuardPlayerListener.java index 1ac5a439..6da3263c 100644 --- a/src/com/sk89q/worldguard/bukkit/WorldGuardPlayerListener.java +++ b/src/com/sk89q/worldguard/bukkit/WorldGuardPlayerListener.java @@ -19,31 +19,16 @@ package com.sk89q.worldguard.bukkit; -import java.io.IOException; -import java.util.Arrays; -import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.player.*; import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.Plugin; -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.blocks.ItemType; -import com.sk89q.worldedit.bukkit.WorldEditAPI; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldguard.*; import com.sk89q.worldguard.blacklist.events.ItemUseBlacklistEvent; -import com.sk89q.worldguard.domains.*; -import com.sk89q.worldguard.protection.*; import static com.sk89q.worldguard.bukkit.BukkitUtil.*; /** @@ -54,12 +39,6 @@ public class WorldGuardPlayerListener extends PlayerListener { * Plugin. */ private WorldGuardPlugin plugin; - /** - * Group pattern used to specify groups for the region command. - */ - private static Pattern groupPattern = Pattern.compile("^[gG]:(.+)$"); - - private static int CMD_LIST_SIZE = 9; /** * Construct the object; @@ -162,665 +141,4 @@ public void onPlayerLogin(PlayerLoginEvent event) { } } } - - /** - * Called when a player attempts to use a command - * - * @param event Relevant event details - */ - @Override - public void onPlayerCommand(PlayerChatEvent event) { - if (handleCommand(event)) { - event.setCancelled(true); - } - } - - /** - * Called when a player attempts to use a command - * - * @param event Relevant event details - */ - public boolean handleCommand(PlayerChatEvent event) { - Player player = event.getPlayer(); - String[] split = event.getMessage().split(" "); - - if (split[0].equalsIgnoreCase("/stopfire") && - plugin.hasPermission(player, "/stopfire")) { - if (!plugin.fireSpreadDisableToggle) { - plugin.getServer().broadcastMessage(ChatColor.YELLOW - + "Fire spread has been globally disabled by " + player.getName() + "."); - } else { - player.sendMessage(ChatColor.YELLOW + "Fire spread was already globally disabled."); - } - - plugin.fireSpreadDisableToggle = true; - } else if (split[0].equalsIgnoreCase("/allowfire") - && plugin.hasPermission(player, "/stopfire")) { - if (plugin.fireSpreadDisableToggle) { - plugin.getServer().broadcastMessage(ChatColor.YELLOW - + "Fire spread has been globally re-enabled by " + player.getName() + "."); - } else { - player.sendMessage(ChatColor.YELLOW + "Fire spread was already globally enabled."); - } - - plugin.fireSpreadDisableToggle = false; - } else if (split[0].equalsIgnoreCase("/god") - && plugin.hasPermission(player, "/god")) { - // Allow setting other people invincible - if (split.length > 1) { - if (!plugin.hasPermission(player, "/godother")) { - player.sendMessage(ChatColor.RED + "You don't have permission to make others invincible."); - return true; - } - - Player other = matchSinglePlayer(plugin.getServer(), split[1]); - if (other == null) { - player.sendMessage(ChatColor.RED + "Player not found."); - } else { - if (!plugin.invinciblePlayers.contains(other.getName())) { - plugin.invinciblePlayers.add(other.getName()); - player.sendMessage(ChatColor.YELLOW + other.getName() + " is now invincible!"); - other.sendMessage(ChatColor.YELLOW + player.getName() + " has made you invincible!"); - } else { - plugin.invinciblePlayers.remove(other.getName()); - player.sendMessage(ChatColor.YELLOW + other.getName() + " is no longer invincible."); - other.sendMessage(ChatColor.YELLOW + player.getName() + " has taken away your invincibility."); - } - } - // Invincibility for one's self - } else { - if (!plugin.invinciblePlayers.contains(player.getName())) { - plugin.invinciblePlayers.add(player.getName()); - player.sendMessage(ChatColor.YELLOW + "You are now invincible!"); - } else { - plugin.invinciblePlayers.remove(player.getName()); - player.sendMessage(ChatColor.YELLOW + "You are no longer invincible."); - } - } - } else if ((split[0].equalsIgnoreCase("/stack") - || split[0].equalsIgnoreCase("/;")) - && plugin.hasPermission(player, "/stack")) { - ItemStack[] items = player.getInventory().getContents(); - int len = items.length; - - int affected = 0; - - for (int i = 0; i < len; i++) { - ItemStack item = items[i]; - - // Avoid infinite stacks and stacks with durability - if (item == null || item.getAmount() <= 0 - || ItemType.shouldNotStack(item.getTypeId())) { - continue; - } - - // Ignore buckets - if (item.getTypeId() >= 325 && item.getTypeId() <= 327) { - continue; - } - - if (item.getAmount() < 64) { - int needed = 64 - item.getAmount(); // Number of needed items until 64 - - // Find another stack of the same type - for (int j = i + 1; j < len; j++) { - ItemStack item2 = items[j]; - - // Avoid infinite stacks and stacks with durability - if (item2 == null || item2.getAmount() <= 0 - || ItemType.shouldNotStack(item.getTypeId())) { - continue; - } - - // Same type? - // Blocks store their color in the damage value - if (item2.getTypeId() == item.getTypeId() && - (!ItemType.usesDamageValue(item.getTypeId()) - || item.getDamage() == item2.getDamage())) { - // This stack won't fit in the parent stack - if (item2.getAmount() > needed) { - item.setAmount(64); - item2.setAmount(item2.getAmount() - needed); - break; - // This stack will - } else { - items[j] = null; - item.setAmount(item.getAmount() + item2.getAmount()); - needed = 64 - item.getAmount(); - } - - affected++; - } - } - } - } - - if (affected > 0) { - player.getInventory().setContents(items); - } - - player.sendMessage(ChatColor.YELLOW + "Items compacted into stacks!"); - } else if (split[0].equalsIgnoreCase("/rg") - || split[0].equalsIgnoreCase("/region")) { - if (split.length < 2) { - player.sendMessage(ChatColor.RED + "/region ..."); - return true; - } - - String action = split[1]; - String[] args = new String[split.length - 1]; - System.arraycopy(split, 1, args, 0, split.length - 1); - - handleRegionCommand(player, action, args); - } else if (split[0].equalsIgnoreCase("/reload") - && plugin.hasPermission(player, "/reload") - && split.length > 1) { - if (split[1].equalsIgnoreCase("WorldGuard")) { - LoggerToChatHandler handler = new LoggerToChatHandler(player); - handler.setLevel(Level.ALL); - Logger minecraftLogger = Logger.getLogger("Minecraft"); - minecraftLogger.addHandler(handler); - - try { - plugin.loadConfiguration(); - plugin.postReload(); - player.sendMessage("WorldGuard configuration reloaded."); - } catch (Throwable t) { - player.sendMessage("Error while reloading: " - + t.getMessage()); - } finally { - minecraftLogger.removeHandler(handler); - } - - return true; - } - } else { - return false; - } - - return true; - } - - /** - * Handles a region command. - * - * @param player - * @param action - * @param args - */ - private void handleRegionCommand(Player player, String action, String[] args) { - if (!plugin.useRegions) { - player.sendMessage(ChatColor.RED + "Regions are disabled."); - return; - } - - if (action.equalsIgnoreCase("define")) { - if (!canUseRegionCommand(player, "/regiondefine")) { - player.sendMessage(ChatColor.RED + "You don't have the /regiondefine permission."); - return; - } - - if (args.length < 2) { - player.sendMessage(ChatColor.RED + "/region define [owner1 [owner2 [owners...]]]"); - return; - } - - try { - String id = args[1].toLowerCase(); - Plugin wePlugin = plugin.getServer().getPluginManager().getPlugin("WorldEdit"); - if (plugin == null) { - player.sendMessage(ChatColor.RED + "WorldEdit must be installed and enabled as a plugin."); - return; - } - - WorldEditPlugin worldEdit = (WorldEditPlugin)wePlugin; - WorldEditAPI api = worldEdit.getAPI(); - - LocalSession session = api.getSession(player); - Region weRegion = session.getRegion(); - - BlockVector min = weRegion.getMinimumPoint().toBlockVector(); - BlockVector max = weRegion.getMaximumPoint().toBlockVector(); - - ProtectedRegion region = new ProtectedCuboidRegion(min, max); - if (args.length >= 3) { - region.setOwners(parseDomainString(args, 2)); - } - plugin.regionManager.addRegion(id, region); - plugin.regionLoader.save(plugin.regionManager); - player.sendMessage(ChatColor.YELLOW + "Region saved as " + id + "."); - } catch (IncompleteRegionException e) { - player.sendMessage(ChatColor.RED + "You must first define an area in WorldEdit."); - } catch (IOException e) { - player.sendMessage(ChatColor.RED + "Region database failed to save: " - + e.getMessage()); - } - } else if (action.equalsIgnoreCase("claim")) { - if (!canUseRegionCommand(player, "/regionclaim")) { - player.sendMessage(ChatColor.RED + "You don't have the /regionclaim permission."); - return; - } - - if (args.length < 1) { - player.sendMessage(ChatColor.RED + "/region claim "); - return; - } - - try { - String id = args[1].toLowerCase(); - Plugin wePlugin = plugin.getServer().getPluginManager().getPlugin("WorldEdit"); - if (plugin == null) { - player.sendMessage(ChatColor.RED + "WorldEdit must be installed and enabled as a plugin."); - return; - } - - ProtectedRegion existing = plugin.regionManager.getRegion(id); - - if (existing != null) { - if (!existing.getOwners().contains(plugin.wrapPlayer(player))) { - player.sendMessage(ChatColor.RED + "You don't own this region."); - return; - } - } - - WorldEditPlugin worldEdit = (WorldEditPlugin)wePlugin; - WorldEditAPI api = worldEdit.getAPI(); - - LocalSession session = api.getSession(player); - Region weRegion = session.getRegion(); - - BlockVector min = weRegion.getMinimumPoint().toBlockVector(); - BlockVector max = weRegion.getMaximumPoint().toBlockVector(); - - ProtectedRegion region = new ProtectedCuboidRegion(min, max); - - if (plugin.regionManager.overlapsUnownedRegion(region, plugin.wrapPlayer(player))) { - player.sendMessage(ChatColor.RED + "This region overlaps with someone else's region."); - return; - } - - region.getOwners().addPlayer(player.getName()); - - plugin.regionManager.addRegion(id, region); - plugin.regionLoader.save(plugin.regionManager); - player.sendMessage(ChatColor.YELLOW + "Region saved as " + id + "."); - } catch (IncompleteRegionException e) { - player.sendMessage(ChatColor.RED + "You must first define an area in WorldEdit."); - } catch (IOException e) { - player.sendMessage(ChatColor.RED + "Region database failed to save: " - + e.getMessage()); - } - } else if (action.equalsIgnoreCase("flag")) { - if (!canUseRegionCommand(player, "/regiondefine")) { - player.sendMessage(ChatColor.RED + "You don't have the /regiondefine permission."); - return; - } - - if (args.length < 4) { - player.sendMessage(ChatColor.RED + "/region flag "); - return; - } - - try { - String id = args[1].toLowerCase(); - String flagStr = args[2]; - String stateStr = args[3]; - ProtectedRegion region = plugin.regionManager.getRegion(id); - - if (region == null) { - player.sendMessage(ChatColor.RED + "Could not find a region by that ID."); - return; - } - - AreaFlags.State state = null; - - if (stateStr.equalsIgnoreCase("allow")) { - state = AreaFlags.State.ALLOW; - } else if (stateStr.equalsIgnoreCase("deny")) { - state = AreaFlags.State.DENY; - } else if (stateStr.equalsIgnoreCase("none")) { - state = AreaFlags.State.NONE; - } else { - player.sendMessage(ChatColor.RED + "Acceptable states: allow, deny, none"); - return; - } - - AreaFlags flags = region.getFlags(); - - if (flagStr.equalsIgnoreCase("build")) { - flags.allowBuild = state; - } else if (flagStr.equalsIgnoreCase("pvp")) { - flags.allowPvP = state; - } else if (flagStr.equalsIgnoreCase("tnt")) { - flags.allowTNT = state; - } else if (flagStr.equalsIgnoreCase("lighter")) { - flags.allowLighter = state; - } else { - player.sendMessage(ChatColor.RED + "Acceptable flags: build, pvp, tnt, lighter"); - return; - } - - plugin.regionLoader.save(plugin.regionManager); - player.sendMessage(ChatColor.YELLOW + "Region '" + id + "' updated."); - } catch (IOException e) { - player.sendMessage(ChatColor.RED + "Region database failed to save: " - + e.getMessage()); - } - /*} else if (action.equalsIgnoreCase("priority")) { - if (!canUseRegionCommand(player, "/regiondefine")) { - player.sendMessage(ChatColor.RED + "You don't have the /regiondefine permission."); - return; - } - - if (args.length < 3) { - player.sendMessage(ChatColor.RED + "/region priority "); - return; - } - - try { - String id = args[1].toLowerCase(); - int priority = 0; - try { - priority = Integer.parseInt(args[2]); - } catch (NumberFormatException e) { - player.sendMessage(ChatColor.RED + "The priority must be a number."); - return; - } - - ProtectedRegion region = plugin.regionManager.getRegion(id); - - if (region == null) { - player.sendMessage(ChatColor.RED + "Could not find a region by that ID."); - return; - } - - region.setPriority(priority); - - plugin.regionLoader.save(plugin.regionManager); - player.sendMessage(ChatColor.YELLOW + "Region '" + id + "' updated."); - } catch (IOException e) { - player.sendMessage(ChatColor.RED + "Region database failed to save: " - + e.getMessage()); - }*/ - } else if (action.equalsIgnoreCase("info")) { - if (!canUseRegionCommand(player, "/regioninfo")) { - player.sendMessage(ChatColor.RED + "You don't have the /regioninfo permission."); - return; - } - - if (args.length < 2) { - player.sendMessage(ChatColor.RED + "/region info "); - return; - } - - String id = args[1].toLowerCase(); - if (!plugin.regionManager.hasRegion(id)) { - player.sendMessage(ChatColor.RED + "A region with ID '" - + id + "' doesn't exist."); - return; - } - - ProtectedRegion region = plugin.regionManager.getRegion(id); - AreaFlags flags = region.getFlags(); - DefaultDomain domain = region.getOwners(); - - player.sendMessage(ChatColor.YELLOW + "Region ID: " + id); - player.sendMessage(ChatColor.GRAY + "Type: " + region.getClass().getCanonicalName()); - player.sendMessage(ChatColor.GRAY + "Priority: " + region.getPriority()); - player.sendMessage(ChatColor.BLUE + "Build: " + flags.allowBuild.name()); - player.sendMessage(ChatColor.BLUE + "PvP: " + flags.allowPvP.name()); - player.sendMessage(ChatColor.BLUE + "TNT: " + flags.allowTNT.name()); - player.sendMessage(ChatColor.BLUE + "Lighter: " + flags.allowLighter.name()); - player.sendMessage(ChatColor.LIGHT_PURPLE + "Players: " + domain.toPlayersString()); - player.sendMessage(ChatColor.LIGHT_PURPLE + "Groups: " + domain.toGroupsString()); - } else if (action.equalsIgnoreCase("addowner")) { - if (!canUseRegionCommand(player, "/regiondefine") - && !canUseRegionCommand(player, "/regionclaim")) { - player.sendMessage(ChatColor.RED + "You don't have the /regiondefine permission."); - return; - } - - if (args.length < 2) { - player.sendMessage(ChatColor.RED + "/region addowner "); - return; - } - - try { - String id = args[1].toLowerCase(); - if (!plugin.regionManager.hasRegion(id)) { - player.sendMessage(ChatColor.RED + "A region with ID '" - + id + "' doesn't exist."); - return; - } - - ProtectedRegion existing = plugin.regionManager.getRegion(id); - - if (!canUseRegionCommand(player, "/regiondefine") - && !existing.getOwners().contains(plugin.wrapPlayer(player))) { - player.sendMessage(ChatColor.RED + "You don't own this region."); - return; - } - - addToDomain(existing.getOwners(), args, 2); - - plugin.regionLoader.save(plugin.regionManager); - player.sendMessage(ChatColor.YELLOW + "Region updated!"); - } catch (IOException e) { - player.sendMessage(ChatColor.RED + "Region database failed to save: " - + e.getMessage()); - } - } else if (action.equalsIgnoreCase("removeowner")) { - if (!canUseRegionCommand(player, "/regiondefine") - && !canUseRegionCommand(player, "/regionclaim")) { - player.sendMessage(ChatColor.RED + "You don't have the /regiondefine permission."); - return; - } - - if (args.length < 2) { - player.sendMessage(ChatColor.RED + "/region removeowner "); - return; - } - - try { - String id = args[1].toLowerCase(); - if (!plugin.regionManager.hasRegion(id)) { - player.sendMessage(ChatColor.RED + "A region with ID '" - + id + "' doesn't exist."); - return; - } - - ProtectedRegion existing = plugin.regionManager.getRegion(id); - - if (!canUseRegionCommand(player, "/regiondefine") - && !existing.getOwners().contains(plugin.wrapPlayer(player))) { - player.sendMessage(ChatColor.RED + "You don't own this region."); - return; - } - - removeFromDomain(existing.getOwners(), args, 2); - - plugin.regionLoader.save(plugin.regionManager); - player.sendMessage(ChatColor.YELLOW + "Region updated!"); - } catch (IOException e) { - player.sendMessage(ChatColor.RED + "Region database failed to save: " - + e.getMessage()); - } - } else if (action.equalsIgnoreCase("list")) { - if (!canUseRegionCommand(player, "/regiondefine")) { - player.sendMessage(ChatColor.RED + "You don't have the /regiondefine permission."); - return; - } - - int page = 0; - - if (args.length >= 2) { - try { - page = Math.max(0, Integer.parseInt(args[1]) - 1); - } catch (NumberFormatException e) { - page = 0; - } - } - - Map regions = plugin.regionManager.getRegions(); - int size = regions.size(); - int pages = (int)Math.ceil(size / (float)CMD_LIST_SIZE); - - String[] regionIDList = new String[size]; - int index = 0; - for (String id : regions.keySet()) { - regionIDList[index] = id; - index++; - } - Arrays.sort(regionIDList); - - - player.sendMessage(ChatColor.RED + "Regions (page " - + (page + 1) + " of " + pages + "):"); - - if (page < pages) { - for (int i = page * CMD_LIST_SIZE; i < page * CMD_LIST_SIZE + CMD_LIST_SIZE; i++) { - if (i >= size) break; - player.sendMessage(ChatColor.YELLOW.toString() + (i + 1) + ". " + regionIDList[i]); - } - } - } else if (action.equalsIgnoreCase("delete")) { - if (!canUseRegionCommand(player, "/regiondelete") - && !canUseRegionCommand(player, "/regionclaim")) { - player.sendMessage(ChatColor.RED + "You don't have the /regiondelete permission."); - return; - } - - if (args.length < 2) { - player.sendMessage(ChatColor.RED + "/region delete "); - return; - } - - try { - String id = args[1].toLowerCase(); - if (!plugin.regionManager.hasRegion(id)) { - player.sendMessage(ChatColor.RED + "A region with ID '" - + id + "' doesn't exist."); - return; - } - - ProtectedRegion existing = plugin.regionManager.getRegion(id); - - if (!canUseRegionCommand(player, "/regiondelete") - && !existing.getOwners().contains(plugin.wrapPlayer(player))) { - player.sendMessage(ChatColor.RED + "You don't own this region."); - return; - } - - plugin.regionManager.removeRegion(id); - plugin.regionLoader.save(plugin.regionManager); - player.sendMessage(ChatColor.YELLOW + "Region removed!"); - } catch (IOException e) { - player.sendMessage(ChatColor.RED + "Region database failed to save: " - + e.getMessage()); - } - } else if (action.equalsIgnoreCase("save")) { - if (!canUseRegionCommand(player, "/regionsave")) { - player.sendMessage(ChatColor.RED + "You don't have the /regionsave permission."); - return; - } - - try { - plugin.regionLoader.save(plugin.regionManager); - player.sendMessage(ChatColor.YELLOW + "Region database saved to file!"); - } catch (IOException e) { - player.sendMessage(ChatColor.RED + "Region database failed to save: " - + e.getMessage()); - } - } else if (action.equalsIgnoreCase("load")) { - if (!canUseRegionCommand(player, "/regionload")) { - player.sendMessage(ChatColor.RED + "You don't have the /regionload permission."); - return; - } - - try { - plugin.regionLoader.load(plugin.regionManager); - player.sendMessage(ChatColor.YELLOW + "Region database loaded from file!"); - } catch (IOException e) { - player.sendMessage(ChatColor.RED + "Region database failed to load: " - + e.getMessage()); - } - } else { - player.sendMessage(ChatColor.RED + "/region ..."); - } - } - - /** - * Checks for the command or /region. - * - * @param player - * @param cmd - * @return - */ - private boolean canUseRegionCommand(Player player, String cmd) { - return plugin.hasPermission(player, "/region") - || plugin.hasPermission(player, cmd); - } - - /** - * Parse a group/player DefaultDomain specification for areas. - * - * @param domain - * @param split - * @param startIndex - */ - private static void addToDomain(DefaultDomain domain, - String[] split, int startIndex) { - for (int i = startIndex; i < split.length; i++) { - String s = split[i]; - Matcher m = groupPattern.matcher(s); - if (m.matches()) { - domain.addGroup(m.group(1)); - } else { - domain.addPlayer(s); - } - } - } - - /** - * Parse a group/player DefaultDomain specification for areas. - * - * @param domain - * @param split - * @param startIndex - */ - private static void removeFromDomain(DefaultDomain domain, - String[] split, int startIndex) { - for (int i = startIndex; i < split.length; i++) { - String s = split[i]; - Matcher m = groupPattern.matcher(s); - if (m.matches()) { - domain.removeGroup(m.group(1)); - } else { - domain.removePlayer(s); - } - } - } - - /** - * Parse a group/player DefaultDomain specification for areas. - * - * @param split - * @param startIndex - * @return - */ - private static DefaultDomain parseDomainString(String[] split, int startIndex) { - DefaultDomain domain = new DefaultDomain(); - - for (int i = startIndex; i < split.length; i++) { - String s = split[i]; - Matcher m = groupPattern.matcher(s); - if (m.matches()) { - domain.addGroup(m.group(1)); - } else { - domain.addPlayer(s); - } - } - - return domain; - } } diff --git a/src/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java b/src/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java index 8899cef6..5213266d 100644 --- a/src/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java +++ b/src/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java @@ -19,29 +19,46 @@ package com.sk89q.worldguard.bukkit; +import static com.sk89q.worldguard.bukkit.BukkitUtil.matchSinglePlayer; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.bukkit.command.Command; import org.bukkit.entity.Player; +import org.bukkit.ChatColor; import org.bukkit.Server; import org.bukkit.event.Event.Priority; import org.bukkit.event.Event; import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginLoader; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.util.config.Configuration; import com.sk89q.bukkit.migration.PermissionsResolverManager; import com.sk89q.bukkit.migration.PermissionsResolverServerListener; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.blocks.ItemType; +import com.sk89q.worldedit.bukkit.WorldEditAPI; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldguard.blacklist.Blacklist; import com.sk89q.worldguard.blacklist.BlacklistLogger; import com.sk89q.worldguard.blacklist.loggers.*; +import com.sk89q.worldguard.domains.DefaultDomain; import com.sk89q.worldguard.protection.*; /** @@ -52,6 +69,9 @@ public class WorldGuardPlugin extends JavaPlugin { private static final Logger logger = Logger.getLogger("Minecraft.WorldGuard"); + private static Pattern groupPattern = Pattern.compile("^[gG]:(.+)$"); + private static int CMD_LIST_SIZE = 9; + private final WorldGuardPlayerListener playerListener = new WorldGuardPlayerListener(this); private final WorldGuardBlockListener blockListener = @@ -112,6 +132,16 @@ public class WorldGuardPlugin extends JavaPlugin { boolean useRegions; int regionWand = 287; + /** + * Construct the plugin. + * + * @param pluginLoader + * @param instance + * @param desc + * @param folder + * @param plugin + * @param cLoader + */ public WorldGuardPlugin(PluginLoader pluginLoader, Server instance, PluginDescriptionFile desc, File folder, File plugin, ClassLoader cLoader) { super(pluginLoader, instance, desc, folder, plugin, cLoader); @@ -132,12 +162,21 @@ public WorldGuardPlugin(PluginLoader pluginLoader, Server instance, registerEvents(); } + /** + * Called on plugin enable. + */ public void onEnable() { } + /** + * Called on plugin disable. + */ public void onDisable() { } + /** + * Register used events. + */ private void registerEvents() { registerEvent(Event.Type.BLOCK_DAMAGED, blockListener, Priority.Normal); registerEvent(Event.Type.BLOCK_FLOW, blockListener, Priority.Normal); @@ -151,7 +190,6 @@ private void registerEvents() { registerEvent(Event.Type.ENTITY_DAMAGEDBY_ENTITY, entityListener, Priority.Normal); registerEvent(Event.Type.ENTITY_EXPLODE, entityListener, Priority.Normal); - registerEvent(Event.Type.PLAYER_COMMAND, playerListener, Priority.Normal); registerEvent(Event.Type.PLAYER_ITEM, playerListener, Priority.Normal); registerEvent(Event.Type.PLAYER_JOIN, playerListener, Priority.Normal); registerEvent(Event.Type.PLAYER_LOGIN, playerListener, Priority.Normal); @@ -160,10 +198,22 @@ private void registerEvents() { permsListener.register(this); } + /** + * Register an event. + * + * @param type + * @param listener + * @param priority + */ private void registerEvent(Event.Type type, Listener listener, Priority priority) { getServer().getPluginManager().registerEvent(type, listener, priority, this); } + /** + * Create a default configuration file from the .jar. + * + * @param name + */ private void createDefaultConfiguration(String name) { File actual = new File(getDataFolder(), name); if (!actual.exists()) { @@ -201,7 +251,7 @@ private void createDefaultConfiguration(String name) { } /** - * Load the configuration + * Load the configuration. */ public void loadConfiguration() { Configuration config = getConfiguration(); @@ -358,13 +408,712 @@ public void postReload() { } catch (NullPointerException e) { // Thrown if loaded too early } } + + /** + * Handles a command. + */ + public boolean onCommand(Player player, Command cmd, String commandLabel, String[] args) { + try { + return handleCommand(player, cmd.getName(), args); + } catch (InsufficientArgumentsException e) { + if (e.getHelp() != null) { + player.sendMessage(ChatColor.RED + e.getHelp()); + return true; + } else { + return false; + } + } catch (InsufficientPermissionsException e) { + player.sendMessage(ChatColor.RED + "You don't have sufficient permission."); + return true; + } + } + + /** + * Internal method to handle a command. + * + * @param player + * @param cmd + * @param args + * @return + * @throws InsufficientArgumentsException + * @throws InsufficientPermissionsException + */ + private boolean handleCommand(Player player, String cmd, String[] args) + throws InsufficientArgumentsException, InsufficientPermissionsException { + + if (cmd.equalsIgnoreCase("stopfire")) { + checkPermission(player, "/stopfire"); + checkArgs(args, 0, 0); + + if (!fireSpreadDisableToggle) { + getServer().broadcastMessage(ChatColor.YELLOW + + "Fire spread has been globally disabled by " + player.getName() + "."); + } else { + player.sendMessage(ChatColor.YELLOW + "Fire spread was already globally disabled."); + } + + fireSpreadDisableToggle = true; + + return true; + } + + if (cmd.equalsIgnoreCase("allowfire")) { + checkPermission(player, "/stopfire"); + checkArgs(args, 0, 0); + + if (fireSpreadDisableToggle) { + getServer().broadcastMessage(ChatColor.YELLOW + + "Fire spread has been globally re-enabled by " + player.getName() + "."); + } else { + player.sendMessage(ChatColor.YELLOW + "Fire spread was already globally enabled."); + } + + fireSpreadDisableToggle = false; + + return true; + } + + if (cmd.equalsIgnoreCase("god")) { + checkPermission(player, "/god"); + checkArgs(args, 0, 1); + + // Allow setting other people invincible + if (args.length > 1) { + if (!hasPermission(player, "/godother")) { + player.sendMessage(ChatColor.RED + "You don't have permission to make others invincible."); + return true; + } + + Player other = matchSinglePlayer(getServer(), args[1]); + if (other == null) { + player.sendMessage(ChatColor.RED + "Player not found."); + } else { + if (!invinciblePlayers.contains(other.getName())) { + invinciblePlayers.add(other.getName()); + player.sendMessage(ChatColor.YELLOW + other.getName() + " is now invincible!"); + other.sendMessage(ChatColor.YELLOW + player.getName() + " has made you invincible!"); + } else { + invinciblePlayers.remove(other.getName()); + player.sendMessage(ChatColor.YELLOW + other.getName() + " is no longer invincible."); + other.sendMessage(ChatColor.YELLOW + player.getName() + " has taken away your invincibility."); + } + } + // Invincibility for one's self + } else { + if (!invinciblePlayers.contains(player.getName())) { + invinciblePlayers.add(player.getName()); + player.sendMessage(ChatColor.YELLOW + "You are now invincible!"); + } else { + invinciblePlayers.remove(player.getName()); + player.sendMessage(ChatColor.YELLOW + "You are no longer invincible."); + } + } + + return true; + } + + if (cmd.equalsIgnoreCase("stack")) { + checkPermission(player, "stack"); + checkArgs(args, 0, 0); + + ItemStack[] items = player.getInventory().getContents(); + int len = items.length; + + int affected = 0; + + for (int i = 0; i < len; i++) { + ItemStack item = items[i]; + + // Avoid infinite stacks and stacks with durability + if (item == null || item.getAmount() <= 0 + || ItemType.shouldNotStack(item.getTypeId())) { + continue; + } + + // Ignore buckets + if (item.getTypeId() >= 325 && item.getTypeId() <= 327) { + continue; + } + + if (item.getAmount() < 64) { + int needed = 64 - item.getAmount(); // Number of needed items until 64 + + // Find another stack of the same type + for (int j = i + 1; j < len; j++) { + ItemStack item2 = items[j]; + + // Avoid infinite stacks and stacks with durability + if (item2 == null || item2.getAmount() <= 0 + || ItemType.shouldNotStack(item.getTypeId())) { + continue; + } + + // Same type? + // Blocks store their color in the damage value + if (item2.getTypeId() == item.getTypeId() && + (!ItemType.usesDamageValue(item.getTypeId()) + || item.getDamage() == item2.getDamage())) { + // This stack won't fit in the parent stack + if (item2.getAmount() > needed) { + item.setAmount(64); + item2.setAmount(item2.getAmount() - needed); + break; + // This stack will + } else { + items[j] = null; + item.setAmount(item.getAmount() + item2.getAmount()); + needed = 64 - item.getAmount(); + } + + affected++; + } + } + } + } + + if (affected > 0) { + player.getInventory().setContents(items); + } + + player.sendMessage(ChatColor.YELLOW + "Items compacted into stacks!"); + + return true; + } + + if (cmd.equalsIgnoreCase("region")) { + checkArgs(args, 1, -1); + + String action = args[1]; + String[] subArgs = new String[args.length - 1]; + System.arraycopy(args, 1, subArgs, 0, args.length - 1); + return handleRegionCommand(player, action, subArgs); + } + + if (cmd.equalsIgnoreCase("reloadwg")) { + checkPermission(player, "reloadwg"); + checkArgs(args, 0, 0); + + LoggerToChatHandler handler = new LoggerToChatHandler(player); + handler.setLevel(Level.ALL); + Logger minecraftLogger = Logger.getLogger("Minecraft"); + minecraftLogger.addHandler(handler); + + try { + loadConfiguration(); + postReload(); + player.sendMessage("WorldGuard configuration reloaded."); + } catch (Throwable t) { + player.sendMessage("Error while reloading: " + + t.getMessage()); + } finally { + minecraftLogger.removeHandler(handler); + } + + return true; + } + + return false; + } + + /** + * Handles a region command. + * + * @param player + * @param action + * @param args + * @throws InsufficientPermissionsException + * @throws InsufficientArgumentsException + */ + private boolean handleRegionCommand(Player player, String action, String[] args) + throws InsufficientPermissionsException, InsufficientArgumentsException { + if (!useRegions) { + player.sendMessage(ChatColor.RED + "Regions are disabled."); + return true; + } + + Plugin wePlugin = getServer().getPluginManager().getPlugin("WorldEdit"); + if (wePlugin == null) { + player.sendMessage(ChatColor.RED + "WorldEdit must be installed and enabled!"); + return true; + } + + if (action.equalsIgnoreCase("define")) { + checkRegionPermission(player, "/regiondefine"); + checkArgs(args, 1, -1, "/region define [owner1 [owner2 [owners...]]]"); + + try { + String id = args[1].toLowerCase(); + + WorldEditPlugin worldEdit = (WorldEditPlugin)wePlugin; + WorldEditAPI api = worldEdit.getAPI(); + + LocalSession session = api.getSession(player); + Region weRegion = session.getRegion(); + + BlockVector min = weRegion.getMinimumPoint().toBlockVector(); + BlockVector max = weRegion.getMaximumPoint().toBlockVector(); + + ProtectedRegion region = new ProtectedCuboidRegion(min, max); + if (args.length >= 2) { + region.setOwners(parseDomainString(args, 2)); + } + regionManager.addRegion(id, region); + regionLoader.save(regionManager); + player.sendMessage(ChatColor.YELLOW + "Region saved as " + id + "."); + } catch (IncompleteRegionException e) { + player.sendMessage(ChatColor.RED + "You must first define an area in WorldEdit."); + } catch (IOException e) { + player.sendMessage(ChatColor.RED + "Region database failed to save: " + + e.getMessage()); + } + + return true; + } + + if (action.equalsIgnoreCase("claim")) { + checkRegionPermission(player, "/regionclaim"); + checkArgs(args, 1, 1, "/region claim "); + + try { + String id = args[1].toLowerCase(); + + ProtectedRegion existing = regionManager.getRegion(id); + + if (existing != null) { + if (!existing.getOwners().contains(wrapPlayer(player))) { + player.sendMessage(ChatColor.RED + "You don't own this region."); + return true; + } + } + + WorldEditPlugin worldEdit = (WorldEditPlugin)wePlugin; + WorldEditAPI api = worldEdit.getAPI(); + + LocalSession session = api.getSession(player); + Region weRegion = session.getRegion(); + + BlockVector min = weRegion.getMinimumPoint().toBlockVector(); + BlockVector max = weRegion.getMaximumPoint().toBlockVector(); + + ProtectedRegion region = new ProtectedCuboidRegion(min, max); + + if (regionManager.overlapsUnownedRegion(region, wrapPlayer(player))) { + player.sendMessage(ChatColor.RED + "This region overlaps with someone else's region."); + return true; + } + + region.getOwners().addPlayer(player.getName()); + + regionManager.addRegion(id, region); + regionLoader.save(regionManager); + player.sendMessage(ChatColor.YELLOW + "Region saved as " + id + "."); + } catch (IncompleteRegionException e) { + player.sendMessage(ChatColor.RED + "You must first define an area in WorldEdit."); + } catch (IOException e) { + player.sendMessage(ChatColor.RED + "Region database failed to save: " + + e.getMessage()); + } + + return true; + } + + if (action.equalsIgnoreCase("flag")) { + checkRegionPermission(player, "/regiondefine"); + checkArgs(args, 3, 3, "/region flag "); + + try { + String id = args[1].toLowerCase(); + String flagStr = args[2]; + String stateStr = args[3]; + ProtectedRegion region = regionManager.getRegion(id); + + if (region == null) { + player.sendMessage(ChatColor.RED + "Could not find a region by that ID."); + return true; + } + + AreaFlags.State state = null; + + if (stateStr.equalsIgnoreCase("allow")) { + state = AreaFlags.State.ALLOW; + } else if (stateStr.equalsIgnoreCase("deny")) { + state = AreaFlags.State.DENY; + } else if (stateStr.equalsIgnoreCase("none")) { + state = AreaFlags.State.NONE; + } else { + player.sendMessage(ChatColor.RED + "Acceptable states: allow, deny, none"); + return true; + } + + AreaFlags flags = region.getFlags(); + + if (flagStr.equalsIgnoreCase("build")) { + flags.allowBuild = state; + } else if (flagStr.equalsIgnoreCase("pvp")) { + flags.allowPvP = state; + } else if (flagStr.equalsIgnoreCase("tnt")) { + flags.allowTNT = state; + } else if (flagStr.equalsIgnoreCase("lighter")) { + flags.allowLighter = state; + } else { + player.sendMessage(ChatColor.RED + "Acceptable flags: build, pvp, tnt, lighter"); + return true; + } + + regionLoader.save(regionManager); + player.sendMessage(ChatColor.YELLOW + "Region '" + id + "' updated."); + } catch (IOException e) { + player.sendMessage(ChatColor.RED + "Region database failed to save: " + + e.getMessage()); + } + + return true; + } + + if (action.equalsIgnoreCase("info")) { + checkRegionPermission(player, "/regioninfo"); + checkArgs(args, 1, 1, "/region info "); + + String id = args[1].toLowerCase(); + if (!regionManager.hasRegion(id)) { + player.sendMessage(ChatColor.RED + "A region with ID '" + + id + "' doesn't exist."); + return true; + } + + ProtectedRegion region = regionManager.getRegion(id); + AreaFlags flags = region.getFlags(); + DefaultDomain domain = region.getOwners(); + + player.sendMessage(ChatColor.YELLOW + "Region ID: " + id); + player.sendMessage(ChatColor.GRAY + "Type: " + region.getClass().getCanonicalName()); + player.sendMessage(ChatColor.GRAY + "Priority: " + region.getPriority()); + player.sendMessage(ChatColor.BLUE + "Build: " + flags.allowBuild.name()); + player.sendMessage(ChatColor.BLUE + "PvP: " + flags.allowPvP.name()); + player.sendMessage(ChatColor.BLUE + "TNT: " + flags.allowTNT.name()); + player.sendMessage(ChatColor.BLUE + "Lighter: " + flags.allowLighter.name()); + player.sendMessage(ChatColor.LIGHT_PURPLE + "Players: " + domain.toPlayersString()); + player.sendMessage(ChatColor.LIGHT_PURPLE + "Groups: " + domain.toGroupsString()); + + return true; + } + + if (action.equalsIgnoreCase("addowner")) { + if (!hasPermission(player, "/regionclaim")) { + checkRegionPermission(player, "/regiondefine"); + } + checkArgs(args, 2, -1, "/region addowner [owner1 [owner2 [owners...]]]"); + + try { + String id = args[1].toLowerCase(); + if (!regionManager.hasRegion(id)) { + player.sendMessage(ChatColor.RED + "A region with ID '" + + id + "' doesn't exist."); + return true; + } + + ProtectedRegion existing = regionManager.getRegion(id); + + if (!canUseRegionCommand(player, "/regiondefine") + && !existing.getOwners().contains(wrapPlayer(player))) { + player.sendMessage(ChatColor.RED + "You don't own this region."); + return true; + } + + addToDomain(existing.getOwners(), args, 2); + + regionLoader.save(regionManager); + player.sendMessage(ChatColor.YELLOW + "Region updated!"); + } catch (IOException e) { + player.sendMessage(ChatColor.RED + "Region database failed to save: " + + e.getMessage()); + } + + return true; + } + + if (action.equalsIgnoreCase("removeowner")) { + if (!hasPermission(player, "/regionclaim")) { + checkRegionPermission(player, "/regiondefine"); + } + checkArgs(args, 2, -1, "/region removeowner [owner1 [owner2 [owners...]]]"); + + try { + String id = args[1].toLowerCase(); + if (!regionManager.hasRegion(id)) { + player.sendMessage(ChatColor.RED + "A region with ID '" + + id + "' doesn't exist."); + return true; + } + + ProtectedRegion existing = regionManager.getRegion(id); + + if (!canUseRegionCommand(player, "/regiondefine") + && !existing.getOwners().contains(wrapPlayer(player))) { + player.sendMessage(ChatColor.RED + "You don't own this region."); + return true; + } + + removeFromDomain(existing.getOwners(), args, 2); + + regionLoader.save(regionManager); + player.sendMessage(ChatColor.YELLOW + "Region updated!"); + } catch (IOException e) { + player.sendMessage(ChatColor.RED + "Region database failed to save: " + + e.getMessage()); + } + + return true; + } + + if (action.equalsIgnoreCase("list")) { + checkRegionPermission(player, "/regionlist"); + checkArgs(args, 0, 1, "/region list [page]"); + + int page = 0; + + if (args.length >= 2) { + try { + page = Math.max(0, Integer.parseInt(args[1]) - 1); + } catch (NumberFormatException e) { + page = 0; + } + } + + Map regions = regionManager.getRegions(); + int size = regions.size(); + int pages = (int)Math.ceil(size / (float)CMD_LIST_SIZE); + + String[] regionIDList = new String[size]; + int index = 0; + for (String id : regions.keySet()) { + regionIDList[index] = id; + index++; + } + Arrays.sort(regionIDList); + + + player.sendMessage(ChatColor.RED + "Regions (page " + + (page + 1) + " of " + pages + "):"); + + if (page < pages) { + for (int i = page * CMD_LIST_SIZE; i < page * CMD_LIST_SIZE + CMD_LIST_SIZE; i++) { + if (i >= size) break; + player.sendMessage(ChatColor.YELLOW.toString() + (i + 1) + ". " + regionIDList[i]); + } + } + + return true; + } + + if (action.equalsIgnoreCase("delete")) { + if (!hasPermission(player, "/regionclaim")) { + checkRegionPermission(player, "/regiondelete"); + } + checkArgs(args, 0, 1, "/region delete "); + + try { + String id = args[1].toLowerCase(); + if (!regionManager.hasRegion(id)) { + player.sendMessage(ChatColor.RED + "A region with ID '" + + id + "' doesn't exist."); + return true; + } + + ProtectedRegion existing = regionManager.getRegion(id); + + if (!canUseRegionCommand(player, "/regiondelete") + && !existing.getOwners().contains(wrapPlayer(player))) { + player.sendMessage(ChatColor.RED + "You don't own this region."); + return true; + } + + regionManager.removeRegion(id); + regionLoader.save(regionManager); + player.sendMessage(ChatColor.YELLOW + "Region removed!"); + } catch (IOException e) { + player.sendMessage(ChatColor.RED + "Region database failed to save: " + + e.getMessage()); + } + + return true; + } + + if (action.equalsIgnoreCase("save")) { + checkRegionPermission(player, "/regionsave"); + checkArgs(args, 0, 0, "/region save"); + + try { + regionLoader.save(regionManager); + player.sendMessage(ChatColor.YELLOW + "Region database saved to file!"); + } catch (IOException e) { + player.sendMessage(ChatColor.RED + "Region database failed to save: " + + e.getMessage()); + } + + return true; + } + + if (action.equalsIgnoreCase("load")) { + checkRegionPermission(player, "/regionload"); + checkArgs(args, 0, 0, "/region load"); + + try { + regionLoader.load(regionManager); + player.sendMessage(ChatColor.YELLOW + "Region database loaded from file!"); + } catch (IOException e) { + player.sendMessage(ChatColor.RED + "Region database failed to load: " + + e.getMessage()); + } + + return true; + } + + return false; + } + + /** + * Parse a group/player DefaultDomain specification for areas. + * + * @param domain + * @param split + * @param startIndex + */ + private static void addToDomain(DefaultDomain domain, + String[] split, int startIndex) { + for (int i = startIndex; i < split.length; i++) { + String s = split[i]; + Matcher m = groupPattern.matcher(s); + if (m.matches()) { + domain.addGroup(m.group(1)); + } else { + domain.addPlayer(s); + } + } + } + + /** + * Parse a group/player DefaultDomain specification for areas. + * + * @param domain + * @param split + * @param startIndex + */ + private static void removeFromDomain(DefaultDomain domain, + String[] split, int startIndex) { + for (int i = startIndex; i < split.length; i++) { + String s = split[i]; + Matcher m = groupPattern.matcher(s); + if (m.matches()) { + domain.removeGroup(m.group(1)); + } else { + domain.removePlayer(s); + } + } + } + + /** + * Parse a group/player DefaultDomain specification for areas. + * + * @param split + * @param startIndex + * @return + */ + private static DefaultDomain parseDomainString(String[] split, int startIndex) { + DefaultDomain domain = new DefaultDomain(); + + for (int i = startIndex; i < split.length; i++) { + String s = split[i]; + Matcher m = groupPattern.matcher(s); + if (m.matches()) { + domain.addGroup(m.group(1)); + } else { + domain.addPlayer(s); + } + } + + return domain; + } + + /** + * Checks for the command or /region. + * + * @param player + * @param cmd + * @return + */ + private boolean canUseRegionCommand(Player player, String cmd) { + return hasPermission(player, "/region") + || hasPermission(player, cmd); + } + + /** + * Checks to see if there are sufficient permissions, otherwise an exception + * is raised in that case. + * + * @param player + * @param permission + * @throws InsufficientPermissionsException + */ + private void checkRegionPermission(Player player, String permission) + throws InsufficientPermissionsException { + if (!hasPermission(player, "/region") && !hasPermission(player, permission)) { + throw new InsufficientPermissionsException(); + } + } + + /** + * Checks to see if there are sufficient permissions, otherwise an exception + * is raised in that case. + * + * @param player + * @param permission + * @throws InsufficientPermissionsException + */ + private void checkPermission(Player player, String permission) + throws InsufficientPermissionsException { + if (!hasPermission(player, permission)) { + throw new InsufficientPermissionsException(); + } + } + + /** + * Checks to make sure that there are enough but not too many arguments. + * + * @param args + * @param min + * @param max -1 for no maximum + * @throws InsufficientArgumentsException + */ + private void checkArgs(String[] args, int min, int max) + throws InsufficientArgumentsException { + if (args.length <= min || (max != -1 && args.length - 1 > max)) { + throw new InsufficientArgumentsException(); + } + } + + /** + * Checks to make sure that there are enough but not too many arguments. + * + * @param args + * @param min + * @param max -1 for no maximum + * @param help + * @throws InsufficientArgumentsException + */ + private void checkArgs(String[] args, int min, int max, String help) + throws InsufficientArgumentsException { + if (args.length <= min || (max != -1 && args.length - 1 > max)) { + throw new InsufficientArgumentsException(help); + } + } boolean inGroup(Player player, String group) { return perms.inGroup(player.getName(), group); } boolean hasPermission(Player player, String perm) { - return perms.hasPermission(player.getName(), perm); + return player.isOp() || perms.hasPermission(player.getName(), perm); } String[] getGroups(Player player) { @@ -374,4 +1123,35 @@ String[] getGroups(Player player) { BukkitPlayer wrapPlayer(Player player) { return new BukkitPlayer(this, player); } + + /** + * Thrown when a player has insufficient permissions. + * + * @author sk89q + */ + private static class InsufficientPermissionsException extends Exception { + private static final long serialVersionUID = 9087662707619954750L; + } + + /** + * Thrown when a command wasn't given sufficient arguments. + * + * @author sk89q + */ + private static class InsufficientArgumentsException extends Exception { + private static final long serialVersionUID = 4153597953889773788L; + private final String help; + + public InsufficientArgumentsException() { + help = null; + } + + public InsufficientArgumentsException(String msg) { + this.help = msg; + } + + public String getHelp() { + return help; + } + } }