This commit is contained in:
Ryan Hamshire 2012-11-07 17:36:25 -08:00
parent 6632af96df
commit e09a6732ba
12 changed files with 8839 additions and 8696 deletions

View File

@ -2,7 +2,7 @@ name: GriefPrevention
main: me.ryanhamshire.GriefPrevention.GriefPrevention main: me.ryanhamshire.GriefPrevention.GriefPrevention
softdepend: [Vault, Multiverse-Core, My Worlds, MystCraft, Transporter] softdepend: [Vault, Multiverse-Core, My Worlds, MystCraft, Transporter]
dev-url: http://dev.bukkit.org/server-mods/grief-prevention dev-url: http://dev.bukkit.org/server-mods/grief-prevention
version: 6.7 version: 6.9
commands: commands:
abandonclaim: abandonclaim:
description: Deletes a claim. description: Deletes a claim.

View File

@ -30,7 +30,10 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.block.Chest; import org.bukkit.block.Chest;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -46,6 +49,7 @@ import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.BlockSpreadEvent; import org.bukkit.event.block.BlockSpreadEvent;
import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.event.world.StructureGrowEvent;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -77,6 +81,36 @@ public class BlockEventHandler implements Listener
this.trashBlocks.add(Material.WORKBENCH); this.trashBlocks.add(Material.WORKBENCH);
} }
//when a wooden button is triggered by an arrow...
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onProjectileHit(ProjectileHitEvent event)
{
Projectile projectile = event.getEntity();
Location location = projectile.getLocation();
Block block = location.getBlock();
//only care about wooden buttons
if(block.getType() != Material.WOOD_BUTTON) return;
//only care about arrows
if(projectile instanceof Arrow)
{
Arrow arrow = (Arrow)projectile;
LivingEntity shooterEntity = arrow.getShooter();
//player arrows only trigger buttons when they have permission
if(shooterEntity instanceof Player)
{
//Player player = (Player)shooterEntity;
}
//other arrows don't trigger buttons, could be used as a workaround to get access to areas without permission
else
{
}
}
}
//when a block is damaged... //when a block is damaged...
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onBlockDamaged(BlockDamageEvent event) public void onBlockDamaged(BlockDamageEvent event)
@ -377,7 +411,7 @@ public class BlockEventHandler implements Listener
//warn players when they place TNT above sea level, since it doesn't destroy blocks there //warn players when they place TNT above sea level, since it doesn't destroy blocks there
if( GriefPrevention.instance.config_blockSurfaceOtherExplosions && block.getType() == Material.TNT && if( GriefPrevention.instance.config_blockSurfaceOtherExplosions && block.getType() == Material.TNT &&
block.getWorld().getEnvironment() != Environment.NETHER && block.getWorld().getEnvironment() != Environment.NETHER &&
block.getY() > block.getWorld().getSeaLevel() - 5) block.getY() > GriefPrevention.instance.getSeaLevel(block.getWorld()) - 5)
{ {
GriefPrevention.sendMessage(player, TextMode.Warn, Messages.NoTNTDamageAboveSeaLevel); GriefPrevention.sendMessage(player, TextMode.Warn, Messages.NoTNTDamageAboveSeaLevel);
} }
@ -514,11 +548,7 @@ public class BlockEventHandler implements Listener
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void onBlockIgnite (BlockIgniteEvent igniteEvent) public void onBlockIgnite (BlockIgniteEvent igniteEvent)
{ {
if(!GriefPrevention.instance.config_fireSpreads && if(!GriefPrevention.instance.config_fireSpreads && igniteEvent.getCause() != IgniteCause.FLINT_AND_STEEL && igniteEvent.getCause() != IgniteCause.LIGHTNING)
igniteEvent.getBlock().getWorld().getEnvironment() == Environment.NORMAL &&
igniteEvent.getCause() != IgniteCause.FLINT_AND_STEEL &&
igniteEvent.getCause() != IgniteCause.LIGHTNING &&
igniteEvent.getCause() != IgniteCause.LAVA)
{ {
igniteEvent.setCancelled(true); igniteEvent.setCancelled(true);
} }

View File

@ -131,7 +131,7 @@ public class Claim
int seaLevel = 0; //clean up all fluids in the end int seaLevel = 0; //clean up all fluids in the end
//respect sea level in normal worlds //respect sea level in normal worlds
if(lesser.getWorld().getEnvironment() == Environment.NORMAL) seaLevel = lesser.getWorld().getSeaLevel(); if(lesser.getWorld().getEnvironment() == Environment.NORMAL) seaLevel = GriefPrevention.instance.getSeaLevel(lesser.getWorld());
for(int x = lesser.getBlockX(); x <= greater.getBlockX(); x++) for(int x = lesser.getBlockX(); x <= greater.getBlockX(); x++)
{ {
@ -165,7 +165,7 @@ public class Claim
int seaLevel = 0; //clean up all fluids in the end int seaLevel = 0; //clean up all fluids in the end
//respect sea level in normal worlds //respect sea level in normal worlds
if(lesser.getWorld().getEnvironment() == Environment.NORMAL) seaLevel = lesser.getWorld().getSeaLevel(); if(lesser.getWorld().getEnvironment() == Environment.NORMAL) seaLevel = GriefPrevention.instance.getSeaLevel(lesser.getWorld());
int waterCount = 0; int waterCount = 0;
for(int x = lesser.getBlockX(); x <= greater.getBlockX(); x++) for(int x = lesser.getBlockX(); x <= greater.getBlockX(); x++)
@ -362,7 +362,10 @@ public class Claim
return this.parent.allowBuild(player); return this.parent.allowBuild(player);
//failure message for all other cases //failure message for all other cases
return GriefPrevention.instance.dataStore.getMessage(Messages.NoBuildPermission, this.getOwnerName()); String reason = GriefPrevention.instance.dataStore.getMessage(Messages.NoBuildPermission, this.getOwnerName());
if(player.hasPermission("griefprevention.ignoreclaims"))
reason += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return reason;
} }
private boolean hasExplicitPermission(Player player, ClaimPermission level) private boolean hasExplicitPermission(Player player, ClaimPermission level)
@ -458,7 +461,10 @@ public class Claim
return this.parent.allowAccess(player); return this.parent.allowAccess(player);
//catch-all error message for all other cases //catch-all error message for all other cases
return GriefPrevention.instance.dataStore.getMessage(Messages.NoAccessPermission, this.getOwnerName()); String reason = GriefPrevention.instance.dataStore.getMessage(Messages.NoAccessPermission, this.getOwnerName());
if(player.hasPermission("griefprevention.ignoreclaims"))
reason += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return reason;
} }
//inventory permission check //inventory permission check
@ -498,7 +504,10 @@ public class Claim
return this.parent.allowContainers(player); return this.parent.allowContainers(player);
//error message for all other cases //error message for all other cases
return GriefPrevention.instance.dataStore.getMessage(Messages.NoContainersPermission, this.getOwnerName()); String reason = GriefPrevention.instance.dataStore.getMessage(Messages.NoContainersPermission, this.getOwnerName());
if(player.hasPermission("griefprevention.ignoreclaims"))
reason += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return reason;
} }
//grant permission check, relatively simple //grant permission check, relatively simple
@ -529,7 +538,10 @@ public class Claim
return this.parent.allowGrantPermission(player); return this.parent.allowGrantPermission(player);
//generic error message //generic error message
return GriefPrevention.instance.dataStore.getMessage(Messages.NoPermissionTrust, this.getOwnerName()); String reason = GriefPrevention.instance.dataStore.getMessage(Messages.NoPermissionTrust, this.getOwnerName());
if(player.hasPermission("griefprevention.ignoreclaims"))
reason += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return reason;
} }
//grants a permission for a player or the public //grants a permission for a player or the public
@ -778,7 +790,7 @@ public class Claim
for(int z = this.lesserBoundaryCorner.getBlockZ(); z <= this.greaterBoundaryCorner.getBlockZ(); z++) for(int z = this.lesserBoundaryCorner.getBlockZ(); z <= this.greaterBoundaryCorner.getBlockZ(); z++)
{ {
int y = this.lesserBoundaryCorner.getBlockY(); int y = this.lesserBoundaryCorner.getBlockY();
for(; y < this.lesserBoundaryCorner.getWorld().getSeaLevel(); y++) for(; y < GriefPrevention.instance.getSeaLevel(this.lesserBoundaryCorner.getWorld()) - 5; y++)
{ {
Block block = this.lesserBoundaryCorner.getWorld().getBlockAt(x, y, z); Block block = this.lesserBoundaryCorner.getWorld().getBlockAt(x, y, z);
if(playerBlocks.contains(block.getTypeId())) if(playerBlocks.contains(block.getTypeId()))
@ -789,7 +801,7 @@ public class Claim
} }
else else
{ {
score += .2; score += .5;
} }
} }
} }

