This commit is contained in:
Ryan Hamshire 2012-06-17 10:33:20 -07:00
parent 03c920f568
commit 0b27cb36d5
13 changed files with 1057 additions and 362 deletions

View File

@ -1,7 +1,7 @@
name: GriefPrevention name: GriefPrevention
main: me.ryanhamshire.GriefPrevention.GriefPrevention main: me.ryanhamshire.GriefPrevention.GriefPrevention
softdepend: [Vault, Multiverse-Core] softdepend: [Vault, Multiverse-Core]
version: 4.5 version: 4.6
commands: commands:
abandonclaim: abandonclaim:
description: Deletes a claim. description: Deletes a claim.
@ -83,7 +83,7 @@ commands:
usage: /SellClaimBlocks <numberOfBlocks> usage: /SellClaimBlocks <numberOfBlocks>
aliases: sellclaim aliases: sellclaim
trapped: trapped:
description: Ejects you to nearby unclaimed land. Usable once per 8 hours. description: Ejects you to nearby unclaimed land. Has a substantial cooldown period.
usage: /Trapped usage: /Trapped
trustlist: trustlist:
description: Lists permissions for the claim you're standing in. description: Lists permissions for the claim you're standing in.
@ -104,6 +104,10 @@ commands:
description: Converts an administrative claim to a private claim. description: Converts an administrative claim to a private claim.
usage: /TransferClaim <player> usage: /TransferClaim <player>
permission: griefprevention.adjustclaimblocks permission: griefprevention.adjustclaimblocks
deathblow:
description: Kills a player, optionally giving his inventory to another player.
usage: /DeathBlow <player> [recipientPlayer]
permission: griefprevention.deathblow
permissions: permissions:
griefprevention.createclaims: griefprevention.createclaims:
description: Grants permission to create claims. description: Grants permission to create claims.
@ -120,6 +124,7 @@ permissions:
griefprevention.spam: true griefprevention.spam: true
griefprevention.lava: true griefprevention.lava: true
griefprevention.eavesdrop: true griefprevention.eavesdrop: true
griefprevention.deathblow: true
griefprevention.restorenature: griefprevention.restorenature:
description: Grants permission to use /RestoreNature. description: Grants permission to use /RestoreNature.
default: op default: op
@ -146,4 +151,7 @@ permissions:
default: op default: op
griefprevention.restorenatureaggressive: griefprevention.restorenatureaggressive:
description: Grants access to /RestoreNatureAggressive and /RestoreNatureFill. description: Grants access to /RestoreNatureAggressive and /RestoreNatureFill.
default: op
griefprevention.deathblow:
description: Grants access to /DeathBlow.
default: op default: op

View File

@ -94,7 +94,7 @@ public class BlockEventHandler implements Listener
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName()); PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName());
if(playerData.siegeData != null) if(playerData.siegeData != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't give away items while involved in a siege."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeNoDrop);
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
@ -109,7 +109,7 @@ public class BlockEventHandler implements Listener
playerData.lastChestDamageLocation = block.getLocation(); playerData.lastChestDamageLocation = block.getLocation();
//give the player instructions //give the player instructions
GriefPrevention.sendMessage(player, TextMode.Instr, "To give away the item(s) in your hand, left-click the chest again."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.DonateItemsInstruction);
} }
//otherwise, try to donate the item stack in hand //otherwise, try to donate the item stack in hand
@ -124,7 +124,7 @@ public class BlockEventHandler implements Listener
if(availableSlot < 0) if(availableSlot < 0)
{ {
//tell the player and stop here //tell the player and stop here
GriefPrevention.sendMessage(player, TextMode.Err, "This chest is full."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.ChestFull);
return; return;
} }
@ -135,7 +135,7 @@ public class BlockEventHandler implements Listener
playerInventory.setItemInHand(new ItemStack(Material.AIR)); playerInventory.setItemInHand(new ItemStack(Material.AIR));
//and confirm for the player //and confirm for the player
GriefPrevention.sendMessage(player, TextMode.Success, "Item(s) transferred to chest!"); GriefPrevention.sendMessage(player, TextMode.Success, Messages.DonationSuccess);
} }
} }
} }
@ -162,8 +162,8 @@ public class BlockEventHandler implements Listener
//if there's a claim here //if there's a claim here
if(claim != null) if(claim != null)
{ {
//if breaking UNDER the claim //if breaking UNDER the claim and the player has permission to build in the claim
if(block.getY() < claim.lesserBoundaryCorner.getBlockY()) if(block.getY() < claim.lesserBoundaryCorner.getBlockY() && claim.allowBuild(player) == null)
{ {
//extend the claim downward beyond the breakage point //extend the claim downward beyond the breakage point
this.dataStore.extendClaim(claim, claim.getLesserBoundaryCorner().getBlockY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance); this.dataStore.extendClaim(claim, claim.getLesserBoundaryCorner().getBlockY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance);
@ -226,27 +226,13 @@ public class BlockEventHandler implements Listener
Location location = otherPlayer.getLocation(); Location location = otherPlayer.getLocation();
if(!otherPlayer.equals(player) && location.distanceSquared(block.getLocation()) < 9) if(!otherPlayer.equals(player) && location.distanceSquared(block.getLocation()) < 9)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't start a fire this close to " + otherPlayer.getName() + "."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerTooCloseForFire, otherPlayer.getName());
placeEvent.setCancelled(true); placeEvent.setCancelled(true);
return; return;
} }
} }
} }
//FEATURE: limit tree planting to grass, and dirt with more earth beneath it
if(block.getType() == Material.SAPLING)
{
Block earthBlock = placeEvent.getBlockAgainst();
if(earthBlock.getType() != Material.GRASS)
{
if(earthBlock.getRelative(BlockFace.DOWN).getType() == Material.AIR ||
earthBlock.getRelative(BlockFace.DOWN).getRelative(BlockFace.DOWN).getType() == Material.AIR)
{
placeEvent.setCancelled(true);
}
}
}
//make sure the player is allowed to build at the location //make sure the player is allowed to build at the location
String noBuildReason = GriefPrevention.instance.allowBuild(player, block.getLocation()); String noBuildReason = GriefPrevention.instance.allowBuild(player, block.getLocation());
if(noBuildReason != null) if(noBuildReason != null)
@ -262,7 +248,7 @@ public class BlockEventHandler implements Listener
if(claim != null) if(claim != null)
{ {
//if the player has permission for the claim and he's placing UNDER the claim //if the player has permission for the claim and he's placing UNDER the claim
if(block.getY() < claim.lesserBoundaryCorner.getBlockY()) if(block.getY() < claim.lesserBoundaryCorner.getBlockY() && claim.allowBuild(player) == null)
{ {
//extend the claim downward //extend the claim downward
this.dataStore.extendClaim(claim, claim.getLesserBoundaryCorner().getBlockY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance); this.dataStore.extendClaim(claim, claim.getLesserBoundaryCorner().getBlockY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance);
@ -277,7 +263,7 @@ public class BlockEventHandler implements Listener
//if the chest is too deep underground, don't create the claim and explain why //if the chest is too deep underground, don't create the claim and explain why
if(GriefPrevention.instance.config_claims_preventTheft && block.getY() < GriefPrevention.instance.config_claims_maxDepth) if(GriefPrevention.instance.config_claims_preventTheft && block.getY() < GriefPrevention.instance.config_claims_maxDepth)
{ {
GriefPrevention.sendMessage(player, TextMode.Warn, "This chest can't be protected because it's too deep underground. Consider moving it."); GriefPrevention.sendMessage(player, TextMode.Warn, Messages.TooDeepToClaim);
return; return;
} }
@ -290,7 +276,7 @@ public class BlockEventHandler implements Listener
if(GriefPrevention.instance.config_claims_automaticClaimsForNewPlayersRadius == 0) if(GriefPrevention.instance.config_claims_automaticClaimsForNewPlayersRadius == 0)
{ {
this.dataStore.createClaim(block.getWorld(), block.getX(), block.getX(), block.getY(), block.getY(), block.getZ(), block.getZ(), player.getName(), null); this.dataStore.createClaim(block.getWorld(), block.getX(), block.getX(), block.getY(), block.getY(), block.getZ(), block.getZ(), player.getName(), null);
GriefPrevention.sendMessage(player, TextMode.Success, "This chest is protected."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.ChestClaimConfirmation);
} }
//otherwise, create a claim in the area around the chest //otherwise, create a claim in the area around the chest
@ -309,7 +295,7 @@ public class BlockEventHandler implements Listener
} }
//notify and explain to player //notify and explain to player
GriefPrevention.sendMessage(player, TextMode.Success, "This chest and nearby blocks are protected from breakage and theft. The gold and glowstone blocks mark the protected area."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.AutomaticClaimNotification);
//show the player the protected area //show the player the protected area
Claim newClaim = this.dataStore.getClaimAt(block.getLocation(), false, null); Claim newClaim = this.dataStore.getClaimAt(block.getLocation(), false, null);
@ -318,21 +304,35 @@ public class BlockEventHandler implements Listener
} }
//instructions for using /trust //instructions for using /trust
GriefPrevention.sendMessage(player, TextMode.Instr, "Use the /trust command to grant other players access."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.TrustCommandAdvertisement);
//unless special permission is required to create a claim with the shovel, educate the player about the shovel //unless special permission is required to create a claim with the shovel, educate the player about the shovel
if(!GriefPrevention.instance.config_claims_creationRequiresPermission) if(!GriefPrevention.instance.config_claims_creationRequiresPermission)
{ {
GriefPrevention.sendMessage(player, TextMode.Instr, "To claim more land, use a golden shovel."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.GoldenShovelAdvertisement);
} }
} }
//check to see if this chest is in a claim, and warn when it isn't //check to see if this chest is in a claim, and warn when it isn't
if(GriefPrevention.instance.config_claims_preventTheft && this.dataStore.getClaimAt(block.getLocation(), false, playerData.lastClaim) == null) if(GriefPrevention.instance.config_claims_preventTheft && this.dataStore.getClaimAt(block.getLocation(), false, playerData.lastClaim) == null)
{ {
GriefPrevention.sendMessage(player, TextMode.Warn, "This chest is NOT protected. Consider expanding an existing claim or creating a new one."); GriefPrevention.sendMessage(player, TextMode.Warn, Messages.UnprotectedChestWarning);
} }
} }
//FEATURE: limit wilderness tree planting to grass, or dirt with more blocks beneath it
else if(block.getType() == Material.SAPLING && GriefPrevention.instance.config_blockSkyTrees)
{
Block earthBlock = placeEvent.getBlockAgainst();
if(earthBlock.getType() != Material.GRASS)
{
if(earthBlock.getRelative(BlockFace.DOWN).getType() == Material.AIR ||
earthBlock.getRelative(BlockFace.DOWN).getRelative(BlockFace.DOWN).getType() == Material.AIR)
{
placeEvent.setCancelled(true);
}
}
}
} }
//blocks "pushing" other players' blocks around (pistons) //blocks "pushing" other players' blocks around (pistons)
@ -416,18 +416,29 @@ public class BlockEventHandler implements Listener
} }
//ensures fluids don't flow out of claims, unless into another claim where the owner is trusted to build //ensures fluids don't flow out of claims, unless into another claim where the owner is trusted to build
private Claim lastSpreadClaim = null;
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onBlockFromTo (BlockFromToEvent spreadEvent) public void onBlockFromTo (BlockFromToEvent spreadEvent)
{ {
//always allow fluids to flow straight down
if(spreadEvent.getFace() == BlockFace.DOWN) return;
//from where? //from where?
Block fromBlock = spreadEvent.getBlock(); Block fromBlock = spreadEvent.getBlock();
Claim fromClaim = this.dataStore.getClaimAt(fromBlock.getLocation(), false, null); Claim fromClaim = this.dataStore.getClaimAt(fromBlock.getLocation(), false, this.lastSpreadClaim);
if(fromClaim != null)
{
this.lastSpreadClaim = fromClaim;
}
//where to? //where to?
Block toBlock = spreadEvent.getToBlock(); Block toBlock = spreadEvent.getToBlock();
Claim toClaim = this.dataStore.getClaimAt(toBlock.getLocation(), false, fromClaim); Claim toClaim = this.dataStore.getClaimAt(toBlock.getLocation(), false, fromClaim);
//block any spread into the wilderness //if it's within the same claim or wilderness to wilderness, allow it
if(fromClaim == toClaim) return;
//block any spread into the wilderness from a claim
if(fromClaim != null && toClaim == null) if(fromClaim != null && toClaim == null)
{ {
spreadEvent.setCancelled(true); spreadEvent.setCancelled(true);
@ -440,10 +451,7 @@ public class BlockEventHandler implements Listener
//who owns the spreading block, if anyone? //who owns the spreading block, if anyone?
OfflinePlayer fromOwner = null; OfflinePlayer fromOwner = null;
if(fromClaim != null) if(fromClaim != null)
{ {
//if it's within the same claim, allow it
if(fromClaim == toClaim) return;
fromOwner = GriefPrevention.instance.getServer().getOfflinePlayer(fromClaim.ownerName); fromOwner = GriefPrevention.instance.getServer().getOfflinePlayer(fromClaim.ownerName);
} }

View File

@ -24,6 +24,7 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
@ -105,7 +106,7 @@ public class Claim
//it may be null //it may be null
public void removeSurfaceFluids(Claim exclusionClaim) public void removeSurfaceFluids(Claim exclusionClaim)
{ {
//don't do this automatically for administrative claims //don't do this for administrative claims
if(this.isAdminClaim()) return; if(this.isAdminClaim()) return;
Location lesser = this.getLesserBoundaryCorner(); Location lesser = this.getLesserBoundaryCorner();
@ -134,8 +135,46 @@ public class Claim
} }
} }
} }
}
}
//determines whether or not a claim has surface fluids (lots of water blocks, or any lava blocks)
//used to warn players when they abandon their claims about automatic fluid cleanup
boolean hasSurfaceFluids()
{
Location lesser = this.getLesserBoundaryCorner();
Location greater = this.getGreaterBoundaryCorner();
int seaLevel = 0; //clean up all fluids in the end
//respect sea level in normal worlds
if(lesser.getWorld().getEnvironment() == Environment.NORMAL) seaLevel = lesser.getWorld().getSeaLevel();
int waterCount = 0;
for(int x = lesser.getBlockX(); x <= greater.getBlockX(); x++)
{
for(int z = lesser.getBlockZ(); z <= greater.getBlockZ(); z++)
{
for(int y = seaLevel - 1; y <= lesser.getWorld().getMaxHeight(); y++)
{
//dodge the exclusion claim
Block block = lesser.getWorld().getBlockAt(x, y, z);
if(block.getType() == Material.STATIONARY_WATER || block.getType() == Material.WATER)
{
waterCount++;
if(waterCount > 10) return true;
}
else if(block.getType() == Material.STATIONARY_LAVA || block.getType() == Material.LAVA)
{
return true;
}
}
}
} }
return false;
} }
//main constructor. note that only creating a claim instance does nothing - a claim must be added to the data store to be effective //main constructor. note that only creating a claim instance does nothing - a claim must be added to the data store to be effective
@ -245,7 +284,7 @@ public class Claim
{ {
if(this.siegeData != null) if(this.siegeData != null)
{ {
return "Claims can't be modified while under siege."; return GriefPrevention.instance.dataStore.getMessage(Messages.NoModifyDuringSiege);
} }
//otherwise, owners can do whatever //otherwise, owners can do whatever
@ -257,7 +296,7 @@ public class Claim
return this.parent.allowBuild(player); return this.parent.allowBuild(player);
//error message if all else fails //error message if all else fails
return "Only " + this.getOwnerName() + " can modify this claim."; return GriefPrevention.instance.dataStore.getMessage(Messages.OnlyOwnersModifyClaims, this.getOwnerName());
} }
//build permission check //build permission check
@ -278,25 +317,24 @@ public class Claim
//no building while under siege //no building while under siege
if(this.siegeData != null) if(this.siegeData != null)
{ {
return "This claim is under siege by " + this.siegeData.attacker.getName() + ". No one can build here."; return GriefPrevention.instance.dataStore.getMessage(Messages.NoBuildUnderSiege, this.siegeData.attacker.getName());
} }
//no building while in pvp combat //no building while in pvp combat
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName()); PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName());
if(playerData.inPvpCombat()) if(playerData.inPvpCombat())
{ {
return "You can't build in claims during PvP combat."; return GriefPrevention.instance.dataStore.getMessage(Messages.NoBuildPvP);
} }
//owners can make changes, or admins with ignore claims mode enabled //owners can make changes, or admins with ignore claims mode enabled
if(this.ownerName.equals(player.getName()) || GriefPrevention.instance.dataStore.getPlayerData(player.getName()).ignoreClaims) return null; if(this.ownerName.equals(player.getName()) || GriefPrevention.instance.dataStore.getPlayerData(player.getName()).ignoreClaims) return null;
//anyone with explicit build permission can make changes //anyone with explicit build permission can make changes
ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get(player.getName().toLowerCase()); if(this.hasExplicitPermission(player, ClaimPermission.Build)) return null;
if(ClaimPermission.Build == permissionLevel) return null;
//also everyone is a member of the "public", so check for public permission //also everyone is a member of the "public", so check for public permission
permissionLevel = this.playerNameToClaimPermissionMap.get("public"); ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get("public");
if(ClaimPermission.Build == permissionLevel) return null; if(ClaimPermission.Build == permissionLevel) return null;
//subdivision permission inheritance //subdivision permission inheritance
@ -304,15 +342,38 @@ public class Claim
return this.parent.allowBuild(player); return this.parent.allowBuild(player);
//failure message for all other cases //failure message for all other cases
return "You don't have " + this.getOwnerName() + "'s permission to build here."; return GriefPrevention.instance.dataStore.getMessage(Messages.NoBuildPermission, this.getOwnerName());
}
private boolean hasExplicitPermission(Player player, ClaimPermission level)
{
String playerName = player.getName();
Set<String> keys = this.playerNameToClaimPermissionMap.keySet();
Iterator<String> iterator = keys.iterator();
while(iterator.hasNext())
{
String identifier = iterator.next();
if(playerName.equalsIgnoreCase(identifier) && this.playerNameToClaimPermissionMap.get(identifier) == level) return true;
else if(identifier.startsWith("[") && identifier.endsWith("]"))
{
//drop the brackets
String permissionIdentifier = identifier.substring(1, identifier.length() - 1);
//defensive coding
if(permissionIdentifier == null || permissionIdentifier.isEmpty()) continue;
//check permission
if(player.hasPermission(permissionIdentifier) && this.playerNameToClaimPermissionMap.get(identifier) == level) return true;
}
}
return false;
} }
//break permission check //break permission check
public String allowBreak(Player player, Material material) public String allowBreak(Player player, Material material)
{ {
//if we don't know who's asking, always say no (i've been told some mods can make this happen somehow)
if(player == null) return "";
//if under siege, some blocks will be breakable //if under siege, some blocks will be breakable
if(this.siegeData != null) if(this.siegeData != null)
{ {
@ -332,11 +393,11 @@ public class Claim
//custom error messages for siege mode //custom error messages for siege mode
if(!breakable) if(!breakable)
{ {
return "That material is too tough to break."; return GriefPrevention.instance.dataStore.getMessage(Messages.NonSiegeMaterial);
} }
else if(this.ownerName.equals(player.getName())) else if(this.ownerName.equals(player.getName()))
{ {
return "You can't make changes while under siege."; return GriefPrevention.instance.dataStore.getMessage(Messages.NoOwnerBuildUnderSiege);
} }
else else
{ {
@ -351,9 +412,6 @@ public class Claim
//access permission check //access permission check
public String allowAccess(Player player) public String allowAccess(Player player)
{ {
//if we don't know who's asking, always say no (i've been told some mods can make this happen somehow)
if(player == null) return "";
//everyone always has access to admin claims //everyone always has access to admin claims
if(this.isAdminClaim()) return null; if(this.isAdminClaim()) return null;
@ -364,19 +422,20 @@ public class Claim
if(this.ownerName.equals(player.getName()) || GriefPrevention.instance.dataStore.getPlayerData(player.getName()).ignoreClaims) return null; if(this.ownerName.equals(player.getName()) || GriefPrevention.instance.dataStore.getPlayerData(player.getName()).ignoreClaims) return null;
//look for explicit individual access, inventory, or build permission //look for explicit individual access, inventory, or build permission
ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get(player.getName().toLowerCase()); if(this.hasExplicitPermission(player, ClaimPermission.Access)) return null;
if(ClaimPermission.Build == permissionLevel || ClaimPermission.Inventory == permissionLevel || ClaimPermission.Access == permissionLevel) return null; if(this.hasExplicitPermission(player, ClaimPermission.Inventory)) return null;
if(this.hasExplicitPermission(player, ClaimPermission.Build)) return null;
//also check for public permission //also check for public permission
permissionLevel = this.playerNameToClaimPermissionMap.get("public"); ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get("public");
if(ClaimPermission.Build == permissionLevel || ClaimPermission.Inventory == permissionLevel || ClaimPermission.Access == permissionLevel) return null; if(ClaimPermission.Build == permissionLevel || ClaimPermission.Inventory == permissionLevel || ClaimPermission.Inventory == permissionLevel) return null;
//permission inheritance for subdivisions //permission inheritance for subdivisions
if(this.parent != null) if(this.parent != null)
return this.parent.allowAccess(player); return this.parent.allowAccess(player);
//catch-all error message for all other cases //catch-all error message for all other cases
return "You don't have " + this.getOwnerName() + "'s permission to use that."; return GriefPrevention.instance.dataStore.getMessage(Messages.NoAccessPermission, this.getOwnerName());
} }
//inventory permission check //inventory permission check
@ -391,7 +450,7 @@ public class Claim
//if under siege, nobody accesses containers //if under siege, nobody accesses containers
if(this.siegeData != null) if(this.siegeData != null)
{ {
return "This claim is under siege by " + siegeData.attacker.getName() + ". No one can access containers here right now."; return GriefPrevention.instance.dataStore.getMessage(Messages.NoContainersSiege, siegeData.attacker.getName());
} }
//containers are always accessible in admin claims //containers are always accessible in admin claims
@ -401,11 +460,11 @@ public class Claim
if(this.ownerName.equals(player.getName()) || GriefPrevention.instance.dataStore.getPlayerData(player.getName()).ignoreClaims) return null; if(this.ownerName.equals(player.getName()) || GriefPrevention.instance.dataStore.getPlayerData(player.getName()).ignoreClaims) return null;
//check for explicit individual container or build permission //check for explicit individual container or build permission
ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get(player.getName().toLowerCase()); if(this.hasExplicitPermission(player, ClaimPermission.Inventory)) return null;
if(ClaimPermission.Build == permissionLevel || ClaimPermission.Inventory == permissionLevel) return null; if(this.hasExplicitPermission(player, ClaimPermission.Build)) return null;
//check for public container or build permission //check for public container or build permission
permissionLevel = this.playerNameToClaimPermissionMap.get("public"); ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get("public");
if(ClaimPermission.Build == permissionLevel || ClaimPermission.Inventory == permissionLevel) return null; if(ClaimPermission.Build == permissionLevel || ClaimPermission.Inventory == permissionLevel) return null;
//permission inheritance for subdivisions //permission inheritance for subdivisions
@ -413,7 +472,7 @@ public class Claim
return this.parent.allowContainers(player); return this.parent.allowContainers(player);
//error message for all other cases //error message for all other cases
return "You don't have " + this.getOwnerName() + "'s permission to use that."; return GriefPrevention.instance.dataStore.getMessage(Messages.NoContainersPermission, this.getOwnerName());
} }
//grant permission check, relatively simple //grant permission check, relatively simple
@ -422,15 +481,29 @@ public class Claim
//if we don't know who's asking, always say no (i've been told some mods can make this happen somehow) //if we don't know who's asking, always say no (i've been told some mods can make this happen somehow)
if(player == null) return ""; if(player == null) return "";
//anyone who can modify the claim, or who's explicitly in the managers (/PermissionTrust) list can do this //anyone who can modify the claim can do this
if(this.allowEdit(player) == null || this.managers.contains(player.getName())) return null; if(this.allowEdit(player) == null) return null;
//anyone who's in the managers (/PermissionTrust) list can do this
for(int i = 0; i < this.managers.size(); i++)
{
String managerID = this.managers.get(i);
if(player.getName().equalsIgnoreCase(managerID)) return null;
else if(managerID.startsWith("[") && managerID.endsWith("]"))
{
managerID = managerID.substring(1, managerID.length() - 1);
if(managerID == null || managerID.isEmpty()) continue;
if(player.hasPermission(managerID)) return null;
}
}
//permission inheritance for subdivisions //permission inheritance for subdivisions
if(this.parent != null) if(this.parent != null)
return this.parent.allowGrantPermission(player); return this.parent.allowGrantPermission(player);
//generic error message //generic error message
return "You don't have " + this.getOwnerName() + "'s permission to grant permission here."; return GriefPrevention.instance.dataStore.getMessage(Messages.NoPermissionTrust, this.getOwnerName());
} }
//grants a permission for a player or the public //grants a permission for a player or the public
@ -503,7 +576,7 @@ public class Claim
return this.parent.getOwnerName(); return this.parent.getOwnerName();
if(this.ownerName.length() == 0) if(this.ownerName.length() == 0)
return "an administrator"; return GriefPrevention.instance.dataStore.getMessage(Messages.OwnerNameForAdminClaims);
return this.ownerName; return this.ownerName;
} }
@ -612,7 +685,7 @@ public class Claim
//determine maximum allowable entity count, based on claim size //determine maximum allowable entity count, based on claim size
int maxEntities = this.getArea() / 50; int maxEntities = this.getArea() / 50;
if(maxEntities == 0) return "This claim isn't big enough for that. Try enlarging it."; if(maxEntities == 0) return GriefPrevention.instance.dataStore.getMessage(Messages.ClaimTooSmallForEntities);
//count current entities (ignoring players) //count current entities (ignoring players)
Chunk lesserChunk = this.getLesserBoundaryCorner().getChunk(); Chunk lesserChunk = this.getLesserBoundaryCorner().getChunk();
@ -627,11 +700,15 @@ public class Claim
for(int i = 0; i < entities.length; i++) for(int i = 0; i < entities.length; i++)
{ {
Entity entity = entities[i]; Entity entity = entities[i];
if(!(entity instanceof Player) && this.contains(entity.getLocation(), false, false)) totalEntities++; if(!(entity instanceof Player) && this.contains(entity.getLocation(), false, false))
{
totalEntities++;
if(totalEntities > maxEntities) entity.remove();
}
} }
} }
if(totalEntities > maxEntities) return "This claim has too many entities already. Try enlarging the claim or removing some animals, monsters, or minecarts."; if(totalEntities > maxEntities) return GriefPrevention.instance.dataStore.getMessage(Messages.TooManyEntitiesInClaim);
return null; return null;
} }

