From 5d6dad4c6d0e152ff357fe108e15e54ec327b6c6 Mon Sep 17 00:00:00 2001 From: sk89q Date: Thu, 14 Aug 2014 21:41:44 -0700 Subject: [PATCH] Don't remove child regions without warning. Also add some missing files. Fixes WORLDGUARD-2311. --- .../commands/region/RegionCommands.java | 13 +- .../commands/region/RegionCommandsBase.java | 358 ++++++++++++++++++ .../bukkit/commands/task/RegionAdder.java | 108 ++++++ .../bukkit/commands/task/RegionLister.java | 232 ++++++++++++ .../bukkit/commands/task/RegionRemover.java | 93 +++++ 5 files changed, 803 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/sk89q/worldguard/bukkit/commands/region/RegionCommandsBase.java create mode 100644 src/main/java/com/sk89q/worldguard/bukkit/commands/task/RegionAdder.java create mode 100644 src/main/java/com/sk89q/worldguard/bukkit/commands/task/RegionLister.java create mode 100644 src/main/java/com/sk89q/worldguard/bukkit/commands/task/RegionRemover.java diff --git a/src/main/java/com/sk89q/worldguard/bukkit/commands/region/RegionCommands.java b/src/main/java/com/sk89q/worldguard/bukkit/commands/region/RegionCommands.java index 3003196c..ba04eda7 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/commands/region/RegionCommands.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/commands/region/RegionCommands.java @@ -48,6 +48,7 @@ import com.sk89q.worldguard.protection.flags.RegionGroup; import com.sk89q.worldguard.protection.flags.RegionGroupFlag; import com.sk89q.worldguard.protection.managers.RegionManager; +import com.sk89q.worldguard.protection.managers.RemovalStrategy; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion.CircularInheritanceException; import com.sk89q.worldguard.protection.util.migrator.MigrationException; @@ -649,11 +650,13 @@ public void setParent(CommandContext args, CommandSender sender) throws CommandE */ @Command(aliases = {"remove", "delete", "del", "rem"}, usage = "", - flags = "w:", + flags = "fuw:", desc = "Remove a region", min = 1, max = 1) public void remove(CommandContext args, CommandSender sender) throws CommandException { World world = checkWorld(args, sender, 'w'); // Get the world + boolean removeChildren = args.hasFlag('f'); + boolean unsetParent = args.hasFlag('u'); // Lookup the existing region RegionManager manager = checkRegionManager(plugin, world); @@ -666,6 +669,14 @@ public void remove(CommandContext args, CommandSender sender) throws CommandExce RegionRemover task = new RegionRemover(manager, existing); + if (removeChildren && unsetParent) { + throw new CommandException("You cannot use both -u (unset parent) and -f (remove children) together."); + } else if (removeChildren) { + task.setRemovalStrategy(RemovalStrategy.REMOVE_CHILDREN); + } else if (unsetParent) { + task.setRemovalStrategy(RemovalStrategy.UNSET_PARENT_IN_CHILDREN); + } + AsyncCommandHelper.wrap(plugin.getExecutorService().submit(task), plugin, sender) .formatUsing(existing.getId()) .registerWithSupervisor("Removing the region '%s'...") diff --git a/src/main/java/com/sk89q/worldguard/bukkit/commands/region/RegionCommandsBase.java b/src/main/java/com/sk89q/worldguard/bukkit/commands/region/RegionCommandsBase.java new file mode 100644 index 00000000..ce28601c --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/bukkit/commands/region/RegionCommandsBase.java @@ -0,0 +1,358 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.bukkit.commands.region; + +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.minecraft.util.commands.CommandException; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.selections.CuboidSelection; +import com.sk89q.worldedit.bukkit.selections.Polygonal2DSelection; +import com.sk89q.worldedit.bukkit.selections.Selection; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.bukkit.permission.RegionPermissionModel; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.flags.InvalidFlagFormat; +import com.sk89q.worldguard.protection.managers.RegionManager; +import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion; +import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; +import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import org.bukkit.ChatColor; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +class RegionCommandsBase { + + /** + * Get the permission model to lookup permissions. + * + * @param sender the sender + * @return the permission model + */ + protected static RegionPermissionModel getPermissionModel(CommandSender sender) { + return new RegionPermissionModel(WorldGuardPlugin.inst(), sender); + } + + /** + * Gets the world from the given flag, or falling back to the the current player + * if the sender is a player, otherwise reporting an error. + * + * @param args the arguments + * @param sender the sender + * @param flag the flag (such as 'w') + * @return a world + * @throws CommandException on error + */ + protected static World checkWorld(CommandContext args, CommandSender sender, char flag) throws CommandException { + if (args.hasFlag(flag)) { + return WorldGuardPlugin.inst().matchWorld(sender, args.getFlag(flag)); + } else { + if (sender instanceof Player) { + return WorldGuardPlugin.inst().checkPlayer(sender).getWorld(); + } else { + throw new CommandException("Please specify " + "the world with -" + flag + " world_name."); + } + } + } + + /** + * Validate a region ID. + * + * @param id the id + * @param allowGlobal whether __global__ is allowed + * @return the id given + * @throws CommandException thrown on an error + */ + protected static String checkRegionId(String id, boolean allowGlobal) throws CommandException { + if (!ProtectedRegion.isValidId(id)) { + throw new CommandException( + "The region name of '" + id + "' contains characters that are not allowed."); + } + + if (!allowGlobal && id.equalsIgnoreCase("__global__")) { // Sorry, no global + throw new CommandException( + "Sorry, you can't use __global__ here."); + } + + return id; + } + + /** + * Get a protected region by a given name, otherwise throw a + * {@link CommandException}. + * + *

