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
main: me.ryanhamshire.GriefPrevention.GriefPrevention
softdepend: [Vault, Multiverse-Core]
version: 4.5
version: 4.6
commands:
abandonclaim:
description: Deletes a claim.
@ -83,7 +83,7 @@ commands:
usage: /SellClaimBlocks <numberOfBlocks>
aliases: sellclaim
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
trustlist:
description: Lists permissions for the claim you're standing in.
@ -104,6 +104,10 @@ commands:
description: Converts an administrative claim to a private claim.
usage: /TransferClaim <player>
permission: griefprevention.adjustclaimblocks
deathblow:
description: Kills a player, optionally giving his inventory to another player.
usage: /DeathBlow <player> [recipientPlayer]
permission: griefprevention.deathblow
permissions:
griefprevention.createclaims:
description: Grants permission to create claims.
@ -120,6 +124,7 @@ permissions:
griefprevention.spam: true
griefprevention.lava: true
griefprevention.eavesdrop: true
griefprevention.deathblow: true
griefprevention.restorenature:
description: Grants permission to use /RestoreNature.
default: op
@ -147,3 +152,6 @@ permissions:
griefprevention.restorenatureaggressive:
description: Grants access to /RestoreNatureAggressive and /RestoreNatureFill.
default: op
griefprevention.deathblow:
description: Grants access to /DeathBlow.
default: op

View File