View File

@ -25,6 +25,8 @@ import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -34,14 +36,21 @@ public class DataStore
//in-memory cache for player data //in-memory cache for player data
private HashMap<String, PlayerData> playerNameToPlayerDataMap = new HashMap<String, PlayerData>(); private HashMap<String, PlayerData> playerNameToPlayerDataMap = new HashMap<String, PlayerData>();
//in-memory cache for group (permission-based) data
private HashMap<String, Integer> permissionToBonusBlocksMap = new HashMap<String, Integer>();
//in-memory cache for claim data //in-memory cache for claim data
private ArrayList<Claim> claims = new ArrayList<Claim>(); ArrayList<Claim> claims = new ArrayList<Claim>();
//in-memory cache for messages
private String [] messages;
//path information, for where stuff stored on disk is well... stored //path information, for where stuff stored on disk is well... stored
private final static String dataLayerFolderPath = "plugins" + File.separator + "GriefPreventionData"; private final static String dataLayerFolderPath = "plugins" + File.separator + "GriefPreventionData";
private final static String playerDataFolderPath = dataLayerFolderPath + File.separator + "PlayerData"; private final static String playerDataFolderPath = dataLayerFolderPath + File.separator + "PlayerData";
private final static String claimDataFolderPath = dataLayerFolderPath + File.separator + "ClaimData"; private final static String claimDataFolderPath = dataLayerFolderPath + File.separator + "ClaimData";
final static String configFilePath = dataLayerFolderPath + File.separator + "config.yml"; final static String configFilePath = dataLayerFolderPath + File.separator + "config.yml";
final static String messagesFilePath = dataLayerFolderPath + File.separator + "messages.yml";
//initialization! //initialization!
DataStore() DataStore()
@ -50,9 +59,45 @@ public class DataStore
new File(playerDataFolderPath).mkdirs(); new File(playerDataFolderPath).mkdirs();
new File(claimDataFolderPath).mkdirs(); new File(claimDataFolderPath).mkdirs();
//load group data into memory
File playerDataFolder = new File(playerDataFolderPath);
File [] files = playerDataFolder.listFiles();
for(int i = 0; i < files.length; i++)
{
File file = files[i];
if(!file.isFile()) continue; //avoids folders
//all group data files start with an underscore. ignoring the rest, which are player data files.
if(!file.getName().startsWith("_")) continue;
String groupName = file.getName().substring(1);
if(groupName == null || groupName.isEmpty()) continue; //defensive coding, avoid unlikely cases
BufferedReader inStream = null;
try
{
inStream = new BufferedReader(new FileReader(file.getAbsolutePath()));
String line = inStream.readLine();
int groupBonusBlocks = Integer.parseInt(line);
this.permissionToBonusBlocksMap.put(groupName, groupBonusBlocks);
}
catch(Exception e)
{
GriefPrevention.AddLogEntry("Unable to load group bonus block data from file \"" + file.getName() + "\": " + e.getMessage());
}
try
{
if(inStream != null) inStream.close();
}
catch(IOException exception) {}
}
//load claims data into memory //load claims data into memory
File claimDataFolder = new File(claimDataFolderPath); File claimDataFolder = new File(claimDataFolderPath);
File [] files = claimDataFolder.listFiles(); files = claimDataFolder.listFiles();
int loadedClaimCount = 0; int loadedClaimCount = 0;
@ -239,6 +284,9 @@ public class DataStore
this.clearCachedPlayerData(playerName); this.clearCachedPlayerData(playerName);
} }
//load up all the messages from messages.yml
this.loadMessages();
//collect garbage, since lots of stuff was loaded into memory and then tossed out //collect garbage, since lots of stuff was loaded into memory and then tossed out
System.gc(); System.gc();
} }
@ -249,6 +297,67 @@ public class DataStore
this.playerNameToPlayerDataMap.remove(playerName); this.playerNameToPlayerDataMap.remove(playerName);
} }
//gets the number of bonus blocks a player has from his permissions
int getGroupBonusBlocks(String playerName)
{
int bonusBlocks = 0;
Set<String> keys = permissionToBonusBlocksMap.keySet();
Iterator<String> iterator = keys.iterator();
while(iterator.hasNext())
{
String groupName = iterator.next();
Player player = GriefPrevention.instance.getServer().getPlayer(playerName);
if(player.hasPermission(groupName))
{
bonusBlocks += this.permissionToBonusBlocksMap.get(groupName);
}
}
return bonusBlocks;
}
//grants a group (players with a specific permission) bonus claim blocks as long as they're still members of the group
public int adjustGroupBonusBlocks(String groupName, int amount)
{
Integer currentValue = this.permissionToBonusBlocksMap.get(groupName);
if(currentValue == null) currentValue = 0;
currentValue += amount;
this.permissionToBonusBlocksMap.put(groupName, currentValue);
//write changes to file to ensure they don't get lost
BufferedWriter outStream = null;
try
{
//open the group's file
File groupDataFile = new File(playerDataFolderPath + File.separator + "_" + groupName);
groupDataFile.createNewFile();
outStream = new BufferedWriter(new FileWriter(groupDataFile));
//first line is number of bonus blocks
outStream.write(currentValue.toString());
outStream.newLine();
}
//if any problem, log it
catch(Exception e)
{
GriefPrevention.AddLogEntry("Unexpected exception saving data for group \"" + groupName + "\": " + e.getMessage());
}
try
{
//close the file
if(outStream != null)
{
outStream.close();
}
}
catch(IOException exception){}
return currentValue;
}
public void changeClaimOwner(Claim claim, String newOwnerName) throws Exception public void changeClaimOwner(Claim claim, String newOwnerName) throws Exception
{ {
//if it's a subdivision, throw an exception //if it's a subdivision, throw an exception
@ -482,6 +591,7 @@ public class DataStore
File playerFile = new File(playerDataFolderPath + File.separator + playerName); File playerFile = new File(playerDataFolderPath + File.separator + playerName);
playerData = new PlayerData(); playerData = new PlayerData();
playerData.playerName = playerName;
//if it doesn't exist as a file //if it doesn't exist as a file
if(!playerFile.exists()) if(!playerFile.exists())
@ -741,6 +851,12 @@ public class DataStore
bigz = z1; bigz = z1;
} }
//creative mode claims always go to bedrock
if(GriefPrevention.instance.config_claims_enabledCreativeWorlds.contains(world))
{
smally = 2;
}
//create a new claim instance (but don't save it, yet) //create a new claim instance (but don't save it, yet)
Claim newClaim = new Claim( Claim newClaim = new Claim(
new Location(world, smallx, smally, smallz), new Location(world, smallx, smally, smallz),
@ -972,7 +1088,7 @@ public class DataStore
if(winner != null) if(winner != null)
{ {
//notify the winner //notify the winner
GriefPrevention.sendMessage(winner, TextMode.Success, "Congratulations! Buttons and levers are temporarily unlocked (five minutes)."); GriefPrevention.sendMessage(winner, TextMode.Success, Messages.SiegeWinDoorsOpen);
//schedule a task to secure the claims in about 5 minutes //schedule a task to secure the claims in about 5 minutes
SecureClaimTask task = new SecureClaimTask(siegeData); SecureClaimTask task = new SecureClaimTask(siegeData);
@ -1146,4 +1262,223 @@ public class DataStore
return result; return result;
} }
private void loadMessages()
{
Messages [] messageIDs = Messages.values();
this.messages = new String[Messages.values().length];
HashMap<String, CustomizableMessage> defaults = new HashMap<String, CustomizableMessage>();
//initialize defaults
this.addDefault(defaults, Messages.RespectingClaims, "Now respecting claims.", null);
this.addDefault(defaults, Messages.IgnoringClaims, "Now ignoring claims.", null);
this.addDefault(defaults, Messages.NoCreativeUnClaim, "You can't unclaim this land. You can only make this claim larger or create additional claims.", null);
this.addDefault(defaults, Messages.SuccessfulAbandon, "Claims abandoned. You now have {0} available claim blocks.", "0: remaining blocks");
this.addDefault(defaults, Messages.RestoreNatureActivate, "Ready to restore some nature! Right click to restore nature, and use /BasicClaims to stop.", null);
this.addDefault(defaults, Messages.RestoreNatureAggressiveActivate, "Aggressive mode activated. Do NOT use this underneath anything you want to keep! Right click to aggressively restore nature, and use /BasicClaims to stop.", null);
this.addDefault(defaults, Messages.FillModeActive, "Fill mode activated with radius {0}. Right click an area to fill.", "0: fill radius");
this.addDefault(defaults, Messages.TransferClaimPermission, "That command requires the administrative claims permission.", null);
this.addDefault(defaults, Messages.TransferClaimMissing, "There's no claim here. Stand in the administrative claim you want to transfer.", null);
this.addDefault(defaults, Messages.TransferClaimAdminOnly, "Only administrative claims may be transferred to a player.", null);
this.addDefault(defaults, Messages.PlayerNotFound, "Player not found.", null);
this.addDefault(defaults, Messages.TransferTopLevel, "Only top level claims (not subdivisions) may be transferred. Stand outside of the subdivision and try again.", null);
this.addDefault(defaults, Messages.TransferSuccess, "Claim transferred.", null);
this.addDefault(defaults, Messages.TrustListNoClaim, "Stand inside the claim you're curious about.", null);
this.addDefault(defaults, Messages.ClearPermsOwnerOnly, "Only the claim owner can clear all permissions.", null);
this.addDefault(defaults, Messages.UntrustIndividualAllClaims, "Revoked {0}'s access to ALL your claims. To set permissions for a single claim, stand inside it.", "0: untrusted player");
this.addDefault(defaults, Messages.UntrustEveryoneAllClaims, "Cleared permissions in ALL your claims. To set permissions for a single claim, stand inside it.", null);
this.addDefault(defaults, Messages.NoPermissionTrust, "You don't have {0}'s permission to manage permissions here.", "0: claim owner's name");
this.addDefault(defaults, Messages.ClearPermissionsOneClaim, "Cleared permissions in this claim. To set permission for ALL your claims, stand outside them.", null);
this.addDefault(defaults, Messages.UntrustIndividualSingleClaim, "Revoked {0}'s access to this claim. To set permissions for a ALL your claims, stand outside them.", "0: untrusted player");
this.addDefault(defaults, Messages.OnlySellBlocks, "Claim blocks may only be sold, not purchased.", null);
this.addDefault(defaults, Messages.BlockPurchaseCost, "Each claim block costs {0}. Your balance is {1}.", "0: cost of one block; 1: player's account balance");
this.addDefault(defaults, Messages.ClaimBlockLimit, "You've reached your claim block limit. You can't purchase more.", null);
this.addDefault(defaults, Messages.InsufficientFunds, "You don't have enough money. You need {0}, but you only have {1}.", "0: total cost; 1: player's account balance");
this.addDefault(defaults, Messages.PurchaseConfirmation, "Withdrew {0} from your account. You now have {1} available claim blocks.", "0: total cost; 1: remaining blocks");
this.addDefault(defaults, Messages.OnlyPurchaseBlocks, "Claim blocks may only be purchased, not sold.", null);
this.addDefault(defaults, Messages.BlockSaleValue, "Each claim block is worth {0}. You have {1} available for sale.", "0: block value; 1: available blocks");
this.addDefault(defaults, Messages.NotEnoughBlocksForSale, "You don't have that many claim blocks available for sale.", null);
this.addDefault(defaults, Messages.BlockSaleConfirmation, "Deposited {0} in your account. You now have {1} available claim blocks.", "0: amount deposited; 1: remaining blocks");
this.addDefault(defaults, Messages.AdminClaimsMode, "Administrative claims mode active. Any claims created will be free and editable by other administrators.", null);
this.addDefault(defaults, Messages.BasicClaimsMode, "Returned to basic claim creation mode.", null);
this.addDefault(defaults, Messages.SubdivisionMode, "Subdivision mode. Use your shovel to create subdivisions in your existing claims. Use /basicclaims to exit.", null);
this.addDefault(defaults, Messages.SubdivisionDemo, "Want a demonstration? http://tinyurl.com/7urdtue", null);
this.addDefault(defaults, Messages.DeleteClaimMissing, "There's no claim here.", null);
this.addDefault(defaults, Messages.DeletionSubdivisionWarning, "This claim includes subdivisions. If you're sure you want to delete it, use /DeleteClaim again.", null);
this.addDefault(defaults, Messages.DeleteSuccess, "Claim deleted.", null);
this.addDefault(defaults, Messages.CantDeleteAdminClaim, "You don't have permission to delete administrative claims.", null);
this.addDefault(defaults, Messages.DeleteAllSuccess, "Deleted all of {0}'s claims.", "0: owner's name");
this.addDefault(defaults, Messages.NoDeletePermission, "You don't have permission to delete claims.", null);
this.addDefault(defaults, Messages.AllAdminDeleted, "Deleted all administrative claims.", null);
this.addDefault(defaults, Messages.AdjustBlocksSuccess, "Adjusted {0}'s bonus claim blocks by {1}. New total bonus blocks: {2}.", "0: player; 1: adjustment; 2: new total");
this.addDefault(defaults, Messages.NotTrappedHere, "You can build here. Save yourself.", null);
this.addDefault(defaults, Messages.TrappedOnCooldown, "You used /trapped within the last {0} hours. You have to wait about {1} more minutes before using it again.", "0: default cooldown hours; 1: remaining minutes");
this.addDefault(defaults, Messages.RescuePending, "If you stay put for 10 seconds, you'll be teleported out. Please wait.", null);
this.addDefault(defaults, Messages.NonSiegeWorld, "Siege is disabled here.", null);
this.addDefault(defaults, Messages.AlreadySieging, "You're already involved in a siege.", null);
this.addDefault(defaults, Messages.AlreadyUnderSiegePlayer, "{0} is already under siege. Join the party!", "0: defending player");
this.addDefault(defaults, Messages.NotSiegableThere, "{0} isn't protected there.", "0: defending player");
this.addDefault(defaults, Messages.SiegeTooFarAway, "You're too far away to siege.", null);
this.addDefault(defaults, Messages.NoSiegeDefenseless, "That player is defenseless. Go pick on somebody else.", null);
this.addDefault(defaults, Messages.AlreadyUnderSiegeArea, "That area is already under siege. Join the party!", null);
this.addDefault(defaults, Messages.NoSiegeAdminClaim, "Siege is disabled in this area.", null);
this.addDefault(defaults, Messages.SiegeOnCooldown, "You're still on siege cooldown for this defender or claim. Find another victim.", null);
this.addDefault(defaults, Messages.SiegeAlert, "You're under siege! If you log out now, you will die. You must defeat {0}, wait for him to give up, or escape.", "0: attacker name");
this.addDefault(defaults, Messages.SiegeConfirmed, "The siege has begun! If you log out now, you will die. You must defeat {0}, chase him away, or admit defeat and walk away.", "0: defender name");
this.addDefault(defaults, Messages.AbandonClaimMissing, "Stand in the claim you want to delete, or consider /AbandonAllClaims.", null);
this.addDefault(defaults, Messages.NotYourClaim, "This isn't your claim.", null);
this.addDefault(defaults, Messages.DeleteTopLevelClaim, "To delete a subdivision, stand inside it. Otherwise, use /AbandonTopLevelClaim to delete this claim and all subdivisions.", null);
this.addDefault(defaults, Messages.AbandonSuccess, "Claim abandoned. You now have {0} available claim blocks.", "0: remaining claim blocks");
this.addDefault(defaults, Messages.CantGrantThatPermission, "You can't grant a permission you don't have yourself.", null);
this.addDefault(defaults, Messages.GrantPermissionNoClaim, "Stand inside the claim where you want to grant permission.", null);
this.addDefault(defaults, Messages.GrantPermissionConfirmation, "Granted {0} permission to {1} {2}.", "0: target player; 1: permission description; 2: scope (changed claims)");
this.addDefault(defaults, Messages.ManageUniversalPermissionsInstruction, "To manage permissions for ALL your claims, stand outside them.", null);
this.addDefault(defaults, Messages.ManageOneClaimPermissionsInstruction, "To manage permissions for a specific claim, stand inside it.", null);
this.addDefault(defaults, Messages.CollectivePublic, "the public", "as in 'granted the public permission to...'");
this.addDefault(defaults, Messages.BuildPermission, "build", null);
this.addDefault(defaults, Messages.ContainersPermission, "access containers and animals", null);
this.addDefault(defaults, Messages.AccessPermission, "use buttons and levers", null);
this.addDefault(defaults, Messages.PermissionsPermission, "manage permissions", null);
this.addDefault(defaults, Messages.LocationCurrentClaim, "in this claim", null);
this.addDefault(defaults, Messages.LocationAllClaims, "in all your claims", null);
this.addDefault(defaults, Messages.PvPImmunityStart, "You're protected from attack by other players as long as your inventory is empty.", null);
this.addDefault(defaults, Messages.SiegeNoDrop, "You can't give away items while involved in a siege.", null);
this.addDefault(defaults, Messages.DonateItemsInstruction, "To give away the item(s) in your hand, left-click the chest again.", null);
this.addDefault(defaults, Messages.ChestFull, "This chest is full.", null);
this.addDefault(defaults, Messages.DonationSuccess, "Item(s) transferred to chest!", null);
this.addDefault(defaults, Messages.PlayerTooCloseForFire, "You can't start a fire this close to {0}.", "0: other player's name");
this.addDefault(defaults, Messages.TooDeepToClaim, "This chest can't be protected because it's too deep underground. Consider moving it.", null);
this.addDefault(defaults, Messages.ChestClaimConfirmation, "This chest is protected.", null);
this.addDefault(defaults, Messages.AutomaticClaimNotification, "This chest and nearby blocks are protected from breakage and theft. The gold and glowstone blocks mark the protected area.", null);
this.addDefault(defaults, Messages.TrustCommandAdvertisement, "Use the /trust command to grant other players access.", null);
this.addDefault(defaults, Messages.GoldenShovelAdvertisement, "To claim more land, use a golden shovel.", null);
this.addDefault(defaults, Messages.UnprotectedChestWarning, "This chest is NOT protected. Consider expanding an existing claim or creating a new one.", null);
this.addDefault(defaults, Messages.ThatPlayerPvPImmune, "You can't injure defenseless players.", null);
this.addDefault(defaults, Messages.CantFightWhileImmune, "You can't fight someone while you're protected from PvP.", null);
this.addDefault(defaults, Messages.NoDamageClaimedEntity, "That belongs to {0}.", "0: owner name");
this.addDefault(defaults, Messages.ShovelBasicClaimMode, "Shovel returned to basic claims mode.", null);
this.addDefault(defaults, Messages.RemainingBlocks, "You may claim up to {0} more blocks.", "0: remaining blocks");
this.addDefault(defaults, Messages.CreativeBasicsDemoAdvertisement, "Want a demonstration? http://tinyurl.com/c7bajb8", null);
this.addDefault(defaults, Messages.SurvivalBasicsDemoAdvertisement, "Want a demonstration? http://tinyurl.com/6nkwegj", null);
this.addDefault(defaults, Messages.TrappedChatKeyword, "trapped", "When mentioned in chat, players get information about the /trapped command.");
this.addDefault(defaults, Messages.TrappedInstructions, "Are you trapped in someone's claim? Consider the /trapped command.", null);
this.addDefault(defaults, Messages.PvPNoDrop, "You can't drop items while in PvP combat.", null);
this.addDefault(defaults, Messages.SiegeNoTeleport, "You can't teleport out of a besieged area.", null);
this.addDefault(defaults, Messages.BesiegedNoTeleport, "You can't teleport into a besieged area.", null);
this.addDefault(defaults, Messages.SiegeNoContainers, "You can't access containers while involved in a siege.", null);
this.addDefault(defaults, Messages.PvPNoContainers, "You can't access containers during PvP combat.", null);
this.addDefault(defaults, Messages.PvPImmunityEnd, "Now you can fight with other players.", null);
this.addDefault(defaults, Messages.NoBedPermission, "{0} hasn't given you permission to sleep here.", "0: claim owner");
this.addDefault(defaults, Messages.NoWildernessBuckets, "You may only dump buckets inside your claim(s) or underground.", null);
this.addDefault(defaults, Messages.NoLavaNearOtherPlayer, "You can't place lava this close to {0}.", "0: nearby player");
this.addDefault(defaults, Messages.TooFarAway, "That's too far away.", null);
this.addDefault(defaults, Messages.BlockNotClaimed, "No one has claimed this block.", null);
this.addDefault(defaults, Messages.BlockClaimed, "That block has been claimed by {0}.", "0: claim owner");
this.addDefault(defaults, Messages.SiegeNoShovel, "You can't use your shovel tool while involved in a siege.", null);
this.addDefault(defaults, Messages.RestoreNaturePlayerInChunk, "Unable to restore. {0} is in that chunk.", "0: nearby player");
this.addDefault(defaults, Messages.NoCreateClaimPermission, "You don't have permission to claim land.", null);
this.addDefault(defaults, Messages.ResizeClaimTooSmall, "This new size would be too small. Claims must be at least {0} x {0}.", "0: minimum claim size");
this.addDefault(defaults, Messages.ResizeNeedMoreBlocks, "You don't have enough blocks for this size. You need {0} more.", "0: how many needed");
this.addDefault(defaults, Messages.ClaimResizeSuccess, "Claim resized. You now have {0} available claim blocks.", "0: remaining blocks");
this.addDefault(defaults, Messages.ResizeFailOverlap, "Can't resize here because it would overlap another nearby claim.", null);
this.addDefault(defaults, Messages.ResizeStart, "Resizing claim. Use your shovel again at the new location for this corner.", null);
this.addDefault(defaults, Messages.ResizeFailOverlapSubdivision, "You can't create a subdivision here because it would overlap another subdivision. Consider /abandonclaim to delete it, or use your shovel at a corner to resize it.", null);
this.addDefault(defaults, Messages.SubdivisionStart, "Subdivision corner set! Use your shovel at the location for the opposite corner of this new subdivision.", null);
this.addDefault(defaults, Messages.CreateSubdivisionOverlap, "Your selected area overlaps another subdivision.", null);
this.addDefault(defaults, Messages.SubdivisionSuccess, "Subdivision created! Use /trust to share it with friends.", null);
this.addDefault(defaults, Messages.CreateClaimFailOverlap, "You can't create a claim here because it would overlap your other claim. Use /abandonclaim to delete it, or use your shovel at a corner to resize it.", null);
this.addDefault(defaults, Messages.CreateClaimFailOverlapOtherPlayer, "You can't create a claim here because it would overlap {0}'s claim.", "0: other claim owner");
this.addDefault(defaults, Messages.ClaimsDisabledWorld, "Land claims are disabled in this world.", null);
this.addDefault(defaults, Messages.ClaimStart, "Claim corner set! Use the shovel again at the opposite corner to claim a rectangle of land. To cancel, put your shovel away.", null);
this.addDefault(defaults, Messages.NewClaimTooSmall, "This claim would be too small. Any claim must be at least {0} x {0}.", "0: minimum claim size");
this.addDefault(defaults, Messages.CreateClaimInsufficientBlocks, "You don't have enough blocks to claim that entire area. You need {0} more blocks.", "0: additional blocks needed");
this.addDefault(defaults, Messages.AbandonClaimAdvertisement, "To delete another claim and free up some blocks, use /AbandonClaim.", null);
this.addDefault(defaults, Messages.CreateClaimFailOverlapShort, "Your selected area overlaps an existing claim.", null);
this.addDefault(defaults, Messages.CreateClaimSuccess, "Claim created! Use /trust to share it with friends.", null);
this.addDefault(defaults, Messages.SiegeWinDoorsOpen, "Congratulations! Buttons and levers are temporarily unlocked (five minutes).", null);
this.addDefault(defaults, Messages.RescueAbortedMoved, "You moved! Rescue cancelled.", null);
this.addDefault(defaults, Messages.SiegeDoorsLockedEjection, "Looting time is up! Ejected from the claim.", null);
this.addDefault(defaults, Messages.NoModifyDuringSiege, "Claims can't be modified while under siege.", null);
this.addDefault(defaults, Messages.OnlyOwnersModifyClaims, "Only {0} can modify this claim.", "0: owner name");
this.addDefault(defaults, Messages.NoBuildUnderSiege, "This claim is under siege by {0}. No one can build here.", "0: attacker name");
this.addDefault(defaults, Messages.NoBuildPvP, "You can't build in claims during PvP combat.", null);
this.addDefault(defaults, Messages.NoBuildPermission, "You don't have {0}'s permission to build here.", "0: owner name");
this.addDefault(defaults, Messages.NonSiegeMaterial, "That material is too tough to break.", null);
this.addDefault(defaults, Messages.NoOwnerBuildUnderSiege, "You can't make changes while under siege.", null);
this.addDefault(defaults, Messages.NoAccessPermission, "You don't have {0}'s permission to use that.", "0: owner name. access permission controls buttons, levers, and beds");
this.addDefault(defaults, Messages.NoContainersSiege, "This claim is under siege by {0}. No one can access containers here right now.", "0: attacker name");
this.addDefault(defaults, Messages.NoContainersPermission, "You don't have {0}'s permission to use that.", "0: owner's name. containers also include crafting blocks");
this.addDefault(defaults, Messages.OwnerNameForAdminClaims, "an administrator", "as in 'You don't have an administrator's permission to build here.'");
this.addDefault(defaults, Messages.ClaimTooSmallForEntities, "This claim isn't big enough for that. Try enlarging it.", null);
this.addDefault(defaults, Messages.TooManyEntitiesInClaim, "This claim has too many entities already. Try enlarging the claim or removing some animals, monsters, paintings, or minecarts.", null);
this.addDefault(defaults, Messages.YouHaveNoClaims, "You don't have any land claims.", null);
this.addDefault(defaults, Messages.ConfirmFluidRemoval, "Abandoning this claim will remove all your lava and water. If you're sure, use /AbandonClaim again.", null);
this.addDefault(defaults, Messages.AutoBanNotify, "Auto-banned {0}({1}). See logs for details.", null);
this.addDefault(defaults, Messages.AdjustGroupBlocksSuccess, "Adjusted bonus claim blocks for players with the {0} permission by {1}. New total: {2}.", "0: permission; 1: adjustment amount; 2: new total bonus");
this.addDefault(defaults, Messages.InvalidPermissionID, "Please specify a player name, or a permission in [brackets].", null);
this.addDefault(defaults, Messages.UntrustOwnerOnly, "Only {0} can revoke permissions here.", "0: claim owner's name");
//load the config file
FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath));
//for each message ID
for(int i = 0; i < messageIDs.length; i++)
{
//get default for this message
Messages messageID = messageIDs[i];
CustomizableMessage messageData = defaults.get(messageID.name());
//if default is missing, log an error and use some fake data for now so that the plugin can run
if(messageData == null)
{
GriefPrevention.AddLogEntry("Missing message for " + messageID.name() + ". Please contact the developer.");
messageData = new CustomizableMessage(messageID, "Missing message! ID: " + messageID.name() + ". Please contact a server admin.", null);
}
//read the message from the file, use default if necessary
this.messages[messageID.ordinal()] = config.getString("Messages." + messageID.name() + ".Text", messageData.text);
config.set("Messages." + messageID.name() + ".Text", this.messages[messageID.ordinal()]);
if(messageData.notes != null)
{
messageData.notes = config.getString("Messages." + messageID.name() + ".Notes", messageData.notes);
config.set("Messages." + messageID.name() + ".Notes", messageData.notes);
}
}
//save any changes
try
{
config.save(DataStore.messagesFilePath);
}
catch(IOException exception)
{
GriefPrevention.AddLogEntry("Unable to write to the configuration file at \"" + DataStore.messagesFilePath + "\"");
}
defaults.clear();
System.gc();
}
private void addDefault(HashMap<String, CustomizableMessage> defaults,
Messages id, String text, String notes)
{
CustomizableMessage message = new CustomizableMessage(id, text, notes);
defaults.put(id.name(), message);
}
public String getMessage(Messages messageID, String... args)
{
String message = messages[messageID.ordinal()];
for(int i = 0; i < args.length; i++)
{
String param = args[i];
message = message.replace("{" + i + "}", param);
}
return message;
}
} }

