This commit is contained in:
Ryan Hamshire 2012-07-01 14:44:07 -07:00
parent 2e39b36f1b
commit beec9c4e50
9 changed files with 338 additions and 48 deletions

View File

@ -1,7 +1,7 @@
name: GriefPrevention
main: me.ryanhamshire.GriefPrevention.GriefPrevention
softdepend: [Vault, Multiverse-Core]
version: 4.7
version: 4.9
commands:
abandonclaim:
description: Deletes a claim.

View File

@ -68,7 +68,7 @@ public class BlockEventHandler implements Listener
if(!GriefPrevention.instance.config_addItemsToClaimedChests) return;
Block block = event.getBlock();
Player player = event.getPlayer();
Player player = event.getPlayer();
//only care about player-damaged blocks
if(player == null) return;
@ -200,9 +200,7 @@ public class BlockEventHandler implements Listener
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
if(notEmpty && playerData.lastMessage != null && !playerData.lastMessage.equals(signMessage))
{
GriefPrevention.AddLogEntry("[Sign Placement] <" + player.getName() + "> " + lines.toString());
GriefPrevention.AddLogEntry("Location: " + GriefPrevention.getfriendlyLocationString(event.getBlock().getLocation()));
GriefPrevention.AddLogEntry("[Sign Placement] <" + player.getName() + "> " + lines.toString() + " @ " + GriefPrevention.getfriendlyLocationString(event.getBlock().getLocation()));
playerData.lastMessage = signMessage;
}
}
@ -275,7 +273,7 @@ public class BlockEventHandler implements Listener
//radius == 0 means protect ONLY the chest
if(GriefPrevention.instance.config_claims_automaticClaimsForNewPlayersRadius == 0)
{
this.dataStore.createClaim(block.getWorld(), block.getX(), block.getX(), block.getY(), block.getY(), block.getZ(), block.getZ(), player.getName(), null);
this.dataStore.createClaim(block.getWorld(), block.getX(), block.getX(), block.getY(), block.getY(), block.getZ(), block.getZ(), player.getName(), null, null);
GriefPrevention.sendMessage(player, TextMode.Success, Messages.ChestClaimConfirmation);
}
@ -289,7 +287,7 @@ public class BlockEventHandler implements Listener
block.getY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance, block.getY(),
block.getZ() - radius, block.getZ() + radius,
player.getName(),
null).succeeded)
null, null).succeeded)
{
radius--;
}
@ -339,13 +337,17 @@ public class BlockEventHandler implements Listener
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onBlockPistonExtend (BlockPistonExtendEvent event)
{
List<Block> blocks = event.getBlocks();
//if no blocks moving, then we don't care
if(blocks.size() == 0) return;
//who owns the piston, if anyone?
String pistonClaimOwnerName = "_";
Claim claim = this.dataStore.getClaimAt(event.getBlock().getLocation(), false, null);
if(claim != null) pistonClaimOwnerName = claim.getOwnerName();
//which blocks are being pushed?
List<Block> blocks = event.getBlocks();
for(int i = 0; i < blocks.size(); i++)
{
//if ANY of the pushed blocks are owned by someone other than the piston owner, cancel the event
@ -354,9 +356,69 @@ public class BlockEventHandler implements Listener
if(claim != null && !claim.getOwnerName().equals(pistonClaimOwnerName))
{
event.setCancelled(true);
event.getBlock().getWorld().createExplosion(event.getBlock().getLocation(), 0);
event.getBlock().getWorld().dropItem(event.getBlock().getLocation(), new ItemStack(event.getBlock().getType()));
event.getBlock().setType(Material.AIR);
return;
}
}
//which direction? note we're ignoring vertical push
int xchange = 0;
int zchange = 0;
Block piston = event.getBlock();
Block firstBlock = blocks.get(0);
if(firstBlock.getX() > piston.getX())
{
xchange = 1;
}
else if(firstBlock.getX() < piston.getX())
{
xchange = -1;
}
else if(firstBlock.getZ() > piston.getZ())
{
zchange = 1;
}
else if(firstBlock.getZ() < piston.getZ())
{
zchange = -1;
}
//if horizontal movement
if(xchange != 0 || zchange != 0)
{
for(int i = 0; i < blocks.size(); i++)
{
Block block = blocks.get(i);
Claim originalClaim = this.dataStore.getClaimAt(block.getLocation(), false, null);
String originalOwnerName = "";
if(originalClaim != null)
{
originalOwnerName = originalClaim.getOwnerName();
}
Claim newClaim = this.dataStore.getClaimAt(block.getLocation().add(xchange, 0, zchange), false, null);
String newOwnerName = "";
if(newClaim != null)
{
newOwnerName = newClaim.getOwnerName();
}
//if pushing this block will change ownership, cancel the event and take away the piston (for performance reasons)
if(!newOwnerName.equals(originalOwnerName))
{
event.setCancelled(true);
event.getBlock().getWorld().createExplosion(event.getBlock().getLocation(), 0);
event.getBlock().getWorld().dropItem(event.getBlock().getLocation(), new ItemStack(event.getBlock().getType()));
event.getBlock().setType(Material.AIR);
return;
}
}
}
}
//blocks theft by pulling blocks out of a claim (again pistons)
@ -469,11 +531,13 @@ public class BlockEventHandler implements Listener
Location rootLocation = growEvent.getLocation();
Claim rootClaim = this.dataStore.getClaimAt(rootLocation, false, null);
//who owns the root, if anyone?
//who owns the spreading block, if anyone?
OfflinePlayer fromOwner = null;
if(rootClaim != null)
{
//tree growth in subdivisions is dependent on who owns the top level claim
if(rootClaim.parent != null) rootClaim = rootClaim.parent;
//if an administrative claim, just let the tree grow where it wants
if(rootClaim.isAdminClaim()) return;

View File

@ -46,6 +46,9 @@ public class Claim
//modification date. this comes from the file timestamp during load, and is updated with runtime changes
public Date modifiedDate;
//id number. unique to this claim, never changes.
Long id = null;
//ownername. for admin claims, this is the empty string
//use getOwnerName() to get a friendly name (will be "an administrator" for admin claims)
public String ownerName;
@ -83,6 +86,12 @@ public class Claim
return this.ownerName.isEmpty();
}
//accessor for ID
public Long getID()
{
return new Long(this.id);
}
//basic constructor, just notes the creation time
//see above declarations for other defaults
Claim()
@ -178,11 +187,14 @@ public class Claim
}
//main constructor. note that only creating a claim instance does nothing - a claim must be added to the data store to be effective
Claim(Location lesserBoundaryCorner, Location greaterBoundaryCorner, String ownerName, String [] builderNames, String [] containerNames, String [] accessorNames, String [] managerNames)
Claim(Location lesserBoundaryCorner, Location greaterBoundaryCorner, String ownerName, String [] builderNames, String [] containerNames, String [] accessorNames, String [] managerNames, Long id)
{
//modification date
this.modifiedDate = Calendar.getInstance().getTime();
//id
this.id = id;
//store corners
this.lesserBoundaryCorner = lesserBoundaryCorner;
this.greaterBoundaryCorner = greaterBoundaryCorner;
@ -253,7 +265,7 @@ public class Claim
Claim claim = new Claim
(new Location(this.lesserBoundaryCorner.getWorld(), this.lesserBoundaryCorner.getBlockX() - howNear, this.lesserBoundaryCorner.getBlockY(), this.lesserBoundaryCorner.getBlockZ() - howNear),
new Location(this.greaterBoundaryCorner.getWorld(), this.greaterBoundaryCorner.getBlockX() + howNear, this.greaterBoundaryCorner.getBlockY(), this.greaterBoundaryCorner.getBlockZ() + howNear),
"", new String[] {}, new String[] {}, new String[] {}, new String[] {});
"", new String[] {}, new String[] {}, new String[] {}, new String[] {}, null);
return claim.contains(location, false, true);
}

