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
softdepend: [Vault, Multiverse-Core, My Worlds, MystCraft, Transporter]
dev-url: http://dev.bukkit.org/server-mods/grief-prevention
version: 6.7
version: 6.9
commands:
abandonclaim:
description: Deletes a claim.

View File

@ -30,7 +30,10 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
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.BlockSpreadEvent;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.event.world.StructureGrowEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
@ -77,6 +81,36 @@ public class BlockEventHandler implements Listener
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...
@EventHandler(ignoreCancelled = true)
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
if( GriefPrevention.instance.config_blockSurfaceOtherExplosions && block.getType() == Material.TNT &&
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);
}
@ -514,11 +548,7 @@ public class BlockEventHandler implements Listener
@EventHandler(priority = EventPriority.LOWEST)
public void onBlockIgnite (BlockIgniteEvent igniteEvent)
{
if(!GriefPrevention.instance.config_fireSpreads &&
igniteEvent.getBlock().getWorld().getEnvironment() == Environment.NORMAL &&
igniteEvent.getCause() != IgniteCause.FLINT_AND_STEEL &&
igniteEvent.getCause() != IgniteCause.LIGHTNING &&
igniteEvent.getCause() != IgniteCause.LAVA)
if(!GriefPrevention.instance.config_fireSpreads && igniteEvent.getCause() != IgniteCause.FLINT_AND_STEEL && igniteEvent.getCause() != IgniteCause.LIGHTNING)
{
igniteEvent.setCancelled(true);
}

View File

@ -131,7 +131,7 @@ public class Claim
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();
if(lesser.getWorld().getEnvironment() == Environment.NORMAL) seaLevel = GriefPrevention.instance.getSeaLevel(lesser.getWorld());
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
//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;
for(int x = lesser.getBlockX(); x <= greater.getBlockX(); x++)
@ -362,7 +362,10 @@ public class Claim
return this.parent.allowBuild(player);
//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)
@ -458,7 +461,10 @@ public class Claim
return this.parent.allowAccess(player);
//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
@ -498,7 +504,10 @@ public class Claim
return this.parent.allowContainers(player);
//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
@ -529,7 +538,10 @@ public class Claim
return this.parent.allowGrantPermission(player);
//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
@ -778,7 +790,7 @@ public class Claim
for(int z = this.lesserBoundaryCorner.getBlockZ(); z <= this.greaterBoundaryCorner.getBlockZ(); z++)
{
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);
if(playerBlocks.contains(block.getTypeId()))
@ -789,7 +801,7 @@ public class Claim
}
else
{
score += .2;
score += .5;
}
}
}

View File