View File

@ -25,11 +25,12 @@ import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Arrow; import org.bukkit.entity.Arrow;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Enderman; import org.bukkit.entity.Enderman;
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.entity.ThrownPotion; import org.bukkit.entity.ThrownPotion;
import org.bukkit.entity.Vehicle; import org.bukkit.entity.Vehicle;
@ -44,6 +45,7 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.ExpBottleEvent;
import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.painting.PaintingBreakByEntityEvent; import org.bukkit.event.painting.PaintingBreakByEntityEvent;
import org.bukkit.event.painting.PaintingBreakEvent; import org.bukkit.event.painting.PaintingBreakEvent;
@ -118,6 +120,17 @@ class EntityEventHandler implements Listener
} }
} }
//when an experience bottle explodes...
@EventHandler(priority = EventPriority.LOWEST)
public void onExpBottle(ExpBottleEvent event)
{
//if in a creative world, cancel the event (don't drop exp on the ground)
if(GriefPrevention.instance.creativeRulesApply(event.getEntity().getLocation()))
{
event.setExperience(0);
}
}
//when a creature spawns... //when a creature spawns...
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void onEntitySpawn(CreatureSpawnEvent event) public void onEntitySpawn(CreatureSpawnEvent event)
@ -129,7 +142,7 @@ class EntityEventHandler implements Listener
//chicken eggs and breeding could potentially make a mess in the wilderness, once griefers get involved //chicken eggs and breeding could potentially make a mess in the wilderness, once griefers get involved
SpawnReason reason = event.getSpawnReason(); SpawnReason reason = event.getSpawnReason();
if(reason == SpawnReason.EGG || reason == SpawnReason.BREEDING) if(reason != SpawnReason.SPAWNER_EGG && reason != SpawnReason.BUILD_IRONGOLEM && reason != SpawnReason.BUILD_SNOWMAN)
{ {
event.setCancelled(true); event.setCancelled(true);
return; return;
@ -241,7 +254,24 @@ class EntityEventHandler implements Listener
{ {
event.setCancelled(true); event.setCancelled(true);
GriefPrevention.sendMessage(event.getPlayer(), TextMode.Err, noBuildReason); GriefPrevention.sendMessage(event.getPlayer(), TextMode.Err, noBuildReason);
} return;
}
//otherwise, apply entity-count limitations for creative worlds
else if(GriefPrevention.instance.creativeRulesApply(event.getPainting().getLocation()))
{
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName());
Claim claim = this.dataStore.getClaimAt(event.getBlock().getLocation(), false, playerData.lastClaim);
if(claim == null) return;
String noEntitiesReason = claim.allowMoreEntities();
if(noEntitiesReason != null)
{
GriefPrevention.sendMessage(event.getPlayer(), TextMode.Err, noEntitiesReason);
event.setCancelled(true);
return;
}
}
} }
//when an entity is damaged //when an entity is damaged
@ -251,6 +281,9 @@ class EntityEventHandler implements Listener
//only actually interested in entities damaging entities (ignoring environmental damage) //only actually interested in entities damaging entities (ignoring environmental damage)
if(!(event instanceof EntityDamageByEntityEvent)) return; if(!(event instanceof EntityDamageByEntityEvent)) return;
//monsters are never protected
if(event.getEntity() instanceof Monster) return;
EntityDamageByEntityEvent subEvent = (EntityDamageByEntityEvent) event; EntityDamageByEntityEvent subEvent = (EntityDamageByEntityEvent) event;
//determine which player is attacking, if any //determine which player is attacking, if any
@ -300,14 +333,14 @@ class EntityEventHandler implements Listener
if(defenderData.pvpImmune) if(defenderData.pvpImmune)
{ {
event.setCancelled(true); event.setCancelled(true);
GriefPrevention.sendMessage(attacker, TextMode.Err, "You can't injure defenseless players."); GriefPrevention.sendMessage(attacker, TextMode.Err, Messages.ThatPlayerPvPImmune);
return; return;
} }
if(attackerData.pvpImmune) if(attackerData.pvpImmune)
{ {
event.setCancelled(true); event.setCancelled(true);
GriefPrevention.sendMessage(attacker, TextMode.Err, "You can't fight someone while you're protected from PvP."); GriefPrevention.sendMessage(attacker, TextMode.Err, Messages.CantFightWhileImmune);
return; return;
} }
} }
@ -327,12 +360,21 @@ class EntityEventHandler implements Listener
//so unless precautions are taken by the owner, a resourceful thief might find ways to steal anyway //so unless precautions are taken by the owner, a resourceful thief might find ways to steal anyway
//if theft protection is enabled //if theft protection is enabled
if(GriefPrevention.instance.config_claims_preventTheft && event instanceof EntityDamageByEntityEvent) if(event instanceof EntityDamageByEntityEvent)
{ {
//if the entity is an animal or a vehicle //if the entity is an non-monster creature (remember monsters disqualified above), or a vehicle
if (subEvent.getEntity() instanceof Animals || subEvent.getEntity() instanceof Vehicle) if ((subEvent.getEntity() instanceof Creature && GriefPrevention.instance.config_claims_protectCreatures) ||
(subEvent.getEntity() instanceof Vehicle && GriefPrevention.instance.config_claims_preventTheft))
{ {
Claim claim = this.dataStore.getClaimAt(event.getEntity().getLocation(), false, null); Claim cachedClaim = null;
PlayerData playerData = null;
if(attacker != null)
{
playerData = this.dataStore.getPlayerData(attacker.getName());
cachedClaim = playerData.lastClaim;
}
Claim claim = this.dataStore.getClaimAt(event.getEntity().getLocation(), false, cachedClaim);
//if it's claimed //if it's claimed
if(claim != null) if(claim != null)
@ -350,8 +392,14 @@ class EntityEventHandler implements Listener
if(noContainersReason != null) if(noContainersReason != null)
{ {
event.setCancelled(true); event.setCancelled(true);
GriefPrevention.sendMessage(attacker, TextMode.Err, "That belongs to " + claim.getOwnerName() + "."); GriefPrevention.sendMessage(attacker, TextMode.Err, Messages.NoDamageClaimedEntity, claim.getOwnerName());
} }
//cache claim for later
if(playerData != null)
{
playerData.lastClaim = claim;
}
} }
} }
} }