View File

@ -45,12 +45,16 @@ public class DataStore
//in-memory cache for messages
private String [] messages;
//next claim ID
Long nextClaimID = (long)0;
//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";
final static String nextClaimIdFilePath = claimDataFolderPath + File.separator + "_nextClaimID";
//initialization!
DataStore()
@ -97,6 +101,32 @@ public class DataStore
//load claims data into memory
File claimDataFolder = new File(claimDataFolderPath);
//load next claim number from file
File nextClaimIdFile = new File(nextClaimIdFilePath);
if(nextClaimIdFile.exists())
{
BufferedReader inStream = null;
try
{
inStream = new BufferedReader(new FileReader(nextClaimIdFile.getAbsolutePath()));
//read the id
String line = inStream.readLine();
//try to parse into a long value
this.nextClaimID = Long.parseLong(line);
}
catch(Exception e){ }
try
{
if(inStream != null) inStream.close();
}
catch(IOException exception) {}
}
//get a list of all the files in the claims data folder
files = claimDataFolder.listFiles();
int loadedClaimCount = 0;
@ -105,6 +135,28 @@ public class DataStore
{
if(files[i].isFile()) //avoids folders
{
//skip any file starting with an underscore, to avoid the _nextClaimID file.
if(files[i].getName().startsWith("_")) continue;
//the filename is the claim ID. try to parse it
long claimID;
try
{
claimID = Long.parseLong(files[i].getName());
}
//because some older versions used a different file name pattern before claim IDs were introduced,
//those files need to be "converted" by renaming them to a unique ID
catch(Exception e)
{
claimID = this.nextClaimID;
this.incrementNextClaimID();
File newFile = new File(claimDataFolderPath + File.separator + String.valueOf(this.nextClaimID));
files[i].renameTo(newFile);
files[i] = newFile;
}
BufferedReader inStream = null;
try
{
@ -153,7 +205,7 @@ public class DataStore
if(topLevelClaim == null)
{
//instantiate
topLevelClaim = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, ownerName, builderNames, containerNames, accessorNames, managerNames);
topLevelClaim = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, ownerName, builderNames, containerNames, accessorNames, managerNames, claimID);
//search for another claim overlapping this one
Claim conflictClaim = this.getClaimAt(topLevelClaim.lesserBoundaryCorner, true, null);
@ -184,7 +236,7 @@ public class DataStore
//otherwise there's already a top level claim, so this must be a subdivision of that top level claim
else
{
Claim subdivision = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, "--subdivision--", builderNames, containerNames, accessorNames, managerNames);
Claim subdivision = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, "--subdivision--", builderNames, containerNames, accessorNames, managerNames, null);
//make sure there are no other subdivisions overlapping this one
@ -487,7 +539,13 @@ public class DataStore
}
//otherwise get a unique identifier for the claim which will be used to name the file on disk
String claimID = this.getClaimID(claim);
if(claim.id == null)
{
claim.id = this.nextClaimID;
this.incrementNextClaimID();
}
String claimID = String.valueOf(claim.id);
BufferedWriter outStream = null;
@ -521,13 +579,41 @@ public class DataStore
catch(IOException exception) {}
}
private void incrementNextClaimID()
{
this.nextClaimID++;
BufferedWriter outStream = null;
try
{
//open the claim's file
File nextClaimIdFile = new File(nextClaimIdFilePath);
nextClaimIdFile.createNewFile();
outStream = new BufferedWriter(new FileWriter(nextClaimIdFile));
outStream.write(String.valueOf(this.nextClaimID));
}
//if any problem, log it
catch(Exception e)
{
GriefPrevention.AddLogEntry("Unexpected exception saving next claim ID: " + e.getMessage());
}
//close the file
try
{
if(outStream != null) outStream.close();
}
catch(IOException exception) {}
}
//actually writes claim data to an output stream
private void writeClaimData(Claim claim, BufferedWriter outStream) throws IOException
{
String claimID = this.getClaimID(claim);
//first line is lesser boundary corner location
outStream.write(claimID);
outStream.write(this.locationToString(claim.getLesserBoundaryCorner()));
outStream.newLine();
//second line is greater boundary corner location
@ -721,12 +807,12 @@ public class DataStore
}
//otherwise, need to update the data store and ensure the claim's file is deleted
String claimID = this.getClaimID(claim);
String claimID = String.valueOf(claim.id);
//remove from memory
for(int i = 0; i < this.claims.size(); i++)
{
if(this.getClaimID(this.claims.get(i)).equals(claimID))
if(claims.get(i).id.equals(claim.id))
{
this.claims.remove(i);
claim.inDataStore = false;
@ -751,7 +837,7 @@ public class DataStore
PlayerData ownerData = this.getPlayerData(claim.getOwnerName());
for(int i = 0; i < ownerData.claims.size(); i++)
{
if(this.getClaimID(ownerData.claims.get(i)).equals(claimID))
if(ownerData.claims.get(i).id.equals(claim.id))
{
ownerData.claims.remove(i);
break;
@ -811,7 +897,7 @@ public class DataStore
//does NOT check a player has permission to create a claim, or enough claim blocks.
//does NOT check minimum claim size constraints
//does NOT visualize the new claim for any players
public CreateClaimResult createClaim(World world, int x1, int x2, int y1, int y2, int z1, int z2, String ownerName, Claim parent)
public CreateClaimResult createClaim(World world, int x1, int x2, int y1, int y2, int z1, int z2, String ownerName, Claim parent, Long id)
{
CreateClaimResult result = new CreateClaimResult();
@ -865,7 +951,8 @@ public class DataStore
new String [] {},
new String [] {},
new String [] {},
new String [] {});
new String [] {},
id);
newClaim.parent = parent;
@ -960,12 +1047,6 @@ public class DataStore
catch(IOException exception){}
}
//gets a unique identifier for a claim
private String getClaimID(Claim claim)
{
return this.locationToString(claim.getLesserBoundaryCorner());
}
//extends a claim to a new depth
//respects the max depth config variable
public void extendClaim(Claim claim, int newDepth)
@ -1216,7 +1297,7 @@ public class DataStore
this.deleteClaim(claim);
//try to create this new claim, ignoring the original when checking for overlap
CreateClaimResult result = this.createClaim(claim.getLesserBoundaryCorner().getWorld(), newx1, newx2, newy1, newy2, newz1, newz2, claim.ownerName, claim.parent);
CreateClaimResult result = this.createClaim(claim.getLesserBoundaryCorner().getWorld(), newx1, newx2, newy1, newy2, newz1, newz2, claim.ownerName, claim.parent, claim.id);
//if succeeded
if(result.succeeded)
@ -1418,7 +1499,7 @@ public class DataStore
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");
this.addDefault(defaults, Messages.HowToClaimRegex, "(^|.*\\W)how\\W.*\\Wclaim(\\W.*|$)", "This is a Java Regular Expression. Look it up before editing! It's used to tell players about the demo video when they ask how to claim land.");
this.addDefault(defaults, Messages.HowToClaimRegex, "(^|.*\\W)how\\W.*\\W(claim|protect)(\\W.*|$)", "This is a Java Regular Expression. Look it up before editing! It's used to tell players about the demo video when they ask how to claim land.");
//load the config file
FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath));

