Added parent-child relationships to regions, overhauled region code, added global build flag, improved flag support.

This commit is contained in:
sk89q 2011-01-21 15:23:11 -08:00
parent 151b5fc561
commit 765d7402fa
18 changed files with 925 additions and 333 deletions

View File

@ -70,6 +70,8 @@ player-damage:
regions: regions:
enable: on enable: on
wand: 287 wand: 287
default:
build: true
blacklist: blacklist:
logging: logging:

View File

@ -23,7 +23,7 @@ commands:
aliases: ; aliases: ;
region: region:
description: Adjust protected regions description: Adjust protected regions
usage: /<command> <define|claim|flag|delete|info|addowner|removeowner|list|save|load> ... usage: /<command> <define|claim|setparent|flag|delete|info|addowner|removeowner|addmember|removemember|list|save|load> ...
aliases: rg, regions aliases: rg, regions
locate: locate:
description: Set your compass towards a person description: Set your compass towards a person

View File

@ -168,7 +168,7 @@ public void onBlockFlow(BlockFromToEvent event) {
public void onBlockIgnite(BlockIgniteEvent event) { public void onBlockIgnite(BlockIgniteEvent event) {
IgniteCause cause = event.getCause(); IgniteCause cause = event.getCause();
Block block = event.getBlock(); Block block = event.getBlock();
Player player = event.getPlayer(); //Player player = event.getPlayer();
World world = block.getWorld(); World world = block.getWorld();
boolean isFireSpread = cause == IgniteCause.SLOW_SPREAD boolean isFireSpread = cause == IgniteCause.SLOW_SPREAD
|| cause == IgniteCause.SPREAD; || cause == IgniteCause.SPREAD;
@ -208,22 +208,38 @@ public void onBlockIgnite(BlockIgniteEvent event) {
} }
} }
if (plugin.useRegions && player != null && !plugin.hasPermission(player, "/regionbypass")) { /*if (plugin.useRegions) {
Vector pt = toVector(block); Vector pt = toVector(block);
LocalPlayer localPlayer = plugin.wrapPlayer(player);
if (cause == IgniteCause.FLINT_AND_STEEL if (player != null && !plugin.hasPermission(player, "/regionbypass")) {
&& !plugin.regionManager.getApplicableRegions(pt).canBuild(localPlayer)) { LocalPlayer localPlayer = plugin.wrapPlayer(player);
if (cause == IgniteCause.FLINT_AND_STEEL
&& !plugin.regionManager.getApplicableRegions(pt).canBuild(localPlayer)) {
event.setCancelled(true);
return;
}
if (cause == IgniteCause.FLINT_AND_STEEL
&& !plugin.regionManager.getApplicableRegions(pt)
.allowsFlag(AreaFlags.FLAG_LIGHTER)) {
event.setCancelled(true);
return;
}
}
f (isFireSpread && !plugin.regionManager.getApplicableRegions(pt)
.allowsFlag(AreaFlags.FLAG_FIRE_SPREAD)) {
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
if (cause == IgniteCause.FLINT_AND_STEEL if (cause == IgniteCause.LAVA && !plugin.regionManager.getApplicableRegions(pt)
&& !plugin.regionManager.getApplicableRegions(pt).allowsLighter()) { .allowsFlag(AreaFlags.FLAG_LAVA_FIRE)) {
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
} }*/
} }
/** /**
@ -260,7 +276,12 @@ public void onBlockInteract(BlockInteractEvent event) {
Block block = event.getBlock(); Block block = event.getBlock();
LivingEntity entity = event.getEntity(); LivingEntity entity = event.getEntity();
if (entity instanceof Player && block.getType() == Material.CHEST) { if (entity instanceof Player
&& (block.getType() == Material.CHEST
|| block.getType() == Material.DISPENSER
|| block.getType() == Material.FURNACE
|| block.getType() == Material.BURNING_FURNACE
|| block.getType() == Material.NOTE_BLOCK)) {
Player player = (Player)entity; Player player = (Player)entity;
if (plugin.useRegions) { if (plugin.useRegions) {
Vector pt = toVector(block); Vector pt = toVector(block);

View File

@ -22,13 +22,16 @@
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.entity.*; import org.bukkit.event.entity.*;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BlockType; import com.sk89q.worldedit.blocks.BlockType;
import com.sk89q.worldguard.protection.AreaFlags;
import static com.sk89q.worldguard.bukkit.BukkitUtil.*; import static com.sk89q.worldguard.bukkit.BukkitUtil.*;
public class WorldGuardEntityListener extends EntityListener { public class WorldGuardEntityListener extends EntityListener {
@ -83,13 +86,40 @@ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
if (plugin.useRegions) { if (plugin.useRegions) {
Vector pt = toVector(defender.getLocation()); Vector pt = toVector(defender.getLocation());
if (!plugin.regionManager.getApplicableRegions(pt).allowsPvP()) { if (!plugin.regionManager.getApplicableRegions(pt)
.allowsFlag(AreaFlags.FLAG_PVP)) {
((Player)attacker).sendMessage(ChatColor.DARK_RED + "You are in a no-PvP area."); ((Player)attacker).sendMessage(ChatColor.DARK_RED + "You are in a no-PvP area.");
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
} }
} }
if (attacker != null && attacker instanceof Monster) {
if (attacker instanceof Creeper && plugin.blockCreeperExplosions) {
event.setCancelled(true);
return;
}
if (plugin.useRegions) {
Vector pt = toVector(defender.getLocation());
if (!plugin.regionManager.getApplicableRegions(pt)
.allowsFlag(AreaFlags.FLAG_MOB_DAMAGE)) {
event.setCancelled(true);
return;
}
if (attacker instanceof Creeper) {
if (!plugin.regionManager.getApplicableRegions(pt)
.allowsFlag(AreaFlags.FLAG_CREEPER_EXPLOSION)) {
event.setCancelled(true);
return;
}
}
}
}
} }
} }
@ -172,10 +202,17 @@ public void onEntityExplode(EntityExplodeEvent event) {
return; return;
} }
if (!plugin.regionManager.getApplicableRegions(BukkitUtil.toVector(event.getEntity().getLocation()))
.allowsFlag(AreaFlags.FLAG_CREEPER_EXPLOSION)) {
event.setCancelled(true);
return;
}
if (plugin.useRegions) { if (plugin.useRegions) {
Vector pt = toVector(event.getEntity().getLocation()); Vector pt = toVector(event.getEntity().getLocation());
if (!plugin.regionManager.getApplicableRegions(pt).allowsCreeperExplosions()) { if (!plugin.regionManager.getApplicableRegions(pt)
.allowsFlag(AreaFlags.FLAG_CREEPER_EXPLOSION)) {
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
@ -189,7 +226,8 @@ public void onEntityExplode(EntityExplodeEvent event) {
if (plugin.useRegions && event.getEntity() != null) { if (plugin.useRegions && event.getEntity() != null) {
Vector pt = toVector(event.getEntity().getLocation()); Vector pt = toVector(event.getEntity().getLocation());
if (!plugin.regionManager.getApplicableRegions(pt).allowsTNT()) { if (!plugin.regionManager.getApplicableRegions(pt)
.allowsFlag(AreaFlags.FLAG_TNT)) {
event.setCancelled(true); event.setCancelled(true);
return; return;
} }

View File

@ -27,6 +27,7 @@
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.*; import com.sk89q.worldguard.*;
import com.sk89q.worldguard.blacklist.events.ItemUseBlacklistEvent; import com.sk89q.worldguard.blacklist.events.ItemUseBlacklistEvent;
import com.sk89q.worldguard.protection.AreaFlags;
import static com.sk89q.worldguard.bukkit.BukkitUtil.*; import static com.sk89q.worldguard.bukkit.BukkitUtil.*;
/** /**
@ -109,7 +110,7 @@ public void onPlayerItem(PlayerItemEvent event) {
} }
} }
if (item != null && plugin.blacklist != null && block != null) { if (plugin.blacklist != null && item != null && block != null) {
if (!plugin.blacklist.check( if (!plugin.blacklist.check(
new ItemUseBlacklistEvent(plugin.wrapPlayer(player), new ItemUseBlacklistEvent(plugin.wrapPlayer(player),
toVector(block.getRelative(event.getBlockFace())), toVector(block.getRelative(event.getBlockFace())),
@ -118,6 +119,16 @@ public void onPlayerItem(PlayerItemEvent event) {
return; return;
} }
} }
if (plugin.useRegions && item != null && block != null && item.getTypeId() == 259) {
Vector pt = toVector(block.getRelative(event.getBlockFace()));
if (!plugin.regionManager.getApplicableRegions(pt)
.allowsFlag(AreaFlags.FLAG_LIGHTER)) {
event.setCancelled(true);
return;
}
}
} }
/** /**

View File

@ -23,7 +23,6 @@
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.util.logging.*; import java.util.logging.*;
import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.bukkit.command.Command; import org.bukkit.command.Command;
@ -53,6 +52,8 @@
import com.sk89q.worldguard.blacklist.loggers.*; import com.sk89q.worldguard.blacklist.loggers.*;
import com.sk89q.worldguard.domains.DefaultDomain; import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.*; import com.sk89q.worldguard.protection.*;
import com.sk89q.worldguard.protection.AreaFlags.State;
import com.sk89q.worldguard.protection.ProtectedRegion.CircularInheritanceException;
/** /**
* Plugin for Bukkit. * Plugin for Bukkit.
@ -77,7 +78,8 @@ public class WorldGuardPlugin extends JavaPlugin {
Blacklist blacklist; Blacklist blacklist;
RegionManager regionManager = new FlatRegionManager(); GlobalFlags globalFlags = new GlobalFlags();
RegionManager regionManager = new FlatRegionManager(globalFlags);
ProtectionDatabase regionLoader; ProtectionDatabase regionLoader;
Set<String> invinciblePlayers = new HashSet<String>(); Set<String> invinciblePlayers = new HashSet<String>();
@ -292,6 +294,7 @@ public void loadConfiguration() {
useRegions = config.getBoolean("regions.enable", true); useRegions = config.getBoolean("regions.enable", true);
regionWand = config.getInt("regions.wand", 287); regionWand = config.getInt("regions.wand", 287);
globalFlags.canBuild = config.getBoolean("regions.default.build", true);
try { try {
regionLoader.load(); regionLoader.load();
@ -422,6 +425,12 @@ public boolean onCommand(Player player, Command cmd, String commandLabel, String
} catch (InsufficientPermissionsException e) { } catch (InsufficientPermissionsException e) {
player.sendMessage(ChatColor.RED + "You don't have sufficient permission."); player.sendMessage(ChatColor.RED + "You don't have sufficient permission.");
return true; return true;
} catch (CommandHandlingException e) {
return true;
} catch (Throwable t) {
player.sendMessage(ChatColor.RED + "ERROR: " + t.getMessage());
t.printStackTrace();
return true;
} }
} }
@ -432,11 +441,10 @@ public boolean onCommand(Player player, Command cmd, String commandLabel, String
* @param cmd * @param cmd
* @param args * @param args
* @return * @return
* @throws InsufficientArgumentsException * @throws CommandHandlingException
* @throws InsufficientPermissionsException
*/ */
private boolean handleCommand(Player player, String cmd, String[] args) private boolean handleCommand(Player player, String cmd, String[] args)
throws InsufficientArgumentsException, InsufficientPermissionsException { throws CommandHandlingException {
if (cmd.equalsIgnoreCase("stopfire")) { if (cmd.equalsIgnoreCase("stopfire")) {
checkPermission(player, "/stopfire"); checkPermission(player, "/stopfire");
@ -711,11 +719,10 @@ private boolean handleCommand(Player player, String cmd, String[] args)
* @param player * @param player
* @param action * @param action
* @param args * @param args
* @throws InsufficientPermissionsException * @throws CommandHandlingException
* @throws InsufficientArgumentsException
*/ */
private boolean handleRegionCommand(Player player, String action, String[] args) private boolean handleRegionCommand(Player player, String action, String[] args)
throws InsufficientPermissionsException, InsufficientArgumentsException { throws CommandHandlingException {
if (!useRegions) { if (!useRegions) {
player.sendMessage(ChatColor.RED + "Regions are disabled."); player.sendMessage(ChatColor.RED + "Regions are disabled.");
return true; return true;
@ -743,11 +750,11 @@ private boolean handleRegionCommand(Player player, String action, String[] args)
BlockVector min = weRegion.getMinimumPoint().toBlockVector(); BlockVector min = weRegion.getMinimumPoint().toBlockVector();
BlockVector max = weRegion.getMaximumPoint().toBlockVector(); BlockVector max = weRegion.getMaximumPoint().toBlockVector();
ProtectedRegion region = new ProtectedCuboidRegion(min, max); ProtectedRegion region = new ProtectedCuboidRegion(id, min, max);
if (args.length >= 2) { if (args.length >= 2) {
region.setOwners(parseDomainString(args, 1)); region.setOwners(parseDomainString(args, 1));
} }
regionManager.addRegion(id, region); regionManager.addRegion(region);
regionLoader.save(regionManager); regionLoader.save(regionManager);
player.sendMessage(ChatColor.YELLOW + "Region saved as " + id + "."); player.sendMessage(ChatColor.YELLOW + "Region saved as " + id + ".");
} catch (IncompleteRegionException e) { } catch (IncompleteRegionException e) {
@ -785,7 +792,7 @@ private boolean handleRegionCommand(Player player, String action, String[] args)
BlockVector min = weRegion.getMinimumPoint().toBlockVector(); BlockVector min = weRegion.getMinimumPoint().toBlockVector();
BlockVector max = weRegion.getMaximumPoint().toBlockVector(); BlockVector max = weRegion.getMaximumPoint().toBlockVector();
ProtectedRegion region = new ProtectedCuboidRegion(min, max); ProtectedRegion region = new ProtectedCuboidRegion(id, min, max);
if (regionManager.overlapsUnownedRegion(region, wrapPlayer(player))) { if (regionManager.overlapsUnownedRegion(region, wrapPlayer(player))) {
player.sendMessage(ChatColor.RED + "This region overlaps with someone else's region."); player.sendMessage(ChatColor.RED + "This region overlaps with someone else's region.");
@ -794,7 +801,7 @@ private boolean handleRegionCommand(Player player, String action, String[] args)
region.getOwners().addPlayer(player.getName()); region.getOwners().addPlayer(player.getName());
regionManager.addRegion(id, region); regionManager.addRegion(region);
regionLoader.save(regionManager); regionLoader.save(regionManager);
player.sendMessage(ChatColor.YELLOW + "Region saved as " + id + "."); player.sendMessage(ChatColor.YELLOW + "Region saved as " + id + ".");
} catch (IncompleteRegionException e) { } catch (IncompleteRegionException e) {
@ -835,23 +842,78 @@ private boolean handleRegionCommand(Player player, String action, String[] args)
return true; return true;
} }
AreaFlags flags = region.getFlags(); if (flagStr.length() == 0) {
player.sendMessage(ChatColor.RED + "A flag must be specified.");
if (flagStr.equalsIgnoreCase("build")) { return true;
flags.allowBuild = state; // Custom flag
} else if (flagStr.equalsIgnoreCase("pvp")) { } else if (flagStr.length() == 2 && flagStr.matches("^_[A-Za-z0-0]$")) {
flags.allowPvP = state;
} else if (flagStr.equalsIgnoreCase("tnt")) {
flags.allowTNT = state;
} else if (flagStr.equalsIgnoreCase("lighter")) {
flags.allowLighter = state;
} else { } else {
player.sendMessage(ChatColor.RED + "Acceptable flags: build, pvp, tnt, lighter"); flagStr = AreaFlags.fromAlias(flagStr);
if (flagStr == null) {
player.sendMessage(ChatColor.RED + "Unknown flag specified.");
return true;
}
}
AreaFlags flags = region.getFlags();
flags.set(flagStr, state);
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("setparent")) {
if (!hasPermission(player, "/regionclaim")) {
checkRegionPermission(player, "/regiondefine");
}
checkArgs(args, 1, 2, "/region setparent <id> <parent-id>");
String id = args[0].toLowerCase();
String parentId = args.length > 1 ? args[1].toLowerCase() : null;
ProtectedRegion region = regionManager.getRegion(id);
if (region == null) {
player.sendMessage(ChatColor.RED + "Could not find a region with ID: " + id);
return true;
}
if (!canUseRegionCommand(player, "/regiondefine")
&& !region.isOwner(wrapPlayer(player))) {
player.sendMessage(ChatColor.RED + "You need to own the target regions");
return true;
}
ProtectedRegion parent = null;
// Set a parent
if (parentId != null) {
parent = regionManager.getRegion(parentId);
if (parent == null) {
player.sendMessage(ChatColor.RED + "Could not find a region with ID: " + parentId);
return true; return true;
} }
if (!canUseRegionCommand(player, "/regiondefine")
&& !parent.isOwner(wrapPlayer(player))) {
player.sendMessage(ChatColor.RED + "You need to own the parent region.");
return true;
}
}
try {
region.setParent(parent);
regionLoader.save(regionManager); regionLoader.save(regionManager);
player.sendMessage(ChatColor.YELLOW + "Region '" + id + "' updated."); player.sendMessage(ChatColor.YELLOW + "Region '" + id + "' updated.");
} catch (CircularInheritanceException e) {
player.sendMessage(ChatColor.RED + "Circular inheritance detected. The operation failed.");
} catch (IOException e) { } catch (IOException e) {
player.sendMessage(ChatColor.RED + "Region database failed to save: " player.sendMessage(ChatColor.RED + "Region database failed to save: "
+ e.getMessage()); + e.getMessage());
@ -873,47 +935,74 @@ private boolean handleRegionCommand(Player player, String action, String[] args)
ProtectedRegion region = regionManager.getRegion(id); ProtectedRegion region = regionManager.getRegion(id);
AreaFlags flags = region.getFlags(); AreaFlags flags = region.getFlags();
DefaultDomain domain = region.getOwners(); DefaultDomain owners = region.getOwners();
DefaultDomain members = region.getMembers();
player.sendMessage(ChatColor.YELLOW + "Region ID: " + id); player.sendMessage(ChatColor.YELLOW + "Region: " + id
player.sendMessage(ChatColor.GRAY + "Type: " + region.getClass().getCanonicalName()); + ChatColor.GRAY + " (type: " + region.getTypeName() + ")");
player.sendMessage(ChatColor.GRAY + "Priority: " + region.getPriority()); player.sendMessage(ChatColor.BLUE + "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());
StringBuilder s = new StringBuilder();
for (Map.Entry<String, State> entry : flags.entrySet()) {
if (s.length() > 0) {
s.append(", ");
}
if (entry.getValue() == State.ALLOW) {
s.append("+");
s.append(AreaFlags.getFlagName(entry.getKey()));
} else if (entry.getValue() == State.DENY) {
s.append("-");
s.append(AreaFlags.getFlagName(entry.getKey()));
}
}
player.sendMessage(ChatColor.BLUE + "Flags: " + s.toString());
player.sendMessage(ChatColor.BLUE + "Parent: "
+ (region.getParent() == null ? "(none)" : region.getParent().getId()));
player.sendMessage(ChatColor.LIGHT_PURPLE + "Owners: "
+ owners.toUserFriendlyString());
player.sendMessage(ChatColor.LIGHT_PURPLE + "Members: "
+ members.toUserFriendlyString());
return true; return true;
} }
if (action.equalsIgnoreCase("addowner")) { if (action.equalsIgnoreCase("addowner") || action.equalsIgnoreCase("addmember")) {
if (!hasPermission(player, "/regionclaim")) { if (!hasPermission(player, "/regionclaim")) {
checkRegionPermission(player, "/regiondefine"); checkRegionPermission(player, "/regiondefine");
} }
checkArgs(args, 2, -1, "/region addowner <id> [owner1 [owner2 [owners...]]]"); checkArgs(args, 2, -1, "/region add[member|owner] <id> [player1 [group1 [players/groups...]]]");
boolean isOwner = action.equalsIgnoreCase("addowner");
String id = args[0].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.isOwner(wrapPlayer(player))) {
player.sendMessage(ChatColor.RED + "You don't own this region.");
return true;
}
if (isOwner) {
addToDomain(existing.getOwners(), args, 1);
} else {
addToDomain(existing.getMembers(), args, 1);
}
try { try {
String id = args[0].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, 1);
regionLoader.save(regionManager); regionLoader.save(regionManager);
player.sendMessage(ChatColor.YELLOW + "Region updated!"); player.sendMessage(ChatColor.YELLOW + "Region updated!");
player.sendMessage(ChatColor.GRAY + "Current owners: "
+ existing.getOwners().toUserFriendlyString());
player.sendMessage(ChatColor.GRAY + "Current members: "
+ existing.getMembers().toUserFriendlyString());
} catch (IOException e) { } catch (IOException e) {
player.sendMessage(ChatColor.RED + "Region database failed to save: " player.sendMessage(ChatColor.RED + "Region database failed to save: "
+ e.getMessage()); + e.getMessage());
@ -922,32 +1011,42 @@ private boolean handleRegionCommand(Player player, String action, String[] args)
return true; return true;
} }
if (action.equalsIgnoreCase("removeowner")) { if (action.equalsIgnoreCase("removeowner") || action.equalsIgnoreCase("removemember")) {
if (!hasPermission(player, "/regionclaim")) { if (!hasPermission(player, "/regionclaim")) {
checkRegionPermission(player, "/regiondefine"); checkRegionPermission(player, "/regiondefine");
} }
checkArgs(args, 2, -1, "/region removeowner <id> [owner1 [owner2 [owners...]]]"); checkArgs(args, 2, -1, "/region removeowner <id> [owner1 [owner2 [owners...]]]");
try { boolean isOwner = action.equalsIgnoreCase("removeowner");
String id = args[0].toLowerCase();
if (!regionManager.hasRegion(id)) {
player.sendMessage(ChatColor.RED + "A region with ID '"
+ id + "' doesn't exist.");
return true;
}
ProtectedRegion existing = regionManager.getRegion(id); String id = args[0].toLowerCase();
if (!regionManager.hasRegion(id)) {
player.sendMessage(ChatColor.RED + "A region with ID '"
+ id + "' doesn't exist.");
return true;
}
if (!canUseRegionCommand(player, "/regiondefine") ProtectedRegion existing = regionManager.getRegion(id);
&& !existing.getOwners().contains(wrapPlayer(player))) {
player.sendMessage(ChatColor.RED + "You don't own this region.");
return true;
}
if (!canUseRegionCommand(player, "/regiondefine")
&& !existing.isOwner(wrapPlayer(player))) {
player.sendMessage(ChatColor.RED + "You don't own this region.");
return true;
}
if (isOwner) {
removeFromDomain(existing.getOwners(), args, 1); removeFromDomain(existing.getOwners(), args, 1);
} else {
removeFromDomain(existing.getMembers(), args, 1);
}
try {
regionLoader.save(regionManager); regionLoader.save(regionManager);
player.sendMessage(ChatColor.YELLOW + "Region updated!"); player.sendMessage(ChatColor.YELLOW + "Region updated!");
player.sendMessage(ChatColor.GRAY + "Current owners: "
+ existing.getOwners().toUserFriendlyString());
player.sendMessage(ChatColor.GRAY + "Current members: "
+ existing.getMembers().toUserFriendlyString());
} catch (IOException e) { } catch (IOException e) {
player.sendMessage(ChatColor.RED + "Region database failed to save: " player.sendMessage(ChatColor.RED + "Region database failed to save: "
+ e.getMessage()); + e.getMessage());
@ -1013,7 +1112,7 @@ private boolean handleRegionCommand(Player player, String action, String[] args)
ProtectedRegion existing = regionManager.getRegion(id); ProtectedRegion existing = regionManager.getRegion(id);
if (!canUseRegionCommand(player, "/regiondelete") if (!canUseRegionCommand(player, "/regiondelete")
&& !existing.getOwners().contains(wrapPlayer(player))) { && !existing.isOwner(wrapPlayer(player))) {
player.sendMessage(ChatColor.RED + "You don't own this region."); player.sendMessage(ChatColor.RED + "You don't own this region.");
return true; return true;
} }
@ -1229,12 +1328,21 @@ BukkitPlayer wrapPlayer(Player player) {
return new BukkitPlayer(this, player); return new BukkitPlayer(this, player);
} }
/**
* Thrown when command handling has raised an exception.
*
* @author sk89q
*/
private static class CommandHandlingException extends Exception {
private static final long serialVersionUID = 7912130636812036780L;
}
/** /**
* Thrown when a player has insufficient permissions. * Thrown when a player has insufficient permissions.
* *
* @author sk89q * @author sk89q
*/ */
private static class InsufficientPermissionsException extends Exception { private static class InsufficientPermissionsException extends CommandHandlingException {
private static final long serialVersionUID = 9087662707619954750L; private static final long serialVersionUID = 9087662707619954750L;
} }
@ -1243,7 +1351,7 @@ private static class InsufficientPermissionsException extends Exception {
* *
* @author sk89q * @author sk89q
*/ */
private static class InsufficientArgumentsException extends Exception { private static class InsufficientArgumentsException extends CommandHandlingException {
private static final long serialVersionUID = 4153597953889773788L; private static final long serialVersionUID = 4153597953889773788L;
private final String help; private final String help;

View File

@ -98,6 +98,7 @@ public String toPlayersString() {
public String toGroupsString() { public String toGroupsString() {
StringBuilder str = new StringBuilder(); StringBuilder str = new StringBuilder();
for (Iterator<String> it = groups.iterator(); it.hasNext(); ) { for (Iterator<String> it = groups.iterator(); it.hasNext(); ) {
str.append("*");
str.append(it.next()); str.append(it.next());
if (it.hasNext()) { if (it.hasNext()) {
str.append(", "); str.append(", ");
@ -105,4 +106,21 @@ public String toGroupsString() {
} }
return str.toString(); return str.toString();
} }
public String toUserFriendlyString() {
StringBuilder str = new StringBuilder();
if (players.size() > 0) {
str.append(toPlayersString());
}
if (groups.size() > 0) {
if (str.length() > 0) {
str.append("; ");
}
str.append(toGroupsString());
}
return str.toString();
}
} }

View File

@ -19,6 +19,8 @@
package com.sk89q.worldguard.protection; package com.sk89q.worldguard.protection;
import java.util.HashSet;
import java.util.Set;
import java.util.SortedMap; import java.util.SortedMap;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.LocalPlayer;
@ -30,175 +32,139 @@
* @author sk89q * @author sk89q
*/ */
public class ApplicableRegionSet { public class ApplicableRegionSet {
private GlobalFlags global;
private Vector pt; private Vector pt;
private SortedMap<String,ProtectedRegion> regions; private SortedMap<String,ProtectedRegion> regions;
public ApplicableRegionSet(Vector pt, SortedMap<String,ProtectedRegion> regions) { /**
* Construct the object.
*
* @param pt
* @param regions
* @param global
*/
public ApplicableRegionSet(Vector pt, SortedMap<String,ProtectedRegion> regions,
GlobalFlags global) {
this.pt = pt; this.pt = pt;
this.regions = regions; this.regions = regions;
this.global = global;
} }
/**
* Checks if a player can build in an area.
*
* @param player
* @return
*/
public boolean canBuild(LocalPlayer player) { public boolean canBuild(LocalPlayer player) {
return isFlagAllowed(AreaFlags.FLAG_BUILD, global.canBuild, player);
}
/**
* Checks a flag.
*
* @param player
* @return
*/
public boolean allowsFlag(String flag) {
return isFlagAllowed(flag, true, null);
}
/**
* Checks to see if a flag is permitted.
*
* @param def default state if there are no regions defined
* @param player null to not check owners and members
* @return
*/
private boolean isFlagAllowed(String flag, boolean def, LocalPlayer player) {
boolean found = false; boolean found = false;
boolean allowed = false; // Used for ALLOW override
int lastPriority = 0; int lastPriority = 0;
for (ProtectedRegion region : regions.values()) { // The algorithm is as follows:
if (region.getFlags().allowBuild == State.ALLOW) continue; // While iterating through the list of regions, if an entry disallows
if (!region.contains(pt)) continue; // the flag, then put it into the needsClear set. If an entry allows
// the flag and it has a parent, then its parent is put into hasCleared.
// In the situation that the child is reached before the parent, upon
// the parent being reached, even if the parent disallows, because the
// parent will be in hasCleared, permission will be allowed. In the
// other case, where the parent is reached first, if it does not allow
// permissions, it will be placed into needsClear. If a child of
// the parent is reached later, the parent will be removed from
// needsClear. At the end, if needsClear is not empty, that means that
// permission should not be given. If a parent has multiple children
// and one child does not allow permissions, then it will be placed into
// needsClear just like as if was a parent.
// Ignore lower priority regions Set<ProtectedRegion> needsClear = new HashSet<ProtectedRegion>();
if (found && region.getPriority() < lastPriority) { Set<ProtectedRegion> hasCleared = new HashSet<ProtectedRegion>();
break;
for (ProtectedRegion region : regions.values()) {
// Ignore non-build regions
if (player != null && region.getFlags().get(AreaFlags.FLAG_PASSTHROUGH) == State.ALLOW) {
continue;
} }
if (!region.getOwners().contains(player)) { // Forget about regions that are not covered
if (!region.contains(pt)) {
continue;
}
// Allow DENY to override everything
if (region.getFlags().get(flag) == State.DENY) {
return false; return false;
} }
found = true; // Forget about regions that allow it, although make sure the
lastPriority = region.getPriority(); // default state is now to allow
} if (region.getFlags().get(flag) == State.ALLOW) {
allowed = true;
return true; continue;
} }
public boolean allowsPvP() {
boolean found = false;
int lastPriority = 0;
for (ProtectedRegion region : regions.values()) {
if (!region.contains(pt)) continue;
if (region.getFlags().allowPvP == State.DENY) return false;
// Ignore lower priority regions // Ignore lower priority regions
if (found && region.getPriority() < lastPriority) { if (found && region.getPriority() < lastPriority) {
break; break;
} }
found = true; if (player != null) {
lastPriority = region.getPriority(); if (hasCleared.contains(region)) {
} // Already cleared, so do nothing
} else {
return true; if (!region.isMember(player)) {
} needsClear.add(region);
} else {
public boolean allowsMobDamage() { // Need to clear all parents
boolean found = false; clearParents(needsClear, hasCleared, region);
int lastPriority = 0; }
}
for (ProtectedRegion region : regions.values()) {
if (!region.contains(pt)) continue;
if (region.getFlags().allowMobDamage == State.DENY) return false;
// Ignore lower priority regions
if (found && region.getPriority() < lastPriority) {
break;
} }
found = true; found = true;
lastPriority = region.getPriority(); lastPriority = region.getPriority();
} }
return true; return found == false ? def : allowed || needsClear.size() == 0;
} }
public boolean allowsCreeperExplosions() { /**
boolean found = false; * Clear a region's parents for isFlagAllowed().
int lastPriority = 0; *
* @param needsClear
* @param hasCleared
* @param region
*/
private void clearParents(Set<ProtectedRegion> needsClear,
Set<ProtectedRegion> hasCleared, ProtectedRegion region) {
ProtectedRegion parent = region.getParent();
for (ProtectedRegion region : regions.values()) { while (parent != null) {
if (!region.contains(pt)) continue; if (!needsClear.remove(parent)) {
if (region.getFlags().allowCreeperExplosions == State.DENY) return false; hasCleared.add(parent);
// Ignore lower priority regions
if (found && region.getPriority() < lastPriority) {
break;
} }
found = true; parent = parent.getParent();
lastPriority = region.getPriority();
} }
return true;
}
public boolean allowsTNT() {
boolean found = false;
int lastPriority = 0;
for (ProtectedRegion region : regions.values()) {
if (!region.contains(pt)) continue;
if (region.getFlags().allowTNT == State.DENY) return false;
// Ignore lower priority regions
if (found && region.getPriority() < lastPriority) {
break;
}
found = true;
lastPriority = region.getPriority();
}
return true;
}
public boolean allowsLighter() {
boolean found = false;
int lastPriority = 0;
for (ProtectedRegion region : regions.values()) {
if (!region.contains(pt)) continue;
if (region.getFlags().allowLighter == State.DENY) return false;
// Ignore lower priority regions
if (found && region.getPriority() < lastPriority) {
break;
}
found = true;
lastPriority = region.getPriority();
}
return true;
}
public boolean allowsFireSpread() {
boolean found = false;
int lastPriority = 0;
for (ProtectedRegion region : regions.values()) {
if (!region.contains(pt)) continue;
if (region.getFlags().allowFireSpread == State.DENY) return false;
// Ignore lower priority regions
if (found && region.getPriority() < lastPriority) {
break;
}
found = true;
lastPriority = region.getPriority();
}
return true;
}
public boolean allowsLavaFire() {
boolean found = false;
int lastPriority = 0;
for (ProtectedRegion region : regions.values()) {
if (!region.contains(pt)) continue;
if (region.getFlags().allowLavaFire == State.DENY) return false;
// Ignore lower priority regions
if (found && region.getPriority() < lastPriority) {
break;
}
found = true;
lastPriority = region.getPriority();
}
return true;
} }
} }

View File

@ -19,7 +19,12 @@
package com.sk89q.worldguard.protection; package com.sk89q.worldguard.protection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/** /**
* Holds the flags for a region.
* *
* @author sk89q * @author sk89q
*/ */
@ -30,14 +35,98 @@ public enum State {
DENY, DENY,
}; };
public State allowBuild = State.NONE; public static final String FLAG_PASSTHROUGH = "z";
public State allowPvP = State.NONE; public static final String FLAG_BUILD = "b";
public State allowMobDamage = State.NONE; public static final String FLAG_PVP = "p";
public State allowCreeperExplosions = State.NONE; public static final String FLAG_MOB_DAMAGE = "m";
public State allowTNT = State.NONE; public static final String FLAG_CREEPER_EXPLOSION = "c";
public State allowLighter = State.NONE; public static final String FLAG_TNT = "t";
public State allowFireSpread = State.NONE; public static final String FLAG_LIGHTER = "l";
public State allowLavaFire = State.NONE; public static final String FLAG_FIRE_SPREAD = "f";
public static final String FLAG_LAVA_FIRE = "F";
/**
* Get the user-friendly name of a flag. If a name isn't known, then
* the flag is returned unchanged.
*
* @param flag
* @return
*/
public static String getFlagName(String flag) {
if (flag.equals(FLAG_PASSTHROUGH)) {
return "passthrough";
} else if (flag.equals(FLAG_BUILD)) {
return "build";
} else if (flag.equals(FLAG_PVP)) {
return "PvP";
} else if (flag.equals(FLAG_MOB_DAMAGE)) {
return "mob damage";
} else if (flag.equals(FLAG_CREEPER_EXPLOSION)) {
return "creeper explosion";
} else if (flag.equals(FLAG_TNT)) {
return "TNT";
} else if (flag.equals(FLAG_LIGHTER)) {
return "lighter";
} else if (flag.equals(FLAG_FIRE_SPREAD)) {
return "fire spread";
} else if (flag.equals(FLAG_LAVA_FIRE)) {
return "lava fire spread";
} else {
return flag;
}
}
/**
* Gets a flag from an alias. May return null.
*
* @param name
* @return
*/
public static String fromAlias(String name) {
if (name.equalsIgnoreCase("passthrough")) {
return FLAG_PASSTHROUGH;
} else if (name.equalsIgnoreCase("build")) {
return FLAG_BUILD;
} else if (name.equalsIgnoreCase("pvp")) {
return FLAG_PVP;
} else if (name.equalsIgnoreCase("mobdamage")) {
return FLAG_MOB_DAMAGE;
} else if (name.equalsIgnoreCase("creeper")) {
return FLAG_CREEPER_EXPLOSION;
} else if (name.equalsIgnoreCase("tnt")) {
return FLAG_TNT;
} else if (name.equalsIgnoreCase("lighter")) {
return FLAG_LIGHTER;
} else if (name.equalsIgnoreCase("firespread")) {
return FLAG_FIRE_SPREAD;
} else if (name.equalsIgnoreCase("lavafirespread")) {
return FLAG_LAVA_FIRE;
} else {
return null;
}
}
private Map<String, State> states = new HashMap<String, State>();
public State get(String flag) {
State state = states.get(flag);
if (state == null) {
return State.NONE;
}
return state;
}
public void set(String flag, State state) {
if (state == State.NONE) {
states.remove(flag);
} else {
states.put(flag, state);
}
}
public Set<Map.Entry<String, State>> entrySet() {
return states.entrySet();
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
@ -46,14 +135,6 @@ public boolean equals(Object obj) {
} }
AreaFlags other = (AreaFlags)obj; AreaFlags other = (AreaFlags)obj;
return other.states.equals(this);
return other.allowBuild == allowBuild
&& other.allowPvP == allowPvP
&& other.allowMobDamage == allowMobDamage
&& other.allowCreeperExplosions == allowCreeperExplosions
&& other.allowTNT == allowTNT
&& other.allowLighter == allowLighter
&& other.allowFireSpread == allowFireSpread
&& other.allowLavaFire == allowLavaFire;
} }
} }

View File

@ -20,6 +20,7 @@
package com.sk89q.worldguard.protection; package com.sk89q.worldguard.protection;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -31,6 +32,8 @@
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.domains.DefaultDomain; import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.AreaFlags.State; import com.sk89q.worldguard.protection.AreaFlags.State;
import com.sk89q.worldguard.protection.ProtectedRegion.CircularInheritanceException;
import com.sk89q.worldguard.util.ArrayReader;
/** /**
* Represents a protected area database that uses CSV files. * Represents a protected area database that uses CSV files.
@ -82,7 +85,7 @@ public void save() throws IOException {
writer.writeNext(new String[] { writer.writeNext(new String[] {
id, id,
"cuboid", "cuboid.2",
String.valueOf(min.getBlockX()), String.valueOf(min.getBlockX()),
String.valueOf(min.getBlockY()), String.valueOf(min.getBlockY()),
String.valueOf(min.getBlockZ()), String.valueOf(min.getBlockZ()),
@ -90,9 +93,12 @@ public void save() throws IOException {
String.valueOf(max.getBlockY()), String.valueOf(max.getBlockY()),
String.valueOf(max.getBlockZ()), String.valueOf(max.getBlockZ()),
String.valueOf(cuboid.getPriority()), String.valueOf(cuboid.getPriority()),
cuboid.getParent() != null ? cuboid.getParent().getId() : "",
writeDomains(cuboid.getOwners()), writeDomains(cuboid.getOwners()),
writeDomains(cuboid.getMembers()),
writeFlags(cuboid.getFlags()), writeFlags(cuboid.getFlags()),
cuboid.getEnterMessage(), cuboid.getEnterMessage() != null ? cuboid.getEnterMessage() : "",
cuboid.getLeaveMessage() != null ? cuboid.getLeaveMessage() : "",
}); });
} }
} finally { } finally {
@ -110,6 +116,8 @@ public void save() throws IOException {
public void load() throws IOException { public void load() throws IOException {
Map<String,ProtectedRegion> regions = Map<String,ProtectedRegion> regions =
new HashMap<String,ProtectedRegion>(); new HashMap<String,ProtectedRegion>();
Map<ProtectedRegion,String> parentSets =
new LinkedHashMap<ProtectedRegion, String>();
CSVReader reader = new CSVReader(new FileReader(file)); CSVReader reader = new CSVReader(new FileReader(file));
@ -117,16 +125,21 @@ public void load() throws IOException {
String[] line; String[] line;
while ((line = reader.readNext()) != null) { while ((line = reader.readNext()) != null) {
if (line.length >= 12) { if (line.length < 2) {
String type = line[1]; logger.warning("Invalid region definition: " + line);
if (!type.equalsIgnoreCase("cuboid")) { continue;
logger.warning("Only cuboid region types are supported: " }
+ line);
break;
String id = line[0].toLowerCase();
String type = line[1];
ArrayReader<String> entries = new ArrayReader<String>(line);
if (type.equalsIgnoreCase("cuboid")) {
if (line.length < 8) {
logger.warning("Invalid region definition: " + line);
continue;
} }
String id = line[0];
Vector pt1 = new Vector( Vector pt1 = new Vector(
Integer.parseInt(line[2]), Integer.parseInt(line[2]),
Integer.parseInt(line[3]), Integer.parseInt(line[3]),
@ -139,19 +152,51 @@ public void load() throws IOException {
BlockVector min = Vector.getMinimum(pt1, pt2).toBlockVector(); BlockVector min = Vector.getMinimum(pt1, pt2).toBlockVector();
BlockVector max = Vector.getMaximum(pt1, pt2).toBlockVector(); BlockVector max = Vector.getMaximum(pt1, pt2).toBlockVector();
int priority = Integer.parseInt(line[8]); int priority = entries.get(8) == null ? 0 : Integer.parseInt(entries.get(8));
String ownersData = line[9]; String ownersData = entries.get(9);
String flagsData = line[10]; String flagsData = entries.get(10);
String enterMessage = line[11]; String enterMessage = nullEmptyString(entries.get(11));
ProtectedRegion region = new ProtectedCuboidRegion(min, max); ProtectedRegion region = new ProtectedCuboidRegion(id, min, max);
region.setPriority(priority); region.setPriority(priority);
region.setFlags(parseFlags(flagsData));
region.setOwners(this.parseDomains(ownersData)); region.setOwners(this.parseDomains(ownersData));
region.setEnterMessage(enterMessage); region.setEnterMessage(enterMessage);
region.setFlags(parseFlags(flagsData));
regions.put(id, region); regions.put(id, region);
} else { } else if (type.equalsIgnoreCase("cuboid.2")) {
logger.warning("Line is invalid: " + line); Vector pt1 = new Vector(
Integer.parseInt(line[2]),
Integer.parseInt(line[3]),
Integer.parseInt(line[4]));
Vector pt2 = new Vector(
Integer.parseInt(line[5]),
Integer.parseInt(line[6]),
Integer.parseInt(line[7]));
BlockVector min = Vector.getMinimum(pt1, pt2).toBlockVector();
BlockVector max = Vector.getMaximum(pt1, pt2).toBlockVector();
int priority = entries.get(8) == null ? 0 : Integer.parseInt(entries.get(8));
String parentId = entries.get(9);
String ownersData = entries.get(10);
String membersData = entries.get(11);
String flagsData = entries.get(12);
String enterMessage = nullEmptyString(entries.get(13));
String leaveMessage = nullEmptyString(entries.get(14));
ProtectedRegion region = new ProtectedCuboidRegion(id, min, max);
region.setPriority(priority);
region.setFlags(parseFlags(flagsData));
region.setOwners(this.parseDomains(ownersData));
region.setMembers(this.parseDomains(membersData));
region.setEnterMessage(enterMessage);
region.setLeaveMessage(leaveMessage);
regions.put(id, region);
// Link children to parents later
if (parentId.length() > 0) {
parentSets.put(region, parentId);
}
} }
} }
} finally { } finally {
@ -161,6 +206,20 @@ public void load() throws IOException {
} }
} }
for (Map.Entry<ProtectedRegion, String> entry : parentSets.entrySet()) {
ProtectedRegion parent = regions.get(entry.getValue());
if (parent != null) {
try {
entry.getKey().setParent(parent);
} catch (CircularInheritanceException e) {
logger.warning("Circular inheritance detect with '"
+ entry.getValue() + "' detected as a parent");
}
} else {
logger.warning("Unknown region parent: " + entry.getValue());
}
}
this.regions = regions; this.regions = regions;
} }
@ -191,6 +250,10 @@ public void save(RegionManager manager) throws IOException {
* @return * @return
*/ */
private DefaultDomain parseDomains(String data) { private DefaultDomain parseDomains(String data) {
if (data == null) {
return new DefaultDomain();
}
DefaultDomain domain = new DefaultDomain(); DefaultDomain domain = new DefaultDomain();
Pattern pattern = Pattern.compile("^([A-Za-z]):(.*)$"); Pattern pattern = Pattern.compile("^([A-Za-z]):(.*)$");
@ -230,33 +293,32 @@ private DefaultDomain parseDomains(String data) {
* @return * @return
*/ */
private AreaFlags parseFlags(String data) { private AreaFlags parseFlags(String data) {
if (data == null) {
return new AreaFlags();
}
AreaFlags flags = new AreaFlags(); AreaFlags flags = new AreaFlags();
State curState = State.ALLOW; State curState = State.ALLOW;
for (int i = 0; i < data.length(); i++) { for (int i = 0; i < data.length(); i++) {
char flag = data.charAt(i); char k = data.charAt(i);
if (flag == '+') { if (k == '+') {
curState = State.ALLOW; curState = State.ALLOW;
} else if (flag == '-') { } else if (k == '-') {
curState = State.DENY; curState = State.DENY;
} else if (flag == 'b') {
flags.allowBuild = curState;
} else if (flag == 'p') {
flags.allowPvP = curState;
} else if (flag == 'm') {
flags.allowMobDamage = curState;
} else if (flag == 'c') {
flags.allowCreeperExplosions = curState;
} else if (flag == 't') {
flags.allowTNT = curState;
} else if (flag == 'l') {
flags.allowLighter = curState;
} else if (flag == 'f') {
flags.allowFireSpread = curState;
} else if (flag == 'F') {
flags.allowLavaFire = curState;
} else { } else {
logger.warning("Unknown area flag/flag modifier: " + flag); String flag;
if (k == '_') {
if (i == data.length() - 1) {
logger.warning("_ read ahead fail");
break;
}
flag = "_" + data.charAt(i + 1);
i++;
} else {
flag = String.valueOf(k);
}
flags.set(flag, curState);
} }
} }
@ -302,6 +364,22 @@ private String writeFlag(State state, String flag) {
return ""; return "";
} }
/**
* Returns a null if a string is null or empty.
*
* @param str
* @return
*/
private String nullEmptyString(String str) {
if (str == null) {
return null;
} else if (str.length() == 0) {
return null;
} else {
return str;
}
}
/** /**
* Used to write the list of flags. * Used to write the list of flags.
* *
@ -310,14 +388,9 @@ private String writeFlag(State state, String flag) {
*/ */
private String writeFlags(AreaFlags flags) { private String writeFlags(AreaFlags flags) {
StringBuilder str = new StringBuilder(); StringBuilder str = new StringBuilder();
str.append(writeFlag(flags.allowBuild, "b")); for (Map.Entry<String, State> entry : flags.entrySet()) {
str.append(writeFlag(flags.allowPvP, "p")); str.append(writeFlag(entry.getValue(), entry.getKey()));
str.append(writeFlag(flags.allowMobDamage, "m")); }
str.append(writeFlag(flags.allowCreeperExplosions, "c"));
str.append(writeFlag(flags.allowTNT, "t"));
str.append(writeFlag(flags.allowLighter, "l"));
str.append(writeFlag(flags.allowFireSpread, "f"));
str.append(writeFlag(flags.allowLavaFire, "F"));
return str.toString(); return str.toString();
} }

View File

@ -39,12 +39,17 @@ public class FlatRegionManager implements RegionManager {
* List of protected regions. * List of protected regions.
*/ */
private SortedMap<String,ProtectedRegion> regions; private SortedMap<String,ProtectedRegion> regions;
/**
* Global flags.
*/
private GlobalFlags global;
/** /**
* Construct the manager. * Construct the manager.
*/ */
public FlatRegionManager() { public FlatRegionManager(GlobalFlags global) {
regions = new TreeMap<String,ProtectedRegion>(); regions = new TreeMap<String,ProtectedRegion>();
this.global = global;
} }
/** /**
@ -71,17 +76,27 @@ public void setRegions(Map<String,ProtectedRegion> regions) {
* @param id * @param id
* @param region * @param region
*/ */
public void addRegion(String id, ProtectedRegion region) { public void addRegion(ProtectedRegion region) {
regions.put(id, region); regions.put(region.getId(), region);
} }
/** /**
* Removes a region. * Removes a region and its children.
* *
* @param id * @param id
*/ */
public void removeRegion(String id) { public void removeRegion(String id) {
ProtectedRegion region = regions.get(id);
regions.remove(id); regions.remove(id);
if (region != null) {
for (Map.Entry<String, ProtectedRegion> entry : regions.entrySet()) {
if (entry.getValue().getParent() == region) {
removeRegion(entry.getKey());
}
}
}
} }
/** /**
@ -110,7 +125,7 @@ public ProtectedRegion getRegion(String id) {
* @return * @return
*/ */
public ApplicableRegionSet getApplicableRegions(Vector pt) { public ApplicableRegionSet getApplicableRegions(Vector pt) {
return new ApplicableRegionSet(pt, regions); return new ApplicableRegionSet(pt, regions, global);
} }
/** /**

View File

@ -0,0 +1,29 @@
// $Id$
/*
* WorldGuard
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection;
/**
* Used for default flags.
*
* @author sk89q
*/
public class GlobalFlags {
public boolean canBuild = true;
}

View File

@ -39,12 +39,13 @@ public class ProtectedCuboidRegion extends ProtectedRegion {
/** /**
* Construct a new instance of this cuboid region. * Construct a new instance of this cuboid region.
* *
* @param id
* @param pos1 * @param pos1
* @param pos2 * @param pos2
* @param priority * @param priority
*/ */
public ProtectedCuboidRegion(BlockVector min, BlockVector max) { public ProtectedCuboidRegion(String id, BlockVector min, BlockVector max) {
super(); super(id);
this.min = min; this.min = min;
this.max = max; this.max = max;
} }
@ -85,6 +86,9 @@ public void setMaximumPoint(BlockVector pt) {
max = pt; max = pt;
} }
/**
* Checks to see if a point is inside this region.
*/
@Override @Override
public boolean contains(Vector pt) { public boolean contains(Vector pt) {
int x = pt.getBlockX(); int x = pt.getBlockX();
@ -94,4 +98,13 @@ public boolean contains(Vector pt) {
&& y >= min.getBlockY() && y <= max.getBlockY() && y >= min.getBlockY() && y <= max.getBlockY()
&& z >= min.getBlockZ() && z <= max.getBlockZ(); && z >= min.getBlockZ() && z <= max.getBlockZ();
} }
/**
* Return the type of region as a user-friendly name.
*
* @return type of region
*/
public String getTypeName() {
return "cuboid";
}
} }

View File

@ -21,6 +21,7 @@
import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.domains.DefaultDomain; import com.sk89q.worldguard.domains.DefaultDomain;
/** /**
@ -30,34 +31,52 @@
*/ */
public abstract class ProtectedRegion implements Comparable<ProtectedRegion> { public abstract class ProtectedRegion implements Comparable<ProtectedRegion> {
/** /**
* Area message. * Holds the region's ID.
*/ */
private String enterMessage; private String id;
/**
* List of owners.
*/
private DefaultDomain owners = new DefaultDomain();
/** /**
* Priority. * Priority.
*/ */
private int priority = 0; private int priority = 0;
/**
* Parent region.
*/
private ProtectedRegion parent;
/**
* List of owners.
*/
private DefaultDomain owners = new DefaultDomain();
/**
* List of members.
*/
private DefaultDomain members = new DefaultDomain();
/** /**
* Area flags. * Area flags.
*/ */
private AreaFlags flags = new AreaFlags(); private AreaFlags flags = new AreaFlags();
/**
* Area message.
*/
private String enterMessage;
/**
* Area message.
*/
private String leaveMessage;
/** /**
* Construct a new instance of this region. * Construct a new instance of this region.
* *
* @param id * @param id
* @param priority
* @param owners
* @param enterMessage
*/ */
public ProtectedRegion() { public ProtectedRegion(String id) {
this.priority = 0; this.id = id;
this.owners = new DefaultDomain(); }
this.enterMessage = null;
/**
* @return the id
*/
public String getId() {
return id;
} }
/** /**
@ -74,6 +93,41 @@ public void setPriority(int priority) {
this.priority = priority; this.priority = priority;
} }
/**
* @return the parent
*/
public ProtectedRegion getParent() {
return parent;
}
/**
* Set the parent. This checks to make sure that it will not result
* in circular inheritance.
*
* @param parent the parent to set
* @throws CircularInheritanceException
*/
public void setParent(ProtectedRegion parent) throws CircularInheritanceException {
if (parent == null) {
this.parent = null;
return;
}
if (parent == this) {
throw new CircularInheritanceException();
}
ProtectedRegion p = parent.getParent();
while (p != null) {
if (p == this) {
throw new CircularInheritanceException();
}
p = p.getParent();
}
this.parent = parent;
}
/** /**
* Se flags. * Se flags.
* @param flags * @param flags
@ -96,6 +150,20 @@ public void setEnterMessage(String enterMessage) {
this.enterMessage = enterMessage; this.enterMessage = enterMessage;
} }
/**
* @return the leaveMessage
*/
public String getLeaveMessage() {
return leaveMessage;
}
/**
* @param leaveMessage the leaveMessage to set
*/
public void setLeaveMessage(String leaveMessage) {
this.leaveMessage = leaveMessage;
}
/** /**
* @return the owners * @return the owners
*/ */
@ -110,6 +178,67 @@ public void setOwners(DefaultDomain owners) {
this.owners = owners; this.owners = owners;
} }
/**
* @return the members
*/
public DefaultDomain getMembers() {
return members;
}
/**
* @param owners the owners to set
*/
public void setMembers(DefaultDomain members) {
this.members = members;
}
/**
* Checks whether a player is an owner of region or any of its parents.
*
* @param player
* @return
*/
public boolean isOwner(LocalPlayer player) {
if (owners.contains(player)) {
return true;
}
ProtectedRegion parent = getParent();
while (parent != null) {
if (parent.getOwners().contains(player)) {
return true;
}
parent = parent.getParent();
}
return false;
}
/**
* Checks whether a player is a member of the region or any of its parents.
*
* @param player
* @return
*/
public boolean isMember(LocalPlayer player) {
if (owners.contains(player) || members.contains(player)) {
return true;
}
ProtectedRegion parent = getParent();
while (parent != null) {
if (parent.getOwners().contains(player)
|| parent.getMembers().contains(player)) {
return true;
}
parent = parent.getParent();
}
return false;
}
/** /**
* Get flags. * Get flags.
* *
@ -143,6 +272,13 @@ public int compareTo(ProtectedRegion other) {
} }
} }
/**
* Return the type of region as a user-friendly, lowercase name.
*
* @return type of region
*/
public abstract String getTypeName();
/** /**
* Checks if two region intersects. * Checks if two region intersects.
* *
@ -172,4 +308,13 @@ public static boolean intersects(ProtectedRegion region1, ProtectedRegion region
throw new UnsupportedIntersectionException(); throw new UnsupportedIntersectionException();
} }
} }
/**
* Thrown when setting a parent would create a circular inheritance
* situation.
*
*/
public static class CircularInheritanceException extends Exception {
private static final long serialVersionUID = 7479613488496776022L;
}
} }

View File

@ -53,7 +53,7 @@ public interface RegionManager {
* @param id * @param id
* @param region * @param region
*/ */
public void addRegion(String id, ProtectedRegion region); public void addRegion(ProtectedRegion region);
/** /**
* Return whether a region exists by an ID. * Return whether a region exists by an ID.
@ -71,7 +71,7 @@ public interface RegionManager {
public ProtectedRegion getRegion(String id); public ProtectedRegion getRegion(String id);
/** /**
* Removes a region. * Removes a region, including inheriting children.
* *
* @param id * @param id
*/ */

View File

@ -0,0 +1,44 @@
// $Id$
/*
* WorldGuard
* Copyright (C) 2010 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.util;
public class ArrayReader<T> {
private T[] arr;
public ArrayReader(T[] arr) {
this.arr = arr;
}
public T get(int index) {
if (arr.length > index) {
return arr[index];
} else {
return null;
}
}
public T get(int index, T def) {
if (arr.length > index) {
return arr[index];
} else {
return def;
}
}
}

View File

@ -26,17 +26,22 @@
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.TestPlayer; import com.sk89q.worldguard.TestPlayer;
import com.sk89q.worldguard.domains.DefaultDomain; import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.AreaFlags.State;
public class ApplicableRegionSetTest { public class ApplicableRegionSetTest {
static String COURTYARD_ID = "courtyard"; static String COURTYARD_ID = "courtyard";
static String FOUNTAIN_ID = "fountain"; static String FOUNTAIN_ID = "fountain";
static String NO_FIRE_ID = "nofire";
static String MEMBER_GROUP = "member"; static String MEMBER_GROUP = "member";
static String COURTYARD_GROUP = "courtyard"; static String COURTYARD_GROUP = "courtyard";
Vector inFountain = new Vector(2, 2, 2); Vector inFountain = new Vector(2, 2, 2);
Vector inCourtyard = new Vector(7, 7, 7); Vector inCourtyard = new Vector(7, 7, 7);
Vector outside = new Vector(15, 15, 15); Vector outside = new Vector(15, 15, 15);
Vector inNoFire = new Vector(150, 150, 150);
RegionManager manager; RegionManager manager;
ProtectedRegion courtyard;
ProtectedRegion fountain;
TestPlayer player1; TestPlayer player1;
TestPlayer player2; TestPlayer player2;
@ -47,6 +52,7 @@ public void setUp() throws Exception {
setUpPlayers(); setUpPlayers();
setUpCourtyardRegion(); setUpCourtyardRegion();
setUpFountainRegion(); setUpFountainRegion();
setUpNoFireRegion();
} }
void setUpPlayers() { void setUpPlayers() {
@ -62,24 +68,41 @@ void setUpCourtyardRegion() {
DefaultDomain domain = new DefaultDomain(); DefaultDomain domain = new DefaultDomain();
domain.addGroup(COURTYARD_GROUP); domain.addGroup(COURTYARD_GROUP);
ProtectedRegion region = new ProtectedCuboidRegion( ProtectedRegion region = new ProtectedCuboidRegion(COURTYARD_ID,
new BlockVector(0, 0, 0), new BlockVector(10, 10, 10)); new BlockVector(0, 0, 0), new BlockVector(10, 10, 10));
AreaFlags flags = new AreaFlags(); AreaFlags flags = new AreaFlags();
flags.allowBuild = AreaFlags.State.NONE; flags.set(AreaFlags.FLAG_BUILD, State.NONE);
flags.allowFireSpread = AreaFlags.State.ALLOW; flags.set(AreaFlags.FLAG_FIRE_SPREAD, State.ALLOW);
region.setFlags(flags); region.setFlags(flags);
region.setOwners(domain); region.setOwners(domain);
manager.addRegion(COURTYARD_ID, region); manager.addRegion(region);
courtyard = region;
} }
void setUpFountainRegion() { void setUpFountainRegion() throws Exception {
ProtectedRegion region = new ProtectedCuboidRegion( DefaultDomain domain = new DefaultDomain();
domain.addGroup(MEMBER_GROUP);
ProtectedRegion region = new ProtectedCuboidRegion(FOUNTAIN_ID,
new BlockVector(0, 0, 0), new BlockVector(5, 5, 5)); new BlockVector(0, 0, 0), new BlockVector(5, 5, 5));
AreaFlags flags = new AreaFlags(); AreaFlags flags = new AreaFlags();
flags.allowBuild = AreaFlags.State.ALLOW; flags.set(AreaFlags.FLAG_FIRE_SPREAD, State.DENY);
flags.allowFireSpread = AreaFlags.State.DENY;
region.setFlags(flags); region.setFlags(flags);
manager.addRegion(FOUNTAIN_ID, region); region.setMembers(domain);
manager.addRegion(region);
fountain = region;
fountain.setParent(courtyard);
}
void setUpNoFireRegion() throws Exception {
ProtectedRegion region = new ProtectedCuboidRegion(NO_FIRE_ID,
new BlockVector(100, 100, 100), new BlockVector(200, 200, 200));
AreaFlags flags = new AreaFlags();
flags.set(AreaFlags.FLAG_FIRE_SPREAD, State.DENY);
region.setFlags(flags);
manager.addRegion(region);
} }
@Test @Test
@ -88,13 +111,17 @@ public void testNonBuildFlag() {
// Outside // Outside
appl = manager.getApplicableRegions(outside); appl = manager.getApplicableRegions(outside);
assertTrue(appl.allowsFireSpread()); assertTrue(appl.allowsFlag(AreaFlags.FLAG_FIRE_SPREAD));
// Inside courtyard // Inside courtyard
appl = manager.getApplicableRegions(inCourtyard); appl = manager.getApplicableRegions(inCourtyard);
assertTrue(appl.allowsFireSpread()); assertTrue(appl.allowsFlag(AreaFlags.FLAG_FIRE_SPREAD));
// Inside fountain // Inside fountain
appl = manager.getApplicableRegions(inFountain); appl = manager.getApplicableRegions(inFountain);
assertFalse(appl.allowsFireSpread()); assertFalse(appl.allowsFlag(AreaFlags.FLAG_FIRE_SPREAD));
// Inside no fire zone
appl = manager.getApplicableRegions(inNoFire);
assertFalse(appl.allowsFlag(AreaFlags.FLAG_FIRE_SPREAD));
} }
@Test @Test

View File

@ -28,6 +28,7 @@
import static org.junit.Assert.*; import static org.junit.Assert.*;
import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldguard.domains.DefaultDomain; import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.AreaFlags.State;
public class CSVDatabaseTest { public class CSVDatabaseTest {
@Before @Before
@ -63,9 +64,9 @@ public void testLoadSave() throws Exception {
private void checkTestRegion1(ProtectedRegion region) { private void checkTestRegion1(ProtectedRegion region) {
AreaFlags flags = new AreaFlags(); AreaFlags flags = new AreaFlags();
flags.allowFireSpread = AreaFlags.State.ALLOW; flags.set(AreaFlags.FLAG_FIRE_SPREAD, State.ALLOW);
flags.allowPvP = AreaFlags.State.DENY; flags.set(AreaFlags.FLAG_PVP, State.DENY);
flags.allowLighter = AreaFlags.State.DENY; flags.set(AreaFlags.FLAG_LIGHTER, State.DENY);
region.setFlags(flags); region.setFlags(flags);
assertEquals(region.getFlags(), flags); assertEquals(region.getFlags(), flags);
@ -75,12 +76,12 @@ private ProtectedRegion getTestRegion1() {
BlockVector min = new BlockVector(1, 2, 3); BlockVector min = new BlockVector(1, 2, 3);
BlockVector max = new BlockVector(4, 5, 6); BlockVector max = new BlockVector(4, 5, 6);
ProtectedRegion region = new ProtectedCuboidRegion(min, max); ProtectedRegion region = new ProtectedCuboidRegion("test2", min, max);
AreaFlags flags = new AreaFlags(); AreaFlags flags = new AreaFlags();
flags.allowFireSpread = AreaFlags.State.ALLOW; flags.set(AreaFlags.FLAG_FIRE_SPREAD, State.ALLOW);
flags.allowPvP = AreaFlags.State.DENY; flags.set(AreaFlags.FLAG_PVP, State.DENY);
flags.allowLighter = AreaFlags.State.DENY; flags.set(AreaFlags.FLAG_LIGHTER, State.DENY);
region.setFlags(flags); region.setFlags(flags);
DefaultDomain domain = new DefaultDomain(); DefaultDomain domain = new DefaultDomain();
@ -101,12 +102,12 @@ private ProtectedRegion getTestRegion2() {
BlockVector min = new BlockVector(7, 8, 9); BlockVector min = new BlockVector(7, 8, 9);
BlockVector max = new BlockVector(10, 11, 12); BlockVector max = new BlockVector(10, 11, 12);
ProtectedRegion region = new ProtectedCuboidRegion(min, max); ProtectedRegion region = new ProtectedCuboidRegion("test2", min, max);
AreaFlags flags = new AreaFlags(); AreaFlags flags = new AreaFlags();
flags.allowFireSpread = AreaFlags.State.DENY; flags.set(AreaFlags.FLAG_FIRE_SPREAD, State.ALLOW);
flags.allowPvP = AreaFlags.State.ALLOW; flags.set(AreaFlags.FLAG_PVP, State.ALLOW);
flags.allowMobDamage = AreaFlags.State.DENY; flags.set(AreaFlags.FLAG_LIGHTER, State.DENY);
region.setFlags(flags); region.setFlags(flags);
DefaultDomain domain = new DefaultDomain(); DefaultDomain domain = new DefaultDomain();