View File

@ -53,13 +53,22 @@ class EquipShovelProcessingTask implements Runnable
if(playerData.shovelMode != ShovelMode.Basic) if(playerData.shovelMode != ShovelMode.Basic)
{ {
playerData.shovelMode = ShovelMode.Basic; playerData.shovelMode = ShovelMode.Basic;
GriefPrevention.sendMessage(player, TextMode.Info, "Shovel returned to basic claims mode."); GriefPrevention.sendMessage(player, TextMode.Info, Messages.ShovelBasicClaimMode);
} }
int remainingBlocks = playerData.getRemainingClaimBlocks(); int remainingBlocks = playerData.getRemainingClaimBlocks();
//instruct him in the steps to create a claim //instruct him in the steps to create a claim
GriefPrevention.sendMessage(player, TextMode.Instr, "You may claim up to " + String.valueOf(remainingBlocks) + " more blocks."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.RemainingBlocks, String.valueOf(remainingBlocks));
GriefPrevention.sendMessage(player, TextMode.Instr, "Want a demonstration? http://tinyurl.com/6nkwegj");
//demo link changes based on game mode
if(GriefPrevention.instance.creativeRulesApply(player.getLocation()))
{
GriefPrevention.sendMessage(player, TextMode.Instr, Messages.CreativeBasicsDemoAdvertisement);
}
else
{
GriefPrevention.sendMessage(player, TextMode.Instr, Messages.SurvivalBasicsDemoAdvertisement);
}
} }
} }

View File