View File

@ -20,6 +20,7 @@
import java.util.Calendar; import java.util.Calendar;
import java.util.Random; import java.util.Random;
import java.util.Vector;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.World; import org.bukkit.World;
@ -63,6 +64,9 @@ class CleanupUnusedClaimsTask implements Runnable
//skip administrative claims //skip administrative claims
if(claim.isAdminClaim()) return; if(claim.isAdminClaim()) return;
//track whether we do any important work which would require cleanup afterward
boolean cleanupChunks = false;
//get data for the player, especially last login timestamp //get data for the player, especially last login timestamp
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(claim.ownerName); PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(claim.ownerName);
@ -75,20 +79,21 @@ class CleanupUnusedClaimsTask implements Runnable
//if he's been gone at least a week, if he has ONLY the new player claim, it will be removed //if he's been gone at least a week, if he has ONLY the new player claim, it will be removed
Calendar sevenDaysAgo = Calendar.getInstance(); Calendar sevenDaysAgo = Calendar.getInstance();
sevenDaysAgo.add(Calendar.DATE, -7); sevenDaysAgo.add(Calendar.DATE, -GriefPrevention.instance.config_claims_chestClaimExpirationDays);
boolean newPlayerClaimsExpired = sevenDaysAgo.getTime().after(playerData.lastLogin); boolean newPlayerClaimsExpired = sevenDaysAgo.getTime().after(playerData.lastLogin);
//if only one claim, and the player hasn't played in a week //if only one claim, and the player hasn't played in a week
if(newPlayerClaimsExpired && playerData.claims.size() == 1) if(newPlayerClaimsExpired && playerData.claims.size() == 1)
{ {
//if that's a chest claim, delete it //if that's a chest claim and those are set to expire
if(claim.getArea() <= areaOfDefaultClaim) if(claim.getArea() <= areaOfDefaultClaim && GriefPrevention.instance.config_claims_chestClaimExpirationDays > 0)
{ {
claim.removeSurfaceFluids(null); claim.removeSurfaceFluids(null);
GriefPrevention.instance.dataStore.deleteClaim(claim); GriefPrevention.instance.dataStore.deleteClaim(claim);
cleanupChunks = true;
//if in a creative mode world, delete the claim //if configured to do so, restore the land to natural
if(GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner())) if((GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()) && GriefPrevention.instance.config_claims_creativeAutoNatureRestoration) || GriefPrevention.instance.config_claims_survivalAutoNatureRestoration)
{ {
GriefPrevention.instance.restoreClaim(claim, 0); GriefPrevention.instance.restoreClaim(claim, 0);
} }
@ -105,18 +110,35 @@ class CleanupUnusedClaimsTask implements Runnable
if(earliestPermissibleLastLogin.getTime().after(playerData.lastLogin)) if(earliestPermissibleLastLogin.getTime().after(playerData.lastLogin))
{ {
//make a copy of this player's claim list
Vector<Claim> claims = new Vector<Claim>();
for(int i = 0; i < playerData.claims.size(); i++)
{
claims.add(playerData.claims.get(i));
}
//delete them
GriefPrevention.instance.dataStore.deleteClaimsForPlayer(claim.getOwnerName(), true); GriefPrevention.instance.dataStore.deleteClaimsForPlayer(claim.getOwnerName(), true);
GriefPrevention.AddLogEntry(" All of " + claim.getOwnerName() + "'s claims have expired."); GriefPrevention.AddLogEntry(" All of " + claim.getOwnerName() + "'s claims have expired.");
}
}
else for(int i = 0; i < claims.size(); i++)
{ {
//if configured to do so, restore the land to natural
if((GriefPrevention.instance.creativeRulesApply(claims.get(i).getLesserBoundaryCorner()) && GriefPrevention.instance.config_claims_creativeAutoNatureRestoration) || GriefPrevention.instance.config_claims_survivalAutoNatureRestoration)
{
GriefPrevention.instance.restoreClaim(claims.get(i), 0);
cleanupChunks = true;
}
}
}
}
else if(GriefPrevention.instance.config_claims_unusedClaimExpirationDays > 0)
{
//if the player has been gone two weeks, scan claim content to assess player investment //if the player has been gone two weeks, scan claim content to assess player investment
Calendar fourteenDaysAgo = Calendar.getInstance(); Calendar earliestAllowedLoginDate = Calendar.getInstance();
fourteenDaysAgo.add(Calendar.DATE, -14); earliestAllowedLoginDate.add(Calendar.DATE, -GriefPrevention.instance.config_claims_unusedClaimExpirationDays);
boolean needsInvestmentScan = fourteenDaysAgo.getTime().after(playerData.lastLogin); boolean needsInvestmentScan = earliestAllowedLoginDate.getTime().after(playerData.lastLogin);
//avoid scanning large claims and administrative claims //avoid scanning large claims and administrative claims
if(claim.isAdminClaim() || claim.getWidth() > 25 || claim.getHeight() > 25) return; if(claim.isAdminClaim() || claim.getWidth() > 25 || claim.getHeight() > 25) return;
@ -131,10 +153,11 @@ class CleanupUnusedClaimsTask implements Runnable
} }
else else
{ {
minInvestment = 200; minInvestment = 100;
} }
long investmentScore = claim.getPlayerInvestmentScore(); long investmentScore = claim.getPlayerInvestmentScore();
cleanupChunks = true;
boolean removeClaim = false; boolean removeClaim = false;
//in creative mode, a build which is almost entirely lava above sea level will be automatically removed, even if the owner is an active player //in creative mode, a build which is almost entirely lava above sea level will be automatically removed, even if the owner is an active player
@ -156,8 +179,8 @@ class CleanupUnusedClaimsTask implements Runnable
GriefPrevention.instance.dataStore.deleteClaim(claim); GriefPrevention.instance.dataStore.deleteClaim(claim);
GriefPrevention.AddLogEntry("Removed " + claim.getOwnerName() + "'s unused claim @ " + GriefPrevention.getfriendlyLocationString(claim.getLesserBoundaryCorner())); GriefPrevention.AddLogEntry("Removed " + claim.getOwnerName() + "'s unused claim @ " + GriefPrevention.getfriendlyLocationString(claim.getLesserBoundaryCorner()));
//if in a creative mode world, restore the claim area //if configured to do so, restore the claim area to natural state
if(GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner())) if((GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()) && GriefPrevention.instance.config_claims_creativeAutoNatureRestoration) || GriefPrevention.instance.config_claims_survivalAutoNatureRestoration)
{ {
GriefPrevention.instance.restoreClaim(claim, 0); GriefPrevention.instance.restoreClaim(claim, 0);
} }
@ -172,8 +195,7 @@ class CleanupUnusedClaimsTask implements Runnable
} }
//since we're potentially loading a lot of chunks to scan parts of the world where there are no players currently playing, be mindful of memory usage //since we're potentially loading a lot of chunks to scan parts of the world where there are no players currently playing, be mindful of memory usage
//unfortunately, java/minecraft don't do a good job of clearing unused memory, leading to out of memory errors from this type of world scanning if(cleanupChunks)
if(this.nextClaimIndex % 20 == 0)
{ {
World world = claim.getLesserBoundaryCorner().getWorld(); World world = claim.getLesserBoundaryCorner().getWorld();
Chunk [] chunks = world.getLoadedChunks(); Chunk [] chunks = world.getLoadedChunks();
@ -182,7 +204,11 @@ class CleanupUnusedClaimsTask implements Runnable
Chunk chunk = chunks[i]; Chunk chunk = chunks[i];
chunk.unload(true, true); chunk.unload(true, true);
} }
}
//unfortunately, java/minecraft don't do a good job of clearing unused memory, leading to out of memory errors from this type of world scanning
if(this.nextClaimIndex % 10 == 0)
{
System.gc(); System.gc();
} }
} }

