2012-03-30 00:27:12 +00:00
/ *
GriefPrevention Server Plugin for Minecraft
Copyright ( C ) 2011 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
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
package me.ryanhamshire.GriefPrevention ;
import java.util.ArrayList ;
import org.bukkit.Location ;
import org.bukkit.Material ;
import org.bukkit.World.Environment ;
import org.bukkit.block.Biome ;
import org.bukkit.entity.Player ;
//non-main-thread task which processes world data to repair the unnatural
//after processing is complete, creates a main thread task to make the necessary changes to the world
class RestoreNatureProcessingTask implements Runnable
{
//world information captured from the main thread
//will be updated and sent back to main thread to be applied to the world
private BlockSnapshot [ ] [ ] [ ] snapshots ;
//other information collected from the main thread.
//not to be updated, only to be passed back to main thread to provide some context about the operation
private int miny ;
private Environment environment ;
private Location lesserBoundaryCorner ;
private Location greaterBoundaryCorner ;
private Player player ; //absolutely must not be accessed. not thread safe.
private Biome biome ;
private int seaLevel ;
2012-05-31 02:16:46 +00:00
private boolean aggressiveMode ;
2012-03-30 00:27:12 +00:00
//two lists of materials
private ArrayList < Integer > notAllowedToHang ; //natural blocks which don't naturally hang in their air
private ArrayList < Integer > playerBlocks ; //a "complete" list of player-placed blocks. MUST BE MAINTAINED as patches introduce more
2012-05-31 02:16:46 +00:00
public RestoreNatureProcessingTask ( BlockSnapshot [ ] [ ] [ ] snapshots , int miny , Environment environment , Biome biome , Location lesserBoundaryCorner , Location greaterBoundaryCorner , int seaLevel , boolean aggressiveMode , Player player )
2012-03-30 00:27:12 +00:00
{
this . snapshots = snapshots ;
this . miny = miny ;
this . environment = environment ;
this . lesserBoundaryCorner = lesserBoundaryCorner ;
this . greaterBoundaryCorner = greaterBoundaryCorner ;
this . biome = biome ;
this . seaLevel = seaLevel ;
2012-05-31 02:16:46 +00:00
this . aggressiveMode = aggressiveMode ;
2012-03-30 00:27:12 +00:00
this . player = player ;
this . notAllowedToHang = new ArrayList < Integer > ( ) ;
this . notAllowedToHang . add ( Material . DIRT . getId ( ) ) ;
2012-05-01 03:11:39 +00:00
this . notAllowedToHang . add ( Material . LONG_GRASS . getId ( ) ) ;
2012-03-30 00:27:12 +00:00
this . notAllowedToHang . add ( Material . SNOW . getId ( ) ) ;
this . notAllowedToHang . add ( Material . LOG . getId ( ) ) ;
2012-05-31 02:16:46 +00:00
if ( this . aggressiveMode )
{
this . notAllowedToHang . add ( Material . GRASS . getId ( ) ) ;
this . notAllowedToHang . add ( Material . STONE . getId ( ) ) ;
}
2012-03-30 00:27:12 +00:00
//NOTE on this list. why not make a list of natural blocks?
//answer: better to leave a few player blocks than to remove too many natural blocks. remember we're "restoring nature"
2012-05-31 02:16:46 +00:00
//a few extra player blocks can be manually removed, but it will be impossible to guess exactly which natural materials to use in manual repair of an overzealous block removal
2012-03-30 00:27:12 +00:00
this . playerBlocks = new ArrayList < Integer > ( ) ;
2012-05-10 00:29:51 +00:00
this . playerBlocks . add ( Material . FIRE . getId ( ) ) ;
2012-03-30 00:27:12 +00:00
this . playerBlocks . add ( Material . BED_BLOCK . getId ( ) ) ;
this . playerBlocks . add ( Material . WOOD . getId ( ) ) ;
this . playerBlocks . add ( Material . BOOKSHELF . getId ( ) ) ;
this . playerBlocks . add ( Material . BREWING_STAND . getId ( ) ) ;
this . playerBlocks . add ( Material . BRICK . getId ( ) ) ;
this . playerBlocks . add ( Material . COBBLESTONE . getId ( ) ) ;
this . playerBlocks . add ( Material . GLASS . getId ( ) ) ;
this . playerBlocks . add ( Material . LAPIS_BLOCK . getId ( ) ) ;
this . playerBlocks . add ( Material . DISPENSER . getId ( ) ) ;
this . playerBlocks . add ( Material . NOTE_BLOCK . getId ( ) ) ;
this . playerBlocks . add ( Material . POWERED_RAIL . getId ( ) ) ;
this . playerBlocks . add ( Material . DETECTOR_RAIL . getId ( ) ) ;
this . playerBlocks . add ( Material . PISTON_STICKY_BASE . getId ( ) ) ;
this . playerBlocks . add ( Material . PISTON_BASE . getId ( ) ) ;
this . playerBlocks . add ( Material . PISTON_EXTENSION . getId ( ) ) ;
this . playerBlocks . add ( Material . WOOL . getId ( ) ) ;
this . playerBlocks . add ( Material . PISTON_MOVING_PIECE . getId ( ) ) ;
this . playerBlocks . add ( Material . GOLD_BLOCK . getId ( ) ) ;
this . playerBlocks . add ( Material . IRON_BLOCK . getId ( ) ) ;
this . playerBlocks . add ( Material . DOUBLE_STEP . getId ( ) ) ;
this . playerBlocks . add ( Material . STEP . getId ( ) ) ;
this . playerBlocks . add ( Material . CROPS . getId ( ) ) ;
this . playerBlocks . add ( Material . TNT . getId ( ) ) ;
this . playerBlocks . add ( Material . MOSSY_COBBLESTONE . getId ( ) ) ;
this . playerBlocks . add ( Material . TORCH . getId ( ) ) ;
this . playerBlocks . add ( Material . FIRE . getId ( ) ) ;
this . playerBlocks . add ( Material . WOOD_STAIRS . getId ( ) ) ;
this . playerBlocks . add ( Material . CHEST . getId ( ) ) ;
this . playerBlocks . add ( Material . REDSTONE_WIRE . getId ( ) ) ;
this . playerBlocks . add ( Material . DIAMOND_BLOCK . getId ( ) ) ;
this . playerBlocks . add ( Material . WORKBENCH . getId ( ) ) ;
this . playerBlocks . add ( Material . SOIL . getId ( ) ) ;
this . playerBlocks . add ( Material . FURNACE . getId ( ) ) ;
this . playerBlocks . add ( Material . BURNING_FURNACE . getId ( ) ) ;
this . playerBlocks . add ( Material . WOODEN_DOOR . getId ( ) ) ;
this . playerBlocks . add ( Material . SIGN_POST . getId ( ) ) ;
this . playerBlocks . add ( Material . LADDER . getId ( ) ) ;
this . playerBlocks . add ( Material . RAILS . getId ( ) ) ;
this . playerBlocks . add ( Material . COBBLESTONE_STAIRS . getId ( ) ) ;
this . playerBlocks . add ( Material . WALL_SIGN . getId ( ) ) ;
this . playerBlocks . add ( Material . STONE_PLATE . getId ( ) ) ;
this . playerBlocks . add ( Material . LEVER . getId ( ) ) ;
this . playerBlocks . add ( Material . IRON_DOOR_BLOCK . getId ( ) ) ;
this . playerBlocks . add ( Material . WOOD_PLATE . getId ( ) ) ;
this . playerBlocks . add ( Material . REDSTONE_TORCH_ON . getId ( ) ) ;
this . playerBlocks . add ( Material . REDSTONE_TORCH_OFF . getId ( ) ) ;
this . playerBlocks . add ( Material . STONE_BUTTON . getId ( ) ) ;
this . playerBlocks . add ( Material . SNOW_BLOCK . getId ( ) ) ;
this . playerBlocks . add ( Material . JUKEBOX . getId ( ) ) ;
this . playerBlocks . add ( Material . FENCE . getId ( ) ) ;
this . playerBlocks . add ( Material . PORTAL . getId ( ) ) ;
this . playerBlocks . add ( Material . JACK_O_LANTERN . getId ( ) ) ;
this . playerBlocks . add ( Material . CAKE_BLOCK . getId ( ) ) ;
this . playerBlocks . add ( Material . DIODE_BLOCK_ON . getId ( ) ) ;
this . playerBlocks . add ( Material . DIODE_BLOCK_OFF . getId ( ) ) ;
this . playerBlocks . add ( Material . TRAP_DOOR . getId ( ) ) ;
this . playerBlocks . add ( Material . SMOOTH_BRICK . getId ( ) ) ;
this . playerBlocks . add ( Material . HUGE_MUSHROOM_1 . getId ( ) ) ;
this . playerBlocks . add ( Material . HUGE_MUSHROOM_2 . getId ( ) ) ;
this . playerBlocks . add ( Material . IRON_FENCE . getId ( ) ) ;
this . playerBlocks . add ( Material . THIN_GLASS . getId ( ) ) ;
this . playerBlocks . add ( Material . MELON_STEM . getId ( ) ) ;
this . playerBlocks . add ( Material . FENCE_GATE . getId ( ) ) ;
this . playerBlocks . add ( Material . BRICK_STAIRS . getId ( ) ) ;
this . playerBlocks . add ( Material . SMOOTH_STAIRS . getId ( ) ) ;
this . playerBlocks . add ( Material . ENCHANTMENT_TABLE . getId ( ) ) ;
this . playerBlocks . add ( Material . BREWING_STAND . getId ( ) ) ;
this . playerBlocks . add ( Material . CAULDRON . getId ( ) ) ;
this . playerBlocks . add ( Material . DIODE_BLOCK_ON . getId ( ) ) ;
2012-06-17 17:33:20 +00:00
this . playerBlocks . add ( Material . DIODE_BLOCK_ON . getId ( ) ) ;
this . playerBlocks . add ( Material . WEB . getId ( ) ) ;
this . playerBlocks . add ( Material . SPONGE . getId ( ) ) ;
2012-03-30 00:27:12 +00:00
//these are unnatural in the standard world, but not in the nether
if ( this . environment ! = Environment . NETHER )
{
this . playerBlocks . add ( Material . NETHERRACK . getId ( ) ) ;
this . playerBlocks . add ( Material . SOUL_SAND . getId ( ) ) ;
this . playerBlocks . add ( Material . GLOWSTONE . getId ( ) ) ;
this . playerBlocks . add ( Material . NETHER_BRICK . getId ( ) ) ;
this . playerBlocks . add ( Material . NETHER_FENCE . getId ( ) ) ;
this . playerBlocks . add ( Material . NETHER_BRICK_STAIRS . getId ( ) ) ;
}
2012-06-17 17:33:20 +00:00
//these are unnatural in the standard and nether worlds, but not in the end
if ( this . environment ! = Environment . THE_END )
{
this . playerBlocks . add ( Material . OBSIDIAN . getId ( ) ) ;
}
2012-03-30 00:27:12 +00:00
//these are unnatural in sandy biomes, but not elsewhere
2012-05-31 02:16:46 +00:00
if ( this . biome = = Biome . DESERT | | this . biome = = Biome . DESERT_HILLS | | this . biome = = Biome . BEACH | | this . aggressiveMode )
2012-03-30 00:27:12 +00:00
{
this . playerBlocks . add ( Material . LEAVES . getId ( ) ) ;
this . playerBlocks . add ( Material . LOG . getId ( ) ) ;
}
2012-05-31 02:16:46 +00:00
//in aggressive mode, also treat these blocks as user placed, to be removed
//this is helpful in the few cases where griefers intentionally use natural blocks to grief,
//like a single-block tower of iron ore or a giant penis constructed with logs
if ( this . aggressiveMode )
{
this . playerBlocks . add ( Material . IRON_ORE . getId ( ) ) ;
this . playerBlocks . add ( Material . PUMPKIN . getId ( ) ) ;
this . playerBlocks . add ( Material . PUMPKIN_STEM . getId ( ) ) ;
this . playerBlocks . add ( Material . MELON_BLOCK . getId ( ) ) ;
this . playerBlocks . add ( Material . MELON_STEM . getId ( ) ) ;
2012-06-17 17:33:20 +00:00
this . playerBlocks . add ( Material . BEDROCK . getId ( ) ) ;
this . playerBlocks . add ( Material . GRAVEL . getId ( ) ) ;
this . playerBlocks . add ( Material . SANDSTONE . getId ( ) ) ;
2012-05-31 02:16:46 +00:00
}
2012-03-30 00:27:12 +00:00
}
@Override
public void run ( )
{
//order is important!
//remove any blocks which are definitely player placed
this . removePlayerBlocks ( ) ;
//remove natural blocks which are unnaturally hanging in the air
this . removeHanging ( ) ;
//remove natural blocks which are unnaturally stacked high
this . removeWallsAndTowers ( ) ;
//cover surface stone and gravel with sand or grass, as the biome requires
this . coverSurfaceStone ( ) ;
//fill unnatural thin trenches and single-block potholes
this . fillHolesAndTrenches ( ) ;
//fill water depressions and fix unnatural surface ripples
this . fixWater ( ) ;
2012-05-31 02:16:46 +00:00
//remove water/lava above sea level
this . removeDumpedFluids ( ) ;
2012-03-30 00:27:12 +00:00
//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 removePlayerBlocks ( )
{
int miny = this . miny ;
if ( miny < 1 ) miny = 1 ;
2012-05-31 02:16:46 +00:00
//remove all player blocks
2012-03-30 00:27:12 +00:00
for ( int x = 1 ; x < snapshots . length - 1 ; x + + )
{
for ( int z = 1 ; z < snapshots [ 0 ] [ 0 ] . length - 1 ; z + + )
{
for ( int y = miny ; y < snapshots [ 0 ] . length - 1 ; y + + )
{
BlockSnapshot block = snapshots [ x ] [ y ] [ z ] ;
if ( this . playerBlocks . contains ( block . typeId ) )
{
block . typeId = Material . AIR . getId ( ) ;
}
}
}
2012-05-31 02:16:46 +00:00
}
2012-03-30 00:27:12 +00:00
}
private void removeHanging ( )
{
int miny = this . miny ;
if ( miny < 1 ) miny = 1 ;
for ( int x = 1 ; x < snapshots . length - 1 ; x + + )
{
for ( int z = 1 ; z < snapshots [ 0 ] [ 0 ] . length - 1 ; z + + )
{
for ( int y = miny ; y < snapshots [ 0 ] . length - 1 ; y + + )
{
BlockSnapshot block = snapshots [ x ] [ y ] [ z ] ;
BlockSnapshot underBlock = snapshots [ x ] [ y - 1 ] [ z ] ;
2012-05-31 02:16:46 +00:00
if ( underBlock . typeId = = Material . AIR . getId ( ) | | underBlock . typeId = = Material . STATIONARY_WATER . getId ( ) | | underBlock . typeId = = Material . STATIONARY_LAVA . getId ( ) | | underBlock . typeId = = Material . LEAVES . getId ( ) )
2012-03-30 00:27:12 +00:00
{
if ( this . notAllowedToHang . contains ( block . typeId ) )
{
block . typeId = Material . AIR . getId ( ) ;
}
}
}
}
}
}
private void removeWallsAndTowers ( )
{
int [ ] excludedBlocksArray = new int [ ]
{
Material . CACTUS . getId ( ) ,
Material . LONG_GRASS . getId ( ) ,
Material . RED_MUSHROOM . getId ( ) ,
Material . BROWN_MUSHROOM . getId ( ) ,
Material . DEAD_BUSH . getId ( ) ,
Material . SAPLING . getId ( ) ,
Material . YELLOW_FLOWER . getId ( ) ,
Material . RED_ROSE . getId ( ) ,
Material . SUGAR_CANE_BLOCK . getId ( ) ,
Material . VINE . getId ( ) ,
Material . PUMPKIN . getId ( ) ,
Material . WATER_LILY . getId ( ) ,
Material . LEAVES . getId ( )
} ;
ArrayList < Integer > excludedBlocks = new ArrayList < Integer > ( ) ;
for ( int i = 0 ; i < excludedBlocksArray . length ; i + + ) excludedBlocks . add ( excludedBlocksArray [ i ] ) ;
boolean changed ;
do
{
changed = false ;
for ( int x = 1 ; x < snapshots . length - 1 ; x + + )
{
for ( int z = 1 ; z < snapshots [ 0 ] [ 0 ] . length - 1 ; z + + )
{
2012-05-31 02:16:46 +00:00
int thisy = this . highestY ( x , z , false ) ;
2012-03-30 00:27:12 +00:00
if ( excludedBlocks . contains ( this . snapshots [ x ] [ thisy ] [ z ] . typeId ) ) continue ;
2012-05-31 02:16:46 +00:00
int righty = this . highestY ( x + 1 , z , false ) ;
int lefty = this . highestY ( x - 1 , z , false ) ;
2012-03-30 00:27:12 +00:00
while ( lefty < thisy & & righty < thisy )
{
this . snapshots [ x ] [ thisy - - ] [ z ] . typeId = Material . AIR . getId ( ) ;
changed = true ;
}
2012-05-31 02:16:46 +00:00
int upy = this . highestY ( x , z + 1 , false ) ;
int downy = this . highestY ( x , z - 1 , false ) ;
2012-03-30 00:27:12 +00:00
while ( upy < thisy & & downy < thisy )
{
this . snapshots [ x ] [ thisy - - ] [ z ] . typeId = Material . AIR . getId ( ) ;
changed = true ;
}
}
}
} while ( changed ) ;
}
private void coverSurfaceStone ( )
{
for ( int x = 1 ; x < snapshots . length - 1 ; x + + )
{
for ( int z = 1 ; z < snapshots [ 0 ] [ 0 ] . length - 1 ; z + + )
{
2012-05-31 02:16:46 +00:00
int y = this . highestY ( x , z , true ) ;
2012-03-30 00:27:12 +00:00
BlockSnapshot block = snapshots [ x ] [ y ] [ z ] ;
if ( block . typeId = = Material . STONE . getId ( ) | | block . typeId = = Material . GRAVEL . getId ( ) | | block . typeId = = Material . DIRT . getId ( ) )
{
if ( this . biome = = Biome . DESERT | | this . biome = = Biome . DESERT_HILLS | | this . biome = = Biome . BEACH )
{
this . snapshots [ x ] [ y ] [ z ] . typeId = Material . SAND . getId ( ) ;
}
else
{
this . snapshots [ x ] [ y ] [ z ] . typeId = Material . GRASS . getId ( ) ;
}
}
}
}
}
private void fillHolesAndTrenches ( )
{
ArrayList < Integer > fillableBlocks = new ArrayList < Integer > ( ) ;
fillableBlocks . add ( Material . AIR . getId ( ) ) ;
fillableBlocks . add ( Material . STATIONARY_WATER . getId ( ) ) ;
fillableBlocks . add ( Material . STATIONARY_LAVA . getId ( ) ) ;
2012-05-10 00:29:51 +00:00
fillableBlocks . add ( Material . LONG_GRASS . getId ( ) ) ;
2012-03-30 00:27:12 +00:00
ArrayList < Integer > notSuitableForFillBlocks = new ArrayList < Integer > ( ) ;
notSuitableForFillBlocks . add ( Material . LONG_GRASS . getId ( ) ) ;
notSuitableForFillBlocks . add ( Material . CACTUS . getId ( ) ) ;
notSuitableForFillBlocks . add ( Material . STATIONARY_WATER . getId ( ) ) ;
notSuitableForFillBlocks . add ( Material . STATIONARY_LAVA . getId ( ) ) ;
boolean changed ;
do
{
changed = false ;
for ( int x = 1 ; x < snapshots . length - 1 ; x + + )
{
for ( int z = 1 ; z < snapshots [ 0 ] [ 0 ] . length - 1 ; z + + )
{
for ( int y = 0 ; y < snapshots [ 0 ] . length - 1 ; y + + )
{
BlockSnapshot block = this . snapshots [ x ] [ y ] [ z ] ;
if ( ! fillableBlocks . contains ( block . typeId ) ) continue ;
BlockSnapshot leftBlock = this . snapshots [ x + 1 ] [ y ] [ z ] ;
BlockSnapshot rightBlock = this . snapshots [ x - 1 ] [ y ] [ z ] ;
if ( ! fillableBlocks . contains ( leftBlock . typeId ) & & ! fillableBlocks . contains ( rightBlock . typeId ) )
{
if ( ! notSuitableForFillBlocks . contains ( rightBlock . typeId ) )
{
block . typeId = rightBlock . typeId ;
changed = true ;
}
}
BlockSnapshot upBlock = this . snapshots [ x ] [ y ] [ z + 1 ] ;
BlockSnapshot downBlock = this . snapshots [ x ] [ y ] [ z - 1 ] ;
if ( ! fillableBlocks . contains ( upBlock . typeId ) & & ! fillableBlocks . contains ( downBlock . typeId ) )
{
if ( ! notSuitableForFillBlocks . contains ( downBlock . typeId ) )
{
block . typeId = downBlock . typeId ;
changed = true ;
}
}
}
}
}
} while ( changed ) ;
}
private void fixWater ( )
{
int miny = this . miny ;
if ( miny < 1 ) miny = 1 ;
boolean changed ;
//remove hanging water or lava
for ( int x = 1 ; x < snapshots . length - 1 ; x + + )
{
for ( int z = 1 ; z < snapshots [ 0 ] [ 0 ] . length - 1 ; z + + )
{
for ( int y = miny ; y < snapshots [ 0 ] . length - 1 ; y + + )
{
BlockSnapshot block = this . snapshots [ x ] [ y ] [ z ] ;
BlockSnapshot underBlock = this . snapshots [ x ] [ y ] [ z ] ;
if ( block . typeId = = Material . STATIONARY_WATER . getId ( ) | | block . typeId = = Material . STATIONARY_LAVA . getId ( ) )
{
if ( underBlock . typeId = = Material . AIR . getId ( ) | | ( underBlock . data ! = 0 ) )
{
block . typeId = Material . AIR . getId ( ) ;
}
}
}
}
}
//fill water depressions
do
{
changed = false ;
for ( int y = this . seaLevel - 10 ; y < = this . seaLevel ; y + + )
{
for ( int x = 1 ; x < snapshots . length - 1 ; x + + )
{
for ( int z = 1 ; z < snapshots [ 0 ] [ 0 ] . length - 1 ; z + + )
{
BlockSnapshot block = snapshots [ x ] [ y ] [ z ] ;
//only consider air blocks and flowing water blocks for upgrade to water source blocks
if ( block . typeId = = Material . AIR . getId ( ) | | ( block . typeId = = Material . STATIONARY_WATER . getId ( ) & & block . data ! = 0 ) )
{
BlockSnapshot leftBlock = this . snapshots [ x + 1 ] [ y ] [ z ] ;
BlockSnapshot rightBlock = this . snapshots [ x - 1 ] [ y ] [ z ] ;
BlockSnapshot upBlock = this . snapshots [ x ] [ y ] [ z + 1 ] ;
BlockSnapshot downBlock = this . snapshots [ x ] [ y ] [ z - 1 ] ;
BlockSnapshot underBlock = this . snapshots [ x ] [ y - 1 ] [ z ] ;
//block underneath MUST be source water
if ( underBlock . typeId ! = Material . STATIONARY_WATER . getId ( ) | | underBlock . data ! = 0 ) continue ;
//count adjacent source water blocks
byte adjacentSourceWaterCount = 0 ;
if ( leftBlock . typeId = = Material . STATIONARY_WATER . getId ( ) & & leftBlock . data = = 0 )
{
adjacentSourceWaterCount + + ;
}
if ( rightBlock . typeId = = Material . STATIONARY_WATER . getId ( ) & & rightBlock . data = = 0 )
{
adjacentSourceWaterCount + + ;
}
if ( upBlock . typeId = = Material . STATIONARY_WATER . getId ( ) & & upBlock . data = = 0 )
{
adjacentSourceWaterCount + + ;
}
if ( downBlock . typeId = = Material . STATIONARY_WATER . getId ( ) & & downBlock . data = = 0 )
{
adjacentSourceWaterCount + + ;
}
//at least two adjacent blocks must be source water
if ( adjacentSourceWaterCount > = 2 )
{
block . typeId = Material . STATIONARY_WATER . getId ( ) ;
block . data = 0 ;
changed = true ;
}
}
}
}
}
} while ( changed ) ;
}
2012-05-31 02:16:46 +00:00
private void removeDumpedFluids ( )
{
//remove any surface water or lava above sea level, presumed to be placed by players
//sometimes, this is naturally generated. but replacing it is very easy with a bucket, so overall this is a good plan
if ( this . environment = = Environment . NETHER ) return ;
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 - 1 ; y + + )
{
BlockSnapshot block = snapshots [ x ] [ y ] [ z ] ;
if ( block . typeId = = Material . STATIONARY_WATER . getId ( ) | | block . typeId = = Material . STATIONARY_LAVA . getId ( ) | |
block . typeId = = Material . WATER . getId ( ) | | block . typeId = = Material . LAVA . getId ( ) )
{
block . typeId = Material . AIR . getId ( ) ;
}
}
}
}
}
private int highestY ( int x , int z , boolean ignoreLeaves )
2012-03-30 00:27:12 +00:00
{
int y ;
2012-05-01 03:11:39 +00:00
for ( y = snapshots [ 0 ] . length - 1 ; y > 0 ; y - - )
2012-03-30 00:27:12 +00:00
{
BlockSnapshot block = this . snapshots [ x ] [ y ] [ z ] ;
2012-05-31 02:16:46 +00:00
if ( block . typeId ! = Material . AIR . getId ( ) & &
! ( ignoreLeaves & & block . typeId = = Material . LEAVES . getId ( ) ) & &
2012-03-30 00:27:12 +00:00
! ( block . typeId = = Material . STATIONARY_WATER . getId ( ) & & block . data ! = 0 ) & &
! ( block . typeId = = Material . STATIONARY_LAVA . getId ( ) & & block . data ! = 0 ) )
{
return y ;
}
}
return y ;
}
}