@ -20,6 +20,7 @@
import java.util.Calendar;
import java.util.Random;
import java.util.Vector;
import org.bukkit.Chunk;
import org.bukkit.World;
@ -63,6 +64,9 @@ class CleanupUnusedClaimsTask implements Runnable
//skip administrative claims
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
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
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);
//if only one claim, and the player hasn't played in a week
if(newPlayerClaimsExpired && playerData.claims.size() == 1)
{
//if that's a chest claim, delete it
if(claim.getArea() <= areaOfDefaultClaim)
//if that's a chest claim and those are set to expire
if(claim.getArea() <= areaOfDefaultClaim && GriefPrevention.instance.config_claims_chestClaimExpirationDays > 0)
{
claim.removeSurfaceFluids(null);
GriefPrevention.instance.dataStore.deleteClaim(claim);
cleanupChunks = true;
//if in a creative mode world, delete the claim
if(GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()))
//if configured to do so, restore the land to natural
if((GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()) && GriefPrevention.instance.config_claims_creativeAutoNatureRestoration) || GriefPrevention.instance.config_claims_survivalAutoNatureRestoration)
{
GriefPrevention.instance.restoreClaim(claim, 0);
}
@ -105,18 +110,35 @@ class CleanupUnusedClaimsTask implements Runnable
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.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
Calendar fourteenDaysAgo = Calendar.getInstance();
fourteenDaysAgo.add(Calendar.DATE, -14);
boolean needsInvestmentScan = fourteenDaysAgo.getTime().after(playerData.lastLogin);
Calendar earliestAllowedLoginDate = Calendar.getInstance();
earliestAllowedLoginDate.add(Calendar.DATE, -GriefPrevention.instance.config_claims_unusedClaimExpirationDays);
boolean needsInvestmentScan = earliestAllowedLoginDate.getTime().after(playerData.lastLogin);
//avoid scanning large claims and administrative claims
if(claim.isAdminClaim() || claim.getWidth() > 25 || claim.getHeight() > 25) return;
@ -131,10 +153,11 @@ class CleanupUnusedClaimsTask implements Runnable
}
else
{
minInvestment = 200;
minInvestment = 100;
}
long investmentScore = claim.getPlayerInvestmentScore();
cleanupChunks = true;
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
@ -156,8 +179,8 @@ class CleanupUnusedClaimsTask implements Runnable
GriefPrevention.instance.dataStore.deleteClaim(claim);
GriefPrevention.AddLogEntry("Removed " + claim.getOwnerName() + "'s unused claim @ " + GriefPrevention.getfriendlyLocationString(claim.getLesserBoundaryCorner()));
//if in a creative mode world, restore the claim area
if(GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()))
//if configured to do so, restore the claim area to natural state
if((GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()) && GriefPrevention.instance.config_claims_creativeAutoNatureRestoration) || GriefPrevention.instance.config_claims_survivalAutoNatureRestoration)
{
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
//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 % 20 == 0)
if(cleanupChunks)
{
World world = claim.getLesserBoundaryCorner().getWorld();
Chunk [] chunks = world.getLoadedChunks();
@ -182,7 +204,11 @@ class CleanupUnusedClaimsTask implements Runnable
Chunk chunk = chunks[i];
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();
}
}

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.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.IgnoreClaimsAdvertisement, "To override, use /IgnoreClaims.", null);
//load the config file
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.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.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.hanging.HangingBreakEvent;
import org.bukkit.event.hanging.HangingPlaceEvent;
import org.bukkit.event.vehicle.VehicleDamageEvent;
//handles events related to entities
@ -74,6 +74,12 @@ class EntityEventHandler implements Listener
{
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
@ -109,7 +115,7 @@ class EntityEventHandler implements Listener
Block block = blocks.get(i);
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--);
}
@ -252,18 +258,18 @@ class EntityEventHandler implements Listener
//when a painting is broken
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPaintingBreak(PaintingBreakEvent event)
public void onHangingBreak(HangingBreakEvent event)
{
//FEATURE: claimed paintings are protected from breakage
//only allow players to break paintings, not anything else (like water and explosions)
if(!(event instanceof PaintingBreakByEntityEvent))
if(!(event instanceof HangingBreakByEntityEvent))
{
event.setCancelled(true);
return;
}
PaintingBreakByEntityEvent entityEvent = (PaintingBreakByEntityEvent)event;
HangingBreakByEntityEvent entityEvent = (HangingBreakByEntityEvent)event;
//who is removing it?
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
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)
{
event.setCancelled(true);
@ -287,12 +293,12 @@ class EntityEventHandler implements Listener
//when a painting is placed...
@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
//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)
{
event.setCancelled(true);
@ -301,7 +307,7 @@ class EntityEventHandler implements Listener
}
//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());
Claim claim = this.dataStore.getClaimAt(event.getBlock().getLocation(), false, playerData.lastClaim);

View File

@ -1,6 +1,6 @@
/*
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
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 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 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_minSize = config.getInt("GriefPrevention.Claims.MinimumSize", 10);
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_noBuildOutsideClaims = config.getBoolean("GriefPrevention.Claims.NoSurvivalBuildingOutsideClaims", false);
this.config_claims_warnOnBuildOutside = config.getBoolean("GriefPrevention.Claims.WarnWhenBuildingOutsideClaims", 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_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.");
@ -961,6 +980,12 @@ public class GriefPrevention extends JavaPlugin
//determine which claim the player is standing in
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
boolean clearPermissions = false;
OfflinePlayer otherPlayer = null;
@ -1796,6 +1821,11 @@ public class GriefPrevention extends JavaPlugin
}
}
else if(recipientName.contains("."))
{
permission = recipientName;
}
else
{
otherPlayer = this.resolvePlayer(recipientName);
@ -2310,8 +2340,10 @@ public class GriefPrevention extends JavaPlugin
//no building in the wilderness in creative mode
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
@ -2350,7 +2382,10 @@ public class GriefPrevention extends JavaPlugin
//no building in the wilderness in creative mode
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()))
@ -2392,7 +2427,7 @@ public class GriefPrevention extends JavaPlugin
for(int z = lesserChunk.getZ(); z <= greaterChunk.getZ(); 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
//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);
}

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, 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.Boat;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.PoweredMinecart;
import org.bukkit.entity.StorageMinecart;
import org.bukkit.entity.Player;
@ -675,9 +676,21 @@ class PlayerEventHandler implements Listener
{
Player player = event.getPlayer();
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
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
if((entity instanceof StorageMinecart || entity instanceof PoweredMinecart))
{
if(playerData.siegeData != null)
@ -850,7 +863,7 @@ class PlayerEventHandler implements Listener
//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"))
if(block.getY() >= GriefPrevention.instance.getSeaLevel(block.getWorld()) - 5 && !player.hasPermission("griefprevention.lava"))
{
if(bucketEvent.getBucket() == Material.LAVA_BUCKET || GriefPrevention.instance.config_blockWildernessWaterBuckets)
{
@ -960,6 +973,7 @@ class PlayerEventHandler implements Listener
clickedBlockType == Material.WORKBENCH ||
clickedBlockType == Material.ENDER_CHEST ||
clickedBlockType == Material.DISPENSER ||
clickedBlockType == Material.ANVIL ||
clickedBlockType == Material.BREWING_STAND ||
clickedBlockType == Material.JUKEBOX ||
clickedBlockType == Material.ENCHANTMENT_TABLE ||
@ -1026,7 +1040,7 @@ class PlayerEventHandler implements Listener
}
//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);
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(!(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.entity.Animals;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.Player;
//this main thread task takes the output from the RestoreNatureProcessingTask\
@ -91,8 +92,15 @@ class RestoreNatureExecutionTask implements Runnable
Entity entity = entities[i];
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();
}
}
//for players, always ensure there's air where the player is standing
else
{
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)
{
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
this.coverSurfaceStone();
//reset leaves to NOT player placed so that they may decay as usual
this.resetLeaves();
//remove any player-placed leaves
this.removePlayerLeaves();
//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);
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task);
}
private void resetLeaves()
private void removePlayerLeaves()
{
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
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.data = (byte)(block.data & ~(1<<2));
//set the "check for natural decay" bit
block.data = (byte)(block.data | (1<<3));
block.typeId = Material.AIR.getId();
}
}
}
@ -708,6 +704,19 @@ class RestoreNatureProcessingTask implements Runnable
playerBlocks.add(Material.WOOD_STEP.getId());
playerBlocks.add(Material.WOOD_DOUBLE_STEP.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
if(environment != Environment.NETHER)

View File

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