View File

@ -29,11 +29,11 @@ import org.bukkit.entity.Arrow;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
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;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@ -45,11 +45,13 @@ 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.EntityInteractEvent;
import org.bukkit.event.entity.ExpBottleEvent;
import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.painting.PaintingBreakByEntityEvent;
import org.bukkit.event.painting.PaintingBreakEvent;
import org.bukkit.event.painting.PaintingPlaceEvent;
import org.bukkit.event.vehicle.VehicleDamageEvent;
//handles events related to entities
class EntityEventHandler implements Listener
@ -62,6 +64,26 @@ class EntityEventHandler implements Listener
this.dataStore = dataStore;
}
//don't allow endermen to change blocks
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onEntityChangeBLock(EntityChangeBlockEvent event)
{
if(!GriefPrevention.instance.config_endermenMoveBlocks && event.getEntityType() == EntityType.ENDERMAN)
{
event.setCancelled(true);
}
}
//don't allow entities to trample crops
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onEntityInteract(EntityInteractEvent event)
{
if(!GriefPrevention.instance.config_creaturesTrampleCrops && event.getBlock().getType() == Material.SOIL)
{
event.setCancelled(true);
}
}
//when an entity explodes...
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onEntityExplode(EntityExplodeEvent explodeEvent)
@ -147,10 +169,10 @@ class EntityEventHandler implements Listener
event.setCancelled(true);
return;
}
//otherwise, just apply the limit on total entities per claim
//otherwise, just apply the limit on total entities per claim (and no spawning in the wilderness!)
Claim claim = this.dataStore.getClaimAt(event.getLocation(), false, null);
if(claim != null && claim.allowMoreEntities() != null)
if(claim == null || claim.allowMoreEntities() != null)
{
event.setCancelled(true);
return;
@ -363,8 +385,7 @@ class EntityEventHandler implements Listener
if(event instanceof EntityDamageByEntityEvent)
{
//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))
if ((subEvent.getEntity() instanceof Creature && GriefPrevention.instance.config_claims_protectCreatures))
{
Claim cachedClaim = null;
PlayerData playerData = null;
@ -405,4 +426,75 @@ class EntityEventHandler implements Listener
}
}
}
//when a vehicle is damaged
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onVehicleDamage (VehicleDamageEvent event)
{
//all of this is anti theft code
if(!GriefPrevention.instance.config_claims_preventTheft) return;
//determine which player is attacking, if any
Player attacker = null;
Entity damageSource = event.getAttacker();
if(damageSource instanceof Player)
{
attacker = (Player)damageSource;
}
else if(damageSource instanceof Arrow)
{
Arrow arrow = (Arrow)damageSource;
if(arrow.getShooter() instanceof Player)
{
attacker = (Player)arrow.getShooter();
}
}
else if(damageSource instanceof ThrownPotion)
{
ThrownPotion potion = (ThrownPotion)damageSource;
if(potion.getShooter() instanceof Player)
{
attacker = (Player)potion.getShooter();
}
}
//NOTE: vehicles can be pushed around.
//so unless precautions are taken by the owner, a resourceful thief might find ways to steal anyway
Claim cachedClaim = null;
PlayerData playerData = null;
if(attacker != null)
{
playerData = this.dataStore.getPlayerData(attacker.getName());
cachedClaim = playerData.lastClaim;
}
Claim claim = this.dataStore.getClaimAt(event.getVehicle().getLocation(), false, cachedClaim);
//if it's claimed
if(claim != null)
{
//if damaged by anything other than a player, cancel the event
if(attacker == null)
{
event.setCancelled(true);
}
//otherwise the player damaging the entity must have permission
else
{
String noContainersReason = claim.allowContainers(attacker);
if(noContainersReason != null)
{
event.setCancelled(true);
GriefPrevention.sendMessage(attacker, TextMode.Err, Messages.NoDamageClaimedEntity, claim.getOwnerName());
}
//cache claim for later
if(playerData != null)
{
playerData.lastClaim = claim;
}
}
}
}
}

