Finished up regions support.

This commit is contained in:
sk89q 2011-01-08 18:26:49 -08:00
parent 119d8b1a81
commit 484fe22e9e
6 changed files with 486 additions and 54 deletions

View File

@ -76,6 +76,7 @@ public void initialize() {
registerHook("HEALTH_CHANGE", PluginListener.Priority.MEDIUM);
registerHook("DAMAGE", PluginListener.Priority.MEDIUM);
registerHook("LIQUID_DESTROY", PluginListener.Priority.MEDIUM);
registerHook("BLOCK_RIGHTCLICKED", PluginListener.Priority.MEDIUM);
if (missingFeatures.size() > 0) {
logger.log(Level.WARNING, "WorldGuard: Your version of hMod does not support "

View File

@ -21,12 +21,14 @@
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.io.*;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.Vector;
@ -52,6 +54,9 @@ public class WorldGuardListener extends PluginListener {
*/
private PropertiesFile properties = new PropertiesFile("worldguard.properties");
private static int CMD_LIST_SIZE = 9;
private static Pattern groupPattern = Pattern.compile("^[gG]:(.+)$");
private RegionManager regionManager = new FlatRegionManager();
private ProtectionDatabase regionLoader =
new CSVDatabase(new File("worldguard-regions.txt"));
@ -90,6 +95,7 @@ public class WorldGuardListener extends PluginListener {
private boolean teleportToHome;
private boolean exactRespawn;
private boolean kickOnDeath;
private int regionWand = 287;
private Blacklist blacklist;
/**
@ -203,6 +209,7 @@ public void loadConfiguration() {
kickOnDeath = properties.getBoolean("kick-on-death", false);
teleportToHome = properties.getBoolean("teleport-to-home-on-death", false);
exactRespawn = properties.getBoolean("exact-respawn", false);
regionWand = properties.getInt("regions-wand", 287);
// Console log configuration
boolean logConsole = properties.getBoolean("log-console", true);
@ -455,48 +462,18 @@ public boolean onCommand(Player player, String[] split) {
player.sendMessage(Colors.Yellow + "Items compacted into stacks!");
return true;
} else if (split[0].equalsIgnoreCase("/definearea")
&& player.canUseCommand("/definearea")) {
if (split.length < 3) {
player.sendMessage(Colors.Rose + "/definearea <id> <owners...>");
} else if (split[0].equalsIgnoreCase("/rg")
|| split[0].equalsIgnoreCase("/region")) {
if (split.length < 2) {
player.sendMessage(Colors.Rose + "/rg <define|flag|delete|info|add|remove|list|save|load> ...");
return true;
}
try {
String id = split[1];
BlockVector min = WorldEditBridge.getRegionMinimumPoint(player).toBlockVector();
BlockVector max = WorldEditBridge.getRegionMaximumPoint(player).toBlockVector();
ProtectedRegion region = new ProtectedCuboidRegion(min, max);
region.setOwners(parseDomainString(split, 2));
regionManager.addRegion(id, region);
regionLoader.save(regionManager);
player.sendMessage(Colors.Yellow + "Region saved!");
} catch (WorldEditNotInstalled e) {
player.sendMessage(Colors.Rose + "WorldEdit must be installed and enabled as a plugin.");
} catch (IncompleteRegionException e) {
player.sendMessage(Colors.Rose + "You must first define an area in WorldEdit.");
} catch (IOException e) {
player.sendMessage(Colors.Rose + "Region database failed to save: "
+ e.getMessage());
}
return true;
} else if (split[0].equalsIgnoreCase("/delarea")
&& player.canUseCommand("/delarea")) {
if (split.length < 2) {
player.sendMessage(Colors.Rose + "/delarea <id>");
return true;
}
try {
String id = split[1];
regionManager.removeRegion(id);
regionLoader.save(regionManager);
player.sendMessage(Colors.Yellow + "Region removed!");
} catch (IOException e) {
player.sendMessage(Colors.Rose + "Region database failed to save: "
+ e.getMessage());
}
String action = split[1];
String[] args = new String[split.length - 1];
System.arraycopy(split, 1, args, 0, split.length - 1);
handleRegionCommand(player, action, args);
return true;
} else if (split[0].equalsIgnoreCase("/reload")
@ -526,6 +503,294 @@ public boolean onCommand(Player player, String[] split) {
return false;
}
/**
* Handles a region command.
*
* @param player
* @param action
* @param args
*/
private void handleRegionCommand(Player player, String action, String[] args) {
if (action.equalsIgnoreCase("define")
&& canUseRegionCommand(player, "/regiondefine")) {
if (args.length < 2) {
player.sendMessage(Colors.Rose + "/rg define <id> [owner1 [owner2 [owners...]]]");
return;
}
try {
String id = args[1].toLowerCase();
BlockVector min = WorldEditBridge.getRegionMinimumPoint(player).toBlockVector();
BlockVector max = WorldEditBridge.getRegionMaximumPoint(player).toBlockVector();
ProtectedRegion region = new ProtectedCuboidRegion(min, max);
if (args.length >= 3) {
region.setOwners(parseDomainString(args, 2));
}
regionManager.addRegion(id, region);
regionLoader.save(regionManager);
player.sendMessage(Colors.Yellow + "Region saved as " + id + ".");
} catch (WorldEditNotInstalled e) {
player.sendMessage(Colors.Rose + "WorldEdit must be installed and enabled as a plugin.");
} catch (IncompleteRegionException e) {
player.sendMessage(Colors.Rose + "You must first define an area in WorldEdit.");
} catch (IOException e) {
player.sendMessage(Colors.Rose + "Region database failed to save: "
+ e.getMessage());
}
} else if (action.equalsIgnoreCase("flag")
&& canUseRegionCommand(player, "/regiondefine")) {
if (args.length < 4) {
player.sendMessage(Colors.Rose + "/rg flag <id> <build|pvp|tnt|lighter> <none|allow|deny>");
return;
}
try {
String id = args[1].toLowerCase();
String flagStr = args[2];
String stateStr = args[3];
ProtectedRegion region = regionManager.getRegion(id);
if (region == null) {
player.sendMessage(Colors.Rose + "Could not find a region by that ID.");
return;
}
AreaFlags.State state = null;
if (stateStr.equalsIgnoreCase("allow")) {
state = AreaFlags.State.ALLOW;
} else if (stateStr.equalsIgnoreCase("deny")) {
state = AreaFlags.State.DENY;
} else if (stateStr.equalsIgnoreCase("none")) {
state = AreaFlags.State.NONE;
} else {
player.sendMessage(Colors.Rose + "Acceptable states: allow, deny, none");
return;
}
AreaFlags flags = region.getFlags();
if (flagStr.equalsIgnoreCase("build")) {
flags.allowBuild = state;
} else if (flagStr.equalsIgnoreCase("pvp")) {
flags.allowPvP = state;
} else if (flagStr.equalsIgnoreCase("tnt")) {
flags.allowTNT = state;
} else if (flagStr.equalsIgnoreCase("lighter")) {
flags.allowLighter = state;
} else {
player.sendMessage(Colors.Rose + "Acceptable flags: build, pvp, tnt, lighter");
return;
}
regionLoader.save(regionManager);
player.sendMessage(Colors.Yellow + "Region '" + id + "' updated.");
} catch (IOException e) {
player.sendMessage(Colors.Rose + "Region database failed to save: "
+ e.getMessage());
}
} else if (action.equalsIgnoreCase("info")
&& canUseRegionCommand(player, "/regioninfo")) {
if (args.length < 2) {
player.sendMessage(Colors.Rose + "/rg info <id>");
return;
}
String id = args[1].toLowerCase();
if (!regionManager.hasRegion(id)) {
player.sendMessage(Colors.Rose + "A region with ID '"
+ id + "' doesn't exist.");
return;
}
ProtectedRegion region = regionManager.getRegion(id);
AreaFlags flags = region.getFlags();
DefaultDomain domain = region.getOwners();
player.sendMessage(Colors.Yellow + "Region ID: " + id);
player.sendMessage(Colors.LightGray + "Type: " + region.getClass().getCanonicalName());
player.sendMessage(Colors.LightBlue + "Build: " + flags.allowBuild.name());
player.sendMessage(Colors.LightBlue + "PvP: " + flags.allowPvP.name());
player.sendMessage(Colors.LightBlue + "TNT: " + flags.allowTNT.name());
player.sendMessage(Colors.LightBlue + "Lighter: " + flags.allowLighter.name());
player.sendMessage(Colors.LightPurple + "Players: " + domain.toPlayersString());
player.sendMessage(Colors.LightPurple + "Groups: " + domain.toGroupsString());
} else if (action.equalsIgnoreCase("add")
&& canUseRegionCommand(player, "/regiondefine")) {
if (args.length < 2) {
player.sendMessage(Colors.Rose + "/rg add <id>");
return;
}
try {
String id = args[1].toLowerCase();
if (!regionManager.hasRegion(id)) {
player.sendMessage(Colors.Rose + "A region with ID '"
+ id + "' doesn't exist.");
return;
}
addToDomain(regionManager.getRegion(id).getOwners(), args, 1);
regionLoader.save(regionManager);
player.sendMessage(Colors.Yellow + "Region updated!");
} catch (IOException e) {
player.sendMessage(Colors.Rose + "Region database failed to save: "
+ e.getMessage());
}
} else if (action.equalsIgnoreCase("remove")
&& canUseRegionCommand(player, "/regiondefine")) {
if (args.length < 2) {
player.sendMessage(Colors.Rose + "/rg remove <id>");
return;
}
try {
String id = args[1].toLowerCase();
if (!regionManager.hasRegion(id)) {
player.sendMessage(Colors.Rose + "A region with ID '"
+ id + "' doesn't exist.");
return;
}
removeFromDomain(regionManager.getRegion(id).getOwners(), args, 1);
regionLoader.save(regionManager);
player.sendMessage(Colors.Yellow + "Region updated!");
} catch (IOException e) {
player.sendMessage(Colors.Rose + "Region database failed to save: "
+ e.getMessage());
}
} else if (action.equalsIgnoreCase("list")
&& canUseRegionCommand(player, "/regionlist")) {
int page = 0;
if (args.length >= 2) {
try {
page = Math.max(0, Integer.parseInt(args[1]) - 1);
} catch (NumberFormatException e) {
page = 0;
}
}
Map<String,ProtectedRegion> regions = regionManager.getRegions();
int size = regions.size();
int pages = (int)Math.ceil(size / (float)CMD_LIST_SIZE);
String[] regionIDList = new String[size];
int index = 0;
for (String id : regions.keySet()) {
regionIDList[index] = id;
index++;
}
Arrays.sort(regionIDList);
player.sendMessage(Colors.Rose + "Regions (page "
+ (page + 1) + " of " + pages + "):");
if (page < pages) {
for (int i = page * CMD_LIST_SIZE; i < page * CMD_LIST_SIZE + CMD_LIST_SIZE; i++) {
if (i >= size) break;
player.sendMessage(Colors.Yellow + (i + 1) + ". " + regionIDList[i]);
}
}
} else if (action.equalsIgnoreCase("delete")
&& canUseRegionCommand(player, "/regiondelete")) {
if (args.length < 2) {
player.sendMessage(Colors.Rose + "/rg delete <id>");
return;
}
try {
String id = args[1].toLowerCase();
if (!regionManager.hasRegion(id)) {
player.sendMessage(Colors.Rose + "A region with ID '"
+ id + "' doesn't exist.");
return;
}
regionManager.removeRegion(id);
regionLoader.save(regionManager);
player.sendMessage(Colors.Yellow + "Region removed!");
} catch (IOException e) {
player.sendMessage(Colors.Rose + "Region database failed to save: "
+ e.getMessage());
}
} else if (action.equalsIgnoreCase("save")
&& canUseRegionCommand(player, "/regionsave")) {
try {
regionLoader.save(regionManager);
player.sendMessage(Colors.Yellow + "Region database saved to file!");
} catch (IOException e) {
player.sendMessage(Colors.Rose + "Region database failed to save: "
+ e.getMessage());
}
} else if (action.equalsIgnoreCase("load")
&& canUseRegionCommand(player, "/regionload")) {
try {
regionLoader.load(regionManager);
player.sendMessage(Colors.Yellow + "Region database loaded from file!");
} catch (IOException e) {
player.sendMessage(Colors.Rose + "Region database failed to load: "
+ e.getMessage());
}
} else {
player.sendMessage(Colors.Rose + "/rg <define|flag|delete|info|add|remove|list|save|load> ...");
}
}
/**
* Checks for the command or /region.
*
* @param player
* @param cmd
* @return
*/
private static boolean canUseRegionCommand(Player player, String cmd) {
return player.canUseCommand("/region")
|| player.canUseCommand(cmd);
}
/**
* Parse a group/player DefaultDomain specification for areas.
*
* @param domain
* @param split
* @param startIndex
*/
private static void addToDomain(DefaultDomain domain,
String[] split, int startIndex) {
for (int i = startIndex; i < split.length; i++) {
String s = split[i];
Matcher m = groupPattern.matcher(s);
if (m.matches()) {
domain.addGroup(m.group(1));
} else {
domain.addPlayer(s);
}
}
}
/**
* Parse a group/player DefaultDomain specification for areas.
*
* @param domain
* @param split
* @param startIndex
*/
private static void removeFromDomain(DefaultDomain domain,
String[] split, int startIndex) {
for (int i = startIndex; i < split.length; i++) {
String s = split[i];
Matcher m = groupPattern.matcher(s);
if (m.matches()) {
domain.removeGroup(m.group(1));
} else {
domain.removePlayer(s);
}
}
}
/**
* Parse a group/player DefaultDomain specification for areas.
*
@ -534,7 +799,6 @@ public boolean onCommand(Player player, String[] split) {
* @return
*/
private static DefaultDomain parseDomainString(String[] split, int startIndex) {
Pattern groupPattern = Pattern.compile("^[gG]:(.+)$");
DefaultDomain domain = new DefaultDomain();
for (int i = startIndex; i < split.length; i++) {
@ -709,7 +973,8 @@ public boolean onItemUse(Player player, Block blockPlaced,
blockPlaced.getY(), blockPlaced.getZ());
LocalPlayer localPlayer = new HMPlayer(player);
if (!regionManager.getApplicableRegions(pt).canBuild(localPlayer)) {
if (!player.canUseCommand("/regionbypass")
&& !regionManager.getApplicableRegions(pt).canBuild(localPlayer)) {
player.sendMessage(Colors.Red + "You don't have permission for this area.");
return true;
}
@ -738,7 +1003,8 @@ public boolean onBlockPlace(Player player, Block blockPlaced,
blockPlaced.getY(), blockPlaced.getZ());
LocalPlayer localPlayer = new HMPlayer(player);
if (!regionManager.getApplicableRegions(pt).canBuild(localPlayer)) {
if (!player.canUseCommand("/regionbypass")
&& !regionManager.getApplicableRegions(pt).canBuild(localPlayer)) {
player.sendMessage(Colors.Red + "You don't have permission for this area.");
return true;
}
@ -812,7 +1078,8 @@ public boolean onBlockBreak(Player player, Block block) {
block.getY(), block.getZ());
LocalPlayer localPlayer = new HMPlayer(player);
if (!regionManager.getApplicableRegions(pt).canBuild(localPlayer)) {
if (!player.canUseCommand("/regionbypass")
&& !regionManager.getApplicableRegions(pt).canBuild(localPlayer)) {
player.sendMessage(Colors.Red + "You don't have permission for this area.");
return true;
}
@ -850,7 +1117,8 @@ public boolean onOpenInventory(Player player, Inventory inventory) {
Vector pt = new Vector(chest.getX(), chest.getY(), chest.getZ());
LocalPlayer localPlayer = new HMPlayer(player);
if (!regionManager.getApplicableRegions(pt).canBuild(localPlayer)) {
if (!player.canUseCommand("/regionbypass")
&& !regionManager.getApplicableRegions(pt).canBuild(localPlayer)) {
player.sendMessage(Colors.Red + "You don't have permission for this area.");
return true;
}
@ -924,12 +1192,18 @@ public boolean onIgnite(Block block, Player player) {
}
}
if (useRegions) {
if (useRegions && !player.canUseCommand("/regionbypass")) {
Vector pt = new Vector(block.getX(),
block.getY(), block.getZ());
LocalPlayer localPlayer = new HMPlayer(player);
if (!regionManager.getApplicableRegions(pt).canBuild(localPlayer)) {
if (block.getStatus() == 2
&& !regionManager.getApplicableRegions(pt).canBuild(localPlayer)) {
return true;
}
if (block.getStatus() == 2
&& !regionManager.getApplicableRegions(pt).allowsLighter()) {
return true;
}
}
@ -956,6 +1230,18 @@ public boolean onExplode(Block block) {
if (blockTNT && block.getStatus() == 1) {
return true;
}
Vector pt = new Vector(block.getX(), block.getY(), block.getZ());
if (useRegions) {
if (block.getStatus() == 1) {
if (!regionManager.getApplicableRegions(pt).allowsTNT()) {
return true;
}
// TODO: TNT check to see if it would hit a region
}
}
return false;
}
@ -1187,11 +1473,58 @@ public boolean onDamage(PluginLoader.DamageType type, BaseEntity attacker,
&& amphibiousPlayers.contains(player.getName())) {
return true;
}
if (attacker.isPlayer()) {
if (useRegions) {
Vector pt = new Vector(defender.getX(),
defender.getY(), defender.getZ());
if (!regionManager.getApplicableRegions(pt).allowsPvP()) {
player.sendMessage(Colors.Red + "You are in a no-PvP area.");
return true;
}
}
}
}
return false;
}
/**
* Called when someone presses right click aimed at a block.
* You can intercept this to add your own right click actions
* to different item types (see itemInHand)
*
* @param player
* @param blockClicked
* @param itemInHand
*/
public void onBlockRightClicked(Player player, Block blockClicked, Item item) {
if (useRegions && item.getType().getId() == regionWand) {
Vector pt = new Vector(blockClicked.getX(),
blockClicked.getY(), blockClicked.getZ());
ApplicableRegionSet app = regionManager.getApplicableRegions(pt);
List<String> regions = regionManager.getApplicableRegionsIDs(pt);
if (regions.size() > 0) {
player.sendMessage(Colors.Yellow + "Can you build? "
+ (app.canBuild(new HMPlayer(player)) ? "Yes" : "No"));
StringBuilder str = new StringBuilder();
for (Iterator<String> it = regions.iterator(); it.hasNext(); ) {
str.append(it.next());
if (it.hasNext()) {
str.append(", ");
}
}
player.sendMessage(Colors.Yellow + "Applicable regions: " + str.toString());
} else {
player.sendMessage(Colors.Yellow + "WorldGuard: No defined regions here!");
}
}
}
/**
* Called when water or lava tries to populate a block, you can prevent
* crushing of torches, railways, flowers etc. You can alternatively allow

View File

@ -20,6 +20,7 @@
package com.sk89q.worldguard.domains;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import com.sk89q.worldguard.LocalPlayer;
@ -34,15 +35,27 @@ public DefaultDomain() {
}
public void addPlayer(String name) {
players.add(name);
players.add(name.toLowerCase());
}
public void addPlayer(LocalPlayer player) {
players.add(player.getName());
players.add(player.getName().toLowerCase());
}
public void removePlayer(String name) {
players.remove(name.toLowerCase());
}
public void removePlayer(LocalPlayer player) {
players.remove(player.getName().toLowerCase());
}
public void addGroup(String name) {
groups.add(name);
groups.add(name.toLowerCase());
}
public void removeGroup(String name) {
groups.remove(name.toLowerCase());
}
public Set<String> getGroups() {
@ -70,4 +83,26 @@ public boolean contains(LocalPlayer player) {
public int size() {
return groups.size();
}
public String toPlayersString() {
StringBuilder str = new StringBuilder();
for (Iterator<String> it = players.iterator(); it.hasNext(); ) {
str.append(it.next());
if (it.hasNext()) {
str.append(", ");
}
}
return str.toString();
}
public String toGroupsString() {
StringBuilder str = new StringBuilder();
for (Iterator<String> it = groups.iterator(); it.hasNext(); ) {
str.append(it.next());
if (it.hasNext()) {
str.append(", ");
}
}
return str.toString();
}
}

View File

@ -60,7 +60,7 @@ public boolean canBuild(LocalPlayer player) {
return found ? allowed : true;
}
public boolean canPvP(LocalPlayer player) {
public boolean allowsPvP() {
for (ProtectedRegion region : regions.values()) {
if (!region.contains(pt)) continue;
if (region.getFlags().allowBuild == State.DENY) return false;

View File

@ -19,6 +19,8 @@
package com.sk89q.worldguard.protection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.LinkedHashMap;
import com.sk89q.worldedit.Vector;
@ -71,6 +73,25 @@ public void removeRegion(String id) {
regions.remove(id);
}
/**
* Return whether a region exists by an ID.
*
* @param id
* @return
*/
public boolean hasRegion(String id) {
return regions.containsKey(id);
}
/**
* Get a region by its ID.
*
* @param id
*/
public ProtectedRegion getRegion(String id) {
return regions.get(id);
}
/**
* Set a list of protected regions.
*
@ -81,7 +102,7 @@ public void setRegions(Map<String,ProtectedRegion> regions) {
}
/**
* Get a LinkedList of regions that contain a point.
* Get an object for a point for rules to be applied with.
*
* @param pt
* @return
@ -90,6 +111,24 @@ public ApplicableRegionSet getApplicableRegions(Vector pt) {
return new ApplicableRegionSet(pt, regions);
}
/**
* Get a list of region IDs that contain a point.
*
* @param pt
* @return
*/
public List<String> getApplicableRegionsIDs(Vector pt) {
List<String> applicable = new ArrayList<String>();
for (Map.Entry<String,ProtectedRegion> entry : regions.entrySet()) {
if (entry.getValue().contains(pt)) {
applicable.add(entry.getKey());
}
}
return applicable;
}
/**
* Get the number of regions.
*

View File

@ -19,6 +19,7 @@
package com.sk89q.worldguard.protection;
import java.util.List;
import java.util.Map;
import com.sk89q.worldedit.Vector;
@ -53,21 +54,44 @@ public interface RegionManager {
*/
public void addRegion(String id, ProtectedRegion region);
/**
* Return whether a region exists by an ID.
*
* @param id
* @return
*/
public boolean hasRegion(String id);
/**
* Get a region by its ID.
*
* @param id
*/
public ProtectedRegion getRegion(String id);
/**
* Removes a region.
*
* @param id
*/
public void removeRegion(String id);
/**
* Get a LinkedList of regions that contain a point.
* Get an object for a point for rules to be applied with.
*
* @param pt
* @return
*/
public ApplicableRegionSet getApplicableRegions(Vector pt);
/**
* Get a list of region IDs that contain a point.
*
* @param pt
* @return
*/
public List<String> getApplicableRegionsIDs(Vector pt);
/**
* Get the number of regions.
*