View File

@ -960,6 +960,7 @@ public abstract class DataStore
this.addDefault(defaults, Messages.NoTeleportPvPCombat, "You can't teleport while fighting another player.", null); this.addDefault(defaults, Messages.NoTeleportPvPCombat, "You can't teleport while fighting another player.", null);
this.addDefault(defaults, Messages.NoTNTDamageAboveSeaLevel, "Warning: TNT will not destroy blocks above sea level.", null); this.addDefault(defaults, Messages.NoTNTDamageAboveSeaLevel, "Warning: TNT will not destroy blocks above sea level.", null);
this.addDefault(defaults, Messages.NoTNTDamageClaims, "Warning: TNT will not destroy claimed blocks.", null); this.addDefault(defaults, Messages.NoTNTDamageClaims, "Warning: TNT will not destroy claimed blocks.", null);
this.addDefault(defaults, Messages.IgnoreClaimsAdvertisement, "To override, use /IgnoreClaims.", null);
//load the config file //load the config file
FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath)); FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath));

View File

@ -50,9 +50,9 @@ import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityInteractEvent; import org.bukkit.event.entity.EntityInteractEvent;
import org.bukkit.event.entity.ExpBottleEvent; import org.bukkit.event.entity.ExpBottleEvent;
import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.painting.PaintingBreakByEntityEvent; import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.painting.PaintingBreakEvent; import org.bukkit.event.hanging.HangingBreakEvent;
import org.bukkit.event.painting.PaintingPlaceEvent; import org.bukkit.event.hanging.HangingPlaceEvent;
import org.bukkit.event.vehicle.VehicleDamageEvent; import org.bukkit.event.vehicle.VehicleDamageEvent;
//handles events related to entities //handles events related to entities
@ -74,6 +74,12 @@ class EntityEventHandler implements Listener
{ {
event.setCancelled(true); event.setCancelled(true);
} }
//don't allow the wither to break blocks, when the wither is determined, too expensive to constantly check for claimed blocks
else if(event.getEntityType() == EntityType.WITHER)
{
event.setCancelled(true);
}
} }
//don't allow zombies to break down doors //don't allow zombies to break down doors
@ -109,7 +115,7 @@ class EntityEventHandler implements Listener
Block block = blocks.get(i); Block block = blocks.get(i);
if(GriefPrevention.instance.config_mods_explodableIds.Contains(new MaterialInfo(block.getTypeId(), block.getData(), null))) continue; if(GriefPrevention.instance.config_mods_explodableIds.Contains(new MaterialInfo(block.getTypeId(), block.getData(), null))) continue;
if(block.getLocation().getBlockY() > location.getWorld().getSeaLevel() - 7) if(block.getLocation().getBlockY() > GriefPrevention.instance.getSeaLevel(location.getWorld()) - 7)
{ {
blocks.remove(i--); blocks.remove(i--);
} }
@ -252,18 +258,18 @@ class EntityEventHandler implements Listener
//when a painting is broken //when a painting is broken
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPaintingBreak(PaintingBreakEvent event) public void onHangingBreak(HangingBreakEvent event)
{ {
//FEATURE: claimed paintings are protected from breakage //FEATURE: claimed paintings are protected from breakage
//only allow players to break paintings, not anything else (like water and explosions) //only allow players to break paintings, not anything else (like water and explosions)
if(!(event instanceof PaintingBreakByEntityEvent)) if(!(event instanceof HangingBreakByEntityEvent))
{ {
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
PaintingBreakByEntityEvent entityEvent = (PaintingBreakByEntityEvent)event; HangingBreakByEntityEvent entityEvent = (HangingBreakByEntityEvent)event;
//who is removing it? //who is removing it?
Entity remover = entityEvent.getRemover(); Entity remover = entityEvent.getRemover();
@ -277,7 +283,7 @@ class EntityEventHandler implements Listener
//if the player doesn't have build permission, don't allow the breakage //if the player doesn't have build permission, don't allow the breakage
Player playerRemover = (Player)entityEvent.getRemover(); Player playerRemover = (Player)entityEvent.getRemover();
String noBuildReason = GriefPrevention.instance.allowBuild(playerRemover, event.getPainting().getLocation()); String noBuildReason = GriefPrevention.instance.allowBuild(playerRemover, event.getEntity().getLocation());
if(noBuildReason != null) if(noBuildReason != null)
{ {
event.setCancelled(true); event.setCancelled(true);
@ -287,12 +293,12 @@ class EntityEventHandler implements Listener
//when a painting is placed... //when a painting is placed...
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPaintingPlace(PaintingPlaceEvent event) public void onPaintingPlace(HangingPlaceEvent event)
{ {
//FEATURE: similar to above, placing a painting requires build permission in the claim //FEATURE: similar to above, placing a painting requires build permission in the claim
//if the player doesn't have permission, don't allow the placement //if the player doesn't have permission, don't allow the placement
String noBuildReason = GriefPrevention.instance.allowBuild(event.getPlayer(), event.getPainting().getLocation()); String noBuildReason = GriefPrevention.instance.allowBuild(event.getPlayer(), event.getEntity().getLocation());
if(noBuildReason != null) if(noBuildReason != null)
{ {
event.setCancelled(true); event.setCancelled(true);
@ -301,7 +307,7 @@ class EntityEventHandler implements Listener
} }
//otherwise, apply entity-count limitations for creative worlds //otherwise, apply entity-count limitations for creative worlds
else if(GriefPrevention.instance.creativeRulesApply(event.getPainting().getLocation())) else if(GriefPrevention.instance.creativeRulesApply(event.getEntity().getLocation()))
{ {
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName()); PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName());
Claim claim = this.dataStore.getClaimAt(event.getBlock().getLocation(), false, playerData.lastClaim); Claim claim = this.dataStore.getClaimAt(event.getBlock().getLocation(), false, playerData.lastClaim);

View File

@ -1,6 +1,6 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -85,6 +85,11 @@ public class GriefPrevention extends JavaPlugin
public boolean config_claims_noBuildOutsideClaims; //whether players can build in survival worlds outside their claimed areas public boolean config_claims_noBuildOutsideClaims; //whether players can build in survival worlds outside their claimed areas
public int config_claims_chestClaimExpirationDays; //number of days of inactivity before an automatic chest claim will be deleted
public int config_claims_unusedClaimExpirationDays; //number of days of inactivity before an unused (nothing build) claim will be deleted
public boolean config_claims_survivalAutoNatureRestoration; //whether survival claims will be automatically restored to nature when auto-deleted
public boolean config_claims_creativeAutoNatureRestoration; //whether creative claims will be automatically restored to nature when auto-deleted
public int config_claims_trappedCooldownHours; //number of hours between uses of the /trapped command 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 Material config_claims_investigationTool; //which material will be used to investigate claims with a right click
@ -256,12 +261,26 @@ public class GriefPrevention extends JavaPlugin
this.config_claims_creationRequiresPermission = config.getBoolean("GriefPrevention.Claims.CreationRequiresPermission", false); this.config_claims_creationRequiresPermission = config.getBoolean("GriefPrevention.Claims.CreationRequiresPermission", false);
this.config_claims_minSize = config.getInt("GriefPrevention.Claims.MinimumSize", 10); this.config_claims_minSize = config.getInt("GriefPrevention.Claims.MinimumSize", 10);
this.config_claims_maxDepth = config.getInt("GriefPrevention.Claims.MaximumDepth", 0); this.config_claims_maxDepth = config.getInt("GriefPrevention.Claims.MaximumDepth", 0);
this.config_claims_expirationDays = config.getInt("GriefPrevention.Claims.IdleLimitDays", 0);
this.config_claims_trappedCooldownHours = config.getInt("GriefPrevention.Claims.TrappedCommandCooldownHours", 8); this.config_claims_trappedCooldownHours = config.getInt("GriefPrevention.Claims.TrappedCommandCooldownHours", 8);
this.config_claims_noBuildOutsideClaims = config.getBoolean("GriefPrevention.Claims.NoSurvivalBuildingOutsideClaims", false); this.config_claims_noBuildOutsideClaims = config.getBoolean("GriefPrevention.Claims.NoSurvivalBuildingOutsideClaims", false);
this.config_claims_warnOnBuildOutside = config.getBoolean("GriefPrevention.Claims.WarnWhenBuildingOutsideClaims", true); this.config_claims_warnOnBuildOutside = config.getBoolean("GriefPrevention.Claims.WarnWhenBuildingOutsideClaims", true);
this.config_claims_allowUnclaimInCreative = config.getBoolean("GriefPrevention.Claims.AllowUnclaimingCreativeModeLand", true); this.config_claims_allowUnclaimInCreative = config.getBoolean("GriefPrevention.Claims.AllowUnclaimingCreativeModeLand", true);
this.config_claims_chestClaimExpirationDays = config.getInt("GriefPrevention.Claims.Expiration.ChestClaimDays", 7);
config.set("GriefPrevention.Claims.Expiration.ChestClaimDays", this.config_claims_chestClaimExpirationDays);
this.config_claims_unusedClaimExpirationDays = config.getInt("GriefPrevention.Claims.Expiration.UnusedClaimDays", 14);
config.set("GriefPrevention.Claims.Expiration.UnusedClaimDays", this.config_claims_unusedClaimExpirationDays);
this.config_claims_expirationDays = config.getInt("GriefPrevention.Claims.Expiration.AllClaimDays", 0);
config.set("GriefPrevention.Claims.Expiration.AllClaimDays", this.config_claims_expirationDays);
this.config_claims_survivalAutoNatureRestoration = config.getBoolean("GriefPrevention.Claims.Expiration.AutomaticNatureRestoration.SurvivalWorlds", false);
config.set("GriefPrevention.Claims.Expiration.AutomaticNatureRestoration.SurvivalWorlds", this.config_claims_survivalAutoNatureRestoration);
this.config_claims_creativeAutoNatureRestoration = config.getBoolean("GriefPrevention.Claims.Expiration.AutomaticNatureRestoration.CreativeWorlds", true);
config.set("GriefPrevention.Claims.Expiration.AutomaticNatureRestoration.CreativeWorlds", this.config_claims_creativeAutoNatureRestoration);
this.config_spam_enabled = config.getBoolean("GriefPrevention.Spam.Enabled", true); this.config_spam_enabled = config.getBoolean("GriefPrevention.Spam.Enabled", true);
this.config_spam_loginCooldownMinutes = config.getInt("GriefPrevention.Spam.LoginCooldownMinutes", 2); this.config_spam_loginCooldownMinutes = config.getInt("GriefPrevention.Spam.LoginCooldownMinutes", 2);
this.config_spam_warningMessage = config.getString("GriefPrevention.Spam.WarningMessage", "Please reduce your noise level. Spammers will be banned."); this.config_spam_warningMessage = config.getString("GriefPrevention.Spam.WarningMessage", "Please reduce your noise level. Spammers will be banned.");
@ -961,6 +980,12 @@ public class GriefPrevention extends JavaPlugin
//determine which claim the player is standing in //determine which claim the player is standing in
Claim claim = this.dataStore.getClaimAt(player.getLocation(), true /*ignore height*/, null); Claim claim = this.dataStore.getClaimAt(player.getLocation(), true /*ignore height*/, null);
//bracket any permissions
if(args[0].contains("."))
{
args[0] = "[" + args[0] + "]";
}
//determine whether a single player or clearing permissions entirely //determine whether a single player or clearing permissions entirely
boolean clearPermissions = false; boolean clearPermissions = false;
OfflinePlayer otherPlayer = null; OfflinePlayer otherPlayer = null;
@ -1796,6 +1821,11 @@ public class GriefPrevention extends JavaPlugin
} }
} }
else if(recipientName.contains("."))
{
permission = recipientName;
}
else else
{ {
otherPlayer = this.resolvePlayer(recipientName); otherPlayer = this.resolvePlayer(recipientName);
@ -2310,8 +2340,10 @@ public class GriefPrevention extends JavaPlugin
//no building in the wilderness in creative mode //no building in the wilderness in creative mode
if(this.creativeRulesApply(location)) if(this.creativeRulesApply(location))
{ {
return this.dataStore.getMessage(Messages.NoBuildOutsideClaims) + " " + this.dataStore.getMessage(Messages.CreativeBasicsDemoAdvertisement); String reason = this.dataStore.getMessage(Messages.NoBuildOutsideClaims) + " " + this.dataStore.getMessage(Messages.CreativeBasicsDemoAdvertisement);
if(player.hasPermission("griefprevention.ignoreclaims"))
reason += " " + this.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return reason;
} }
//no building in survival wilderness when that is configured //no building in survival wilderness when that is configured
@ -2350,7 +2382,10 @@ public class GriefPrevention extends JavaPlugin
//no building in the wilderness in creative mode //no building in the wilderness in creative mode
if(this.creativeRulesApply(location)) if(this.creativeRulesApply(location))
{ {
return this.dataStore.getMessage(Messages.NoBuildOutsideClaims) + " " + this.dataStore.getMessage(Messages.CreativeBasicsDemoAdvertisement); String reason = this.dataStore.getMessage(Messages.NoBuildOutsideClaims) + " " + this.dataStore.getMessage(Messages.CreativeBasicsDemoAdvertisement);
if(player.hasPermission("griefprevention.ignoreclaims"))
reason += " " + this.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
return reason;
} }
else if(this.config_claims_noBuildOutsideClaims && this.config_claims_enabledWorlds.contains(location.getWorld())) else if(this.config_claims_noBuildOutsideClaims && this.config_claims_enabledWorlds.contains(location.getWorld()))
@ -2392,7 +2427,7 @@ public class GriefPrevention extends JavaPlugin
for(int z = lesserChunk.getZ(); z <= greaterChunk.getZ(); z++) for(int z = lesserChunk.getZ(); z <= greaterChunk.getZ(); z++)
{ {
Chunk chunk = lesserChunk.getWorld().getChunkAt(x, z); Chunk chunk = lesserChunk.getWorld().getChunkAt(x, z);
this.restoreChunk(chunk, chunk.getWorld().getSeaLevel() - 15, false, delayInTicks, null); this.restoreChunk(chunk, this.getSeaLevel(chunk.getWorld()) - 15, false, delayInTicks, null);
} }
} }
@ -2421,7 +2456,7 @@ public class GriefPrevention extends JavaPlugin
//create task //create task
//when done processing, this task will create a main thread task to actually update the world with processing results //when done processing, this task will create a main thread task to actually update the world with processing results
RestoreNatureProcessingTask task = new RestoreNatureProcessingTask(snapshots, miny, chunk.getWorld().getEnvironment(), lesserBoundaryCorner.getBlock().getBiome(), lesserBoundaryCorner, greaterBoundaryCorner, chunk.getWorld().getSeaLevel(), aggressiveMode, GriefPrevention.instance.creativeRulesApply(lesserBoundaryCorner), playerReceivingVisualization); RestoreNatureProcessingTask task = new RestoreNatureProcessingTask(snapshots, miny, chunk.getWorld().getEnvironment(), lesserBoundaryCorner.getBlock().getBiome(), lesserBoundaryCorner, greaterBoundaryCorner, this.getSeaLevel(chunk.getWorld()), aggressiveMode, GriefPrevention.instance.creativeRulesApply(lesserBoundaryCorner), playerReceivingVisualization);
GriefPrevention.instance.getServer().getScheduler().scheduleAsyncDelayedTask(GriefPrevention.instance, task, delayInTicks); GriefPrevention.instance.getServer().getScheduler().scheduleAsyncDelayedTask(GriefPrevention.instance, task, delayInTicks);
} }

View File

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

View File

@ -36,6 +36,7 @@ import org.bukkit.block.BlockFace;
import org.bukkit.entity.Animals; import org.bukkit.entity.Animals;
import org.bukkit.entity.Boat; import org.bukkit.entity.Boat;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.PoweredMinecart; import org.bukkit.entity.PoweredMinecart;
import org.bukkit.entity.StorageMinecart; import org.bukkit.entity.StorageMinecart;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -675,9 +676,21 @@ class PlayerEventHandler implements Listener
{ {
Player player = event.getPlayer(); Player player = event.getPlayer();
Entity entity = event.getRightClicked(); Entity entity = event.getRightClicked();
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
//don't allow interaction with item frames in claimed areas without build permission
if(entity instanceof Hanging)
{
String noBuildReason = GriefPrevention.instance.allowBuild(player, entity.getLocation());
if(noBuildReason != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, noBuildReason);
event.setCancelled(true);
return;
}
}
//don't allow container access during pvp combat //don't allow container access during pvp combat
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
if((entity instanceof StorageMinecart || entity instanceof PoweredMinecart)) if((entity instanceof StorageMinecart || entity instanceof PoweredMinecart))
{ {
if(playerData.siegeData != null) if(playerData.siegeData != null)
@ -850,7 +863,7 @@ class PlayerEventHandler implements Listener
//otherwise no wilderness dumping (unless underground) in worlds where claims are enabled //otherwise no wilderness dumping (unless underground) in worlds where claims are enabled
else if(GriefPrevention.instance.config_claims_enabledWorlds.contains(block.getWorld())) else if(GriefPrevention.instance.config_claims_enabledWorlds.contains(block.getWorld()))
{ {
if(block.getY() >= block.getWorld().getSeaLevel() - 5 && !player.hasPermission("griefprevention.lava")) if(block.getY() >= GriefPrevention.instance.getSeaLevel(block.getWorld()) - 5 && !player.hasPermission("griefprevention.lava"))
{ {
if(bucketEvent.getBucket() == Material.LAVA_BUCKET || GriefPrevention.instance.config_blockWildernessWaterBuckets) if(bucketEvent.getBucket() == Material.LAVA_BUCKET || GriefPrevention.instance.config_blockWildernessWaterBuckets)
{ {
@ -960,6 +973,7 @@ class PlayerEventHandler implements Listener
clickedBlockType == Material.WORKBENCH || clickedBlockType == Material.WORKBENCH ||
clickedBlockType == Material.ENDER_CHEST || clickedBlockType == Material.ENDER_CHEST ||
clickedBlockType == Material.DISPENSER || clickedBlockType == Material.DISPENSER ||
clickedBlockType == Material.ANVIL ||
clickedBlockType == Material.BREWING_STAND || clickedBlockType == Material.BREWING_STAND ||
clickedBlockType == Material.JUKEBOX || clickedBlockType == Material.JUKEBOX ||
clickedBlockType == Material.ENCHANTMENT_TABLE || clickedBlockType == Material.ENCHANTMENT_TABLE ||
@ -1026,7 +1040,7 @@ class PlayerEventHandler implements Listener
} }
//otherwise apply rules for buttons and switches //otherwise apply rules for buttons and switches
else if(GriefPrevention.instance.config_claims_preventButtonsSwitches && (clickedBlockType == null || clickedBlockType == Material.STONE_BUTTON || clickedBlockType == Material.LEVER || GriefPrevention.instance.config_mods_accessTrustIds.Contains(new MaterialInfo(clickedBlock.getTypeId(), clickedBlock.getData(), null)))) else if(GriefPrevention.instance.config_claims_preventButtonsSwitches && (clickedBlockType == null || clickedBlockType == Material.STONE_BUTTON || clickedBlockType == Material.WOOD_BUTTON || clickedBlockType == Material.LEVER || GriefPrevention.instance.config_mods_accessTrustIds.Contains(new MaterialInfo(clickedBlock.getTypeId(), clickedBlock.getData(), null))))
{ {
Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, playerData.lastClaim); Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, playerData.lastClaim);
if(claim != null) if(claim != null)
@ -1216,9 +1230,9 @@ class PlayerEventHandler implements Listener
//if not in aggressive mode, extend the selection down to a little below sea level //if not in aggressive mode, extend the selection down to a little below sea level
if(!(playerData.shovelMode == ShovelMode.RestoreNatureAggressive)) if(!(playerData.shovelMode == ShovelMode.RestoreNatureAggressive))
{ {
if(miny > chunk.getWorld().getSeaLevel() - 10) if(miny > GriefPrevention.instance.getSeaLevel(chunk.getWorld()) - 10)
{ {
miny = chunk.getWorld().getSeaLevel() - 10; miny = GriefPrevention.instance.getSeaLevel(chunk.getWorld()) - 10;
} }
} }

View File

@ -25,6 +25,7 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.entity.Animals; import org.bukkit.entity.Animals;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
//this main thread task takes the output from the RestoreNatureProcessingTask\ //this main thread task takes the output from the RestoreNatureProcessingTask\
@ -91,8 +92,15 @@ class RestoreNatureExecutionTask implements Runnable
Entity entity = entities[i]; Entity entity = entities[i];
if(!(entity instanceof Player || entity instanceof Animals)) if(!(entity instanceof Player || entity instanceof Animals))
{ {
//hanging entities (paintings, item frames) are protected when they're in land claims
if(!(entity instanceof Hanging) || GriefPrevention.instance.dataStore.getClaimAt(entity.getLocation(), false, null) == null)
{
//everything else is removed
entity.remove(); entity.remove();
} }
}
//for players, always ensure there's air where the player is standing
else else
{ {
Block feetBlock = entity.getLocation().getBlock(); Block feetBlock = entity.getLocation().getBlock();
@ -101,7 +109,7 @@ class RestoreNatureExecutionTask implements Runnable
} }
} }
//show visualization to player //show visualization to player who started the restoration
if(player != null) if(player != null)
{ {
Claim claim = new Claim(lesserCorner, greaterCorner, "", new String[] {}, new String[] {}, new String[] {}, new String[] {}, null); Claim claim = new Claim(lesserCorner, greaterCorner, "", new String[] {}, new String[] {}, new String[] {}, new String[] {}, null);

View File

@ -144,15 +144,15 @@ class RestoreNatureProcessingTask implements Runnable
//cover surface stone and gravel with sand or grass, as the biome requires //cover surface stone and gravel with sand or grass, as the biome requires
this.coverSurfaceStone(); this.coverSurfaceStone();
//reset leaves to NOT player placed so that they may decay as usual //remove any player-placed leaves
this.resetLeaves(); this.removePlayerLeaves();
//schedule main thread task to apply the result to the world //schedule main thread task to apply the result to the world
RestoreNatureExecutionTask task = new RestoreNatureExecutionTask(this.snapshots, this.miny, this.lesserBoundaryCorner, this.greaterBoundaryCorner, this.player); RestoreNatureExecutionTask task = new RestoreNatureExecutionTask(this.snapshots, this.miny, this.lesserBoundaryCorner, this.greaterBoundaryCorner, this.player);
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task); GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task);
} }
private void resetLeaves() private void removePlayerLeaves()
{ {
for(int x = 1; x < snapshots.length - 1; x++) for(int x = 1; x < snapshots.length - 1; x++)
{ {
@ -162,13 +162,9 @@ class RestoreNatureProcessingTask implements Runnable
{ {
//note: see minecraft wiki data values for leaves //note: see minecraft wiki data values for leaves
BlockSnapshot block = snapshots[x][y][z]; BlockSnapshot block = snapshots[x][y][z];
if(block.typeId == Material.LEAVES.getId()) if(block.typeId == Material.LEAVES.getId() && (block.data & 0x4) != 0)
{ {
//clear "player placed" bit block.typeId = Material.AIR.getId();
block.data = (byte)(block.data & ~(1<<2));
//set the "check for natural decay" bit
block.data = (byte)(block.data | (1<<3));
} }
} }
} }
@ -708,6 +704,19 @@ class RestoreNatureProcessingTask implements Runnable
playerBlocks.add(Material.WOOD_STEP.getId()); playerBlocks.add(Material.WOOD_STEP.getId());
playerBlocks.add(Material.WOOD_DOUBLE_STEP.getId()); playerBlocks.add(Material.WOOD_DOUBLE_STEP.getId());
playerBlocks.add(Material.ENDER_CHEST.getId()); playerBlocks.add(Material.ENDER_CHEST.getId());
playerBlocks.add(Material.SANDSTONE_STAIRS.getId());
playerBlocks.add(Material.SPRUCE_WOOD_STAIRS.getId());
playerBlocks.add(Material.JUNGLE_WOOD_STAIRS.getId());
playerBlocks.add(Material.COMMAND.getId());
playerBlocks.add(Material.BEACON.getId());
playerBlocks.add(Material.COBBLE_WALL.getId());
playerBlocks.add(Material.FLOWER_POT.getId());
playerBlocks.add(Material.CARROT.getId());
playerBlocks.add(Material.POTATO.getId());
playerBlocks.add(Material.WOOD_BUTTON.getId());
playerBlocks.add(Material.SKULL.getId());
playerBlocks.add(Material.ANVIL.getId());
//these are unnatural in the standard world, but not in the nether //these are unnatural in the standard world, but not in the nether
if(environment != Environment.NETHER) if(environment != Environment.NETHER)

View File

@ -220,6 +220,8 @@ public class Visualization
block.getType() == Material.LEAVES || block.getType() == Material.LEAVES ||
block.getType() == Material.RED_ROSE || block.getType() == Material.RED_ROSE ||
block.getType() == Material.CHEST || block.getType() == Material.CHEST ||
block.getType() == Material.TORCH ||
block.getType() == Material.VINE ||
block.getType() == Material.YELLOW_FLOWER ); block.getType() == Material.YELLOW_FLOWER );
} }
} }