@ -35,6 +35,7 @@ import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.command.*; import org.bukkit.command.*;
@ -63,6 +64,7 @@ public class GriefPrevention extends JavaPlugin
public ArrayList<World> config_claims_enabledCreativeWorlds; //list of worlds where additional creative mode anti-grief rules apply public ArrayList<World> config_claims_enabledCreativeWorlds; //list of worlds where additional creative mode anti-grief rules apply
public boolean config_claims_preventTheft; //whether containers and crafting blocks are protectable public boolean config_claims_preventTheft; //whether containers and crafting blocks are protectable
public boolean config_claims_protectCreatures; //whether claimed animals may be injured by players without permission
public boolean config_claims_preventButtonsSwitches; //whether buttons and switches are protectable public boolean config_claims_preventButtonsSwitches; //whether buttons and switches are protectable
public int config_claims_initialBlocks; //the number of claim blocks a new player starts with public int config_claims_initialBlocks; //the number of claim blocks a new player starts with
@ -101,6 +103,8 @@ public class GriefPrevention extends JavaPlugin
public double config_economy_claimBlocksSellValue; //return on a sold claim block. set to zero to disable sale. public double config_economy_claimBlocksSellValue; //return on a sold claim block. set to zero to disable sale.
public boolean config_blockSurfaceExplosions; //whether creeper/TNT explosions near or above the surface destroy blocks public boolean config_blockSurfaceExplosions; //whether creeper/TNT explosions near or above the surface destroy blocks
public boolean config_blockWildernessWaterBuckets; //whether players can dump water buckets outside their claims
public boolean config_blockSkyTrees; //whether players can build trees on platforms in the sky
public boolean config_fireSpreads; //whether fire spreads outside of claims public boolean config_fireSpreads; //whether fire spreads outside of claims
public boolean config_fireDestroys; //whether fire destroys blocks outside of claims public boolean config_fireDestroys; //whether fire destroys blocks outside of claims
@ -204,6 +208,7 @@ public class GriefPrevention extends JavaPlugin
} }
this.config_claims_preventTheft = config.getBoolean("GriefPrevention.Claims.PreventTheft", true); this.config_claims_preventTheft = config.getBoolean("GriefPrevention.Claims.PreventTheft", true);
this.config_claims_protectCreatures = config.getBoolean("GriefPrevention.Claims.ProtectCreatures", true);
this.config_claims_preventButtonsSwitches = config.getBoolean("GriefPrevention.Claims.PreventButtonsSwitches", true); this.config_claims_preventButtonsSwitches = config.getBoolean("GriefPrevention.Claims.PreventButtonsSwitches", true);
this.config_claims_initialBlocks = config.getInt("GriefPrevention.Claims.InitialBlocks", 100); this.config_claims_initialBlocks = config.getInt("GriefPrevention.Claims.InitialBlocks", 100);
this.config_claims_blocksAccruedPerHour = config.getInt("GriefPrevention.Claims.BlocksAccruedPerHour", 100); this.config_claims_blocksAccruedPerHour = config.getInt("GriefPrevention.Claims.BlocksAccruedPerHour", 100);
@ -236,7 +241,9 @@ public class GriefPrevention extends JavaPlugin
this.config_economy_claimBlocksSellValue = config.getDouble("GriefPrevention.Economy.ClaimBlocksSellValue", 0); this.config_economy_claimBlocksSellValue = config.getDouble("GriefPrevention.Economy.ClaimBlocksSellValue", 0);
this.config_blockSurfaceExplosions = config.getBoolean("GriefPrevention.BlockSurfaceExplosions", true); this.config_blockSurfaceExplosions = config.getBoolean("GriefPrevention.BlockSurfaceExplosions", true);
this.config_blockWildernessWaterBuckets = config.getBoolean("GriefPrevention.LimitSurfaceWaterBuckets", true);
this.config_blockSkyTrees = config.getBoolean("GriefPrevention.LimitSkyTrees", true);
this.config_fireSpreads = config.getBoolean("GriefPrevention.FireSpreads", false); this.config_fireSpreads = config.getBoolean("GriefPrevention.FireSpreads", false);
this.config_fireDestroys = config.getBoolean("GriefPrevention.FireDestroys", false); this.config_fireDestroys = config.getBoolean("GriefPrevention.FireDestroys", false);
@ -320,6 +327,7 @@ public class GriefPrevention extends JavaPlugin
config.set("GriefPrevention.Claims.Worlds", claimsEnabledWorldNames); config.set("GriefPrevention.Claims.Worlds", claimsEnabledWorldNames);
config.set("GriefPrevention.Claims.CreativeRulesWorlds", creativeClaimsEnabledWorldNames); config.set("GriefPrevention.Claims.CreativeRulesWorlds", creativeClaimsEnabledWorldNames);
config.set("GriefPrevention.Claims.PreventTheft", this.config_claims_preventTheft); config.set("GriefPrevention.Claims.PreventTheft", this.config_claims_preventTheft);
config.set("GriefPrevention.Claims.ProtectCreatures", this.config_claims_protectCreatures);
config.set("GriefPrevention.Claims.PreventButtonsSwitches", this.config_claims_preventButtonsSwitches); config.set("GriefPrevention.Claims.PreventButtonsSwitches", this.config_claims_preventButtonsSwitches);
config.set("GriefPrevention.Claims.InitialBlocks", this.config_claims_initialBlocks); config.set("GriefPrevention.Claims.InitialBlocks", this.config_claims_initialBlocks);
config.set("GriefPrevention.Claims.BlocksAccruedPerHour", this.config_claims_blocksAccruedPerHour); config.set("GriefPrevention.Claims.BlocksAccruedPerHour", this.config_claims_blocksAccruedPerHour);
@ -352,6 +360,8 @@ public class GriefPrevention extends JavaPlugin
config.set("GriefPrevention.Economy.ClaimBlocksSellValue", this.config_economy_claimBlocksSellValue); config.set("GriefPrevention.Economy.ClaimBlocksSellValue", this.config_economy_claimBlocksSellValue);
config.set("GriefPrevention.BlockSurfaceExplosions", this.config_blockSurfaceExplosions); config.set("GriefPrevention.BlockSurfaceExplosions", this.config_blockSurfaceExplosions);
config.set("GriefPrevention.LimitSurfaceWaterBuckets", this.config_blockWildernessWaterBuckets);
config.set("GriefPrevention.LimitSkyTrees", this.config_blockSkyTrees);
config.set("GriefPrevention.FireSpreads", this.config_fireSpreads); config.set("GriefPrevention.FireSpreads", this.config_fireSpreads);
config.set("GriefPrevention.FireDestroys", this.config_fireDestroys); config.set("GriefPrevention.FireDestroys", this.config_fireDestroys);
@ -392,6 +402,10 @@ public class GriefPrevention extends JavaPlugin
this.getServer().getScheduler().scheduleSyncRepeatingTask(this, task, 20L * 60 * 5, 20L * 60 * 5); this.getServer().getScheduler().scheduleSyncRepeatingTask(this, task, 20L * 60 * 5, 20L * 60 * 5);
} }
//start the recurring cleanup event for entities in creative worlds
EntityCleanupTask task = new EntityCleanupTask(0);
this.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task, 20L);
//register for events //register for events
PluginManager pluginManager = this.getServer().getPluginManager(); PluginManager pluginManager = this.getServer().getPluginManager();
@ -475,11 +489,11 @@ public class GriefPrevention extends JavaPlugin
//toggle ignore claims mode on or off //toggle ignore claims mode on or off
if(!playerData.ignoreClaims) if(!playerData.ignoreClaims)
{ {
GriefPrevention.sendMessage(player, TextMode.Success, "Now respecting claims."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.RespectingClaims);
} }
else else
{ {
GriefPrevention.sendMessage(player, TextMode.Success, "Now ignoring claims."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.IgnoringClaims);
} }
return true; return true;
@ -492,7 +506,7 @@ public class GriefPrevention extends JavaPlugin
if(creativeRulesApply(player.getLocation())) if(creativeRulesApply(player.getLocation()))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Creative mode claims can't be abandoned."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoCreativeUnClaim);
return true; return true;
} }
@ -503,7 +517,7 @@ public class GriefPrevention extends JavaPlugin
//check count //check count
if(originalClaimCount == 0) if(originalClaimCount == 0)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You haven't claimed any land."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.YouHaveNoClaims);
return true; return true;
} }
@ -512,7 +526,7 @@ public class GriefPrevention extends JavaPlugin
//inform the player //inform the player
int remainingBlocks = playerData.getRemainingClaimBlocks(); int remainingBlocks = playerData.getRemainingClaimBlocks();
GriefPrevention.sendMessage(player, TextMode.Success, "Claims abandoned. You now have " + String.valueOf(remainingBlocks) + " available claim blocks."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.SuccessfulAbandon, String.valueOf(remainingBlocks));
//revert any current visualization //revert any current visualization
Visualization.Revert(player); Visualization.Revert(player);
@ -526,7 +540,7 @@ public class GriefPrevention extends JavaPlugin
//change shovel mode //change shovel mode
PlayerData playerData = this.dataStore.getPlayerData(player.getName()); PlayerData playerData = this.dataStore.getPlayerData(player.getName());
playerData.shovelMode = ShovelMode.RestoreNature; playerData.shovelMode = ShovelMode.RestoreNature;
GriefPrevention.sendMessage(player, TextMode.Instr, "Ready to restore some nature! Right click to restore nature, and use /BasicClaims to stop."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.RestoreNatureActivate);
return true; return true;
} }
@ -536,7 +550,7 @@ public class GriefPrevention extends JavaPlugin
//change shovel mode //change shovel mode
PlayerData playerData = this.dataStore.getPlayerData(player.getName()); PlayerData playerData = this.dataStore.getPlayerData(player.getName());
playerData.shovelMode = ShovelMode.RestoreNatureAggressive; playerData.shovelMode = ShovelMode.RestoreNatureAggressive;
GriefPrevention.sendMessage(player, TextMode.Warn, "Aggressive mode activated. Do NOT use this underneath anything you want to keep! Right click to aggressively restore nature, and use /BasicClaims to stop."); GriefPrevention.sendMessage(player, TextMode.Warn, Messages.RestoreNatureAggressiveActivate);
return true; return true;
} }
@ -560,7 +574,7 @@ public class GriefPrevention extends JavaPlugin
if(playerData.fillRadius < 0) playerData.fillRadius = 2; if(playerData.fillRadius < 0) playerData.fillRadius = 2;
GriefPrevention.sendMessage(player, TextMode.Success, "Fill mode activated with radius " + playerData.fillRadius + ". Right-click an area to fill."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.FillModeActive, String.valueOf(playerData.fillRadius));
return true; return true;
} }
@ -585,7 +599,7 @@ public class GriefPrevention extends JavaPlugin
//check additional permission //check additional permission
if(!player.hasPermission("griefprevention.adminclaims")) if(!player.hasPermission("griefprevention.adminclaims"))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "That command requires the administrative claims permission."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.TransferClaimPermission);
return true; return true;
} }
@ -593,19 +607,19 @@ public class GriefPrevention extends JavaPlugin
Claim claim = this.dataStore.getClaimAt(player.getLocation(), true, null); Claim claim = this.dataStore.getClaimAt(player.getLocation(), true, null);
if(claim == null) if(claim == null)
{ {
GriefPrevention.sendMessage(player, TextMode.Instr, "There's no claim here. Stand in the administrative claim you want to transfer."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.TransferClaimMissing);
return true; return true;
} }
else if(!claim.isAdminClaim()) else if(!claim.isAdminClaim())
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Only administrative claims may be transferred to a player."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.TransferClaimAdminOnly);
return true; return true;
} }
OfflinePlayer targetPlayer = this.resolvePlayer(args[0]); OfflinePlayer targetPlayer = this.resolvePlayer(args[0]);
if(targetPlayer == null) if(targetPlayer == null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Player not found."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
return true; return true;
} }
@ -616,12 +630,12 @@ public class GriefPrevention extends JavaPlugin
} }
catch(Exception e) catch(Exception e)
{ {
GriefPrevention.sendMessage(player, TextMode.Instr, "Only top level claims (not subdivisions) may be transferred. Stand outside of the subdivision and try again."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.TransferTopLevel);
return true; return true;
} }
//confirm //confirm
GriefPrevention.sendMessage(player, TextMode.Success, "Claim transferred."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.TransferSuccess);
GriefPrevention.AddLogEntry(player.getName() + " transferred a claim at " + GriefPrevention.getfriendlyLocationString(claim.getLesserBoundaryCorner()) + " to " + targetPlayer.getName() + "."); GriefPrevention.AddLogEntry(player.getName() + " transferred a claim at " + GriefPrevention.getfriendlyLocationString(claim.getLesserBoundaryCorner()) + " to " + targetPlayer.getName() + ".");
return true; return true;
@ -635,7 +649,7 @@ public class GriefPrevention extends JavaPlugin
//if no claim here, error message //if no claim here, error message
if(claim == null) if(claim == null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Stand inside the claim you're curious about."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.TrustListNoClaim);
return true; return true;
} }
@ -703,7 +717,7 @@ public class GriefPrevention extends JavaPlugin
return true; return true;
} }
//untrust <player> //untrust <player> or untrust [<group>]
else if(cmd.getName().equalsIgnoreCase("untrust") && player != null) else if(cmd.getName().equalsIgnoreCase("untrust") && player != null)
{ {
//requires exactly one parameter, the other player's name //requires exactly one parameter, the other player's name
@ -723,24 +737,27 @@ public class GriefPrevention extends JavaPlugin
} }
else else
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Only the claim owner can clear all permissions."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.ClearPermsOwnerOnly);
return true; return true;
} }
} }
else else
{ {
//validate player argument //validate player argument or group argument
otherPlayer = this.resolvePlayer(args[0]); if(!args[0].startsWith("[") || !args[0].endsWith("]"))
if(!clearPermissions && otherPlayer == null && !args[0].equals("public"))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Player not found."); otherPlayer = this.resolvePlayer(args[0]);
return true; if(!clearPermissions && otherPlayer == null && !args[0].equals("public"))
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
return true;
}
//correct to proper casing
if(otherPlayer != null)
args[0] = otherPlayer.getName();
} }
//correct to proper casing
if(otherPlayer != null)
args[0] = otherPlayer.getName();
} }
//if no claim here, apply changes to all his claims //if no claim here, apply changes to all his claims
@ -777,18 +794,18 @@ public class GriefPrevention extends JavaPlugin
//confirmation message //confirmation message
if(!clearPermissions) if(!clearPermissions)
{ {
GriefPrevention.sendMessage(player, TextMode.Success, "Revoked " + args[0] + "'s access to ALL your claims. To set permissions for a single claim, stand inside it."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.UntrustIndividualAllClaims, args[0]);
} }
else else
{ {
GriefPrevention.sendMessage(player, TextMode.Success, "Cleared permissions in ALL your claims. To set permissions for a single claim, stand inside it."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.UntrustEveryoneAllClaims);
} }
} }
//otherwise, apply changes to only this claim //otherwise, apply changes to only this claim
else if(claim.allowGrantPermission(player) != null) else if(claim.allowGrantPermission(player) != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You don't have " + claim.getOwnerName() + "'s permission to manage permissions here."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoPermissionTrust, claim.getOwnerName());
} }
else else
{ {
@ -796,7 +813,7 @@ public class GriefPrevention extends JavaPlugin
if(clearPermissions) if(clearPermissions)
{ {
claim.clearPermissions(); claim.clearPermissions();
GriefPrevention.sendMessage(player, TextMode.Success, "Cleared permissions in this claim. To set permission for ALL your claims, stand outside them."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.ClearPermissionsOneClaim);
} }
//otherwise individual permission drop //otherwise individual permission drop
@ -813,7 +830,11 @@ public class GriefPrevention extends JavaPlugin
args[0] = "the public"; args[0] = "the public";
} }
GriefPrevention.sendMessage(player, TextMode.Success, "Revoked " + args[0] + "'s access to this claim. To set permissions for a ALL your claims, stand outside them."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.UntrustIndividualSingleClaim, args[0]);
}
else
{
GriefPrevention.sendMessage(player, TextMode.Success, Messages.UntrustOwnerOnly, claim.getOwnerName());
} }
} }
@ -866,14 +887,14 @@ public class GriefPrevention extends JavaPlugin
//if purchase disabled, send error message //if purchase disabled, send error message
if(GriefPrevention.instance.config_economy_claimBlocksPurchaseCost == 0) if(GriefPrevention.instance.config_economy_claimBlocksPurchaseCost == 0)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Claim blocks may only be sold, not purchased."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.OnlySellBlocks);
return true; return true;
} }
//if no parameter, just tell player cost per block and balance //if no parameter, just tell player cost per block and balance
if(args.length != 1) if(args.length != 1)
{ {
GriefPrevention.sendMessage(player, TextMode.Info, "Each claim block costs " + GriefPrevention.instance.config_economy_claimBlocksPurchaseCost + ". Your balance is " + GriefPrevention.economy.getBalance(player.getName()) + "."); GriefPrevention.sendMessage(player, TextMode.Info, Messages.BlockPurchaseCost, String.valueOf(GriefPrevention.instance.config_economy_claimBlocksPurchaseCost), String.valueOf(GriefPrevention.economy.getBalance(player.getName())));
return false; return false;
} }
@ -886,7 +907,7 @@ public class GriefPrevention extends JavaPlugin
//if the player is at his max, tell him so //if the player is at his max, tell him so
if(maxPurchasable <= 0) if(maxPurchasable <= 0)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You've reached your claim block limit. You can't purchase more."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.ClaimBlockLimit);
return true; return true;
} }
@ -912,7 +933,7 @@ public class GriefPrevention extends JavaPlugin
double totalCost = blockCount * GriefPrevention.instance.config_economy_claimBlocksPurchaseCost; double totalCost = blockCount * GriefPrevention.instance.config_economy_claimBlocksPurchaseCost;
if(totalCost > balance) if(totalCost > balance)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You don't have enough money. You need " + totalCost + ", but you only have " + balance + "."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.InsufficientFunds, String.valueOf(totalCost), String.valueOf(balance));
} }
//otherwise carry out transaction //otherwise carry out transaction
@ -926,7 +947,7 @@ public class GriefPrevention extends JavaPlugin
this.dataStore.savePlayerData(player.getName(), playerData); this.dataStore.savePlayerData(player.getName(), playerData);
//inform player //inform player
GriefPrevention.sendMessage(player, TextMode.Success, "Withdrew " + totalCost + " from your account. You now have " + playerData.getRemainingClaimBlocks() + " available claim blocks."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.PurchaseConfirmation, String.valueOf(totalCost), String.valueOf(playerData.getRemainingClaimBlocks()));
} }
return true; return true;
@ -942,7 +963,7 @@ public class GriefPrevention extends JavaPlugin
//if disabled, error message //if disabled, error message
if(GriefPrevention.instance.config_economy_claimBlocksSellValue == 0) if(GriefPrevention.instance.config_economy_claimBlocksSellValue == 0)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Claim blocks may only be purchased, not sold."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.OnlyPurchaseBlocks);
return true; return true;
} }
@ -953,7 +974,7 @@ public class GriefPrevention extends JavaPlugin
//if no amount provided, just tell player value per block sold, and how many he can sell //if no amount provided, just tell player value per block sold, and how many he can sell
if(args.length != 1) if(args.length != 1)
{ {
GriefPrevention.sendMessage(player, TextMode.Info, "Each claim block is worth " + GriefPrevention.instance.config_economy_claimBlocksSellValue + ". You have " + availableBlocks + " available for sale."); GriefPrevention.sendMessage(player, TextMode.Info, Messages.BlockSaleValue, String.valueOf(GriefPrevention.instance.config_economy_claimBlocksSellValue), String.valueOf(availableBlocks));
return false; return false;
} }
@ -971,7 +992,7 @@ public class GriefPrevention extends JavaPlugin
//if he doesn't have enough blocks, tell him so //if he doesn't have enough blocks, tell him so
if(blockCount > availableBlocks) if(blockCount > availableBlocks)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You don't have that many claim blocks available for sale."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NotEnoughBlocksForSale);
} }
//otherwise carry out the transaction //otherwise carry out the transaction
@ -986,7 +1007,7 @@ public class GriefPrevention extends JavaPlugin
this.dataStore.savePlayerData(player.getName(), playerData); this.dataStore.savePlayerData(player.getName(), playerData);
//inform player //inform player
GriefPrevention.sendMessage(player, TextMode.Success, "Deposited " + totalValue + " in your account. You now have " + playerData.getRemainingClaimBlocks() + " available claim blocks."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.BlockSaleConfirmation, String.valueOf(totalValue), String.valueOf(playerData.getRemainingClaimBlocks()));
} }
return true; return true;
@ -997,7 +1018,7 @@ public class GriefPrevention extends JavaPlugin
{ {
PlayerData playerData = this.dataStore.getPlayerData(player.getName()); PlayerData playerData = this.dataStore.getPlayerData(player.getName());
playerData.shovelMode = ShovelMode.Admin; playerData.shovelMode = ShovelMode.Admin;
GriefPrevention.sendMessage(player, TextMode.Success, "Administrative claims mode active. Any claims created will be free and editable by other administrators."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.AdminClaimsMode);
return true; return true;
} }
@ -1008,7 +1029,7 @@ public class GriefPrevention extends JavaPlugin
PlayerData playerData = this.dataStore.getPlayerData(player.getName()); PlayerData playerData = this.dataStore.getPlayerData(player.getName());
playerData.shovelMode = ShovelMode.Basic; playerData.shovelMode = ShovelMode.Basic;
playerData.claimSubdividing = null; playerData.claimSubdividing = null;
GriefPrevention.sendMessage(player, TextMode.Success, "Returned to basic claim creation mode."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.BasicClaimsMode);
return true; return true;
} }
@ -1019,7 +1040,8 @@ public class GriefPrevention extends JavaPlugin
PlayerData playerData = this.dataStore.getPlayerData(player.getName()); PlayerData playerData = this.dataStore.getPlayerData(player.getName());
playerData.shovelMode = ShovelMode.Subdivide; playerData.shovelMode = ShovelMode.Subdivide;
playerData.claimSubdividing = null; playerData.claimSubdividing = null;
GriefPrevention.sendMessage(player, TextMode.Instr, "Subdivision mode. Use your shovel to create subdivisions in your existing claims. Use /basicclaims to exit."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.SubdivisionMode);
GriefPrevention.sendMessage(player, TextMode.Instr, Messages.SubdivisionDemo);
return true; return true;
} }
@ -1032,7 +1054,7 @@ public class GriefPrevention extends JavaPlugin
if(claim == null) if(claim == null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "There's no claim here."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.DeleteClaimMissing);
} }
else else
@ -1043,14 +1065,14 @@ public class GriefPrevention extends JavaPlugin
PlayerData playerData = this.dataStore.getPlayerData(player.getName()); PlayerData playerData = this.dataStore.getPlayerData(player.getName());
if(claim.children.size() > 0 && !playerData.warnedAboutMajorDeletion) if(claim.children.size() > 0 && !playerData.warnedAboutMajorDeletion)
{ {
GriefPrevention.sendMessage(player, TextMode.Warn, "This claim includes subdivisions. If you're sure you want to delete it, use /DeleteClaim again."); GriefPrevention.sendMessage(player, TextMode.Warn, Messages.DeletionSubdivisionWarning);
playerData.warnedAboutMajorDeletion = true; playerData.warnedAboutMajorDeletion = true;
} }
else else
{ {
claim.removeSurfaceFluids(null); claim.removeSurfaceFluids(null);
this.dataStore.deleteClaim(claim); this.dataStore.deleteClaim(claim);
GriefPrevention.sendMessage(player, TextMode.Success, "Claim deleted."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.DeleteSuccess);
GriefPrevention.AddLogEntry(player.getName() + " deleted " + claim.getOwnerName() + "'s claim at " + GriefPrevention.getfriendlyLocationString(claim.getLesserBoundaryCorner())); GriefPrevention.AddLogEntry(player.getName() + " deleted " + claim.getOwnerName() + "'s claim at " + GriefPrevention.getfriendlyLocationString(claim.getLesserBoundaryCorner()));
//revert any current visualization //revert any current visualization
@ -1061,7 +1083,7 @@ public class GriefPrevention extends JavaPlugin
} }
else else
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You don't have permission to delete administrative claims."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.CantDeleteAdminClaim);
} }
} }
@ -1069,7 +1091,7 @@ public class GriefPrevention extends JavaPlugin
} }
//deleteallclaims <player> //deleteallclaims <player>
else if(cmd.getName().equalsIgnoreCase("deleteallclaims") && player != null) else if(cmd.getName().equalsIgnoreCase("deleteallclaims"))
{ {
//requires exactly one parameter, the other player's name //requires exactly one parameter, the other player's name
if(args.length != 1) return false; if(args.length != 1) return false;
@ -1078,55 +1100,115 @@ public class GriefPrevention extends JavaPlugin
OfflinePlayer otherPlayer = this.resolvePlayer(args[0]); OfflinePlayer otherPlayer = this.resolvePlayer(args[0]);
if(otherPlayer == null) if(otherPlayer == null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Player not found."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
return true; return true;
} }
//delete all that player's claims //delete all that player's claims
this.dataStore.deleteClaimsForPlayer(otherPlayer.getName(), true); this.dataStore.deleteClaimsForPlayer(otherPlayer.getName(), true);
GriefPrevention.sendMessage(player, TextMode.Success, "Deleted all of " + otherPlayer.getName() + "'s claims."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.DeleteAllSuccess, otherPlayer.getName());
if(player != null)
{
GriefPrevention.AddLogEntry(player.getName() + " deleted all claims belonging to " + otherPlayer.getName() + ".");
//revert any current visualization //revert any current visualization
Visualization.Revert(player); Visualization.Revert(player);
}
return true;
}
//deathblow <player> [recipientPlayer]
else if(cmd.getName().equalsIgnoreCase("deathblow"))
{
//requires at least one parameter, the target player's name
if(args.length < 1) return false;
//try to find that player
Player targetPlayer = this.getServer().getPlayer(args[0]);
if(targetPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
return true;
}
//try to find the recipient player, if specified
Player recipientPlayer = null;
if(args.length > 1)
{
recipientPlayer = this.getServer().getPlayer(args[1]);
if(recipientPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
return true;
}
}
//if giving inventory to another player, teleport the target player to that receiving player
if(recipientPlayer != null)
{
targetPlayer.teleport(recipientPlayer);
}
//otherwise, plan to "pop" the player in place
else
{
//if in a normal world, shoot him up to the sky first, so his items will fall on the surface.
if(targetPlayer.getWorld().getEnvironment() == Environment.NORMAL)
{
Location location = targetPlayer.getLocation();
location.setY(location.getWorld().getMaxHeight());
targetPlayer.teleport(location);
}
}
//kill target player
targetPlayer.setHealth(0);
//log entry
if(player != null)
{
GriefPrevention.AddLogEntry(player.getName() + " used /DeathBlow to kill " + targetPlayer.getName() + ".");
}
else
{
GriefPrevention.AddLogEntry("Killed " + targetPlayer.getName() + ".");
}
return true; return true;
} }
//deletealladminclaims //deletealladminclaims
else if(cmd.getName().equalsIgnoreCase("deletealladminclaims") && player != null) else if(cmd.getName().equalsIgnoreCase("deletealladminclaims"))
{ {
if(!player.hasPermission("griefprevention.deleteclaims")) if(!player.hasPermission("griefprevention.deleteclaims"))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You don't have permission to delete claims."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoDeletePermission);
return true; return true;
} }
//delete all admin claims //delete all admin claims
this.dataStore.deleteClaimsForPlayer("", true); //empty string for owner name indicates an administrative claim this.dataStore.deleteClaimsForPlayer("", true); //empty string for owner name indicates an administrative claim
GriefPrevention.sendMessage(player, TextMode.Success, "Deleted all administrative claims."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.AllAdminDeleted);
if(player != null)
{
GriefPrevention.AddLogEntry(player.getName() + " deleted all administrative claims.");
//revert any current visualization //revert any current visualization
Visualization.Revert(player); Visualization.Revert(player);
}
return true; return true;
} }
//adjustbonusclaimblocks <player> <amount> //adjustbonusclaimblocks <player> <amount> or [<permission>] amount
else if(cmd.getName().equalsIgnoreCase("adjustbonusclaimblocks") && player != null) else if(cmd.getName().equalsIgnoreCase("adjustbonusclaimblocks"))
{ {
//requires exactly two parameters, the other player's name and the adjustment //requires exactly two parameters, the other player or group's name and the adjustment
if(args.length != 2) return false; if(args.length != 2) return false;
//find the specified player
OfflinePlayer targetPlayer = this.resolvePlayer(args[0]);
if(targetPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, "Player \"" + args[0] + "\" not found.");
return true;
}
//parse the adjustment amount //parse the adjustment amount
int adjustment; int adjustment;
try try
@ -1138,13 +1220,33 @@ public class GriefPrevention extends JavaPlugin
return false; //causes usage to be displayed return false; //causes usage to be displayed
} }
//if granting blocks to all players with a specific permission
if(args[0].startsWith("[") && args[0].endsWith("]"))
{
String permissionIdentifier = args[0].substring(1, args[0].length() - 1);
int newTotal = this.dataStore.adjustGroupBonusBlocks(permissionIdentifier, adjustment);
GriefPrevention.sendMessage(player, TextMode.Success, Messages.AdjustGroupBlocksSuccess, permissionIdentifier, String.valueOf(adjustment), String.valueOf(newTotal));
if(player != null) GriefPrevention.AddLogEntry(player.getName() + " adjusted " + permissionIdentifier + "'s bonus claim blocks by " + adjustment + ".");
return true;
}
//otherwise, find the specified player
OfflinePlayer targetPlayer = this.resolvePlayer(args[0]);
if(targetPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
return true;
}
//give blocks to player //give blocks to player
PlayerData playerData = this.dataStore.getPlayerData(targetPlayer.getName()); PlayerData playerData = this.dataStore.getPlayerData(targetPlayer.getName());
playerData.bonusClaimBlocks += adjustment; playerData.bonusClaimBlocks += adjustment;
this.dataStore.savePlayerData(targetPlayer.getName(), playerData); this.dataStore.savePlayerData(targetPlayer.getName(), playerData);
GriefPrevention.sendMessage(player, TextMode.Success, "Adjusted " + targetPlayer.getName() + "'s bonus claim blocks by " + adjustment + ". New total bonus blocks: " + playerData.bonusClaimBlocks + "."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.AdjustBlocksSuccess, targetPlayer.getName(), String.valueOf(adjustment), String.valueOf(playerData.bonusClaimBlocks));
GriefPrevention.AddLogEntry(player.getName() + " adjusted " + targetPlayer.getName() + "'s bonus claim blocks by " + adjustment + "."); if(player != null) GriefPrevention.AddLogEntry(player.getName() + " adjusted " + targetPlayer.getName() + "'s bonus claim blocks by " + adjustment + ".");
return true; return true;
} }
@ -1166,7 +1268,7 @@ public class GriefPrevention extends JavaPlugin
//if the player isn't in a claim or has permission to build, tell him to man up //if the player isn't in a claim or has permission to build, tell him to man up
if(claim == null || claim.allowBuild(player) == null) if(claim == null || claim.allowBuild(player) == null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can build here. Save yourself."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NotTrappedHere);
return true; return true;
} }
@ -1176,12 +1278,12 @@ public class GriefPrevention extends JavaPlugin
long now = Calendar.getInstance().getTimeInMillis(); long now = Calendar.getInstance().getTimeInMillis();
if(now < nextTrappedUsage) if(now < nextTrappedUsage)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You used /trapped within the last " + this.config_claims_trappedCooldownHours + " hours. You have to wait about " + ((nextTrappedUsage - now) / (1000 * 60) + 1) + " more minutes before using it again."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.TrappedOnCooldown, String.valueOf(this.config_claims_trappedCooldownHours), String.valueOf((nextTrappedUsage - now) / (1000 * 60) + 1));
return true; return true;
} }
//send instructions //send instructions
GriefPrevention.sendMessage(player, TextMode.Instr, "If you stay put for 10 seconds, you'll be teleported out. Please wait."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.RescuePending);
//create a task to rescue this player in a little while //create a task to rescue this player in a little while
PlayerRescueTask task = new PlayerRescueTask(player, player.getLocation()); PlayerRescueTask task = new PlayerRescueTask(player, player.getLocation());
@ -1196,7 +1298,7 @@ public class GriefPrevention extends JavaPlugin
//error message for when siege mode is disabled //error message for when siege mode is disabled
if(!this.siegeEnabledForWorld(player.getWorld())) if(!this.siegeEnabledForWorld(player.getWorld()))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Siege is disabled here."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NonSiegeWorld);
return true; return true;
} }
@ -1211,7 +1313,7 @@ public class GriefPrevention extends JavaPlugin
PlayerData attackerData = this.dataStore.getPlayerData(attacker.getName()); PlayerData attackerData = this.dataStore.getPlayerData(attacker.getName());
if(attackerData.siegeData != null) if(attackerData.siegeData != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You're already involved in a siege."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.AlreadySieging);
return true; return true;
} }
@ -1222,7 +1324,7 @@ public class GriefPrevention extends JavaPlugin
defender = this.getServer().getPlayer(args[0]); defender = this.getServer().getPlayer(args[0]);
if(defender == null) if(defender == null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Player not found."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
return true; return true;
} }
} }
@ -1246,14 +1348,14 @@ public class GriefPrevention extends JavaPlugin
PlayerData defenderData = this.dataStore.getPlayerData(defender.getName()); PlayerData defenderData = this.dataStore.getPlayerData(defender.getName());
if(defenderData.siegeData != null) if(defenderData.siegeData != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, defender.getName() + " is already under siege. Join the party!"); GriefPrevention.sendMessage(player, TextMode.Err, Messages.AlreadyUnderSiegePlayer);
return true; return true;
} }
//victim must not be pvp immune //victim must not be pvp immune
if(defenderData.pvpImmune) if(defenderData.pvpImmune)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, defender.getName() + " is defenseless. Go pick on somebody else."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoSiegeDefenseless);
return true; return true;
} }
@ -1262,35 +1364,35 @@ public class GriefPrevention extends JavaPlugin
//defender must have some level of permission there to be protected //defender must have some level of permission there to be protected
if(defenderClaim == null || defenderClaim.allowAccess(defender) != null) if(defenderClaim == null || defenderClaim.allowAccess(defender) != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, defender.getName() + " isn't protected there."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NotSiegableThere);
return true; return true;
} }
//attacker must be close to the claim he wants to siege //attacker must be close to the claim he wants to siege
if(!defenderClaim.isNear(attacker.getLocation(), 25)) if(!defenderClaim.isNear(attacker.getLocation(), 25))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You're too far away from " + defender.getName() + " to siege."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeTooFarAway);
return true; return true;
} }
//claim can't be under siege already //claim can't be under siege already
if(defenderClaim.siegeData != null) if(defenderClaim.siegeData != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "That area is already under siege. Join the party!"); GriefPrevention.sendMessage(player, TextMode.Err, Messages.AlreadyUnderSiegeArea);
return true; return true;
} }
//can't siege admin claims //can't siege admin claims
if(defenderClaim.isAdminClaim()) if(defenderClaim.isAdminClaim())
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Siege is disabled in this area."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoSiegeAdminClaim);
return true; return true;
} }
//can't be on cooldown //can't be on cooldown
if(dataStore.onCooldown(attacker, defender, defenderClaim)) if(dataStore.onCooldown(attacker, defender, defenderClaim))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You're still on siege cooldown for this defender or claim. Find another victim."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeOnCooldown);
return true; return true;
} }
@ -1298,8 +1400,8 @@ public class GriefPrevention extends JavaPlugin
dataStore.startSiege(attacker, defender, defenderClaim); dataStore.startSiege(attacker, defender, defenderClaim);
//confirmation message for attacker, warning message for defender //confirmation message for attacker, warning message for defender
GriefPrevention.sendMessage(defender, TextMode.Warn, "You're under siege! If you log out now, you will die. You must defeat " + attacker.getName() + ", wait for him to give up, or escape."); GriefPrevention.sendMessage(defender, TextMode.Warn, Messages.SiegeAlert, attacker.getName());
GriefPrevention.sendMessage(player, TextMode.Success, "The siege has begun! If you log out now, you will die. You must defeat " + defender.getName() + ", chase him away, or admit defeat and walk away."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.SiegeConfirmed, defender.getName());
} }
return false; return false;
@ -1312,31 +1414,41 @@ public class GriefPrevention extends JavaPlugin
private boolean abandonClaimHandler(Player player, boolean deleteTopLevelClaim) private boolean abandonClaimHandler(Player player, boolean deleteTopLevelClaim)
{ {
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
//which claim is being abandoned? //which claim is being abandoned?
Claim claim = this.dataStore.getClaimAt(player.getLocation(), true /*ignore height*/, null); Claim claim = this.dataStore.getClaimAt(player.getLocation(), true /*ignore height*/, null);
if(claim == null) if(claim == null)
{ {
GriefPrevention.sendMessage(player, TextMode.Instr, "Stand in the claim you want to delete, or consider /AbandonAllClaims."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.AbandonClaimMissing);
}
else if(this.creativeRulesApply(player.getLocation()))
{
GriefPrevention.sendMessage(player, TextMode.Err, "Creative-mode claims can't be abandoned.");
} }
//verify ownership //verify ownership
else if(claim.allowEdit(player) != null) else if(claim.allowEdit(player) != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "This isn't your claim."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NotYourClaim);
}
//don't allow abandon of creative mode claims
else if(this.creativeRulesApply(player.getLocation()))
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoCreativeUnClaim);
} }
//warn if has children and we're not explicitly deleting a top level claim //warn if has children and we're not explicitly deleting a top level claim
else if(claim.children.size() > 0 && !deleteTopLevelClaim) else if(claim.children.size() > 0 && !deleteTopLevelClaim)
{ {
GriefPrevention.sendMessage(player, TextMode.Instr, "To delete a subdivision, stand inside it. Otherwise, use /AbandonTopLevelClaim to delete this claim and all subdivisions."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.DeleteTopLevelClaim);
return true; return true;
} }
//if the claim has lots of surface water or some surface lava, warn the player it will be cleaned up
else if(!playerData.warnedAboutMajorDeletion && claim.hasSurfaceFluids())
{
GriefPrevention.sendMessage(player, TextMode.Warn, Messages.ConfirmFluidRemoval);
playerData.warnedAboutMajorDeletion = true;
}
else else
{ {
//delete it //delete it
@ -1344,12 +1456,13 @@ public class GriefPrevention extends JavaPlugin
this.dataStore.deleteClaim(claim); this.dataStore.deleteClaim(claim);
//tell the player how many claim blocks he has left //tell the player how many claim blocks he has left
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
int remainingBlocks = playerData.getRemainingClaimBlocks(); int remainingBlocks = playerData.getRemainingClaimBlocks();
GriefPrevention.sendMessage(player, TextMode.Success, "Claim abandoned. You now have " + String.valueOf(remainingBlocks) + " available claim blocks."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.AbandonSuccess, String.valueOf(remainingBlocks));
//revert any current visualization //revert any current visualization
Visualization.Revert(player); Visualization.Revert(player);
playerData.warnedAboutMajorDeletion = false;
} }
return true; return true;
@ -1362,21 +1475,36 @@ public class GriefPrevention extends JavaPlugin
//determine which claim the player is standing in //determine which claim the player is standing in
Claim claim = this.dataStore.getClaimAt(player.getLocation(), true /*ignore height*/, null); Claim claim = this.dataStore.getClaimAt(player.getLocation(), true /*ignore height*/, null);
//validate player argument //validate player or group argument
OfflinePlayer otherPlayer = this.resolvePlayer(recipientName); String permission = null;
if(otherPlayer == null && !recipientName.equals("public")) OfflinePlayer otherPlayer = null;
if(recipientName.startsWith("[") && recipientName.endsWith("]"))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Player not found."); permission = recipientName.substring(1, recipientName.length() - 1);
return; if(permission == null || permission.isEmpty())
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.InvalidPermissionID);
return;
}
} }
if(otherPlayer != null)
{
recipientName = otherPlayer.getName();
}
else else
{ {
recipientName = "public"; otherPlayer = this.resolvePlayer(recipientName);
if(otherPlayer == null && !recipientName.equals("public"))
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
return;
}
if(otherPlayer != null)
{
recipientName = otherPlayer.getName();
}
else
{
recipientName = "public";
}
} }
//determine which claims should be modified //determine which claims should be modified
@ -1394,7 +1522,7 @@ public class GriefPrevention extends JavaPlugin
//check permission here //check permission here
if(claim.allowGrantPermission(player) != null) if(claim.allowGrantPermission(player) != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You don't have " + claim.getOwnerName() + "'s permission to grant permissions here."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoPermissionTrust, claim.getOwnerName());
return; return;
} }
@ -1430,7 +1558,7 @@ public class GriefPrevention extends JavaPlugin
//error message for trying to grant a permission the player doesn't have //error message for trying to grant a permission the player doesn't have
if(errorMessage != null) if(errorMessage != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, errorMessage + " You can't grant a permission you don't have yourself."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.CantGrantThatPermission);
return; return;
} }
@ -1440,7 +1568,7 @@ public class GriefPrevention extends JavaPlugin
//if we didn't determine which claims to modify, tell the player to be specific //if we didn't determine which claims to modify, tell the player to be specific
if(targetClaims.size() == 0) if(targetClaims.size() == 0)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Stand inside the claim where you want to grant permission."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.GrantPermissionNoClaim);
return; return;
} }
@ -1463,36 +1591,36 @@ public class GriefPrevention extends JavaPlugin
} }
//notify player //notify player
if(recipientName.equals("public")) recipientName = "the public"; if(recipientName.equals("public")) recipientName = this.dataStore.getMessage(Messages.CollectivePublic);
StringBuilder resultString = new StringBuilder(); String permissionDescription;
resultString.append("Granted " + recipientName + " ");
if(permissionLevel == null) if(permissionLevel == null)
{ {
resultString.append("manager status"); permissionDescription = this.dataStore.getMessage(Messages.PermissionsPermission);
} }
else if(permissionLevel == ClaimPermission.Build) else if(permissionLevel == ClaimPermission.Build)
{ {
resultString.append("permission to build in"); permissionDescription = this.dataStore.getMessage(Messages.BuildPermission);
} }
else if(permissionLevel == ClaimPermission.Access) else if(permissionLevel == ClaimPermission.Access)
{ {
resultString.append("permission to use buttons and levers in"); permissionDescription = this.dataStore.getMessage(Messages.AccessPermission);
} }
else if(permissionLevel == ClaimPermission.Inventory) else //ClaimPermission.Inventory
{ {
resultString.append("permission to access containers in"); permissionDescription = this.dataStore.getMessage(Messages.ContainersPermission);
} }
String location;
if(claim == null) if(claim == null)
{ {
resultString.append(" ALL your claims. To modify only one claim, stand inside it."); location = this.dataStore.getMessage(Messages.LocationAllClaims);
} }
else else
{ {
resultString.append(" this claim. To modify ALL your claims, stand outside them."); location = this.dataStore.getMessage(Messages.LocationCurrentClaim);
} }
GriefPrevention.sendMessage(player, TextMode.Success, resultString.toString()); GriefPrevention.sendMessage(player, TextMode.Success, Messages.GrantPermissionConfirmation, recipientName, permissionDescription, location);
} }
//helper method to resolve a player by name //helper method to resolve a player by name
@ -1552,7 +1680,7 @@ public class GriefPrevention extends JavaPlugin
playerData.pvpImmune = true; playerData.pvpImmune = true;
//inform the player //inform the player
GriefPrevention.sendMessage(player, TextMode.Success, "You're protected from attack by other players as long as your inventory is empty."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.PvPImmunityStart);
} }
//checks whether players can create claims in a world //checks whether players can create claims in a world
@ -1797,10 +1925,24 @@ public class GriefPrevention extends JavaPlugin
while(!chunk.isLoaded() || !chunk.load(true)); while(!chunk.isLoaded() || !chunk.load(true));
} }
//sends a color-coded message to a player
static void sendMessage(Player player, ChatColor color, Messages messageID, String... args)
{
String message = GriefPrevention.instance.dataStore.getMessage(messageID, args);
sendMessage(player, color, message);
}
//sends a color-coded message to a player //sends a color-coded message to a player
static void sendMessage(Player player, ChatColor color, String message) static void sendMessage(Player player, ChatColor color, String message)
{ {
player.sendMessage(color + message); if(player == null)
{
GriefPrevention.AddLogEntry(color + message);
}
else
{
player.sendMessage(color + message);
}
} }
//determines whether creative anti-grief rules apply at a location //determines whether creative anti-grief rules apply at a location
@ -1825,19 +1967,20 @@ public class GriefPrevention extends JavaPlugin
return "You can't build here. Use the golden shovel to claim some land first."; return "You can't build here. Use the golden shovel to claim some land first.";
} }
//but it's fine in survival mode
else else
{ {
//cache the claim for later reference //but it's fine in survival mode
playerData.lastClaim = claim;
return null; return null;
} }
} }
//if not in the wilderness, then apply claim rules (permissions, etc) //if not in the wilderness, then apply claim rules (permissions, etc)
return claim.allowBuild(player); else
{
//cache the claim for later reference
playerData.lastClaim = claim;
return claim.allowBuild(player);
}
} }
public String allowBreak(Player player, Location location) public String allowBreak(Player player, Location location)
@ -1854,20 +1997,22 @@ public class GriefPrevention extends JavaPlugin
//exception: administrators in ignore claims mode //exception: administrators in ignore claims mode
if(playerData.ignoreClaims) return null; if(playerData.ignoreClaims) return null;
return "You can't build here. Use the golden shovel to claim some land first."; return "You can only build where you have claimed land. To claim, watch this: http://tinyurl.com/c7bajb8";
} }
//but it's fine in survival mode //but it's fine in survival mode
else else
{ {
//cache the claim for later reference
playerData.lastClaim = claim;
return null; return null;
} }
} }
else
{
//cache the claim for later reference
playerData.lastClaim = claim;
//if not in the wilderness, then apply claim rules (permissions, etc) //if not in the wilderness, then apply claim rules (permissions, etc)
return claim.allowBreak(player, location.getBlock().getType()); return claim.allowBreak(player, location.getBlock().getType());
}
} }
} }

