This commit is contained in:
Ryan Hamshire 2012-10-06 10:52:17 -07:00
parent 1f6223526b
commit 6632af96df
12 changed files with 388 additions and 42 deletions

View File

@ -1,8 +1,8 @@
name: GriefPrevention name: GriefPrevention
main: me.ryanhamshire.GriefPrevention.GriefPrevention main: me.ryanhamshire.GriefPrevention.GriefPrevention
softdepend: [Vault, Multiverse-Core, My Worlds] 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.4 version: 6.7
commands: commands:
abandonclaim: abandonclaim:
description: Deletes a claim. description: Deletes a claim.
@ -19,7 +19,7 @@ commands:
trust: trust:
description: Grants a player full access to your claim(s). description: Grants a player full access to your claim(s).
usage: /Trust <player> Graants a player permission to build. See also /UnTrust, /ContainerTrust, /AccessTrust, and /PermissionTrust. usage: /Trust <player> Graants a player permission to build. See also /UnTrust, /ContainerTrust, /AccessTrust, and /PermissionTrust.
aliases: t aliases: tr
permission: griefprevention.claims permission: griefprevention.claims
untrust: untrust:
description: Revokes a player's access to your claim(s). description: Revokes a player's access to your claim(s).

View File

@ -25,6 +25,7 @@ import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.World.Environment;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
@ -261,6 +262,12 @@ public class BlockEventHandler implements Listener
Claim claim = this.dataStore.getClaimAt(block.getLocation(), true, playerData.lastClaim); Claim claim = this.dataStore.getClaimAt(block.getLocation(), true, playerData.lastClaim);
if(claim != null) if(claim != null)
{ {
//warn about TNT not destroying claimed blocks
if(block.getType() == Material.TNT)
{
GriefPrevention.sendMessage(player, TextMode.Warn, Messages.NoTNTDamageClaims);
}
//if the player has permission for the claim and he's placing UNDER the claim //if the player has permission for the claim and he's placing UNDER the claim
if(block.getY() < claim.lesserBoundaryCorner.getBlockY() && claim.allowBuild(player) == null) if(block.getY() < claim.lesserBoundaryCorner.getBlockY() && claim.allowBuild(player) == null)
{ {
@ -338,7 +345,7 @@ public class BlockEventHandler implements Listener
} }
//FEATURE: limit wilderness tree planting to grass, or dirt with more blocks beneath it //FEATURE: limit wilderness tree planting to grass, or dirt with more blocks beneath it
else if(block.getType() == Material.SAPLING && GriefPrevention.instance.config_blockSkyTrees) else if(block.getType() == Material.SAPLING && GriefPrevention.instance.config_blockSkyTrees && GriefPrevention.instance.claimsEnabledForWorld(player.getWorld()))
{ {
Block earthBlock = placeEvent.getBlockAgainst(); Block earthBlock = placeEvent.getBlockAgainst();
if(earthBlock.getType() != Material.GRASS) if(earthBlock.getType() != Material.GRASS)
@ -366,6 +373,14 @@ 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)
{
GriefPrevention.sendMessage(player, TextMode.Warn, Messages.NoTNTDamageAboveSeaLevel);
}
} }
//blocks "pushing" other players' blocks around (pistons) //blocks "pushing" other players' blocks around (pistons)
@ -499,14 +514,40 @@ public class BlockEventHandler implements Listener
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void onBlockIgnite (BlockIgniteEvent igniteEvent) public void onBlockIgnite (BlockIgniteEvent igniteEvent)
{ {
if(igniteEvent.getCause() != IgniteCause.FLINT_AND_STEEL && !GriefPrevention.instance.config_fireSpreads) igniteEvent.setCancelled(true); 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)
{
igniteEvent.setCancelled(true);
}
} }
//fire doesn't spread unless configured to, but other blocks still do (mushrooms and vines, for example) //fire doesn't spread unless configured to, but other blocks still do (mushrooms and vines, for example)
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void onBlockSpread (BlockSpreadEvent spreadEvent) public void onBlockSpread (BlockSpreadEvent spreadEvent)
{ {
if(spreadEvent.getSource().getType() == Material.FIRE && !GriefPrevention.instance.config_fireSpreads) spreadEvent.setCancelled(true); if(spreadEvent.getSource().getType() != Material.FIRE) return;
if(!GriefPrevention.instance.config_fireSpreads)
{
spreadEvent.setCancelled(true);
return;
}
//never spread into a claimed area, regardless of settings
if(this.dataStore.getClaimAt(spreadEvent.getBlock().getLocation(), false, null) != null)
{
spreadEvent.setCancelled(true);
//if the source of the spread is not fire on netherrack, put out that source fire to save cpu cycles
Block source = spreadEvent.getSource();
if(source.getType() == Material.FIRE && source.getRelative(BlockFace.DOWN).getType() != Material.NETHERRACK)
{
source.setType(Material.AIR);
}
}
} }
//blocks are not destroyed by fire, unless configured to do so //blocks are not destroyed by fire, unless configured to do so
@ -516,6 +557,7 @@ public class BlockEventHandler implements Listener
if(!GriefPrevention.instance.config_fireDestroys) if(!GriefPrevention.instance.config_fireDestroys)
{ {
burnEvent.setCancelled(true); burnEvent.setCancelled(true);
return;
} }
//never burn claimed blocks, regardless of settings //never burn claimed blocks, regardless of settings
@ -530,6 +572,9 @@ public class BlockEventHandler implements Listener
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onBlockFromTo (BlockFromToEvent spreadEvent) public void onBlockFromTo (BlockFromToEvent spreadEvent)
{ {
//don't track fluid movement in worlds where claims are not enabled
if(!GriefPrevention.instance.config_claims_enabledWorlds.contains(spreadEvent.getBlock().getWorld())) return;
//always allow fluids to flow straight down //always allow fluids to flow straight down
if(spreadEvent.getFace() == BlockFace.DOWN) return; if(spreadEvent.getFace() == BlockFace.DOWN) return;
@ -602,7 +647,7 @@ public class BlockEventHandler implements Listener
//into wilderness is NOT OK when surface buckets are limited //into wilderness is NOT OK when surface buckets are limited
Material materialDispensed = dispenseEvent.getItem().getType(); Material materialDispensed = dispenseEvent.getItem().getType();
if((materialDispensed == Material.WATER_BUCKET || materialDispensed == Material.LAVA_BUCKET) && GriefPrevention.instance.config_blockWildernessWaterBuckets && toClaim == null) if((materialDispensed == Material.WATER_BUCKET || materialDispensed == Material.LAVA_BUCKET) && GriefPrevention.instance.config_blockWildernessWaterBuckets && GriefPrevention.instance.claimsEnabledForWorld(fromBlock.getWorld()) && toClaim == null)
{ {
dispenseEvent.setCancelled(true); dispenseEvent.setCancelled(true);
return; return;

View File

@ -166,7 +166,10 @@ class CleanupUnusedClaimsTask implements Runnable
} }
//toss that player data out of the cache, it's probably not needed in memory right now //toss that player data out of the cache, it's probably not needed in memory right now
GriefPrevention.instance.dataStore.clearCachedPlayerData(claim.ownerName); if(!GriefPrevention.instance.getServer().getOfflinePlayer(claim.ownerName).isOnline())
{
GriefPrevention.instance.dataStore.clearCachedPlayerData(claim.ownerName);
}
//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 //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

View File

@ -956,7 +956,10 @@ public abstract class DataStore
this.addDefault(defaults, Messages.TrappedWontWorkHere, "Sorry, unable to find a safe location to teleport you to. Contact an admin, or consider /kill if you don't want to wait.", null); this.addDefault(defaults, Messages.TrappedWontWorkHere, "Sorry, unable to find a safe location to teleport you to. Contact an admin, or consider /kill if you don't want to wait.", null);
this.addDefault(defaults, Messages.CommandBannedInPvP, "You can't use that command while in PvP combat.", null); this.addDefault(defaults, Messages.CommandBannedInPvP, "You can't use that command while in PvP combat.", null);
this.addDefault(defaults, Messages.UnclaimCleanupWarning, "The land you've unclaimed may be changed by other players or cleaned up by administrators. If you've built something there you want to keep, you should reclaim it.", null); this.addDefault(defaults, Messages.UnclaimCleanupWarning, "The land you've unclaimed may be changed by other players or cleaned up by administrators. If you've built something there you want to keep, you should reclaim it.", null);
this.addDefault(defaults, Messages.BuySellNotConfigured, "Sorry, buying anhd selling claim blocks is disabled.", null); this.addDefault(defaults, Messages.BuySellNotConfigured, "Sorry, buying anhd selling claim blocks is disabled.", 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.NoTNTDamageClaims, "Warning: TNT will not destroy claimed blocks.", 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

@ -33,7 +33,7 @@ class DeliverClaimBlocksTask implements Runnable
//ensure players get at least 1 block (if accrual is totally disabled, this task won't even be scheduled) //ensure players get at least 1 block (if accrual is totally disabled, this task won't even be scheduled)
int accruedBlocks = GriefPrevention.instance.config_claims_blocksAccruedPerHour / 12; int accruedBlocks = GriefPrevention.instance.config_claims_blocksAccruedPerHour / 12;
if(accruedBlocks == 0) accruedBlocks = 1; if(accruedBlocks < 0) accruedBlocks = 1;
//for each online player //for each online player
for(int i = 0; i < players.length; i++) for(int i = 0; i < players.length; i++)
@ -48,6 +48,11 @@ class DeliverClaimBlocksTask implements Runnable
//if he's not in a vehicle and has moved at least three blocks since the last check //if he's not in a vehicle and has moved at least three blocks since the last check
if(!player.isInsideVehicle() && (lastLocation == null || lastLocation.distanceSquared(player.getLocation()) >= 9)) if(!player.isInsideVehicle() && (lastLocation == null || lastLocation.distanceSquared(player.getLocation()) >= 9))
{ {
//if player is over accrued limit, accrued limit was probably reduced in config file AFTER he accrued
//in that case, leave his blocks where they are
if(playerData.accruedClaimBlocks > GriefPrevention.instance.config_claims_maxAccruedBlocks) continue;
//add blocks
playerData.accruedClaimBlocks += accruedBlocks; playerData.accruedClaimBlocks += accruedBlocks;
//respect limits //respect limits

View File

@ -102,12 +102,12 @@ class EntityEventHandler implements Listener
//FEATURE: explosions don't destroy blocks when they explode near or above sea level in standard worlds //FEATURE: explosions don't destroy blocks when they explode near or above sea level in standard worlds
boolean isCreeper = (explodeEvent.getEntity() != null && explodeEvent.getEntity() instanceof Creeper); boolean isCreeper = (explodeEvent.getEntity() != null && explodeEvent.getEntity() instanceof Creeper);
if( location.getWorld().getEnvironment() == Environment.NORMAL && ((isCreeper && GriefPrevention.instance.config_blockSurfaceCreeperExplosions) || (!isCreeper && GriefPrevention.instance.config_blockSurfaceOtherExplosions))) if( location.getWorld().getEnvironment() == Environment.NORMAL && GriefPrevention.instance.config_claims_enabledWorlds.contains(location.getWorld()) && ((isCreeper && GriefPrevention.instance.config_blockSurfaceCreeperExplosions) || (!isCreeper && GriefPrevention.instance.config_blockSurfaceOtherExplosions)))
{ {
for(int i = 0; i < blocks.size(); i++) for(int i = 0; i < blocks.size(); i++)
{ {
Block block = blocks.get(i); Block block = blocks.get(i);
if(GriefPrevention.instance.config_mods_explodableIds.contains(block.getTypeId())) 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() > location.getWorld().getSeaLevel() - 7)
{ {
@ -122,7 +122,7 @@ class EntityEventHandler implements Listener
for(int i = 0; i < blocks.size(); i++) for(int i = 0; i < blocks.size(); i++)
{ {
Block block = blocks.get(i); Block block = blocks.get(i);
if(GriefPrevention.instance.config_mods_explodableIds.contains(block.getTypeId())) continue; if(GriefPrevention.instance.config_mods_explodableIds.Contains(new MaterialInfo(block.getTypeId(), block.getData(), null))) continue;
blocks.remove(i--); blocks.remove(i--);
} }
@ -135,7 +135,7 @@ class EntityEventHandler implements Listener
Block block = blocks.get(i); Block block = blocks.get(i);
if(block.getType() == Material.AIR) continue; //if it's air, we don't care if(block.getType() == Material.AIR) continue; //if it's air, we don't care
if(GriefPrevention.instance.config_mods_explodableIds.contains(block.getTypeId())) continue; if(GriefPrevention.instance.config_mods_explodableIds.Contains(new MaterialInfo(block.getTypeId(), block.getData(), null))) continue;
claim = this.dataStore.getClaimAt(block.getLocation(), false, claim); claim = this.dataStore.getClaimAt(block.getLocation(), false, claim);
//if the block is claimed, remove it from the list of destroyed blocks //if the block is claimed, remove it from the list of destroyed blocks

View File

@ -22,6 +22,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -130,13 +131,15 @@ public class GriefPrevention extends JavaPlugin
public boolean config_creaturesTrampleCrops; //whether or not non-player entities may trample crops public boolean config_creaturesTrampleCrops; //whether or not non-player entities may trample crops
public boolean config_zombiesBreakDoors; //whether or not hard-mode zombies may break down wooden doors public boolean config_zombiesBreakDoors; //whether or not hard-mode zombies may break down wooden doors
public List<Integer> config_mods_accessTrustIds; //list of block IDs which should require /accesstrust for player interaction public MaterialCollection config_mods_accessTrustIds; //list of block IDs which should require /accesstrust for player interaction
public List<Integer> config_mods_containerTrustIds; //list of block IDs which should require /containertrust for player interaction public MaterialCollection config_mods_containerTrustIds; //list of block IDs which should require /containertrust for player interaction
public List<String> config_mods_ignoreClaimsAccounts; //list of player names which ALWAYS ignore claims public List<String> config_mods_ignoreClaimsAccounts; //list of player names which ALWAYS ignore claims
public List<Integer> config_mods_explodableIds; //list of block IDs which can be destroyed by explosions, even in claimed areas public MaterialCollection config_mods_explodableIds; //list of block IDs which can be destroyed by explosions, even in claimed areas
public boolean config_claims_warnOnBuildOutside; //whether players should be warned when they're building in an unclaimed area public boolean config_claims_warnOnBuildOutside; //whether players should be warned when they're building in an unclaimed area
public HashMap<String, Integer> config_seaLevelOverride; //override for sea level, because bukkit doesn't report the right value for all situations
//reference to the economy plugin, if economy integration is enabled //reference to the economy plugin, if economy integration is enabled
public static Economy economy = null; public static Economy economy = null;
@ -230,6 +233,15 @@ public class GriefPrevention extends JavaPlugin
} }
} }
//sea level
this.config_seaLevelOverride = new HashMap<String, Integer>();
for(int i = 0; i < worlds.size(); i++)
{
int seaLevelOverride = config.getInt("GriefPrevention.SeaLevelOverrides." + worlds.get(i).getName(), -1);
config.set("GriefPrevention.SeaLevelOverrides." + worlds.get(i).getName(), seaLevelOverride);
this.config_seaLevelOverride.put(worlds.get(i).getName(), seaLevelOverride);
}
this.config_claims_preventTheft = config.getBoolean("GriefPrevention.Claims.PreventTheft", true); this.config_claims_preventTheft = config.getBoolean("GriefPrevention.Claims.PreventTheft", true);
this.config_claims_protectCreatures = config.getBoolean("GriefPrevention.Claims.ProtectCreatures", true); this.config_claims_protectCreatures = config.getBoolean("GriefPrevention.Claims.ProtectCreatures", true);
this.config_claims_preventButtonsSwitches = config.getBoolean("GriefPrevention.Claims.PreventButtonsSwitches", true); this.config_claims_preventButtonsSwitches = config.getBoolean("GriefPrevention.Claims.PreventButtonsSwitches", true);
@ -288,17 +300,74 @@ public class GriefPrevention extends JavaPlugin
this.config_creaturesTrampleCrops = config.getBoolean("GriefPrevention.CreaturesTrampleCrops", false); this.config_creaturesTrampleCrops = config.getBoolean("GriefPrevention.CreaturesTrampleCrops", false);
this.config_zombiesBreakDoors = config.getBoolean("GriefPrevention.HardModeZombiesBreakDoors", false); this.config_zombiesBreakDoors = config.getBoolean("GriefPrevention.HardModeZombiesBreakDoors", false);
this.config_mods_accessTrustIds = config.getIntegerList("GriefPrevention.Mods.BlockIdsRequiringAccessTrust");
if(this.config_mods_accessTrustIds == null) this.config_mods_accessTrustIds = new ArrayList<Integer>();
this.config_mods_containerTrustIds = config.getIntegerList("GriefPrevention.Mods.BlockIdsRequiringContainerTrust");
if(this.config_mods_containerTrustIds == null) this.config_mods_containerTrustIds = new ArrayList<Integer>();
this.config_mods_ignoreClaimsAccounts = config.getStringList("GriefPrevention.Mods.PlayersIgnoringAllClaims"); this.config_mods_ignoreClaimsAccounts = config.getStringList("GriefPrevention.Mods.PlayersIgnoringAllClaims");
if(this.config_mods_ignoreClaimsAccounts == null) this.config_mods_ignoreClaimsAccounts = new ArrayList<String>(); if(this.config_mods_ignoreClaimsAccounts == null) this.config_mods_ignoreClaimsAccounts = new ArrayList<String>();
this.config_mods_explodableIds = config.getIntegerList("GriefPrevention.Mods.BlockIdsExplodable"); this.config_mods_accessTrustIds = new MaterialCollection();
if(this.config_mods_explodableIds == null) this.config_mods_explodableIds = new ArrayList<Integer>(); List<String> accessTrustStrings = config.getStringList("GriefPrevention.Mods.BlockIdsRequiringAccessTrust");
//default values for access trust mod blocks
if(accessTrustStrings == null || accessTrustStrings.size() == 0)
{
//none by default
}
this.parseMaterialListFromConfig(accessTrustStrings, this.config_mods_accessTrustIds);
this.config_mods_containerTrustIds = new MaterialCollection();
List<String> containerTrustStrings = config.getStringList("GriefPrevention.Mods.BlockIdsRequiringContainerTrust");
//default values for container trust mod blocks
if(containerTrustStrings == null || containerTrustStrings.size() == 0)
{
containerTrustStrings.add(new MaterialInfo(227, "Battery Box").toString());
containerTrustStrings.add(new MaterialInfo(130, "Transmutation Tablet").toString());
containerTrustStrings.add(new MaterialInfo(128, "Alchemical Chest and Energy Condenser").toString());
containerTrustStrings.add(new MaterialInfo(181, "Various Chests").toString());
containerTrustStrings.add(new MaterialInfo(178, "Ender Chest").toString());
containerTrustStrings.add(new MaterialInfo(150, "Various BuildCraft Gadgets").toString());
containerTrustStrings.add(new MaterialInfo(155, "Filler").toString());
containerTrustStrings.add(new MaterialInfo(157, "Builder").toString());
containerTrustStrings.add(new MaterialInfo(158, "Template Drawing Table").toString());
containerTrustStrings.add(new MaterialInfo(126, "Various EE Gadgets").toString());
containerTrustStrings.add(new MaterialInfo(138, "Various RedPower Gadgets").toString());
containerTrustStrings.add(new MaterialInfo(137, "BuildCraft Project Table and Furnaces").toString());
containerTrustStrings.add(new MaterialInfo(250, "Various IC2 Machines").toString());
containerTrustStrings.add(new MaterialInfo(161, "BuildCraft Engines").toString());
containerTrustStrings.add(new MaterialInfo(169, "Automatic Crafting Table").toString());
containerTrustStrings.add(new MaterialInfo(177, "Wireless Components").toString());
containerTrustStrings.add(new MaterialInfo(183, "Solar Arrays").toString());
containerTrustStrings.add(new MaterialInfo(187, "Charging Benches").toString());
containerTrustStrings.add(new MaterialInfo(188, "More IC2 Machines").toString());
containerTrustStrings.add(new MaterialInfo(190, "Generators, Fabricators, Strainers").toString());
containerTrustStrings.add(new MaterialInfo(194, "More Gadgets").toString());
containerTrustStrings.add(new MaterialInfo(207, "Computer").toString());
containerTrustStrings.add(new MaterialInfo(208, "Computer Peripherals").toString());
containerTrustStrings.add(new MaterialInfo(246, "IC2 Generators").toString());
containerTrustStrings.add(new MaterialInfo(24303, "Teleport Pipe").toString());
containerTrustStrings.add(new MaterialInfo(24304, "Waterproof Teleport Pipe").toString());
containerTrustStrings.add(new MaterialInfo(24305, "Power Teleport Pipe").toString());
containerTrustStrings.add(new MaterialInfo(4311, "Diamond Sorting Pipe").toString());
containerTrustStrings.add(new MaterialInfo(216, "Turtle").toString());
}
//parse the strings from the config file
this.parseMaterialListFromConfig(containerTrustStrings, this.config_mods_containerTrustIds);
this.config_mods_explodableIds = new MaterialCollection();
List<String> explodableStrings = config.getStringList("GriefPrevention.Mods.BlockIdsExplodable");
//default values for explodable mod blocks
if(explodableStrings == null || explodableStrings.size() == 0)
{
explodableStrings.add(new MaterialInfo(161, "BuildCraft Engines").toString());
explodableStrings.add(new MaterialInfo(246, (byte)5 ,"Nuclear Reactor").toString());
}
//parse the strings from the config file
this.parseMaterialListFromConfig(explodableStrings, this.config_mods_explodableIds);
//default for claim investigation tool //default for claim investigation tool
String investigationToolMaterialName = Material.STICK.name(); String investigationToolMaterialName = Material.STICK.name();
@ -478,6 +547,9 @@ public class GriefPrevention extends JavaPlugin
config.set("GriefPrevention.Mods.BlockIdsRequiringContainerTrust", this.config_mods_containerTrustIds); config.set("GriefPrevention.Mods.BlockIdsRequiringContainerTrust", this.config_mods_containerTrustIds);
config.set("GriefPrevention.Mods.BlockIdsExplodable", this.config_mods_explodableIds); config.set("GriefPrevention.Mods.BlockIdsExplodable", this.config_mods_explodableIds);
config.set("GriefPrevention.Mods.PlayersIgnoringAllClaims", this.config_mods_ignoreClaimsAccounts); config.set("GriefPrevention.Mods.PlayersIgnoringAllClaims", this.config_mods_ignoreClaimsAccounts);
config.set("GriefPrevention.Mods.BlockIdsRequiringAccessTrust", accessTrustStrings);
config.set("GriefPrevention.Mods.BlockIdsRequiringContainerTrust", containerTrustStrings);
config.set("GriefPrevention.Mods.BlockIdsExplodable", explodableStrings);
try try
{ {
@ -2349,7 +2421,51 @@ 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() + 1, aggressiveMode, GriefPrevention.instance.creativeRulesApply(lesserBoundaryCorner), playerReceivingVisualization); RestoreNatureProcessingTask task = new RestoreNatureProcessingTask(snapshots, miny, chunk.getWorld().getEnvironment(), lesserBoundaryCorner.getBlock().getBiome(), lesserBoundaryCorner, greaterBoundaryCorner, chunk.getWorld().getSeaLevel(), aggressiveMode, GriefPrevention.instance.creativeRulesApply(lesserBoundaryCorner), playerReceivingVisualization);
GriefPrevention.instance.getServer().getScheduler().scheduleAsyncDelayedTask(GriefPrevention.instance, task, delayInTicks); GriefPrevention.instance.getServer().getScheduler().scheduleAsyncDelayedTask(GriefPrevention.instance, task, delayInTicks);
} }
private void parseMaterialListFromConfig(List<String> stringsToParse, MaterialCollection materialCollection)
{
materialCollection.clear();
//for each string in the list
for(int i = 0; i < stringsToParse.size(); i++)
{
//try to parse the string value into a material info
MaterialInfo materialInfo = MaterialInfo.fromString(stringsToParse.get(i));
//null value returned indicates an error parsing the string from the config file
if(materialInfo == null)
{
//show error in log
GriefPrevention.AddLogEntry("ERROR: Unable to read a material entry from the config file. Please update your config.yml.");
//update string, which will go out to config file to help user find the error entry
if(!stringsToParse.get(i).contains("can't"))
{
stringsToParse.set(i, stringsToParse.get(i) + " <-- can't understand this entry, see BukkitDev documentation");
}
}
//otherwise store the valid entry in config data
else
{
materialCollection.Add(materialInfo);
}
}
}
public int getSeaLevel(World world)
{
Integer overrideValue = this.config_seaLevelOverride.get(world.getName());
if(overrideValue == null || overrideValue == -1)
{
return world.getSeaLevel();
}
else
{
return overrideValue;
}
}
} }

View File

@ -0,0 +1,56 @@
package me.ryanhamshire.GriefPrevention;
import java.util.ArrayList;
//ordered list of material info objects, for fast searching
public class MaterialCollection
{
ArrayList<MaterialInfo> materials = new ArrayList<MaterialInfo>();
void Add(MaterialInfo material)
{
int i;
for(i = 0; i < this.materials.size() && this.materials.get(i).typeID <= material.typeID; i++);
this.materials.add(i, material);
}
boolean Contains(MaterialInfo material)
{
for(int i = 0; i < this.materials.size() ; i++)
{
MaterialInfo thisMaterial = this.materials.get(i);
if(material.typeID == thisMaterial.typeID && (thisMaterial.allDataValues || material.data == thisMaterial.data))
{
return true;
}
else if(thisMaterial.typeID > material.typeID)
{
return false;
}
}
return false;
}
@Override
public String toString()
{
StringBuilder stringBuilder = new StringBuilder();
for(int i = 0; i < this.materials.size(); i++)
{
stringBuilder.append(this.materials.get(i).toString() + " ");
}
return stringBuilder.toString();
}
public int size()
{
return this.materials.size();
}
public void clear()
{
this.materials.clear();
}
}

View File

@ -0,0 +1,75 @@
package me.ryanhamshire.GriefPrevention;
//represents a material or collection of materials
public class MaterialInfo
{
int typeID;
byte data;
boolean allDataValues;
String description;
public MaterialInfo(int typeID, byte data, String description)
{
this.typeID = typeID;
this.data = data;
this.allDataValues = false;
this.description = description;
}
public MaterialInfo(int typeID, String description)
{
this.typeID = typeID;
this.data = 0;
this.allDataValues = true;
this.description = description;
}
private MaterialInfo(int typeID, byte data, boolean allDataValues, String description)
{
this.typeID = typeID;
this.data = data;
this.allDataValues = allDataValues;
this.description = description;
}
@Override
public String toString()
{
String returnValue = String.valueOf(this.typeID) + ":" + (this.allDataValues?"*":String.valueOf(this.data));
if(this.description != null) returnValue += ":" + this.description;
return returnValue;
}
public static MaterialInfo fromString(String string)
{
if(string == null || string.isEmpty()) return null;
String [] parts = string.split(":");
if(parts.length < 3) return null;
try
{
int typeID = Integer.parseInt(parts[0]);
byte data;
boolean allDataValues;
if(parts[1].equals("*"))
{
allDataValues = true;
data = 0;
}
else
{
allDataValues = false;
data = Byte.parseByte(parts[1]);
}
return new MaterialInfo(typeID, data, allDataValues, parts[2]);
}
catch(NumberFormatException exception)
{
return null;
}
}
}

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 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
} }

View File

@ -77,6 +77,12 @@ class PlayerEventHandler implements Listener
void onPlayerChat (AsyncPlayerChatEvent event) void onPlayerChat (AsyncPlayerChatEvent event)
{ {
Player player = event.getPlayer(); Player player = event.getPlayer();
if(!player.isOnline())
{
event.setCancelled(true);
return;
}
String message = event.getMessage(); String message = event.getMessage();
event.setCancelled(this.handlePlayerChat(player, message, event)); event.setCancelled(this.handlePlayerChat(player, message, event));
@ -636,6 +642,14 @@ class PlayerEventHandler implements Listener
Player player = event.getPlayer(); Player player = event.getPlayer();
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
if(playerData.inPvpCombat())
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoTeleportPvPCombat);
event.setCancelled(true);
return;
}
Location source = event.getFrom(); Location source = event.getFrom();
Claim sourceClaim = this.dataStore.getClaimAt(source, false, null); Claim sourceClaim = this.dataStore.getClaimAt(source, false, null);
if(sourceClaim != null && sourceClaim.siegeData != null) if(sourceClaim != null && sourceClaim.siegeData != null)
@ -778,8 +792,11 @@ class PlayerEventHandler implements Listener
playerData.claimResizing = null; playerData.claimResizing = null;
//give the player his available claim blocks count and claiming instructions, but only if he keeps the shovel equipped for a minimum time, to avoid mouse wheel spam //give the player his available claim blocks count and claiming instructions, but only if he keeps the shovel equipped for a minimum time, to avoid mouse wheel spam
EquipShovelProcessingTask task = new EquipShovelProcessingTask(player); if(GriefPrevention.instance.claimsEnabledForWorld(player.getWorld()))
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task, 15L); //15L is approx. 3/4 of a second {
EquipShovelProcessingTask task = new EquipShovelProcessingTask(player);
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task, 15L); //15L is approx. 3/4 of a second
}
} }
} }
@ -946,7 +963,7 @@ class PlayerEventHandler implements Listener
clickedBlockType == Material.BREWING_STAND || clickedBlockType == Material.BREWING_STAND ||
clickedBlockType == Material.JUKEBOX || clickedBlockType == Material.JUKEBOX ||
clickedBlockType == Material.ENCHANTMENT_TABLE || clickedBlockType == Material.ENCHANTMENT_TABLE ||
GriefPrevention.instance.config_mods_containerTrustIds.contains(clickedBlock.getTypeId())))) GriefPrevention.instance.config_mods_containerTrustIds.Contains(new MaterialInfo(clickedBlock.getTypeId(), clickedBlock.getData(), null)))))
{ {
//block container use while under siege, so players can't hide items from attackers //block container use while under siege, so players can't hide items from attackers
if(playerData.siegeData != null) if(playerData.siegeData != null)
@ -1009,7 +1026,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(clickedBlock.getTypeId()))) 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))))
{ {
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)

View File

@ -99,7 +99,6 @@ class RestoreNatureProcessingTask implements Runnable
{ {
this.playerBlocks.add(Material.LEAVES.getId()); this.playerBlocks.add(Material.LEAVES.getId());
this.playerBlocks.add(Material.LOG.getId()); this.playerBlocks.add(Material.LOG.getId());
this.playerBlocks.add(Material.LEAVES.getId());
this.playerBlocks.add(Material.VINE.getId()); this.playerBlocks.add(Material.VINE.getId());
} }
} }
@ -145,11 +144,37 @@ 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
this.resetLeaves();
//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()
{
for(int x = 1; x < snapshots.length - 1; x++)
{
for(int z = 1; z < snapshots[0][0].length - 1; z++)
{
for(int y = this.seaLevel - 1; y < snapshots[0].length; y++)
{
//note: see minecraft wiki data values for leaves
BlockSnapshot block = snapshots[x][y][z];
if(block.typeId == Material.LEAVES.getId())
{
//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));
}
}
}
}
}
private void fillBigHoles() private void fillBigHoles()
{ {
for(int x = 1; x < snapshots.length - 1; x++) for(int x = 1; x < snapshots.length - 1; x++)
@ -157,15 +182,15 @@ class RestoreNatureProcessingTask implements Runnable
for(int z = 1; z < snapshots[0][0].length - 1; z++) for(int z = 1; z < snapshots[0][0].length - 1; z++)
{ {
//replace air, lava, or running water at sea level with stone //replace air, lava, or running water at sea level with stone
if(this.snapshots[x][this.seaLevel - 3][z].typeId == Material.AIR.getId() || this.snapshots[x][this.seaLevel - 3][z].typeId == Material.LAVA.getId() || (this.snapshots[x][this.seaLevel - 3][z].typeId == Material.WATER.getId() || this.snapshots[x][this.seaLevel - 3][z].data != 0)) if(this.snapshots[x][this.seaLevel - 2][z].typeId == Material.AIR.getId() || this.snapshots[x][this.seaLevel - 2][z].typeId == Material.LAVA.getId() || (this.snapshots[x][this.seaLevel - 2][z].typeId == Material.WATER.getId() || this.snapshots[x][this.seaLevel - 2][z].data != 0))
{ {
this.snapshots[x][this.seaLevel - 3][z].typeId = Material.STONE.getId(); this.snapshots[x][this.seaLevel - 2][z].typeId = Material.STONE.getId();
} }
//do the same for one layer beneath that (because a future restoration step may convert surface stone to sand, which falls down) //do the same for one layer beneath that (because a future restoration step may convert surface stone to sand, which falls down)
if(this.snapshots[x][this.seaLevel - 4][z].typeId == Material.AIR.getId() || this.snapshots[x][this.seaLevel - 4][z].typeId == Material.LAVA.getId() || (this.snapshots[x][this.seaLevel - 4][z].typeId == Material.WATER.getId() || this.snapshots[x][this.seaLevel - 4][z].data != 0)) if(this.snapshots[x][this.seaLevel - 3][z].typeId == Material.AIR.getId() || this.snapshots[x][this.seaLevel - 3][z].typeId == Material.LAVA.getId() || (this.snapshots[x][this.seaLevel - 3][z].typeId == Material.WATER.getId() || this.snapshots[x][this.seaLevel - 3][z].data != 0))
{ {
this.snapshots[x][this.seaLevel - 4][z].typeId = Material.STONE.getId(); this.snapshots[x][this.seaLevel - 3][z].typeId = Material.STONE.getId();
} }
} }
} }
@ -219,7 +244,7 @@ class RestoreNatureProcessingTask implements Runnable
{ {
int thisy = this.highestY(x, z, true); int thisy = this.highestY(x, z, true);
while(thisy > this.seaLevel - 2 && (this.snapshots[x][thisy][z].typeId == Material.STONE.getId() || this.snapshots[x][thisy][z].typeId == Material.SANDSTONE.getId())) while(thisy > this.seaLevel - 1 && (this.snapshots[x][thisy][z].typeId == Material.STONE.getId() || this.snapshots[x][thisy][z].typeId == Material.SANDSTONE.getId()))
{ {
BlockSnapshot leftBlock = this.snapshots[x + 1][thisy][z]; BlockSnapshot leftBlock = this.snapshots[x + 1][thisy][z];
BlockSnapshot rightBlock = this.snapshots[x - 1][thisy][z]; BlockSnapshot rightBlock = this.snapshots[x - 1][thisy][z];
@ -265,7 +290,7 @@ class RestoreNatureProcessingTask implements Runnable
{ {
for(int z = 1; z < snapshots[0][0].length - 1; z++) for(int z = 1; z < snapshots[0][0].length - 1; z++)
{ {
for(int y = this.seaLevel - 2; y < snapshots[0].length; y++) for(int y = this.seaLevel - 1; y < snapshots[0].length; y++)
{ {
BlockSnapshot block = snapshots[x][y][z]; BlockSnapshot block = snapshots[x][y][z];
@ -401,7 +426,7 @@ class RestoreNatureProcessingTask implements Runnable
int y = this.highestY(x, z, true); int y = this.highestY(x, z, true);
BlockSnapshot block = snapshots[x][y][z]; BlockSnapshot block = snapshots[x][y][z];
if(block.typeId == Material.STONE.getId() || block.typeId == Material.GRAVEL.getId() || block.typeId == Material.DIRT.getId() || block.typeId == Material.SANDSTONE.getId()) if(block.typeId == Material.STONE.getId() || block.typeId == Material.GRAVEL.getId() || block.typeId == Material.SOIL.getId() || block.typeId == Material.DIRT.getId() || block.typeId == Material.SANDSTONE.getId())
{ {
if(this.biome == Biome.DESERT || this.biome == Biome.DESERT_HILLS || this.biome == Biome.BEACH) if(this.biome == Biome.DESERT || this.biome == Biome.DESERT_HILLS || this.biome == Biome.BEACH)
{ {
@ -587,8 +612,10 @@ class RestoreNatureProcessingTask implements Runnable
if(block.typeId != Material.AIR.getId() && if(block.typeId != Material.AIR.getId() &&
!(ignoreLeaves && block.typeId == Material.SNOW.getId()) && !(ignoreLeaves && block.typeId == Material.SNOW.getId()) &&
!(ignoreLeaves && block.typeId == Material.LEAVES.getId()) && !(ignoreLeaves && block.typeId == Material.LEAVES.getId()) &&
!(block.typeId == Material.STATIONARY_WATER.getId() && block.data != 0) && !(block.typeId == Material.STATIONARY_WATER.getId()) &&
!(block.typeId == Material.STATIONARY_LAVA.getId() && block.data != 0)) !(block.typeId == Material.WATER.getId()) &&
!(block.typeId == Material.LAVA.getId()) &&
!(block.typeId == Material.STATIONARY_LAVA.getId()))
{ {
return y; return y;
} }
@ -635,7 +662,6 @@ class RestoreNatureProcessingTask implements Runnable
playerBlocks.add(Material.REDSTONE_WIRE.getId()); playerBlocks.add(Material.REDSTONE_WIRE.getId());
playerBlocks.add(Material.DIAMOND_BLOCK.getId()); playerBlocks.add(Material.DIAMOND_BLOCK.getId());
playerBlocks.add(Material.WORKBENCH.getId()); playerBlocks.add(Material.WORKBENCH.getId());
playerBlocks.add(Material.SOIL.getId());
playerBlocks.add(Material.FURNACE.getId()); playerBlocks.add(Material.FURNACE.getId());
playerBlocks.add(Material.BURNING_FURNACE.getId()); playerBlocks.add(Material.BURNING_FURNACE.getId());
playerBlocks.add(Material.WOODEN_DOOR.getId()); playerBlocks.add(Material.WOODEN_DOOR.getId());