This also validates the region ID.

+ * + * @param regionManager the region manager + * @param id the name to search + * @param allowGlobal true to allow selecting __global__ + * @throws CommandException thrown if no region is found by the given name + */ + protected static ProtectedRegion checkExistingRegion(RegionManager regionManager, String id, boolean allowGlobal) throws CommandException { + // Validate the id + checkRegionId(id, allowGlobal); + + ProtectedRegion region = regionManager.getRegion(id); + + // No region found! + if (region == null) { + // But we want a __global__, so let's create one + if (id.equalsIgnoreCase("__global__")) { + region = new GlobalProtectedRegion(id); + regionManager.addRegion(region); + return region; + } + + throw new CommandException( + "No region could be found with the name of '" + id + "'."); + } + + return region; + } + + + /** + * Get the region at the player's location, if possible. + * + *

If the player is standing in several regions, an error will be raised + * and a list of regions will be provided.

+ * + * @param regionManager the region manager + * @param player the player + * @return a region + * @throws CommandException thrown if no region was found + */ + protected static ProtectedRegion checkRegionStandingIn(RegionManager regionManager, Player player) throws CommandException { + return checkRegionStandingIn(regionManager, player, false); + } + + /** + * Get the region at the player's location, if possible. + * + *

If the player is standing in several regions, an error will be raised + * and a list of regions will be provided.

+ * + *

If the player is not standing in any regions, the global region will + * returned if allowGlobal is true and it exists.

+ * + * @param regionManager the region manager + * @param player the player + * @param allowGlobal whether to search for a global region if no others are found + * @return a region + * @throws CommandException thrown if no region was found + */ + protected static ProtectedRegion checkRegionStandingIn(RegionManager regionManager, Player player, boolean allowGlobal) throws CommandException { + ApplicableRegionSet set = regionManager.getApplicableRegions(player.getLocation()); + + if (set.size() == 0) { + if (allowGlobal) { + ProtectedRegion global = checkExistingRegion(regionManager, "__global__", true); + player.sendMessage(ChatColor.GRAY + "You're not standing in any " + + "regions. Using the global region for this world instead."); + return global; + } + throw new CommandException( + "You're not standing in a region." + + "Specify an ID if you want to select a specific region."); + } else if (set.size() > 1) { + StringBuilder builder = new StringBuilder(); + boolean first = true; + + for (ProtectedRegion region : set) { + if (!first) { + builder.append(", "); + } + first = false; + builder.append(region.getId()); + } + + throw new CommandException( + "You're standing in several regions (please pick one).\nYou're in: " + builder.toString()); + } + + return set.iterator().next(); + } + + /** + * Get a WorldEdit selection for a player, or emit an exception if there is none + * available. + * + * @param player the player + * @return the selection + * @throws CommandException thrown on an error + */ + protected static Selection checkSelection(Player player) throws CommandException { + WorldEditPlugin worldEdit = WorldGuardPlugin.inst().getWorldEdit(); + Selection selection = worldEdit.getSelection(player); + + if (selection == null) { + throw new CommandException( + "Please select an area first. " + + "Use WorldEdit to make a selection! " + + "(wiki: http://wiki.sk89q.com/wiki/WorldEdit)."); + } + + return selection; + } + + /** + * Check that a region with the given ID does not already exist. + * + * @param manager the manager + * @param id the ID + * @throws CommandException thrown if the ID already exists + */ + protected static void checkRegionDoesNotExist(RegionManager manager, String id, boolean mayRedefine) throws CommandException { + if (manager.hasRegion(id)) { + throw new CommandException("A region with that name already exists. Please choose another name." + + (mayRedefine ? " To change the shape, use /region redefine " + id + "." : "")); + } + } + + /** + * Check that the given region manager is not null. + * + * @param plugin the plugin + * @param world the world + * @throws CommandException thrown if the manager is null + */ + protected static RegionManager checkRegionManager(WorldGuardPlugin plugin, World world) throws CommandException { + RegionManager manager = plugin.getRegionContainer().get(world); + if (manager == null) { + throw new CommandException("Either region support is disabled or region data failed to load in the target world."); + } + return manager; + } + + /** + * Create a {@link ProtectedRegion} from the player's selection. + * + * @param player the player + * @param id the ID of the new region + * @return a new region + * @throws CommandException thrown on an error + */ + protected static ProtectedRegion checkRegionFromSelection(Player player, String id) throws CommandException { + Selection selection = checkSelection(player); + + // Detect the type of region from WorldEdit + if (selection instanceof Polygonal2DSelection) { + Polygonal2DSelection polySel = (Polygonal2DSelection) selection; + int minY = polySel.getNativeMinimumPoint().getBlockY(); + int maxY = polySel.getNativeMaximumPoint().getBlockY(); + return new ProtectedPolygonalRegion(id, polySel.getNativePoints(), minY, maxY); + } else if (selection instanceof CuboidSelection) { + BlockVector min = selection.getNativeMinimumPoint().toBlockVector(); + BlockVector max = selection.getNativeMaximumPoint().toBlockVector(); + return new ProtectedCuboidRegion(id, min, max); + } else { + throw new CommandException("Sorry, you can only use cuboids and polygons for WorldGuard regions."); + } + } + + /** + * Warn the sender if the dimensions of the given region are worrying. + * + * @param sender the sender to send the message to + * @param region the region + */ + protected static void warnAboutDimensions(CommandSender sender, ProtectedRegion region) { + int height = region.getMaximumPoint().getBlockY() - region.getMinimumPoint().getBlockY(); + if (height <= 2) { + sender.sendMessage(ChatColor.GRAY + "(Warning: The height of the region was " + (height + 1) + " block(s).)"); + } + } + + /** + * Inform a new user about automatic protection. + * + * @param sender the sender to send the message to + * @param manager the region manager + * @param region the region + */ + protected static void informNewUser(CommandSender sender, RegionManager manager, ProtectedRegion region) { + if (manager.getRegions().size() <= 2) { + sender.sendMessage(ChatColor.GRAY + + "(This region is NOW PROTECTED from modification from others. " + + "Don't want that? Use " + + ChatColor.AQUA + "/rg flag " + region.getId() + " passthrough allow" + + ChatColor.GRAY + ")"); + } + } + + /** + * Set a player's selection to a given region. + * + * @param player the player + * @param region the region + * @throws CommandException thrown on a command error + */ + protected static void setPlayerSelection(Player player, ProtectedRegion region) throws CommandException { + WorldEditPlugin worldEdit = WorldGuardPlugin.inst().getWorldEdit(); + + World world = player.getWorld(); + + // Set selection + if (region instanceof ProtectedCuboidRegion) { + ProtectedCuboidRegion cuboid = (ProtectedCuboidRegion) region; + Vector pt1 = cuboid.getMinimumPoint(); + Vector pt2 = cuboid.getMaximumPoint(); + CuboidSelection selection = new CuboidSelection(world, pt1, pt2); + worldEdit.setSelection(player, selection); + player.sendMessage(ChatColor.YELLOW + "Region selected as a cuboid."); + + } else if (region instanceof ProtectedPolygonalRegion) { + ProtectedPolygonalRegion poly2d = (ProtectedPolygonalRegion) region; + Polygonal2DSelection selection = new Polygonal2DSelection( + world, poly2d.getPoints(), + poly2d.getMinimumPoint().getBlockY(), + poly2d.getMaximumPoint().getBlockY() ); + worldEdit.setSelection(player, selection); + player.sendMessage(ChatColor.YELLOW + "Region selected as a polygon."); + + } else if (region instanceof GlobalProtectedRegion) { + throw new CommandException( + "Can't select global regions! " + + "That would cover the entire world."); + + } else { + throw new CommandException("Unknown region type: " + + region.getClass().getCanonicalName()); + } + } + + /** + * Utility method to set a flag. + * + * @param region the region + * @param flag the flag + * @param sender the sender + * @param value the value + * @throws InvalidFlagFormat thrown if the value is invalid + */ + protected static void setFlag(ProtectedRegion region, Flag flag, CommandSender sender, String value) throws InvalidFlagFormat { + region.setFlag(flag, flag.parseInput(WorldGuardPlugin.inst(), sender, value)); + } + +} diff --git a/src/main/java/com/sk89q/worldguard/bukkit/commands/task/RegionAdder.java b/src/main/java/com/sk89q/worldguard/bukkit/commands/task/RegionAdder.java new file mode 100644 index 00000000..e66491c6 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/bukkit/commands/task/RegionAdder.java @@ -0,0 +1,108 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.bukkit.commands.task; + +import com.sk89q.minecraft.util.commands.CommandContext; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.domains.DefaultDomain; +import com.sk89q.worldguard.protection.managers.RegionManager; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.protection.util.DomainInputResolver; +import com.sk89q.worldguard.protection.util.DomainInputResolver.UserLocatorPolicy; + +import javax.annotation.Nullable; +import java.util.concurrent.Callable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Creates a new region. + */ +public class RegionAdder implements Callable { + + private final WorldGuardPlugin plugin; + private final RegionManager manager; + private final ProtectedRegion region; + @Nullable + private String[] ownersInput; + private UserLocatorPolicy locatorPolicy = UserLocatorPolicy.UUID_ONLY; + + /** + * Create a new instance. + * + * @param plugin the plugin + * @param manager the manage + * @param region the region + */ + public RegionAdder(WorldGuardPlugin plugin, RegionManager manager, ProtectedRegion region) { + checkNotNull(plugin); + checkNotNull(manager); + checkNotNull(region); + + this.plugin = plugin; + this.manager = manager; + this.region = region; + } + + /** + * Add the owners from the command's arguments. + * + * @param args the arguments + * @param namesIndex the index in the list of arguments to read the first name from + */ + public void addOwnersFromCommand(CommandContext args, int namesIndex) { + if (args.argsLength() >= namesIndex) { + setLocatorPolicy(args.hasFlag('n') ? UserLocatorPolicy.NAME_ONLY : UserLocatorPolicy.UUID_ONLY); + setOwnersInput(args.getSlice(namesIndex)); + } + } + + @Override + public ProtectedRegion call() throws Exception { + if (ownersInput != null) { + DomainInputResolver resolver = new DomainInputResolver(plugin.getProfileService(), ownersInput); + resolver.setLocatorPolicy(locatorPolicy); + DefaultDomain domain = resolver.call(); + region.getOwners().addAll(domain); + } + + manager.addRegion(region); + + return region; + } + + @Nullable + public String[] getOwnersInput() { + return ownersInput; + } + + public void setOwnersInput(@Nullable String[] ownersInput) { + this.ownersInput = ownersInput; + } + + public UserLocatorPolicy getLocatorPolicy() { + return locatorPolicy; + } + + public void setLocatorPolicy(UserLocatorPolicy locatorPolicy) { + this.locatorPolicy = locatorPolicy; + } + +} diff --git a/src/main/java/com/sk89q/worldguard/bukkit/commands/task/RegionLister.java b/src/main/java/com/sk89q/worldguard/bukkit/commands/task/RegionLister.java new file mode 100644 index 00000000..d5f1d43c --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/bukkit/commands/task/RegionLister.java @@ -0,0 +1,232 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.bukkit.commands.task; + +import com.sk89q.minecraft.util.commands.CommandException; +import com.sk89q.squirrelid.Profile; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.domains.DefaultDomain; +import com.sk89q.worldguard.protection.managers.RegionManager; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class RegionLister implements Callable { + + private static final Logger log = Logger.getLogger(RegionLister.class.getCanonicalName()); + + private final WorldGuardPlugin plugin; + private final CommandSender sender; + private final RegionManager manager; + private OwnerMatcher ownerMatcher; + private int page; + + public RegionLister(WorldGuardPlugin plugin, RegionManager manager, CommandSender sender) { + checkNotNull(plugin); + checkNotNull(manager); + checkNotNull(sender); + + this.plugin = plugin; + this.manager = manager; + this.sender = sender; + } + + public int getPage() { + return page; + } + + public void setPage(int page) { + this.page = page; + } + + public void filterOwnedByPlayer(final Player player) { + ownerMatcher = new OwnerMatcher() { + @Override + public String getName() { + return player.getName(); + } + + @Override + public boolean isContainedWithin(DefaultDomain domain) throws CommandException { + return domain.contains(player.getUniqueId()); + } + }; + } + + public void filterOwnedByName(String name, boolean nameOnly) { + if (nameOnly) { + filterOwnedByName(name); + } else { + filterOwnedByProfile(name); + } + } + + private void filterOwnedByName(final String name) { + ownerMatcher = new OwnerMatcher() { + @Override + public String getName() { + return name; + } + + @Override + public boolean isContainedWithin(DefaultDomain domain) throws CommandException { + return domain.contains(name); + } + }; + } + + private void filterOwnedByProfile(final String name) { + ownerMatcher = new OwnerMatcher() { + private UUID uniqueId; + + @Override + public String getName() { + return name; + } + + @Override + public boolean isContainedWithin(DefaultDomain domain) throws CommandException { + if (uniqueId == null) { + Profile profile; + + try { + profile = plugin.getProfileService().findByName(name); + } catch (IOException e) { + log.log(Level.WARNING, "Failed UUID lookup of '" + name + "'", e); + throw new CommandException("Failed to lookup the UUID of '" + name + "'"); + } catch (InterruptedException e) { + log.log(Level.WARNING, "Failed UUID lookup of '" + name + "'", e); + throw new CommandException("The lookup the UUID of '" + name + "' was interrupted"); + } + + if (profile == null) { + throw new CommandException("A user by the name of '" + name + "' does not seem to exist."); + } + + uniqueId = profile.getUniqueId(); + } + + return domain.contains(uniqueId); + } + }; + } + + @Override + public Integer call() throws Exception { + Map regions = manager.getRegions(); + + // Build a list of regions to show + List entries = new ArrayList(); + + int index = 0; + for (String id : regions.keySet()) { + RegionListEntry entry = new RegionListEntry(id, index++); + + // Filtering by owner? + ProtectedRegion region = regions.get(id); + if (ownerMatcher != null) { + entry.isOwner = ownerMatcher.isContainedWithin(region.getOwners()); + entry.isMember = ownerMatcher.isContainedWithin(region.getMembers()); + + if (!entry.isOwner && !entry.isMember) { + continue; // Skip + } + } + + entries.add(entry); + } + + Collections.sort(entries); + + final int totalSize = entries.size(); + final int pageSize = 10; + final int pages = (int) Math.ceil(totalSize / (float) pageSize); + + sender.sendMessage(ChatColor.RED + + (ownerMatcher == null ? "Regions (page " : "Regions for " + ownerMatcher.getName() + " (page ") + + (page + 1) + " of " + pages + "):"); + + if (page < pages) { + // Print + for (int i = page * pageSize; i < page * pageSize + pageSize; i++) { + if (i >= totalSize) { + break; + } + + sender.sendMessage(ChatColor.YELLOW.toString() + entries.get(i)); + } + } + + return page; + } + + private static interface OwnerMatcher { + public String getName(); + + public boolean isContainedWithin(DefaultDomain domain) throws CommandException; + } + + private class RegionListEntry implements Comparable { + private final String id; + private final int index; + boolean isOwner; + boolean isMember; + + private RegionListEntry(String id, int index) { + this.id = id; + this.index = index; + } + + @Override + public int compareTo(RegionListEntry o) { + if (isOwner != o.isOwner) { + return isOwner ? 1 : -1; + } + if (isMember != o.isMember) { + return isMember ? 1 : -1; + } + return id.compareTo(o.id); + } + + @Override + public String toString() { + if (isOwner) { + return (index + 1) + ". +" + id; + } else if (isMember) { + return (index + 1) + ". -" + id; + } else { + return (index + 1) + ". " + id; + } + } + } +} diff --git a/src/main/java/com/sk89q/worldguard/bukkit/commands/task/RegionRemover.java b/src/main/java/com/sk89q/worldguard/bukkit/commands/task/RegionRemover.java new file mode 100644 index 00000000..4653f707 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/bukkit/commands/task/RegionRemover.java @@ -0,0 +1,93 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.bukkit.commands.task; + +import com.sk89q.minecraft.util.commands.CommandException; +import com.sk89q.worldguard.protection.managers.RegionManager; +import com.sk89q.worldguard.protection.managers.RemovalStrategy; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; + +import javax.annotation.Nullable; +import java.util.Set; +import java.util.concurrent.Callable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Removes a region. + */ +public class RegionRemover implements Callable> { + + private final RegionManager manager; + private final ProtectedRegion region; + @Nullable + private RemovalStrategy removalStrategy; + + /** + * Create a new instance. + * + * @param manager a region manager + * @param region the region to remove + */ + public RegionRemover(RegionManager manager, ProtectedRegion region) { + checkNotNull(manager); + checkNotNull(region); + this.manager = manager; + this.region = region; + } + + /** + * GSet a parent removal strategy. + * + * @return a removal strategy or null (see{@link #setRemovalStrategy(RemovalStrategy)} + */ + @Nullable + public RemovalStrategy getRemovalStrategy() { + return removalStrategy; + } + + /** + * Set a parent removal strategy. Set it to {@code null} to have the code + * check for children and throw an error if any are found. + * + * @param removalStrategy a removal strategy, or {@code null} to error if children exist + */ + public void setRemovalStrategy(@Nullable RemovalStrategy removalStrategy) { + this.removalStrategy = removalStrategy; + } + + @Override + public Set call() throws Exception { + if (removalStrategy == null) { + for (ProtectedRegion test : manager.getRegions().values()) { + ProtectedRegion parent = test.getParent(); + if (parent != null && parent.equals(region)) { + throw new CommandException( + "The region '" + region.getId() + "' has child regions. Use -f to force removal of children " + + "or -u to unset the parent value of these children."); + } + } + + return manager.removeRegion(region.getId(), RemovalStrategy.UNSET_PARENT_IN_CHILDREN); + } else { + return manager.removeRegion(region.getId(), removalStrategy); + } + } +}