View File

@ -2,5 +2,5 @@ package me.ryanhamshire.GriefPrevention;
public enum Messages public enum Messages
{ {
RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionDemo, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, TrappedOnCooldown, RescuePending, NonSiegeWorld, AlreadySieging, NotSiegableThere, SiegeTooFarAway, NoSiegeDefenseless, AlreadyUnderSiegePlayer, AlreadyUnderSiegeArea, NoSiegeAdminClaim, SiegeOnCooldown, SiegeAlert, SiegeConfirmed, AbandonClaimMissing, NotYourClaim, DeleteTopLevelClaim, AbandonSuccess, CantGrantThatPermission, GrantPermissionNoClaim, GrantPermissionConfirmation, ManageUniversalPermissionsInstruction, ManageOneClaimPermissionsInstruction, CollectivePublic, BuildPermission, ContainersPermission, AccessPermission, PermissionsPermission, LocationCurrentClaim, LocationAllClaims, PvPImmunityStart, SiegeNoDrop, DonateItemsInstruction, ChestFull, DonationSuccess, PlayerTooCloseForFire, TooDeepToClaim, ChestClaimConfirmation, AutomaticClaimNotification, TrustCommandAdvertisement, GoldenShovelAdvertisement, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsDemoAdvertisement, SurvivalBasicsDemoAdvertisement, TrappedChatKeyword, TrappedInstructions, PvPNoDrop, SiegeNoTeleport, BesiegedNoTeleport, SiegeNoContainers, PvPNoContainers, PvPImmunityEnd, NoBedPermission, NoWildernessBuckets, NoLavaNearOtherPlayer, TooFarAway, BlockNotClaimed, BlockClaimed, SiegeNoShovel, RestoreNaturePlayerInChunk, NoCreateClaimPermission, ResizeClaimTooSmall, ResizeNeedMoreBlocks, NoCreativeUnClaim, ClaimResizeSuccess, ResizeFailOverlap, ResizeStart, ResizeFailOverlapSubdivision, SubdivisionStart, CreateSubdivisionOverlap, SubdivisionSuccess, CreateClaimFailOverlap, CreateClaimFailOverlapOtherPlayer, ClaimsDisabledWorld, ClaimStart, NewClaimTooSmall, CreateClaimInsufficientBlocks, AbandonClaimAdvertisement, CreateClaimFailOverlapShort, CreateClaimSuccess, SiegeWinDoorsOpen, RescueAbortedMoved, SiegeDoorsLockedEjection, NoModifyDuringSiege, OnlyOwnersModifyClaims, NoBuildUnderSiege, NoBuildPvP, NoBuildPermission, NonSiegeMaterial, NoOwnerBuildUnderSiege, NoAccessPermission, NoContainersSiege, NoContainersPermission, OwnerNameForAdminClaims, ClaimTooSmallForEntities, TooManyEntitiesInClaim, YouHaveNoClaims, ConfirmFluidRemoval, AutoBanNotify RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionDemo, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, TrappedOnCooldown, RescuePending, NonSiegeWorld, AlreadySieging, NotSiegableThere, SiegeTooFarAway, NoSiegeDefenseless, AlreadyUnderSiegePlayer, AlreadyUnderSiegeArea, NoSiegeAdminClaim, SiegeOnCooldown, SiegeAlert, SiegeConfirmed, AbandonClaimMissing, NotYourClaim, DeleteTopLevelClaim, AbandonSuccess, CantGrantThatPermission, GrantPermissionNoClaim, GrantPermissionConfirmation, ManageUniversalPermissionsInstruction, ManageOneClaimPermissionsInstruction, CollectivePublic, BuildPermission, ContainersPermission, AccessPermission, PermissionsPermission, LocationCurrentClaim, LocationAllClaims, PvPImmunityStart, SiegeNoDrop, DonateItemsInstruction, ChestFull, DonationSuccess, PlayerTooCloseForFire, TooDeepToClaim, ChestClaimConfirmation, AutomaticClaimNotification, TrustCommandAdvertisement, GoldenShovelAdvertisement, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsDemoAdvertisement, SurvivalBasicsDemoAdvertisement, TrappedChatKeyword, TrappedInstructions, PvPNoDrop, SiegeNoTeleport, BesiegedNoTeleport, SiegeNoContainers, PvPNoContainers, PvPImmunityEnd, NoBedPermission, NoWildernessBuckets, NoLavaNearOtherPlayer, TooFarAway, BlockNotClaimed, BlockClaimed, SiegeNoShovel, RestoreNaturePlayerInChunk, NoCreateClaimPermission, ResizeClaimTooSmall, ResizeNeedMoreBlocks, NoCreativeUnClaim, ClaimResizeSuccess, ResizeFailOverlap, ResizeStart, ResizeFailOverlapSubdivision, SubdivisionStart, CreateSubdivisionOverlap, SubdivisionSuccess, CreateClaimFailOverlap, CreateClaimFailOverlapOtherPlayer, ClaimsDisabledWorld, ClaimStart, NewClaimTooSmall, CreateClaimInsufficientBlocks, AbandonClaimAdvertisement, CreateClaimFailOverlapShort, CreateClaimSuccess, SiegeWinDoorsOpen, RescueAbortedMoved, SiegeDoorsLockedEjection, NoModifyDuringSiege, OnlyOwnersModifyClaims, NoBuildUnderSiege, NoBuildPvP, NoBuildPermission, NonSiegeMaterial, NoOwnerBuildUnderSiege, NoAccessPermission, NoContainersSiege, NoContainersPermission, OwnerNameForAdminClaims, ClaimTooSmallForEntities, TooManyEntitiesInClaim, YouHaveNoClaims, ConfirmFluidRemoval, AutoBanNotify, AdjustGroupBlocksSuccess, InvalidPermissionID, UntrustOwnerOnly
} }

View File

@ -27,6 +27,9 @@ import org.bukkit.Location;
//holds all of GriefPrevention's player-tied data //holds all of GriefPrevention's player-tied data
public class PlayerData public class PlayerData
{ {
//the player's name
public String playerName;
//the player's claims //the player's claims
public Vector<Claim> claims = new Vector<Claim>(); public Vector<Claim> claims = new Vector<Claim>();
@ -71,9 +74,6 @@ public class PlayerData
public int spamCount = 0; //number of consecutive "spams" public int spamCount = 0; //number of consecutive "spams"
public boolean spamWarned = false; //whether the player recently received a warning public boolean spamWarned = false; //whether the player recently received a warning
//last logout timestamp, default to long enough to trigger a join message, see player join event
public long lastLogout = Calendar.getInstance().getTimeInMillis() - GriefPrevention.NOTIFICATION_SECONDS * 2000;
//visualization //visualization
public Visualization currentVisualization = null; public Visualization currentVisualization = null;
@ -138,6 +138,9 @@ public class PlayerData
remainingBlocks -= claim.getArea(); remainingBlocks -= claim.getArea();
} }
//add any blocks this player might have based on group membership (permissions)
remainingBlocks += GriefPrevention.instance.dataStore.getGroupBonusBlocks(this.playerName);
return remainingBlocks; return remainingBlocks;
} }
} }

View File