@ -94,7 +94,7 @@ public class BlockEventHandler implements Listener
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName());
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);
return;
}
@ -109,7 +109,7 @@ public class BlockEventHandler implements Listener
playerData.lastChestDamageLocation = block.getLocation();
//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
@ -124,7 +124,7 @@ public class BlockEventHandler implements Listener
if(availableSlot < 0)
{
//tell the player and stop here
GriefPrevention.sendMessage(player, TextMode.Err, "This chest is full.");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.ChestFull);
return;
}
@ -135,7 +135,7 @@ public class BlockEventHandler implements Listener
playerInventory.setItemInHand(new ItemStack(Material.AIR));
//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(claim != null)
{
//if breaking UNDER the claim
if(block.getY() < claim.lesserBoundaryCorner.getBlockY())
//if breaking UNDER the claim and the player has permission to build in the claim
if(block.getY() < claim.lesserBoundaryCorner.getBlockY() && claim.allowBuild(player) == null)
{
//extend the claim downward beyond the breakage point
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();
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);
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
String noBuildReason = GriefPrevention.instance.allowBuild(player, block.getLocation());
if(noBuildReason != null)
@ -262,7 +248,7 @@ public class BlockEventHandler implements Listener
if(claim != null)
{
//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
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(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;
}
@ -290,7 +276,7 @@ public class BlockEventHandler implements Listener
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);
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
@ -309,7 +295,7 @@ public class BlockEventHandler implements Listener
}
//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
Claim newClaim = this.dataStore.getClaimAt(block.getLocation(), false, null);
@ -318,19 +304,33 @@ public class BlockEventHandler implements Listener
}
//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
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
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);
}
}
}
}
@ -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
private Claim lastSpreadClaim = null;
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onBlockFromTo (BlockFromToEvent spreadEvent)
{
//always allow fluids to flow straight down
if(spreadEvent.getFace() == BlockFace.DOWN) return;
//from where?
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?
Block toBlock = spreadEvent.getToBlock();
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)
{
spreadEvent.setCancelled(true);
@ -441,9 +452,6 @@ public class BlockEventHandler implements Listener
OfflinePlayer fromOwner = null;
if(fromClaim != null)
{
//if it's within the same claim, allow it
if(fromClaim == toClaim) return;
fromOwner = GriefPrevention.instance.getServer().getOfflinePlayer(fromClaim.ownerName);
}

View File

@ -24,6 +24,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.bukkit.*;
import org.bukkit.World.Environment;
@ -105,7 +106,7 @@ public class Claim
//it may be null
public void removeSurfaceFluids(Claim exclusionClaim)
{
//don't do this automatically for administrative claims
//don't do this for administrative claims
if(this.isAdminClaim()) return;
Location lesser = this.getLesserBoundaryCorner();
@ -135,7 +136,45 @@ 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
@ -245,7 +284,7 @@ public class Claim
{
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
@ -257,7 +296,7 @@ public class Claim
return this.parent.allowBuild(player);
//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
@ -278,25 +317,24 @@ public class Claim
//no building while under siege
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
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName());
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
if(this.ownerName.equals(player.getName()) || GriefPrevention.instance.dataStore.getPlayerData(player.getName()).ignoreClaims) return null;
//anyone with explicit build permission can make changes
ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get(player.getName().toLowerCase());
if(ClaimPermission.Build == permissionLevel) return null;
if(this.hasExplicitPermission(player, ClaimPermission.Build)) return null;
//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;
//subdivision permission inheritance
@ -304,15 +342,38 @@ public class Claim
return this.parent.allowBuild(player);
//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
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(this.siegeData != null)
{
@ -332,11 +393,11 @@ public class Claim
//custom error messages for siege mode
if(!breakable)
{
return "That material is too tough to break.";
return GriefPrevention.instance.dataStore.getMessage(Messages.NonSiegeMaterial);
}
else if(this.ownerName.equals(player.getName()))
{
return "You can't make changes while under siege.";
return GriefPrevention.instance.dataStore.getMessage(Messages.NoOwnerBuildUnderSiege);
}
else
{
@ -351,9 +412,6 @@ public class Claim
//access permission check
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
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;
//look for explicit individual access, inventory, or build permission
ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get(player.getName().toLowerCase());
if(ClaimPermission.Build == permissionLevel || ClaimPermission.Inventory == permissionLevel || ClaimPermission.Access == permissionLevel) return null;
if(this.hasExplicitPermission(player, ClaimPermission.Access)) return null;
if(this.hasExplicitPermission(player, ClaimPermission.Inventory)) return null;
if(this.hasExplicitPermission(player, ClaimPermission.Build)) return null;
//also check for public permission
permissionLevel = this.playerNameToClaimPermissionMap.get("public");
if(ClaimPermission.Build == permissionLevel || ClaimPermission.Inventory == permissionLevel || ClaimPermission.Access == permissionLevel) return null;
ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get("public");
if(ClaimPermission.Build == permissionLevel || ClaimPermission.Inventory == permissionLevel || ClaimPermission.Inventory == permissionLevel) return null;
//permission inheritance for subdivisions
if(this.parent != null)
return this.parent.allowAccess(player);
//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
@ -391,7 +450,7 @@ public class Claim
//if under siege, nobody accesses containers
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
@ -401,11 +460,11 @@ public class Claim
if(this.ownerName.equals(player.getName()) || GriefPrevention.instance.dataStore.getPlayerData(player.getName()).ignoreClaims) return null;
//check for explicit individual container or build permission
ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get(player.getName().toLowerCase());
if(ClaimPermission.Build == permissionLevel || ClaimPermission.Inventory == permissionLevel) return null;
if(this.hasExplicitPermission(player, ClaimPermission.Inventory)) return null;
if(this.hasExplicitPermission(player, ClaimPermission.Build)) return null;
//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;
//permission inheritance for subdivisions
@ -413,7 +472,7 @@ public class Claim
return this.parent.allowContainers(player);
//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
@ -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(player == null) return "";
//anyone who can modify the claim, or who's explicitly in the managers (/PermissionTrust) list can do this
if(this.allowEdit(player) == null || this.managers.contains(player.getName())) return null;
//anyone who can modify the claim can do this
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
if(this.parent != null)
return this.parent.allowGrantPermission(player);
//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
@ -503,7 +576,7 @@ public class Claim
return this.parent.getOwnerName();
if(this.ownerName.length() == 0)
return "an administrator";
return GriefPrevention.instance.dataStore.getMessage(Messages.OwnerNameForAdminClaims);
return this.ownerName;
}
@ -612,7 +685,7 @@ public class Claim
//determine maximum allowable entity count, based on claim size
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)
Chunk lesserChunk = this.getLesserBoundaryCorner().getChunk();
@ -627,11 +700,15 @@ public class Claim
for(int i = 0; i < entities.length; 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;
}

View File

@ -25,6 +25,8 @@ import java.text.SimpleDateFormat;
import java.util.*;
import org.bukkit.*;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -34,14 +36,21 @@ public class DataStore
//in-memory cache for player data
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
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
private final static String dataLayerFolderPath = "plugins" + File.separator + "GriefPreventionData";
private final static String playerDataFolderPath = dataLayerFolderPath + File.separator + "PlayerData";
private final static String claimDataFolderPath = dataLayerFolderPath + File.separator + "ClaimData";
final static String configFilePath = dataLayerFolderPath + File.separator + "config.yml";
final static String messagesFilePath = dataLayerFolderPath + File.separator + "messages.yml";
//initialization!
DataStore()
@ -50,9 +59,45 @@ public class DataStore
new File(playerDataFolderPath).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
File claimDataFolder = new File(claimDataFolderPath);
File [] files = claimDataFolder.listFiles();
files = claimDataFolder.listFiles();
int loadedClaimCount = 0;
@ -239,6 +284,9 @@ public class DataStore
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
System.gc();
}
@ -249,6 +297,67 @@ public class DataStore
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
{
//if it's a subdivision, throw an exception
@ -482,6 +591,7 @@ public class DataStore
File playerFile = new File(playerDataFolderPath + File.separator + playerName);
playerData = new PlayerData();
playerData.playerName = playerName;
//if it doesn't exist as a file
if(!playerFile.exists())
@ -741,6 +851,12 @@ public class DataStore
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)
Claim newClaim = new Claim(
new Location(world, smallx, smally, smallz),
@ -972,7 +1088,7 @@ public class DataStore
if(winner != null)
{
//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
SecureClaimTask task = new SecureClaimTask(siegeData);
@ -1146,4 +1262,223 @@ public class DataStore
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.World.Environment;
import org.bukkit.block.Block;
import org.bukkit.entity.Animals;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.entity.ThrownPotion;
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.EntityDeathEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.ExpBottleEvent;
import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.painting.PaintingBreakByEntityEvent;
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...
@EventHandler(priority = EventPriority.LOWEST)
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
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);
return;
@ -241,7 +254,24 @@ class EntityEventHandler implements Listener
{
event.setCancelled(true);
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
@ -251,6 +281,9 @@ class EntityEventHandler implements Listener
//only actually interested in entities damaging entities (ignoring environmental damage)
if(!(event instanceof EntityDamageByEntityEvent)) return;
//monsters are never protected
if(event.getEntity() instanceof Monster) return;
EntityDamageByEntityEvent subEvent = (EntityDamageByEntityEvent) event;
//determine which player is attacking, if any
@ -300,14 +333,14 @@ class EntityEventHandler implements Listener
if(defenderData.pvpImmune)
{
event.setCancelled(true);
GriefPrevention.sendMessage(attacker, TextMode.Err, "You can't injure defenseless players.");
GriefPrevention.sendMessage(attacker, TextMode.Err, Messages.ThatPlayerPvPImmune);
return;
}
if(attackerData.pvpImmune)
{
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;
}
}
@ -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
//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 (subEvent.getEntity() instanceof Animals || subEvent.getEntity() instanceof Vehicle)
//if the entity is an non-monster creature (remember monsters disqualified above), or a 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(claim != null)
@ -350,7 +392,13 @@ class EntityEventHandler implements Listener
if(noContainersReason != null)
{
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)
{
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();
//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, "Want a demonstration? http://tinyurl.com/6nkwegj");
GriefPrevention.sendMessage(player, TextMode.Instr, Messages.RemainingBlocks, String.valueOf(remainingBlocks));
//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.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
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 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 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 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_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_protectCreatures = config.getBoolean("GriefPrevention.Claims.ProtectCreatures", true);
this.config_claims_preventButtonsSwitches = config.getBoolean("GriefPrevention.Claims.PreventButtonsSwitches", true);
this.config_claims_initialBlocks = config.getInt("GriefPrevention.Claims.InitialBlocks", 100);
this.config_claims_blocksAccruedPerHour = config.getInt("GriefPrevention.Claims.BlocksAccruedPerHour", 100);
@ -236,6 +241,8 @@ public class GriefPrevention extends JavaPlugin
this.config_economy_claimBlocksSellValue = config.getDouble("GriefPrevention.Economy.ClaimBlocksSellValue", 0);
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_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.CreativeRulesWorlds", creativeClaimsEnabledWorldNames);
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.InitialBlocks", this.config_claims_initialBlocks);
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.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.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);
}
//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
PluginManager pluginManager = this.getServer().getPluginManager();
@ -475,11 +489,11 @@ public class GriefPrevention extends JavaPlugin
//toggle ignore claims mode on or off
if(!playerData.ignoreClaims)
{
GriefPrevention.sendMessage(player, TextMode.Success, "Now respecting claims.");
GriefPrevention.sendMessage(player, TextMode.Success, Messages.RespectingClaims);
}
else
{
GriefPrevention.sendMessage(player, TextMode.Success, "Now ignoring claims.");
GriefPrevention.sendMessage(player, TextMode.Success, Messages.IgnoringClaims);
}
return true;
@ -492,7 +506,7 @@ public class GriefPrevention extends JavaPlugin
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;
}
@ -503,7 +517,7 @@ public class GriefPrevention extends JavaPlugin
//check count
if(originalClaimCount == 0)
{
GriefPrevention.sendMessage(player, TextMode.Err, "You haven't claimed any land.");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.YouHaveNoClaims);
return true;
}
@ -512,7 +526,7 @@ public class GriefPrevention extends JavaPlugin
//inform the player
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
Visualization.Revert(player);
@ -526,7 +540,7 @@ public class GriefPrevention extends JavaPlugin
//change shovel mode
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
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;
}
@ -536,7 +550,7 @@ public class GriefPrevention extends JavaPlugin
//change shovel mode
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
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;
}
@ -560,7 +574,7 @@ public class GriefPrevention extends JavaPlugin
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;
}
@ -585,7 +599,7 @@ public class GriefPrevention extends JavaPlugin
//check additional permission
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;
}
@ -593,19 +607,19 @@ public class GriefPrevention extends JavaPlugin
Claim claim = this.dataStore.getClaimAt(player.getLocation(), true, 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;
}
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;
}
OfflinePlayer targetPlayer = this.resolvePlayer(args[0]);
if(targetPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, "Player not found.");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
return true;
}
@ -616,12 +630,12 @@ public class GriefPrevention extends JavaPlugin
}
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;
}
//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() + ".");
return true;
@ -635,7 +649,7 @@ public class GriefPrevention extends JavaPlugin
//if no claim here, error message
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;
}
@ -703,7 +717,7 @@ public class GriefPrevention extends JavaPlugin
return true;
}
//untrust <player>
//untrust <player> or untrust [<group>]
else if(cmd.getName().equalsIgnoreCase("untrust") && player != null)
{
//requires exactly one parameter, the other player's name
@ -723,24 +737,27 @@ public class GriefPrevention extends JavaPlugin
}
else
{
GriefPrevention.sendMessage(player, TextMode.Err, "Only the claim owner can clear all permissions.");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.ClearPermsOwnerOnly);
return true;
}
}
else
{
//validate player argument
otherPlayer = this.resolvePlayer(args[0]);
if(!clearPermissions && otherPlayer == null && !args[0].equals("public"))
//validate player argument or group argument
if(!args[0].startsWith("[") || !args[0].endsWith("]"))
{
GriefPrevention.sendMessage(player, TextMode.Err, "Player not found.");
return true;
}
otherPlayer = this.resolvePlayer(args[0]);
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
@ -777,18 +794,18 @@ public class GriefPrevention extends JavaPlugin
//confirmation message
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
{
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
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
{
@ -796,7 +813,7 @@ public class GriefPrevention extends JavaPlugin
if(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
@ -813,7 +830,11 @@ public class GriefPrevention extends JavaPlugin
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(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;
}
//if no parameter, just tell player cost per block and balance
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;
}
@ -886,7 +907,7 @@ public class GriefPrevention extends JavaPlugin
//if the player is at his max, tell him so
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;
}
@ -912,7 +933,7 @@ public class GriefPrevention extends JavaPlugin
double totalCost = blockCount * GriefPrevention.instance.config_economy_claimBlocksPurchaseCost;
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
@ -926,7 +947,7 @@ public class GriefPrevention extends JavaPlugin
this.dataStore.savePlayerData(player.getName(), playerData);
//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;
@ -942,7 +963,7 @@ public class GriefPrevention extends JavaPlugin
//if disabled, error message
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;
}
@ -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(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;
}
@ -971,7 +992,7 @@ public class GriefPrevention extends JavaPlugin
//if he doesn't have enough blocks, tell him so
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
@ -986,7 +1007,7 @@ public class GriefPrevention extends JavaPlugin
this.dataStore.savePlayerData(player.getName(), playerData);
//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;
@ -997,7 +1018,7 @@ public class GriefPrevention extends JavaPlugin
{
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
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;
}
@ -1008,7 +1029,7 @@ public class GriefPrevention extends JavaPlugin
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
playerData.shovelMode = ShovelMode.Basic;
playerData.claimSubdividing = null;
GriefPrevention.sendMessage(player, TextMode.Success, "Returned to basic claim creation mode.");
GriefPrevention.sendMessage(player, TextMode.Success, Messages.BasicClaimsMode);
return true;
}
@ -1019,7 +1040,8 @@ public class GriefPrevention extends JavaPlugin
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
playerData.shovelMode = ShovelMode.Subdivide;
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;
}
@ -1032,7 +1054,7 @@ public class GriefPrevention extends JavaPlugin
if(claim == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, "There's no claim here.");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.DeleteClaimMissing);
}
else
@ -1043,14 +1065,14 @@ public class GriefPrevention extends JavaPlugin
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
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;
}
else
{
claim.removeSurfaceFluids(null);
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()));
//revert any current visualization
@ -1061,7 +1083,7 @@ public class GriefPrevention extends JavaPlugin
}
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>
else if(cmd.getName().equalsIgnoreCase("deleteallclaims") && player != null)
else if(cmd.getName().equalsIgnoreCase("deleteallclaims"))
{
//requires exactly one parameter, the other player's name
if(args.length != 1) return false;
@ -1078,55 +1100,115 @@ public class GriefPrevention extends JavaPlugin
OfflinePlayer otherPlayer = this.resolvePlayer(args[0]);
if(otherPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, "Player not found.");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
return true;
}
//delete all that player's claims
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
Visualization.Revert(player);
//revert any current visualization
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;
}
//deletealladminclaims
else if(cmd.getName().equalsIgnoreCase("deletealladminclaims") && player != null)
else if(cmd.getName().equalsIgnoreCase("deletealladminclaims"))
{
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;
}
//delete all admin claims
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
Visualization.Revert(player);
//revert any current visualization
Visualization.Revert(player);
}
return true;
}
//adjustbonusclaimblocks <player> <amount>
else if(cmd.getName().equalsIgnoreCase("adjustbonusclaimblocks") && player != null)
//adjustbonusclaimblocks <player> <amount> or [<permission>] amount
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;
//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
int adjustment;
try
@ -1138,13 +1220,33 @@ public class GriefPrevention extends JavaPlugin
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
PlayerData playerData = this.dataStore.getPlayerData(targetPlayer.getName());
playerData.bonusClaimBlocks += adjustment;
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.AddLogEntry(player.getName() + " adjusted " + targetPlayer.getName() + "'s bonus claim blocks by " + adjustment + ".");
GriefPrevention.sendMessage(player, TextMode.Success, Messages.AdjustBlocksSuccess, targetPlayer.getName(), String.valueOf(adjustment), String.valueOf(playerData.bonusClaimBlocks));
if(player != null) GriefPrevention.AddLogEntry(player.getName() + " adjusted " + targetPlayer.getName() + "'s bonus claim blocks by " + adjustment + ".");
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(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;
}
@ -1176,12 +1278,12 @@ public class GriefPrevention extends JavaPlugin
long now = Calendar.getInstance().getTimeInMillis();
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;
}
//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
PlayerRescueTask task = new PlayerRescueTask(player, player.getLocation());
@ -1196,7 +1298,7 @@ public class GriefPrevention extends JavaPlugin
//error message for when siege mode is disabled
if(!this.siegeEnabledForWorld(player.getWorld()))
{
GriefPrevention.sendMessage(player, TextMode.Err, "Siege is disabled here.");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NonSiegeWorld);
return true;
}
@ -1211,7 +1313,7 @@ public class GriefPrevention extends JavaPlugin
PlayerData attackerData = this.dataStore.getPlayerData(attacker.getName());
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;
}
@ -1222,7 +1324,7 @@ public class GriefPrevention extends JavaPlugin
defender = this.getServer().getPlayer(args[0]);
if(defender == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, "Player not found.");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
return true;
}
}
@ -1246,14 +1348,14 @@ public class GriefPrevention extends JavaPlugin
PlayerData defenderData = this.dataStore.getPlayerData(defender.getName());
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;
}
//victim must not be pvp immune
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;
}
@ -1262,35 +1364,35 @@ public class GriefPrevention extends JavaPlugin
//defender must have some level of permission there to be protected
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;
}
//attacker must be close to the claim he wants to siege
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;
}
//claim can't be under siege already
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;
}
//can't siege admin claims
if(defenderClaim.isAdminClaim())
{
GriefPrevention.sendMessage(player, TextMode.Err, "Siege is disabled in this area.");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoSiegeAdminClaim);
return true;
}
//can't be on cooldown
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;
}
@ -1298,8 +1400,8 @@ public class GriefPrevention extends JavaPlugin
dataStore.startSiege(attacker, defender, defenderClaim);
//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(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(defender, TextMode.Warn, Messages.SiegeAlert, attacker.getName());
GriefPrevention.sendMessage(player, TextMode.Success, Messages.SiegeConfirmed, defender.getName());
}
return false;
@ -1312,31 +1414,41 @@ public class GriefPrevention extends JavaPlugin
private boolean abandonClaimHandler(Player player, boolean deleteTopLevelClaim)
{
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
//which claim is being abandoned?
Claim claim = this.dataStore.getClaimAt(player.getLocation(), true /*ignore height*/, null);
if(claim == null)
{
GriefPrevention.sendMessage(player, TextMode.Instr, "Stand in the claim you want to delete, or consider /AbandonAllClaims.");
}
else if(this.creativeRulesApply(player.getLocation()))
{
GriefPrevention.sendMessage(player, TextMode.Err, "Creative-mode claims can't be abandoned.");
GriefPrevention.sendMessage(player, TextMode.Instr, Messages.AbandonClaimMissing);
}
//verify ownership
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
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;
}
//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
{
//delete it
@ -1344,12 +1456,13 @@ public class GriefPrevention extends JavaPlugin
this.dataStore.deleteClaim(claim);
//tell the player how many claim blocks he has left
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
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
Visualization.Revert(player);
playerData.warnedAboutMajorDeletion = false;
}
return true;
@ -1362,21 +1475,36 @@ public class GriefPrevention extends JavaPlugin
//determine which claim the player is standing in
Claim claim = this.dataStore.getClaimAt(player.getLocation(), true /*ignore height*/, null);
//validate player argument
OfflinePlayer otherPlayer = this.resolvePlayer(recipientName);
if(otherPlayer == null && !recipientName.equals("public"))
//validate player or group argument
String permission = null;
OfflinePlayer otherPlayer = null;
if(recipientName.startsWith("[") && recipientName.endsWith("]"))
{
GriefPrevention.sendMessage(player, TextMode.Err, "Player not found.");
return;
permission = recipientName.substring(1, recipientName.length() - 1);
if(permission == null || permission.isEmpty())
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.InvalidPermissionID);
return;
}
}
if(otherPlayer != null)
{
recipientName = otherPlayer.getName();
}
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
@ -1394,7 +1522,7 @@ public class GriefPrevention extends JavaPlugin
//check permission here
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;
}
@ -1430,7 +1558,7 @@ public class GriefPrevention extends JavaPlugin
//error message for trying to grant a permission the player doesn't have
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;
}
@ -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(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;
}
@ -1463,36 +1591,36 @@ public class GriefPrevention extends JavaPlugin
}
//notify player
if(recipientName.equals("public")) recipientName = "the public";
StringBuilder resultString = new StringBuilder();
resultString.append("Granted " + recipientName + " ");
if(recipientName.equals("public")) recipientName = this.dataStore.getMessage(Messages.CollectivePublic);
String permissionDescription;
if(permissionLevel == null)
{
resultString.append("manager status");
permissionDescription = this.dataStore.getMessage(Messages.PermissionsPermission);
}
else if(permissionLevel == ClaimPermission.Build)
{
resultString.append("permission to build in");
permissionDescription = this.dataStore.getMessage(Messages.BuildPermission);
}
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)
{
resultString.append(" ALL your claims. To modify only one claim, stand inside it.");
location = this.dataStore.getMessage(Messages.LocationAllClaims);
}
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
@ -1552,7 +1680,7 @@ public class GriefPrevention extends JavaPlugin
playerData.pvpImmune = true;
//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
@ -1797,10 +1925,24 @@ public class GriefPrevention extends JavaPlugin
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
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
@ -1825,19 +1967,20 @@ public class GriefPrevention extends JavaPlugin
return "You can't build here. Use the golden shovel to claim some land first.";
}
//but it's fine in survival mode
else
{
//cache the claim for later reference
playerData.lastClaim = claim;
//but it's fine in survival mode
return null;
}
}
//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)
@ -1854,20 +1997,22 @@ public class GriefPrevention extends JavaPlugin
//exception: administrators in ignore claims mode
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
else
{
//cache the claim for later reference
playerData.lastClaim = claim;
return null;
}
}
else
{
//cache the claim for later reference
playerData.lastClaim = claim;
//if not in the wilderness, then apply claim rules (permissions, etc)
return claim.allowBreak(player, location.getBlock().getType());
//if not in the wilderness, then apply claim rules (permissions, etc)
return claim.allowBreak(player, location.getBlock().getType());
}
}
}