View File

@ -80,6 +80,8 @@ public class GriefPrevention extends JavaPlugin
public int config_claims_trappedCooldownHours; //number of hours between uses of the /trapped command
public Material config_claims_investigationTool; //which material will be used to investigate claims with a right click
public ArrayList<World> config_siege_enabledWorlds; //whether or not /siege is enabled on this server
public ArrayList<Material> config_siege_blocks; //which blocks will be breakable in siege mode
@ -114,6 +116,9 @@ public class GriefPrevention extends JavaPlugin
public boolean config_smartBan; //whether to ban accounts which very likely owned by a banned player
public boolean config_endermenMoveBlocks; //whether or not endermen may move blocks around
public boolean config_creaturesTrampleCrops; //whether or not non-player entities may trample crops
//reference to the economy plugin, if economy integration is enabled
public static Economy economy = null;
@ -252,6 +257,23 @@ public class GriefPrevention extends JavaPlugin
this.config_smartBan = config.getBoolean("GriefPrevention.SmartBan", true);
this.config_endermenMoveBlocks = config.getBoolean("GriefPrevention.EndermenMoveBlocks", false);
this.config_creaturesTrampleCrops = config.getBoolean("GriefPrevention.CreaturesTrampleCrops", false);
//default for claim investigation tool
String investigationToolMaterialName = Material.STICK.name();
//get investigation tool from config
investigationToolMaterialName = config.getString("GriefPrevention.Claims.InvestigationTool", investigationToolMaterialName);
//validate investigation tool
this.config_claims_investigationTool = Material.getMaterial(investigationToolMaterialName);
if(this.config_claims_investigationTool == null)
{
GriefPrevention.AddLogEntry("ERROR: Material " + investigationToolMaterialName + " not found. Defaulting to the stick. Please update your config.yml.");
this.config_claims_investigationTool = Material.STICK;
}
//default for siege worlds list
ArrayList<String> defaultSiegeWorldNames = new ArrayList<String>();
@ -339,6 +361,7 @@ public class GriefPrevention extends JavaPlugin
config.set("GriefPrevention.Claims.MaximumDepth", this.config_claims_maxDepth);
config.set("GriefPrevention.Claims.IdleLimitDays", this.config_claims_expirationDays);
config.set("GriefPrevention.Claims.TrappedCommandCooldownHours", this.config_claims_trappedCooldownHours);
config.set("GriefPrevention.Claims.InvestigationTool", this.config_claims_investigationTool.name());
config.set("GriefPrevention.Spam.Enabled", this.config_spam_enabled);
config.set("GriefPrevention.Spam.LoginCooldownMinutes", this.config_spam_loginCooldownMinutes);
@ -367,13 +390,16 @@ public class GriefPrevention extends JavaPlugin
config.set("GriefPrevention.FireDestroys", this.config_fireDestroys);
config.set("GriefPrevention.AddItemsToClaimedChests", this.config_addItemsToClaimedChests);
config.set("GriefPrevention.EavesdropEnabled", this.config_eavesdrop);
config.set("GriefPrevention.EavesdropEnabled", this.config_eavesdrop);
config.set("GriefPrevention.SmartBan", this.config_smartBan);
config.set("GriefPrevention.Siege.Worlds", siegeEnabledWorldNames);
config.set("GriefPrevention.Siege.BreakableBlocks", breakableBlocksList);
config.set("GriefPrevention.EndermenMoveBlocks", this.config_endermenMoveBlocks);
config.set("GriefPrevention.CreaturesTrampleCrops", this.config_creaturesTrampleCrops);
try
{
config.save(DataStore.configFilePath);
@ -1655,6 +1681,9 @@ public class GriefPrevention extends JavaPlugin
//if pvp is disabled, do nothing
if(!player.getWorld().getPVP()) return;
//if player is in creative mode, do nothing
if(player.getGameMode() == GameMode.CREATIVE) return;
//if anti spawn camping feature is not enabled, do nothing
if(!this.config_pvp_protectFreshSpawns) return;

View File

@ -70,7 +70,7 @@ public class PlayerData
//spam
public Date lastLogin; //when the player last logged into the server
public String lastMessage = ""; //the player's last chat message, or slash command complete with parameters
public Date lastMessageTimestamp = new Date(); //last time the player sent a chat message or used a monitored slash command
public Date lastMessageTimestamp = new Date(); //last time the player sent a chat message or used a monitored slash command
public int spamCount = 0; //number of consecutive "spams"
public boolean spamWarned = false; //whether the player recently received a warning

View File

@ -126,6 +126,14 @@ class PlayerEventHandler implements Listener
boolean spam = false;
boolean muted = false;
//single-character messages will not be sent
if(message.length() == 1)
{
playerData.spamCount++;
spam = true;
muted = true;
}
//check message content and timing
long millisecondsSinceLastMessage = (new Date()).getTime() - playerData.lastMessageTimestamp.getTime();
@ -137,8 +145,8 @@ class PlayerEventHandler implements Listener
spam = true;
}
//if it's very similar to the last message
if(!muted && this.stringsAreSimilar(message, playerData.lastMessage))
//if it's very similar to the last message and less than 10 seconds have passed
if(!muted && this.stringsAreSimilar(message, playerData.lastMessage) && millisecondsSinceLastMessage < 10000)
{
playerData.spamCount++;
spam = true;
@ -148,7 +156,7 @@ class PlayerEventHandler implements Listener
//filter IP addresses
if(!muted && !(event instanceof PlayerCommandPreprocessEvent))
{
Pattern ipAddressPattern = Pattern.compile("\\d+\\.\\d+\\.\\d+\\.\\d+");
Pattern ipAddressPattern = Pattern.compile("\\d{1,4}\\D{1,3}\\d{1,4}\\D{1,3}\\d{1,4}\\D{1,3}\\d{1,4}");
Matcher matcher = ipAddressPattern.matcher(event.getMessage());
//if it looks like an IP address
@ -515,6 +523,9 @@ class PlayerEventHandler implements Listener
{
if(player.getHealth() > 0) player.setHealth(0); //might already be zero from above, this avoids a double death message
}
//drop data about this player
this.dataStore.clearCachedPlayerData(player.getName());
}
//determines whether or not a login or logout notification should be silenced, depending on how many there have been in the last minute
@ -993,8 +1004,8 @@ class PlayerEventHandler implements Listener
return;
}
//if it's stick or arrow, he's investigating a claim
else if(materialInHand == Material.STICK)
//if he's investigating a claim
else if(materialInHand == GriefPrevention.instance.config_claims_investigationTool)
{
//air indicates too far away
if(clickedBlockType == Material.AIR)
@ -1316,7 +1327,7 @@ class PlayerEventHandler implements Listener
Claim newClaim = new Claim(
new Location(oldClaim.getLesserBoundaryCorner().getWorld(), newx1, newy1, newz1),
new Location(oldClaim.getLesserBoundaryCorner().getWorld(), newx2, newy2, newz2),
"", new String[]{}, new String[]{}, new String[]{}, new String[]{});
"", new String[]{}, new String[]{}, new String[]{}, new String[]{}, null);
//if the new claim is smaller
if(!newClaim.contains(oldClaim.getLesserBoundaryCorner(), true, false) || !newClaim.contains(oldClaim.getGreaterBoundaryCorner(), true, false))
@ -1423,7 +1434,8 @@ class PlayerEventHandler implements Listener
playerData.lastShovelLocation.getBlockY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance, clickedBlock.getY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance,
playerData.lastShovelLocation.getBlockZ(), clickedBlock.getZ(),
"--subdivision--", //owner name is not used for subdivisions
playerData.claimSubdividing);
playerData.claimSubdividing,
null);
//if it didn't succeed, tell the player why
if(!result.succeeded)
@ -1532,7 +1544,7 @@ class PlayerEventHandler implements Listener
lastShovelLocation.getBlockY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance, clickedBlock.getY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance,
lastShovelLocation.getBlockZ(), clickedBlock.getZ(),
playerName,
null);
null, null);
//if it didn't succeed, tell the player why
if(!result.succeeded)

View File

@ -90,7 +90,7 @@ class RestoreNatureExecutionTask implements Runnable
}
//show visualization to player
Claim claim = new Claim(lesserCorner, greaterCorner, "", new String[] {}, new String[] {}, new String[] {}, new String[] {});
Claim claim = new Claim(lesserCorner, greaterCorner, "", new String[] {}, new String[] {}, new String[] {}, new String[] {}, null);
Visualization visualization = Visualization.FromClaim(claim, player.getLocation().getBlockY(), VisualizationType.RestoreNature);
Visualization.Apply(player, visualization);
}