@ -20,6 +20,7 @@ package me.ryanhamshire.GriefPrevention;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -59,6 +60,9 @@ class PlayerEventHandler implements Listener
//number of milliseconds in a day //number of milliseconds in a day
private final long MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24; private final long MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24;
//timestamps of login and logout notifications in the last minute
private ArrayList<Long> recentLoginLogoutNotifications = new ArrayList<Long>();
//typical constructor, yawn //typical constructor, yawn
PlayerEventHandler(DataStore dataStore, GriefPrevention plugin) PlayerEventHandler(DataStore dataStore, GriefPrevention plugin)
{ {
@ -75,9 +79,9 @@ class PlayerEventHandler implements Listener
//FEATURE: automatically educate players about the /trapped command //FEATURE: automatically educate players about the /trapped command
//check for "trapped" or "stuck" to educate players about the /trapped command //check for "trapped" or "stuck" to educate players about the /trapped command
if(message.contains("trapped") || message.contains("stuck")) if(message.contains("trapped") || message.contains("stuck") || message.contains(this.dataStore.getMessage(Messages.TrappedChatKeyword)))
{ {
GriefPrevention.sendMessage(player, TextMode.Info, "Are you trapped in someone's claim? Consider the /trapped command."); GriefPrevention.sendMessage(player, TextMode.Info, Messages.TrappedInstructions);
} }
//FEATURE: monitor for chat and command spam //FEATURE: monitor for chat and command spam
@ -101,8 +105,27 @@ class PlayerEventHandler implements Listener
boolean spam = false; boolean spam = false;
boolean muted = false; boolean muted = false;
//check message content and timing
long millisecondsSinceLastMessage = (new Date()).getTime() - playerData.lastMessageTimestamp.getTime();
//if the message came too close to the last one
if(millisecondsSinceLastMessage < 3000)
{
//increment the spam counter
playerData.spamCount++;
spam = true;
}
//if it's very similar to the last message
if(!muted && this.stringsAreSimilar(message, playerData.lastMessage))
{
playerData.spamCount++;
spam = true;
muted = true;
}
//filter IP addresses //filter IP addresses
if(!(event instanceof PlayerCommandPreprocessEvent)) if(!muted && !(event instanceof PlayerCommandPreprocessEvent))
{ {
Pattern ipAddressPattern = Pattern.compile("\\d+\\.\\d+\\.\\d+\\.\\d+"); Pattern ipAddressPattern = Pattern.compile("\\d+\\.\\d+\\.\\d+\\.\\d+");
Matcher matcher = ipAddressPattern.matcher(event.getMessage()); Matcher matcher = ipAddressPattern.matcher(event.getMessage());
@ -126,27 +149,8 @@ class PlayerEventHandler implements Listener
} }
} }
//check message content and timing
long millisecondsSinceLastMessage = (new Date()).getTime() - playerData.lastMessageTimestamp.getTime();
//if the message came too close to the last one
if(millisecondsSinceLastMessage < 3000)
{
//increment the spam counter
playerData.spamCount++;
spam = true;
}
//if it's very similar to the last message
if(this.stringsAreSimilar(message, playerData.lastMessage))
{
playerData.spamCount++;
spam = true;
muted = true;
}
//if the message was mostly non-alpha-numerics or doesn't include much whitespace, consider it a spam (probably ansi art or random text gibberish) //if the message was mostly non-alpha-numerics or doesn't include much whitespace, consider it a spam (probably ansi art or random text gibberish)
if(message.length() > 5) if(!muted && message.length() > 5)
{ {
int symbolsCount = 0; int symbolsCount = 0;
int whitespaceCount = 0; int whitespaceCount = 0;
@ -167,6 +171,7 @@ class PlayerEventHandler implements Listener
if(symbolsCount > message.length() / 2 || (message.length() > 15 && whitespaceCount < message.length() / 10)) if(symbolsCount > message.length() / 2 || (message.length() > 15 && whitespaceCount < message.length() / 10))
{ {
spam = true; spam = true;
if(playerData.spamCount > 0) muted = true;
playerData.spamCount++; playerData.spamCount++;
} }
} }
@ -347,7 +352,7 @@ class PlayerEventHandler implements Listener
playerData.ipAddress = event.getAddress(); playerData.ipAddress = event.getAddress();
//FEATURE: auto-ban accounts who use an IP address which was very recently used by another banned account //FEATURE: auto-ban accounts who use an IP address which was very recently used by another banned account
if(GriefPrevention.instance.config_smartBan) if(GriefPrevention.instance.config_smartBan && !player.hasPlayedBefore())
{ {
//if logging-in account is banned, remember IP address for later //if logging-in account is banned, remember IP address for later
long now = Calendar.getInstance().getTimeInMillis(); long now = Calendar.getInstance().getTimeInMillis();
@ -399,6 +404,16 @@ class PlayerEventHandler implements Listener
event.setResult(Result.KICK_BANNED); event.setResult(Result.KICK_BANNED);
event.disallow(event.getResult(), ""); event.disallow(event.getResult(), "");
GriefPrevention.AddLogEntry("Auto-banned " + player.getName() + " because that account is using an IP address very recently used by banned player " + info.bannedAccountName + " (" + info.address.toString() + ")."); GriefPrevention.AddLogEntry("Auto-banned " + player.getName() + " because that account is using an IP address very recently used by banned player " + info.bannedAccountName + " (" + info.address.toString() + ").");
//notify any online ops
Player [] players = GriefPrevention.instance.getServer().getOnlinePlayers();
for(int k = 0; k < players.length; k++)
{
if(players[k].isOp())
{
GriefPrevention.sendMessage(players[k], TextMode.Success, Messages.AutoBanNotify, player.getName(), info.bannedAccountName);
}
}
} }
} }
} }
@ -430,42 +445,34 @@ class PlayerEventHandler implements Listener
//check inventory, may need pvp protection //check inventory, may need pvp protection
GriefPrevention.instance.checkPvpProtectionNeeded(event.getPlayer()); GriefPrevention.instance.checkPvpProtectionNeeded(event.getPlayer());
//how long since the last logout? //silence notifications when they're coming too fast
long elapsed = Calendar.getInstance().getTimeInMillis() - playerData.lastLogout; if(event.getJoinMessage() != null && this.shouldSilenceNotification())
//remember message, then silence it. may broadcast it later
String message = event.getJoinMessage();
event.setJoinMessage(null);
if(message != null && elapsed >= GriefPrevention.NOTIFICATION_SECONDS * 1000)
{ {
//start a timer for a delayed join notification message (will only show if player is still online in 30 seconds) event.setJoinMessage(null);
JoinLeaveAnnouncementTask task = new JoinLeaveAnnouncementTask(event.getPlayer(), message, true);
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task, 20L * GriefPrevention.NOTIFICATION_SECONDS);
} }
} }
//when a player quits...
@EventHandler(priority = EventPriority.HIGHEST)
void onPlayerKicked(PlayerKickEvent event)
{
Player player = event.getPlayer();
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
if(player.isBanned())
{
long now = Calendar.getInstance().getTimeInMillis();
this.tempBannedIps.add(new IpBanInfo(playerData.ipAddress, now + this.MILLISECONDS_IN_DAY, player.getName()));
}
}
//when a player quits... //when a player quits...
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
void onPlayerQuit(PlayerQuitEvent event) void onPlayerQuit(PlayerQuitEvent event)
{ {
this.onPlayerDisconnect(event.getPlayer(), event.getQuitMessage()); Player player = event.getPlayer();
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
//silence the leave message (may be broadcast later, if the player stays offline) //if banned, add IP to the temporary IP ban list
event.setQuitMessage(null); if(player.isBanned())
{
long now = Calendar.getInstance().getTimeInMillis();
this.tempBannedIps.add(new IpBanInfo(playerData.ipAddress, now + this.MILLISECONDS_IN_DAY, player.getName()));
}
//silence notifications when they're coming too fast
if(event.getQuitMessage() != null && this.shouldSilenceNotification())
{
event.setQuitMessage(null);
}
this.onPlayerDisconnect(event.getPlayer(), event.getQuitMessage());
} }
//helper for above //helper for above
@ -487,21 +494,33 @@ class PlayerEventHandler implements Listener
{ {
if(player.getHealth() > 0) player.setHealth(0); //might already be zero from above, this avoids a double death message if(player.getHealth() > 0) player.setHealth(0); //might already be zero from above, this avoids a double death message
} }
}
//determines whether or not a login or logout notification should be silenced, depending on how many there have been in the last minute
private boolean shouldSilenceNotification()
{
final long ONE_MINUTE = 60000;
final int MAX_ALLOWED = 20;
Long now = Calendar.getInstance().getTimeInMillis();
//how long was the player online? //eliminate any expired entries (longer than a minute ago)
long now = Calendar.getInstance().getTimeInMillis(); for(int i = 0; i < this.recentLoginLogoutNotifications.size(); i++)
long elapsed = now - playerData.lastLogin.getTime();
//remember logout time
playerData.lastLogout = Calendar.getInstance().getTimeInMillis();
//if notification message isn't null and the player has been online for at least 30 seconds...
if(notificationMessage != null && elapsed >= 1000 * GriefPrevention.NOTIFICATION_SECONDS)
{ {
//start a timer for a delayed leave notification message (will only show if player is still offline in 30 seconds) Long notificationTimestamp = this.recentLoginLogoutNotifications.get(i);
JoinLeaveAnnouncementTask task = new JoinLeaveAnnouncementTask(player, notificationMessage, false); if(now - notificationTimestamp > ONE_MINUTE)
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task, 20L * GriefPrevention.NOTIFICATION_SECONDS); {
this.recentLoginLogoutNotifications.remove(i--);
}
else
{
break;
}
} }
//add the new entry
this.recentLoginLogoutNotifications.add(now);
return this.recentLoginLogoutNotifications.size() > MAX_ALLOWED;
} }
//when a player drops an item //when a player drops an item
@ -525,14 +544,14 @@ class PlayerEventHandler implements Listener
//if in combat, don't let him drop it //if in combat, don't let him drop it
if(!GriefPrevention.instance.config_pvp_allowCombatItemDrop && playerData.inPvpCombat()) if(!GriefPrevention.instance.config_pvp_allowCombatItemDrop && playerData.inPvpCombat())
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't drop items while in PvP combat."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.PvPNoDrop);
event.setCancelled(true); event.setCancelled(true);
} }
//if he's under siege, don't let him drop it //if he's under siege, don't let him drop it
else if(playerData.siegeData != null) else if(playerData.siegeData != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't drop items while involved in a siege."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeNoDrop);
event.setCancelled(true); event.setCancelled(true);
} }
} }
@ -552,7 +571,7 @@ class PlayerEventHandler implements Listener
Claim sourceClaim = this.dataStore.getClaimAt(source, false, null); Claim sourceClaim = this.dataStore.getClaimAt(source, false, null);
if(sourceClaim != null && sourceClaim.siegeData != null) if(sourceClaim != null && sourceClaim.siegeData != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't teleport out of a besieged area."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeNoTeleport);
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
@ -561,7 +580,7 @@ class PlayerEventHandler implements Listener
Claim destinationClaim = this.dataStore.getClaimAt(destination, false, null); Claim destinationClaim = this.dataStore.getClaimAt(destination, false, null);
if(destinationClaim != null && destinationClaim.siegeData != null) if(destinationClaim != null && destinationClaim.siegeData != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't teleport into a besieged area."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.BesiegedNoTeleport);
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
@ -580,14 +599,14 @@ class PlayerEventHandler implements Listener
{ {
if(playerData.siegeData != null) if(playerData.siegeData != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't access containers while under siege."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeNoContainers);
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
if(playerData.inPvpCombat()) if(playerData.inPvpCombat())
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't access containers during PvP combat."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.PvPNoContainers);
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
@ -627,7 +646,7 @@ class PlayerEventHandler implements Listener
{ {
if(claim.allowContainers(player) != null) if(claim.allowContainers(player) != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "That animal belongs to " + claim.getOwnerName() + "."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoDamageClaimedEntity);
event.setCancelled(true); event.setCancelled(true);
} }
} }
@ -661,7 +680,7 @@ class PlayerEventHandler implements Listener
//otherwise take away his immunity. he may be armed now. at least, he's worth killing for some loot //otherwise take away his immunity. he may be armed now. at least, he's worth killing for some loot
playerData.pvpImmune = false; playerData.pvpImmune = false;
GriefPrevention.sendMessage(player, TextMode.Warn, "Now you can fight with other players."); GriefPrevention.sendMessage(player, TextMode.Warn, Messages.PvPImmunityEnd);
} }
} }
} }
@ -698,7 +717,7 @@ class PlayerEventHandler implements Listener
if(claim.allowAccess(player) != null) if(claim.allowAccess(player) != null)
{ {
bedEvent.setCancelled(true); bedEvent.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, claim.getOwnerName() + " hasn't given you permission to sleep here."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoBedPermission, claim.getOwnerName());
} }
} }
} }
@ -727,15 +746,18 @@ class PlayerEventHandler implements Listener
minLavaDistance = 3; minLavaDistance = 3;
} }
//otherwise no dumping anything unless underground //otherwise no wilderness dumping (unless underground) in worlds where claims are enabled
else else if(GriefPrevention.instance.config_claims_enabledWorlds.contains(block.getWorld()))
{ {
if(block.getY() >= block.getWorld().getSeaLevel() - 5 && !player.hasPermission("griefprevention.lava")) if(block.getY() >= block.getWorld().getSeaLevel() - 5 && !player.hasPermission("griefprevention.lava"))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You may only dump buckets inside your claim(s) or underground."); if(bucketEvent.getBucket() == Material.LAVA_BUCKET || GriefPrevention.instance.config_blockWildernessWaterBuckets)
bucketEvent.setCancelled(true); {
return; GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoWildernessBuckets);
} bucketEvent.setCancelled(true);
return;
}
}
} }
//lava buckets can't be dumped near other players unless pvp is on //lava buckets can't be dumped near other players unless pvp is on
@ -750,7 +772,7 @@ class PlayerEventHandler implements Listener
Location location = otherPlayer.getLocation(); Location location = otherPlayer.getLocation();
if(!otherPlayer.equals(player) && block.getY() >= location.getBlockY() - 1 && location.distanceSquared(block.getLocation()) < minLavaDistance * minLavaDistance) if(!otherPlayer.equals(player) && block.getY() >= location.getBlockY() - 1 && location.distanceSquared(block.getLocation()) < minLavaDistance * minLavaDistance)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't place lava this close to " + otherPlayer.getName() + "."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoLavaNearOtherPlayer, otherPlayer.getName());
bucketEvent.setCancelled(true); bucketEvent.setCancelled(true);
return; return;
} }
@ -791,6 +813,9 @@ class PlayerEventHandler implements Listener
if(clickedBlock == null) if(clickedBlock == null)
{ {
//try to find a far away non-air block along line of sight //try to find a far away non-air block along line of sight
HashSet<Byte> transparentMaterials = new HashSet<Byte>();
transparentMaterials.add(Byte.valueOf((byte)Material.AIR.getId()));
transparentMaterials.add(Byte.valueOf((byte)Material.SNOW.getId()));
clickedBlock = player.getTargetBlock(null, 250); clickedBlock = player.getTargetBlock(null, 250);
} }
} }
@ -807,23 +832,8 @@ class PlayerEventHandler implements Listener
Material clickedBlockType = clickedBlock.getType(); Material clickedBlockType = clickedBlock.getType();
//apply rules for buttons and switches //apply rules for containers and crafting blocks
if(GriefPrevention.instance.config_claims_preventButtonsSwitches && (clickedBlockType == null || clickedBlockType == Material.STONE_BUTTON || clickedBlockType == Material.LEVER)) if( GriefPrevention.instance.config_claims_preventTheft && (
{
Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, null);
if(claim != null)
{
String noAccessReason = claim.allowAccess(player);
if(noAccessReason != null)
{
event.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, noAccessReason);
}
}
}
//otherwise apply rules for containers and crafting blocks
else if( GriefPrevention.instance.config_claims_preventTheft && (
event.getAction() == Action.RIGHT_CLICK_BLOCK && ( event.getAction() == Action.RIGHT_CLICK_BLOCK && (
clickedBlock.getState() instanceof InventoryHolder || clickedBlock.getState() instanceof InventoryHolder ||
clickedBlockType == Material.BREWING_STAND || clickedBlockType == Material.BREWING_STAND ||
@ -835,7 +845,7 @@ class PlayerEventHandler implements Listener
PlayerData playerData = this.dataStore.getPlayerData(player.getName()); PlayerData playerData = this.dataStore.getPlayerData(player.getName());
if(playerData.siegeData != null) if(playerData.siegeData != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't access containers while involved in a siege."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeNoContainers);
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
@ -843,7 +853,7 @@ class PlayerEventHandler implements Listener
//block container use during pvp combat, same reason //block container use during pvp combat, same reason
if(playerData.inPvpCombat()) if(playerData.inPvpCombat())
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't access containers during PvP combat."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.PvPNoContainers);
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
@ -857,6 +867,7 @@ class PlayerEventHandler implements Listener
{ {
event.setCancelled(true); event.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, noContainersReason); GriefPrevention.sendMessage(player, TextMode.Err, noContainersReason);
return;
} }
} }
@ -865,15 +876,48 @@ class PlayerEventHandler implements Listener
if(playerData.pvpImmune) if(playerData.pvpImmune)
{ {
playerData.pvpImmune = false; playerData.pvpImmune = false;
GriefPrevention.sendMessage(player, TextMode.Warn, "Now you can fight with other players."); GriefPrevention.sendMessage(player, TextMode.Warn, Messages.PvPImmunityEnd);
} }
} }
//otherwise apply rules for buttons and switches
else if(GriefPrevention.instance.config_claims_preventButtonsSwitches && (clickedBlockType == null || clickedBlockType == Material.STONE_BUTTON || clickedBlockType == Material.LEVER))
{
Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, null);
if(claim != null)
{
String noAccessReason = claim.allowAccess(player);
if(noAccessReason != null)
{
event.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, noAccessReason);
return;
}
}
}
//apply rule for players trampling tilled soil back to dirt (never allow it) //apply rule for players trampling tilled soil back to dirt (never allow it)
//NOTE: that this event applies only to players. monsters and animals can still trample. //NOTE: that this event applies only to players. monsters and animals can still trample.
else if(event.getAction() == Action.PHYSICAL && clickedBlockType == Material.SOIL) else if(event.getAction() == Action.PHYSICAL && clickedBlockType == Material.SOIL)
{ {
event.setCancelled(true); event.setCancelled(true);
return;
}
//apply rule for note blocks
else if(clickedBlockType == Material.NOTE_BLOCK)
{
Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, null);
if(claim != null)
{
String noBuildReason = claim.allowBuild(player);
if(noBuildReason != null)
{
event.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason);
return;
}
}
} }
//otherwise handle right click (shovel, string, bonemeal) //otherwise handle right click (shovel, string, bonemeal)
@ -886,8 +930,8 @@ class PlayerEventHandler implements Listener
//what's the player holding? //what's the player holding?
Material materialInHand = player.getItemInHand().getType(); Material materialInHand = player.getItemInHand().getType();
//if it's bonemeal, check for build permission (ink sac == bone meal, must be a Bukkit bug?) //if it's bonemeal or a boat, check for build permission (ink sac == bone meal, must be a Bukkit bug?)
if(materialInHand == Material.INK_SACK) if(materialInHand == Material.INK_SACK || materialInHand == Material.BOAT)
{ {
String noBuildReason = GriefPrevention.instance.allowBuild(player, clickedBlock.getLocation()); String noBuildReason = GriefPrevention.instance.allowBuild(player, clickedBlock.getLocation());
if(noBuildReason != null) if(noBuildReason != null)
@ -899,8 +943,8 @@ class PlayerEventHandler implements Listener
return; return;
} }
//if it's a spawn egg or minecart and this is a creative world, apply special rules //if it's a spawn egg, minecart, or boat, and this is a creative world, apply special rules
else if((materialInHand == Material.MONSTER_EGG || materialInHand == Material.MINECART || materialInHand == Material.POWERED_MINECART || materialInHand == Material.STORAGE_MINECART) && GriefPrevention.instance.creativeRulesApply(clickedBlock.getLocation())) else if((materialInHand == Material.MONSTER_EGG || materialInHand == Material.MINECART || materialInHand == Material.POWERED_MINECART || materialInHand == Material.STORAGE_MINECART || materialInHand == Material.BOAT) && GriefPrevention.instance.creativeRulesApply(clickedBlock.getLocation()))
{ {
//player needs build permission at this location //player needs build permission at this location
String noBuildReason = GriefPrevention.instance.allowBuild(player, clickedBlock.getLocation()); String noBuildReason = GriefPrevention.instance.allowBuild(player, clickedBlock.getLocation());
@ -933,7 +977,7 @@ class PlayerEventHandler implements Listener
//air indicates too far away //air indicates too far away
if(clickedBlockType == Material.AIR) if(clickedBlockType == Material.AIR)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "That's too far away."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.TooFarAway);
return; return;
} }
@ -942,14 +986,14 @@ class PlayerEventHandler implements Listener
//no claim case //no claim case
if(claim == null) if(claim == null)
{ {
GriefPrevention.sendMessage(player, TextMode.Info, "No one has claimed this block."); GriefPrevention.sendMessage(player, TextMode.Info, Messages.BlockNotClaimed);
Visualization.Revert(player); Visualization.Revert(player);
} }
//claim case //claim case
else else
{ {
GriefPrevention.sendMessage(player, TextMode.Info, "This block has been claimed by " + claim.getOwnerName() + "."); GriefPrevention.sendMessage(player, TextMode.Info, Messages.BlockClaimed, claim.getOwnerName());
//visualize boundary //visualize boundary
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.Claim); Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.Claim);
@ -967,7 +1011,7 @@ class PlayerEventHandler implements Listener
//disable golden shovel while under siege //disable golden shovel while under siege
if(playerData.siegeData != null) if(playerData.siegeData != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't use your shovel tool while involved in a siege."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeNoShovel);
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
@ -975,7 +1019,7 @@ class PlayerEventHandler implements Listener
//can't use the shovel from too far away //can't use the shovel from too far away
if(clickedBlockType == Material.AIR) if(clickedBlockType == Material.AIR)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "That's too far away!"); GriefPrevention.sendMessage(player, TextMode.Err, Messages.TooFarAway);
return; return;
} }
@ -988,7 +1032,7 @@ class PlayerEventHandler implements Listener
Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, playerData.lastClaim); Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, playerData.lastClaim);
if(claim != null) if(claim != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, claim.getOwnerName() + " claimed that block."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.BlockClaimed, claim.getOwnerName());
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.ErrorClaim); Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.ErrorClaim);
Visualization.Apply(player, visualization); Visualization.Apply(player, visualization);
@ -1005,7 +1049,7 @@ class PlayerEventHandler implements Listener
if(entities[i] instanceof Player) if(entities[i] instanceof Player)
{ {
Player otherPlayer = (Player)entities[i]; Player otherPlayer = (Player)entities[i];
GriefPrevention.sendMessage(player, TextMode.Err, "Unable to restore. " + otherPlayer.getName() + " is in that chunk."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.RestoreNaturePlayerInChunk, otherPlayer.getName());
return; return;
} }
} }
@ -1072,9 +1116,17 @@ class PlayerEventHandler implements Listener
allowedFillBlocks.add(Material.SANDSTONE); allowedFillBlocks.add(Material.SANDSTONE);
allowedFillBlocks.add(Material.DIRT); allowedFillBlocks.add(Material.DIRT);
allowedFillBlocks.add(Material.GRASS); allowedFillBlocks.add(Material.GRASS);
allowedFillBlocks.add(Material.ICE);
} }
Block centerBlock = clickedBlock; Block centerBlock = clickedBlock;
//sink through a snow layer
if(centerBlock.getType() == Material.SNOW)
{
centerBlock = centerBlock.getRelative(BlockFace.DOWN);
}
int maxHeight = centerBlock.getY(); int maxHeight = centerBlock.getY();
int minx = centerBlock.getX() - playerData.fillRadius; int minx = centerBlock.getX() - playerData.fillRadius;
int maxx = centerBlock.getX() + playerData.fillRadius; int maxx = centerBlock.getX() + playerData.fillRadius;
@ -1105,8 +1157,8 @@ class PlayerEventHandler implements Listener
break; break;
} }
//only replace air and spilling water //only replace air, spilling water, snow
if(block.getType() == Material.AIR || block.getType() == Material.STATIONARY_WATER && block.getData() != 0) if(block.getType() == Material.AIR || block.getType() == Material.SNOW || (block.getType() == Material.STATIONARY_WATER && block.getData() != 0))
{ {
//look to neighbors for an appropriate fill block //look to neighbors for an appropriate fill block
Block eastBlock = block.getRelative(BlockFace.EAST); Block eastBlock = block.getRelative(BlockFace.EAST);
@ -1155,7 +1207,7 @@ class PlayerEventHandler implements Listener
//if the player doesn't have claims permission, don't do anything //if the player doesn't have claims permission, don't do anything
if(GriefPrevention.instance.config_claims_creationRequiresPermission && !player.hasPermission("griefprevention.createclaims")) if(GriefPrevention.instance.config_claims_creationRequiresPermission && !player.hasPermission("griefprevention.createclaims"))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You don't have permission to claim land."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoCreateClaimPermission);
return; return;
} }
@ -1214,7 +1266,7 @@ class PlayerEventHandler implements Listener
if(!playerData.claimResizing.isAdminClaim() && (newWidth < GriefPrevention.instance.config_claims_minSize || newHeight < GriefPrevention.instance.config_claims_minSize)) if(!playerData.claimResizing.isAdminClaim() && (newWidth < GriefPrevention.instance.config_claims_minSize || newHeight < GriefPrevention.instance.config_claims_minSize))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "This new size would be too small. Claims must be at least " + GriefPrevention.instance.config_claims_minSize + " x " + GriefPrevention.instance.config_claims_minSize + "."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeClaimTooSmall, String.valueOf(GriefPrevention.instance.config_claims_minSize));
return; return;
} }
@ -1226,7 +1278,7 @@ class PlayerEventHandler implements Listener
if(blocksRemainingAfter < 0) if(blocksRemainingAfter < 0)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You don't have enough blocks for this size. You need " + Math.abs(blocksRemainingAfter) + " more."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeNeedMoreBlocks, String.valueOf(Math.abs(blocksRemainingAfter)));
return; return;
} }
} }
@ -1250,7 +1302,7 @@ class PlayerEventHandler implements Listener
//enforce creative mode rule //enforce creative mode rule
if(!player.hasPermission("griefprevention.deleteclaims") && GriefPrevention.instance.creativeRulesApply(player.getLocation())) if(!player.hasPermission("griefprevention.deleteclaims") && GriefPrevention.instance.creativeRulesApply(player.getLocation()))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't un-claim creative mode land. You can only make this claim larger or create additional claims."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoCreativeUnClaim);
return; return;
} }
@ -1265,7 +1317,7 @@ class PlayerEventHandler implements Listener
if(result.succeeded) if(result.succeeded)
{ {
//inform and show the player //inform and show the player
GriefPrevention.sendMessage(player, TextMode.Success, "Claim resized. You now have " + playerData.getRemainingClaimBlocks() + " available claim blocks."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.ClaimResizeSuccess, String.valueOf(playerData.getRemainingClaimBlocks()));
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim); Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim);
Visualization.Apply(player, visualization); Visualization.Apply(player, visualization);
@ -1282,7 +1334,7 @@ class PlayerEventHandler implements Listener
else else
{ {
//inform player //inform player
GriefPrevention.sendMessage(player, TextMode.Err, "Can't resize here because it would overlap another nearby claim."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeFailOverlap);
//show the player the conflicting claim //show the player the conflicting claim
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim); Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim);
@ -1307,7 +1359,7 @@ class PlayerEventHandler implements Listener
{ {
playerData.claimResizing = claim; playerData.claimResizing = claim;
playerData.lastShovelLocation = clickedBlock.getLocation(); playerData.lastShovelLocation = clickedBlock.getLocation();
player.sendMessage("Resizing claim. Use your shovel again at the new location for this corner."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.ResizeStart);
} }
//if he didn't click on a corner and is in subdivision mode, he's creating a new subdivision //if he didn't click on a corner and is in subdivision mode, he's creating a new subdivision
@ -1319,13 +1371,13 @@ class PlayerEventHandler implements Listener
//if the clicked claim was a subdivision, tell him he can't start a new subdivision here //if the clicked claim was a subdivision, tell him he can't start a new subdivision here
if(claim.parent != null) if(claim.parent != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't create a subdivision here because it would overlap another subdivision. Consider /abandonclaim to delete it, or use your shovel at a corner to resize it."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeFailOverlapSubdivision);
} }
//otherwise start a new subdivision //otherwise start a new subdivision
else else
{ {
GriefPrevention.sendMessage(player, TextMode.Instr, "Subdivision corner set! Use your shovel at the location for the opposite corner of this new subdivision."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.SubdivisionStart);
playerData.lastShovelLocation = clickedBlock.getLocation(); playerData.lastShovelLocation = clickedBlock.getLocation();
playerData.claimSubdividing = claim; playerData.claimSubdividing = claim;
} }
@ -1354,7 +1406,7 @@ class PlayerEventHandler implements Listener
//if it didn't succeed, tell the player why //if it didn't succeed, tell the player why
if(!result.succeeded) if(!result.succeeded)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Your selected area overlaps another subdivision."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateSubdivisionOverlap);
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim); Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim);
Visualization.Apply(player, visualization); Visualization.Apply(player, visualization);
@ -1365,7 +1417,7 @@ class PlayerEventHandler implements Listener
//otherwise, advise him on the /trust command and show him his new subdivision //otherwise, advise him on the /trust command and show him his new subdivision
else else
{ {
GriefPrevention.sendMessage(player, TextMode.Success, "Subdivision created! Use /trust to share it with friends."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.SubdivisionSuccess);
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim); Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim);
Visualization.Apply(player, visualization); Visualization.Apply(player, visualization);
playerData.lastShovelLocation = null; playerData.lastShovelLocation = null;
@ -1378,7 +1430,7 @@ class PlayerEventHandler implements Listener
//also advise him to consider /abandonclaim or resizing the existing claim //also advise him to consider /abandonclaim or resizing the existing claim
else else
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't create a claim here because it would overlap your other claim. Use /abandonclaim to delete it, or use your shovel at a corner to resize it."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimFailOverlap);
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.Claim); Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.Claim);
Visualization.Apply(player, visualization); Visualization.Apply(player, visualization);
} }
@ -1387,7 +1439,7 @@ class PlayerEventHandler implements Listener
//otherwise tell the player he can't claim here because it's someone else's claim, and show him the claim //otherwise tell the player he can't claim here because it's someone else's claim, and show him the claim
else else
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You can't create a claim here because it would overlap " + claim.getOwnerName() + "'s claim."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimFailOverlapOtherPlayer, claim.getOwnerName());
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.ErrorClaim); Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.ErrorClaim);
Visualization.Apply(player, visualization); Visualization.Apply(player, visualization);
} }
@ -1404,13 +1456,13 @@ class PlayerEventHandler implements Listener
//if claims are not enabled in this world and it's not an administrative claim, display an error message and stop //if claims are not enabled in this world and it's not an administrative claim, display an error message and stop
if(!GriefPrevention.instance.claimsEnabledForWorld(player.getWorld()) && playerData.shovelMode != ShovelMode.Admin) if(!GriefPrevention.instance.claimsEnabledForWorld(player.getWorld()) && playerData.shovelMode != ShovelMode.Admin)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Land claims are disabled in this world."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.ClaimsDisabledWorld);
return; return;
} }
//remember it, and start him on the new claim //remember it, and start him on the new claim
playerData.lastShovelLocation = clickedBlock.getLocation(); playerData.lastShovelLocation = clickedBlock.getLocation();
GriefPrevention.sendMessage(player, TextMode.Instr, "Claim corner set! Use the shovel again at the opposite corner to claim a rectangle of land. To cancel, put your shovel away."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.ClaimStart);
} }
//otherwise, he's trying to finish creating a claim by setting the other boundary corner //otherwise, he's trying to finish creating a claim by setting the other boundary corner
@ -1430,7 +1482,7 @@ class PlayerEventHandler implements Listener
if(playerData.shovelMode != ShovelMode.Admin && (newClaimWidth < GriefPrevention.instance.config_claims_minSize || newClaimHeight < GriefPrevention.instance.config_claims_minSize)) if(playerData.shovelMode != ShovelMode.Admin && (newClaimWidth < GriefPrevention.instance.config_claims_minSize || newClaimHeight < GriefPrevention.instance.config_claims_minSize))
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "This claim would be too small. Any claim must be at least " + GriefPrevention.instance.config_claims_minSize + " x " + GriefPrevention.instance.config_claims_minSize + "."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.NewClaimTooSmall, String.valueOf(GriefPrevention.instance.config_claims_minSize));
return; return;
} }
@ -1441,8 +1493,8 @@ class PlayerEventHandler implements Listener
int remainingBlocks = playerData.getRemainingClaimBlocks(); int remainingBlocks = playerData.getRemainingClaimBlocks();
if(newClaimArea > remainingBlocks) if(newClaimArea > remainingBlocks)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You don't have enough blocks to claim that entire area. You need " + (newClaimArea - remainingBlocks) + " more blocks."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimInsufficientBlocks, String.valueOf(newClaimArea - remainingBlocks));
GriefPrevention.sendMessage(player, TextMode.Instr, "To delete another claim and free up some blocks, use /AbandonClaim."); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.AbandonClaimAdvertisement);
return; return;
} }
} }
@ -1463,7 +1515,7 @@ class PlayerEventHandler implements Listener
//if it didn't succeed, tell the player why //if it didn't succeed, tell the player why
if(!result.succeeded) if(!result.succeeded)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Your selected area overlaps an existing claim."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimFailOverlapShort);
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim); Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim);
Visualization.Apply(player, visualization); Visualization.Apply(player, visualization);
@ -1474,7 +1526,7 @@ class PlayerEventHandler implements Listener
//otherwise, advise him on the /trust command and show him his new claim //otherwise, advise him on the /trust command and show him his new claim
else else
{ {
GriefPrevention.sendMessage(player, TextMode.Success, "Claim created! Use /trust to share it with friends."); GriefPrevention.sendMessage(player, TextMode.Success, Messages.CreateClaimSuccess);
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim); Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim);
Visualization.Apply(player, visualization); Visualization.Apply(player, visualization);
playerData.lastShovelLocation = null; playerData.lastShovelLocation = null;