View File

@ -2,5 +2,5 @@ package me.ryanhamshire.GriefPrevention;
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
public class PlayerData
{
//the player's name
public String playerName;
//the player's claims
public Vector<Claim> claims = new Vector<Claim>();
@ -71,9 +74,6 @@ public class PlayerData
public int spamCount = 0; //number of consecutive "spams"
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
public Visualization currentVisualization = null;
@ -138,6 +138,9 @@ public class PlayerData
remainingBlocks -= claim.getArea();
}
//add any blocks this player might have based on group membership (permissions)
remainingBlocks += GriefPrevention.instance.dataStore.getGroupBonusBlocks(this.playerName);
return remainingBlocks;
}
}

View File

@ -20,6 +20,7 @@ package me.ryanhamshire.GriefPrevention;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -59,6 +60,9 @@ class PlayerEventHandler implements Listener
//number of milliseconds in a day
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
PlayerEventHandler(DataStore dataStore, GriefPrevention plugin)
{
@ -75,9 +79,9 @@ class PlayerEventHandler implements Listener
//FEATURE: automatically 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
@ -101,8 +105,27 @@ class PlayerEventHandler implements Listener
boolean spam = 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
if(!(event instanceof PlayerCommandPreprocessEvent))
if(!muted && !(event instanceof PlayerCommandPreprocessEvent))
{
Pattern ipAddressPattern = Pattern.compile("\\d+\\.\\d+\\.\\d+\\.\\d+");
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(message.length() > 5)
if(!muted && message.length() > 5)
{
int symbolsCount = 0;
int whitespaceCount = 0;
@ -167,6 +171,7 @@ class PlayerEventHandler implements Listener
if(symbolsCount > message.length() / 2 || (message.length() > 15 && whitespaceCount < message.length() / 10))
{
spam = true;
if(playerData.spamCount > 0) muted = true;
playerData.spamCount++;
}
}
@ -347,7 +352,7 @@ class PlayerEventHandler implements Listener
playerData.ipAddress = event.getAddress();
//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
long now = Calendar.getInstance().getTimeInMillis();
@ -399,6 +404,16 @@ class PlayerEventHandler implements Listener
event.setResult(Result.KICK_BANNED);
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() + ").");
//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,31 +445,10 @@ class PlayerEventHandler implements Listener
//check inventory, may need pvp protection
GriefPrevention.instance.checkPvpProtectionNeeded(event.getPlayer());
//how long since the last logout?
long elapsed = Calendar.getInstance().getTimeInMillis() - playerData.lastLogout;
//remember message, then silence it. may broadcast it later
String message = event.getJoinMessage();
event.setJoinMessage(null);
if(message != null && elapsed >= GriefPrevention.NOTIFICATION_SECONDS * 1000)
//silence notifications when they're coming too fast
if(event.getJoinMessage() != null && this.shouldSilenceNotification())
{
//start a timer for a delayed join notification message (will only show if player is still online in 30 seconds)
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()));
event.setJoinMessage(null);
}
}
@ -462,10 +456,23 @@ class PlayerEventHandler implements Listener
@EventHandler(priority = EventPriority.HIGHEST)
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)
event.setQuitMessage(null);
//if banned, add IP to the temporary IP ban list
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
@ -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
}
}
//how long was the player online?
long now = Calendar.getInstance().getTimeInMillis();
long elapsed = now - playerData.lastLogin.getTime();
//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();
//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)
//eliminate any expired entries (longer than a minute ago)
for(int i = 0; i < this.recentLoginLogoutNotifications.size(); i++)
{
//start a timer for a delayed leave notification message (will only show if player is still offline in 30 seconds)
JoinLeaveAnnouncementTask task = new JoinLeaveAnnouncementTask(player, notificationMessage, false);
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task, 20L * GriefPrevention.NOTIFICATION_SECONDS);
Long notificationTimestamp = this.recentLoginLogoutNotifications.get(i);
if(now - notificationTimestamp > ONE_MINUTE)
{
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
@ -525,14 +544,14 @@ class PlayerEventHandler implements Listener
//if in combat, don't let him drop it
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);
}
//if he's under siege, don't let him drop it
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);
}
}
@ -552,7 +571,7 @@ class PlayerEventHandler implements Listener
Claim sourceClaim = this.dataStore.getClaimAt(source, false, 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);
return;
}
@ -561,7 +580,7 @@ class PlayerEventHandler implements Listener
Claim destinationClaim = this.dataStore.getClaimAt(destination, false, 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);
return;
}
@ -580,14 +599,14 @@ class PlayerEventHandler implements Listener
{
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);
return;
}
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);
return;
}
@ -627,7 +646,7 @@ class PlayerEventHandler implements Listener
{
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);
}
}
@ -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
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)
{
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,14 +746,17 @@ class PlayerEventHandler implements Listener
minLavaDistance = 3;
}
//otherwise no dumping anything unless underground
else
//otherwise no wilderness dumping (unless underground) in worlds where claims are enabled
else if(GriefPrevention.instance.config_claims_enabledWorlds.contains(block.getWorld()))
{
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.");
bucketEvent.setCancelled(true);
return;
if(bucketEvent.getBucket() == Material.LAVA_BUCKET || GriefPrevention.instance.config_blockWildernessWaterBuckets)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoWildernessBuckets);
bucketEvent.setCancelled(true);
return;
}
}
}
@ -750,7 +772,7 @@ class PlayerEventHandler implements Listener
Location location = otherPlayer.getLocation();
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);
return;
}
@ -791,6 +813,9 @@ class PlayerEventHandler implements Listener
if(clickedBlock == null)
{
//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);
}
}
@ -807,23 +832,8 @@ class PlayerEventHandler implements Listener
Material clickedBlockType = clickedBlock.getType();
//apply rules for buttons and switches
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);
}
}
}
//otherwise apply rules for containers and crafting blocks
else if( GriefPrevention.instance.config_claims_preventTheft && (
//apply rules for containers and crafting blocks
if( GriefPrevention.instance.config_claims_preventTheft && (
event.getAction() == Action.RIGHT_CLICK_BLOCK && (
clickedBlock.getState() instanceof InventoryHolder ||
clickedBlockType == Material.BREWING_STAND ||
@ -835,7 +845,7 @@ class PlayerEventHandler implements Listener
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
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);
return;
}
@ -843,7 +853,7 @@ class PlayerEventHandler implements Listener
//block container use during pvp combat, same reason
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);
return;
}
@ -857,6 +867,7 @@ class PlayerEventHandler implements Listener
{
event.setCancelled(true);
GriefPrevention.sendMessage(player, TextMode.Err, noContainersReason);
return;
}
}
@ -865,7 +876,23 @@ class PlayerEventHandler implements Listener
if(playerData.pvpImmune)
{
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;
}
}
}
@ -874,6 +901,23 @@ class PlayerEventHandler implements Listener
else if(event.getAction() == Action.PHYSICAL && clickedBlockType == Material.SOIL)
{
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)
@ -886,8 +930,8 @@ class PlayerEventHandler implements Listener
//what's the player holding?
Material materialInHand = player.getItemInHand().getType();
//if it's bonemeal, check for build permission (ink sac == bone meal, must be a Bukkit bug?)
if(materialInHand == Material.INK_SACK)
//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 || materialInHand == Material.BOAT)
{
String noBuildReason = GriefPrevention.instance.allowBuild(player, clickedBlock.getLocation());
if(noBuildReason != null)
@ -899,8 +943,8 @@ class PlayerEventHandler implements Listener
return;
}
//if it's a spawn egg or minecart 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()))
//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 || materialInHand == Material.BOAT) && GriefPrevention.instance.creativeRulesApply(clickedBlock.getLocation()))
{
//player needs build permission at this location
String noBuildReason = GriefPrevention.instance.allowBuild(player, clickedBlock.getLocation());
@ -933,7 +977,7 @@ class PlayerEventHandler implements Listener
//air indicates too far away
if(clickedBlockType == Material.AIR)
{
GriefPrevention.sendMessage(player, TextMode.Err, "That's too far away.");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.TooFarAway);
return;
}
@ -942,14 +986,14 @@ class PlayerEventHandler implements Listener
//no claim case
if(claim == null)
{
GriefPrevention.sendMessage(player, TextMode.Info, "No one has claimed this block.");
GriefPrevention.sendMessage(player, TextMode.Info, Messages.BlockNotClaimed);
Visualization.Revert(player);
}
//claim case
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
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.Claim);
@ -967,7 +1011,7 @@ class PlayerEventHandler implements Listener
//disable golden shovel while under siege
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);
return;
}
@ -975,7 +1019,7 @@ class PlayerEventHandler implements Listener
//can't use the shovel from too far away
if(clickedBlockType == Material.AIR)
{
GriefPrevention.sendMessage(player, TextMode.Err, "That's too far away!");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.TooFarAway);
return;
}
@ -988,7 +1032,7 @@ class PlayerEventHandler implements Listener
Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, playerData.lastClaim);
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.Apply(player, visualization);
@ -1005,7 +1049,7 @@ class PlayerEventHandler implements Listener
if(entities[i] instanceof Player)
{
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;
}
}
@ -1072,9 +1116,17 @@ class PlayerEventHandler implements Listener
allowedFillBlocks.add(Material.SANDSTONE);
allowedFillBlocks.add(Material.DIRT);
allowedFillBlocks.add(Material.GRASS);
allowedFillBlocks.add(Material.ICE);
}
Block centerBlock = clickedBlock;
//sink through a snow layer
if(centerBlock.getType() == Material.SNOW)
{
centerBlock = centerBlock.getRelative(BlockFace.DOWN);
}
int maxHeight = centerBlock.getY();
int minx = centerBlock.getX() - playerData.fillRadius;
int maxx = centerBlock.getX() + playerData.fillRadius;
@ -1105,8 +1157,8 @@ class PlayerEventHandler implements Listener
break;
}
//only replace air and spilling water
if(block.getType() == Material.AIR || block.getType() == Material.STATIONARY_WATER && block.getData() != 0)
//only replace air, spilling water, snow
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
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(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;
}
@ -1214,7 +1266,7 @@ class PlayerEventHandler implements Listener
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;
}
@ -1226,7 +1278,7 @@ class PlayerEventHandler implements Listener
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;
}
}
@ -1250,7 +1302,7 @@ class PlayerEventHandler implements Listener
//enforce creative mode rule
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;
}
@ -1265,7 +1317,7 @@ class PlayerEventHandler implements Listener
if(result.succeeded)
{
//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.Apply(player, visualization);
@ -1282,7 +1334,7 @@ class PlayerEventHandler implements Listener
else
{
//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
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim);
@ -1307,7 +1359,7 @@ class PlayerEventHandler implements Listener
{
playerData.claimResizing = claim;
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
@ -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(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
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.claimSubdividing = claim;
}
@ -1354,7 +1406,7 @@ class PlayerEventHandler implements Listener
//if it didn't succeed, tell the player why
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.Apply(player, visualization);
@ -1365,7 +1417,7 @@ class PlayerEventHandler implements Listener
//otherwise, advise him on the /trust command and show him his new subdivision
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.Apply(player, visualization);
playerData.lastShovelLocation = null;
@ -1378,7 +1430,7 @@ class PlayerEventHandler implements Listener
//also advise him to consider /abandonclaim or resizing the existing claim
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.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
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.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(!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;
}
//remember it, and start him on the new claim
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
@ -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))
{
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;
}
@ -1441,8 +1493,8 @@ class PlayerEventHandler implements Listener
int remainingBlocks = playerData.getRemainingClaimBlocks();
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.Instr, "To delete another claim and free up some blocks, use /AbandonClaim.");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimInsufficientBlocks, String.valueOf(newClaimArea - remainingBlocks));
GriefPrevention.sendMessage(player, TextMode.Instr, Messages.AbandonClaimAdvertisement);
return;
}
}
@ -1463,7 +1515,7 @@ class PlayerEventHandler implements Listener
//if it didn't succeed, tell the player why
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.Apply(player, visualization);
@ -1474,7 +1526,7 @@ class PlayerEventHandler implements Listener
//otherwise, advise him on the /trust command and show him his new claim
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.Apply(player, visualization);
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(player.getLocation().distance(this.location) > 3)
{
GriefPrevention.sendMessage(player, TextMode.Err, "You moved! Rescue cancelled.");
GriefPrevention.sendMessage(player, TextMode.Err, Messages.RescueAbortedMoved);
return;
}

View File

@ -84,7 +84,6 @@ class RestoreNatureProcessingTask implements Runnable
this.playerBlocks.add(Material.BREWING_STAND.getId());
this.playerBlocks.add(Material.BRICK.getId());
this.playerBlocks.add(Material.COBBLESTONE.getId());
this.playerBlocks.add(Material.OBSIDIAN.getId());
this.playerBlocks.add(Material.GLASS.getId());
this.playerBlocks.add(Material.LAPIS_BLOCK.getId());
this.playerBlocks.add(Material.DISPENSER.getId());
@ -149,6 +148,8 @@ class RestoreNatureProcessingTask implements Runnable
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.WEB.getId());
this.playerBlocks.add(Material.SPONGE.getId());
//these are unnatural in the standard world, but not in the nether
if(this.environment != Environment.NETHER)
@ -161,6 +162,12 @@ class RestoreNatureProcessingTask implements Runnable
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
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.MELON_BLOCK.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];
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);
}
}