View File

@ -53,7 +53,7 @@ class PlayerRescueTask implements Runnable
//if the player moved three or more blocks from where he used /trapped, admonish him and don't save him //if the player moved three or more blocks from where he used /trapped, admonish him and don't save him
if(player.getLocation().distance(this.location) > 3) if(player.getLocation().distance(this.location) > 3)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "You moved! Rescue cancelled."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.RescueAbortedMoved);
return; return;
} }

View File

@ -84,7 +84,6 @@ class RestoreNatureProcessingTask implements Runnable
this.playerBlocks.add(Material.BREWING_STAND.getId()); this.playerBlocks.add(Material.BREWING_STAND.getId());
this.playerBlocks.add(Material.BRICK.getId()); this.playerBlocks.add(Material.BRICK.getId());
this.playerBlocks.add(Material.COBBLESTONE.getId()); this.playerBlocks.add(Material.COBBLESTONE.getId());
this.playerBlocks.add(Material.OBSIDIAN.getId());
this.playerBlocks.add(Material.GLASS.getId()); this.playerBlocks.add(Material.GLASS.getId());
this.playerBlocks.add(Material.LAPIS_BLOCK.getId()); this.playerBlocks.add(Material.LAPIS_BLOCK.getId());
this.playerBlocks.add(Material.DISPENSER.getId()); this.playerBlocks.add(Material.DISPENSER.getId());
@ -148,7 +147,9 @@ class RestoreNatureProcessingTask implements Runnable
this.playerBlocks.add(Material.BREWING_STAND.getId()); this.playerBlocks.add(Material.BREWING_STAND.getId());
this.playerBlocks.add(Material.CAULDRON.getId()); this.playerBlocks.add(Material.CAULDRON.getId());
this.playerBlocks.add(Material.DIODE_BLOCK_ON.getId()); this.playerBlocks.add(Material.DIODE_BLOCK_ON.getId());
this.playerBlocks.add(Material.DIODE_BLOCK_ON.getId()); this.playerBlocks.add(Material.DIODE_BLOCK_ON.getId());
this.playerBlocks.add(Material.WEB.getId());
this.playerBlocks.add(Material.SPONGE.getId());
//these are unnatural in the standard world, but not in the nether //these are unnatural in the standard world, but not in the nether
if(this.environment != Environment.NETHER) if(this.environment != Environment.NETHER)
@ -161,6 +162,12 @@ class RestoreNatureProcessingTask implements Runnable
this.playerBlocks.add(Material.NETHER_BRICK_STAIRS.getId()); this.playerBlocks.add(Material.NETHER_BRICK_STAIRS.getId());
} }
//these are unnatural in the standard and nether worlds, but not in the end
if(this.environment != Environment.THE_END)
{
this.playerBlocks.add(Material.OBSIDIAN.getId());
}
//these are unnatural in sandy biomes, but not elsewhere //these are unnatural in sandy biomes, but not elsewhere
if(this.biome == Biome.DESERT || this.biome == Biome.DESERT_HILLS || this.biome == Biome.BEACH || this.aggressiveMode) if(this.biome == Biome.DESERT || this.biome == Biome.DESERT_HILLS || this.biome == Biome.BEACH || this.aggressiveMode)
{ {
@ -178,6 +185,9 @@ class RestoreNatureProcessingTask implements Runnable
this.playerBlocks.add(Material.PUMPKIN_STEM.getId()); this.playerBlocks.add(Material.PUMPKIN_STEM.getId());
this.playerBlocks.add(Material.MELON_BLOCK.getId()); this.playerBlocks.add(Material.MELON_BLOCK.getId());
this.playerBlocks.add(Material.MELON_STEM.getId()); this.playerBlocks.add(Material.MELON_STEM.getId());
this.playerBlocks.add(Material.BEDROCK.getId());
this.playerBlocks.add(Material.GRAVEL.getId());
this.playerBlocks.add(Material.SANDSTONE.getId());
} }
} }

View File

@ -47,7 +47,7 @@ class SecureClaimTask implements Runnable
Player player = onlinePlayers[j]; Player player = onlinePlayers[j];
if(claim.contains(player.getLocation(), false, false) && claim.allowAccess(player) != null) if(claim.contains(player.getLocation(), false, false) && claim.allowAccess(player) != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, "Looting time is up! Ejected from the claim."); GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeDoorsLockedEjection);
GriefPrevention.instance.ejectPlayer(player); GriefPrevention.instance.ejectPlayer(player);
} }
} }