2011-04-01 20:04:08 +02:00
package com.wimbli.WorldBorder ;
2018-08-22 07:20:04 +02:00
import java.util.EnumSet ;
2011-04-01 20:04:08 +02:00
2011-12-14 13:03:00 +01:00
import org.bukkit.Chunk ;
2011-04-01 20:04:08 +02:00
import org.bukkit.Location ;
2018-08-22 07:20:04 +02:00
import org.bukkit.Material ;
2011-04-01 20:04:08 +02:00
import org.bukkit.World ;
2011-04-01 20:22:01 +02:00
public class BorderData
{
2011-04-01 20:04:08 +02:00
// the main data interacted with
private double x = 0 ;
private double z = 0 ;
2013-02-14 10:35:35 +01:00
private int radiusX = 0 ;
private int radiusZ = 0 ;
2011-05-08 11:36:50 +02:00
private Boolean shapeRound = null ;
2013-04-14 11:51:57 +02:00
private boolean wrapping = false ;
2011-04-01 20:04:08 +02:00
// some extra data kept handy for faster border checks
private double maxX ;
private double minX ;
private double maxZ ;
private double minZ ;
2013-02-14 10:35:35 +01:00
private double radiusXSquared ;
private double radiusZSquared ;
private double DefiniteRectangleX ;
private double DefiniteRectangleZ ;
private double radiusSquaredQuotient ;
2011-04-01 20:04:08 +02:00
2013-04-14 11:51:57 +02:00
public BorderData ( double x , double z , int radiusX , int radiusZ , Boolean shapeRound , boolean wrap )
{
setData ( x , z , radiusX , radiusZ , shapeRound , wrap ) ;
}
2013-02-14 10:35:35 +01:00
public BorderData ( double x , double z , int radiusX , int radiusZ )
2011-05-08 11:36:50 +02:00
{
2013-03-29 23:32:21 +01:00
setData ( x , z , radiusX , radiusZ , null ) ;
2011-05-08 11:36:50 +02:00
}
2013-02-14 10:35:35 +01:00
public BorderData ( double x , double z , int radiusX , int radiusZ , Boolean shapeRound )
2011-05-08 11:36:50 +02:00
{
2013-02-14 10:35:35 +01:00
setData ( x , z , radiusX , radiusZ , shapeRound ) ;
2011-05-08 11:36:50 +02:00
}
2013-03-29 23:32:21 +01:00
public BorderData ( double x , double z , int radius )
{
setData ( x , z , radius , null ) ;
}
public BorderData ( double x , double z , int radius , Boolean shapeRound )
{
setData ( x , z , radius , shapeRound ) ;
}
2013-04-14 11:51:57 +02:00
public final void setData ( double x , double z , int radiusX , int radiusZ , Boolean shapeRound , boolean wrap )
2011-04-01 20:04:08 +02:00
{
this . x = x ;
this . z = z ;
2011-05-08 11:36:50 +02:00
this . shapeRound = shapeRound ;
2013-04-14 11:51:57 +02:00
this . wrapping = wrap ;
2013-02-14 10:35:35 +01:00
this . setRadiusX ( radiusX ) ;
this . setRadiusZ ( radiusZ ) ;
2011-04-01 20:04:08 +02:00
}
2013-04-14 11:51:57 +02:00
public final void setData ( double x , double z , int radiusX , int radiusZ , Boolean shapeRound )
{
2013-04-14 13:39:48 +02:00
setData ( x , z , radiusX , radiusZ , shapeRound , false ) ;
2013-04-14 11:51:57 +02:00
}
2013-03-29 23:32:21 +01:00
public final void setData ( double x , double z , int radius , Boolean shapeRound )
{
2013-04-14 11:51:57 +02:00
setData ( x , z , radius , radius , shapeRound , false ) ;
2013-03-29 23:32:21 +01:00
}
2011-04-01 20:04:08 +02:00
2011-07-19 07:12:14 +02:00
public BorderData copy ( )
{
2013-04-14 11:51:57 +02:00
return new BorderData ( x , z , radiusX , radiusZ , shapeRound , wrapping ) ;
2011-07-19 07:12:14 +02:00
}
2011-04-01 20:04:08 +02:00
public double getX ( )
{
return x ;
}
public void setX ( double x )
{
this . x = x ;
2013-02-14 10:35:35 +01:00
this . maxX = x + radiusX ;
this . minX = x - radiusX ;
2011-04-01 20:04:08 +02:00
}
public double getZ ( )
{
return z ;
}
public void setZ ( double z )
{
this . z = z ;
2013-02-14 10:35:35 +01:00
this . maxZ = z + radiusZ ;
this . minZ = z - radiusZ ;
2011-04-01 20:04:08 +02:00
}
2013-02-14 10:35:35 +01:00
public int getRadiusX ( )
2011-04-01 20:04:08 +02:00
{
2013-02-14 10:35:35 +01:00
return radiusX ;
2011-04-01 20:04:08 +02:00
}
2013-02-14 10:35:35 +01:00
public int getRadiusZ ( )
2011-04-01 20:04:08 +02:00
{
2013-02-14 10:35:35 +01:00
return radiusZ ;
}
public void setRadiusX ( int radiusX )
{
this . radiusX = radiusX ;
this . maxX = x + radiusX ;
this . minX = x - radiusX ;
this . radiusXSquared = ( double ) radiusX * ( double ) radiusX ;
this . radiusSquaredQuotient = this . radiusXSquared / this . radiusZSquared ;
this . DefiniteRectangleX = Math . sqrt ( . 5 * this . radiusXSquared ) ;
}
public void setRadiusZ ( int radiusZ )
{
this . radiusZ = radiusZ ;
this . maxZ = z + radiusZ ;
this . minZ = z - radiusZ ;
this . radiusZSquared = ( double ) radiusZ * ( double ) radiusZ ;
this . radiusSquaredQuotient = this . radiusXSquared / this . radiusZSquared ;
this . DefiniteRectangleZ = Math . sqrt ( . 5 * this . radiusZSquared ) ;
2011-04-01 20:04:08 +02:00
}
2013-03-29 23:32:21 +01:00
// backwards-compatible methods from before elliptical/rectangular shapes were supported
/ * *
* @deprecated Replaced by { @link # getRadiusX ( ) } and { @link # getRadiusZ ( ) } ;
* this method now returns an average of those two values and is thus imprecise
* /
public int getRadius ( )
{
return ( radiusX + radiusZ ) / 2 ; // average radius; not great, but probably best for backwards compatibility
}
public void setRadius ( int radius )
{
setRadiusX ( radius ) ;
setRadiusZ ( radius ) ;
}
2011-05-08 11:36:50 +02:00
public Boolean getShape ( )
{
return shapeRound ;
}
public void setShape ( Boolean shapeRound )
{
this . shapeRound = shapeRound ;
}
2013-04-14 11:51:57 +02:00
public boolean getWrapping ( )
{
return wrapping ;
}
public void setWrapping ( boolean wrap )
{
this . wrapping = wrap ;
}
2011-04-01 20:04:08 +02:00
@Override
public String toString ( )
{
2013-04-14 11:51:57 +02:00
return " radius " + ( ( radiusX = = radiusZ ) ? radiusX : radiusX + " x " + radiusZ ) + " at X: " + Config . coord . format ( x ) + " Z: " + Config . coord . format ( z ) + ( shapeRound ! = null ? ( " (shape override: " + Config . ShapeName ( shapeRound . booleanValue ( ) ) + " ) " ) : " " ) + ( wrapping ? ( " (wrapping) " ) : " " ) ;
2011-04-01 20:04:08 +02:00
}
// This algorithm of course needs to be fast, since it will be run very frequently
public boolean insideBorder ( double xLoc , double zLoc , boolean round )
{
2011-05-08 11:36:50 +02:00
// if this border has a shape override set, use it
if ( shapeRound ! = null )
round = shapeRound . booleanValue ( ) ;
2011-04-03 11:40:50 +02:00
// square border
if ( ! round )
return ! ( xLoc < minX | | xLoc > maxX | | zLoc < minZ | | zLoc > maxZ ) ;
// round border
else
2011-04-01 20:04:08 +02:00
{
2011-04-03 11:40:50 +02:00
// elegant round border checking algorithm is from rBorder by Reil with almost no changes, all credit to him for it
2011-04-01 20:04:08 +02:00
double X = Math . abs ( x - xLoc ) ;
double Z = Math . abs ( z - zLoc ) ;
2013-02-14 10:35:35 +01:00
if ( X < DefiniteRectangleX & & Z < DefiniteRectangleZ )
2011-04-01 20:04:08 +02:00
return true ; // Definitely inside
2013-03-29 23:32:21 +01:00
else if ( X > = radiusX | | Z > = radiusZ )
2011-04-01 20:04:08 +02:00
return false ; // Definitely outside
2013-02-14 10:35:35 +01:00
else if ( X * X + Z * Z * radiusSquaredQuotient < radiusXSquared )
2011-04-03 11:40:50 +02:00
return true ; // After further calculation, inside
2011-04-01 20:04:08 +02:00
else
return false ; // Apparently outside, then
}
}
2011-06-07 13:08:21 +02:00
public boolean insideBorder ( double xLoc , double zLoc )
{
return insideBorder ( xLoc , zLoc , Config . ShapeRound ( ) ) ;
}
2011-06-07 20:17:46 +02:00
public boolean insideBorder ( Location loc )
{
return insideBorder ( loc . getX ( ) , loc . getZ ( ) , Config . ShapeRound ( ) ) ;
}
2013-03-30 08:56:12 +01:00
public boolean insideBorder ( CoordXZ coord , boolean round )
{
return insideBorder ( coord . x , coord . z , round ) ;
}
public boolean insideBorder ( CoordXZ coord )
{
return insideBorder ( coord . x , coord . z , Config . ShapeRound ( ) ) ;
}
2011-04-01 20:04:08 +02:00
2013-03-29 23:57:52 +01:00
public Location correctedPosition ( Location loc , boolean round , boolean flying )
2011-04-01 20:04:08 +02:00
{
2011-05-08 11:36:50 +02:00
// if this border has a shape override set, use it
if ( shapeRound ! = null )
round = shapeRound . booleanValue ( ) ;
2011-04-01 20:04:08 +02:00
double xLoc = loc . getX ( ) ;
double zLoc = loc . getZ ( ) ;
double yLoc = loc . getY ( ) ;
2011-04-03 11:40:50 +02:00
// square border
if ( ! round )
2011-04-01 20:04:08 +02:00
{
2013-04-14 11:51:57 +02:00
if ( wrapping )
2013-04-03 22:19:51 +02:00
{
if ( xLoc < = minX )
xLoc = maxX - Config . KnockBack ( ) ;
else if ( xLoc > = maxX )
xLoc = minX + Config . KnockBack ( ) ;
if ( zLoc < = minZ )
zLoc = maxZ - Config . KnockBack ( ) ;
else if ( zLoc > = maxZ )
zLoc = minZ + Config . KnockBack ( ) ;
}
else
{
if ( xLoc < = minX )
xLoc = minX + Config . KnockBack ( ) ;
else if ( xLoc > = maxX )
xLoc = maxX - Config . KnockBack ( ) ;
if ( zLoc < = minZ )
zLoc = minZ + Config . KnockBack ( ) ;
else if ( zLoc > = maxZ )
zLoc = maxZ - Config . KnockBack ( ) ;
}
2011-04-01 20:04:08 +02:00
}
2011-04-03 11:40:50 +02:00
// round border
else
2011-04-01 20:04:08 +02:00
{
2013-03-29 23:32:21 +01:00
// algorithm originally from: http://stackoverflow.com/questions/300871/best-way-to-find-a-point-on-a-circle-closest-to-a-given-point
// modified by Lang Lukas to support elliptical border shape
2013-02-14 10:35:35 +01:00
//Transform the ellipse to a circle with radius 1 (we need to transform the point the same way)
double dX = xLoc - x ;
double dZ = zLoc - z ;
double dU = Math . sqrt ( dX * dX + dZ * dZ ) ; //distance of the untransformed point from the center
double dT = Math . sqrt ( dX * dX / radiusXSquared + dZ * dZ / radiusZSquared ) ; //distance of the transformed point from the center
double f = ( 1 / dT - Config . KnockBack ( ) / dU ) ; //"correction" factor for the distances
2013-04-14 11:51:57 +02:00
if ( wrapping )
2013-04-03 22:19:51 +02:00
{
xLoc = x - dX * f ;
zLoc = z - dZ * f ;
} else {
xLoc = x + dX * f ;
zLoc = z + dZ * f ;
}
2011-04-01 20:04:08 +02:00
}
2011-12-14 13:03:00 +01:00
int ixLoc = Location . locToBlock ( xLoc ) ;
int izLoc = Location . locToBlock ( zLoc ) ;
// Make sure the chunk we're checking in is actually loaded
Chunk tChunk = loc . getWorld ( ) . getChunkAt ( CoordXZ . blockToChunk ( ixLoc ) , CoordXZ . blockToChunk ( izLoc ) ) ;
if ( ! tChunk . isLoaded ( ) )
tChunk . load ( ) ;
2013-03-29 23:57:52 +01:00
yLoc = getSafeY ( loc . getWorld ( ) , ixLoc , Location . locToBlock ( yLoc ) , izLoc , flying ) ;
2011-04-01 20:04:08 +02:00
if ( yLoc = = - 1 )
return null ;
return new Location ( loc . getWorld ( ) , Math . floor ( xLoc ) + 0 . 5 , yLoc , Math . floor ( zLoc ) + 0 . 5 , loc . getYaw ( ) , loc . getPitch ( ) ) ;
}
2013-03-29 23:57:52 +01:00
public Location correctedPosition ( Location loc , boolean round )
{
return correctedPosition ( loc , round , false ) ;
}
2011-06-07 13:08:21 +02:00
public Location correctedPosition ( Location loc )
{
2013-03-29 23:57:52 +01:00
return correctedPosition ( loc , Config . ShapeRound ( ) , false ) ;
2011-06-07 13:08:21 +02:00
}
2011-04-01 20:04:08 +02:00
//these material IDs are acceptable for places to teleport player; breathable blocks and water
2018-08-22 07:20:04 +02:00
public static final EnumSet < Material > safeOpenBlocks = EnumSet . noneOf ( Material . class ) ;
static
{
safeOpenBlocks . add ( Material . AIR ) ;
safeOpenBlocks . add ( Material . CAVE_AIR ) ;
safeOpenBlocks . add ( Material . OAK_SAPLING ) ;
safeOpenBlocks . add ( Material . SPRUCE_SAPLING ) ;
safeOpenBlocks . add ( Material . BIRCH_SAPLING ) ;
safeOpenBlocks . add ( Material . JUNGLE_SAPLING ) ;
safeOpenBlocks . add ( Material . ACACIA_SAPLING ) ;
safeOpenBlocks . add ( Material . DARK_OAK_SAPLING ) ;
safeOpenBlocks . add ( Material . WATER ) ;
safeOpenBlocks . add ( Material . RAIL ) ;
safeOpenBlocks . add ( Material . POWERED_RAIL ) ;
safeOpenBlocks . add ( Material . DETECTOR_RAIL ) ;
safeOpenBlocks . add ( Material . ACTIVATOR_RAIL ) ;
safeOpenBlocks . add ( Material . COBWEB ) ;
safeOpenBlocks . add ( Material . GRASS ) ;
safeOpenBlocks . add ( Material . FERN ) ;
safeOpenBlocks . add ( Material . DEAD_BUSH ) ;
safeOpenBlocks . add ( Material . DANDELION ) ;
safeOpenBlocks . add ( Material . POPPY ) ;
safeOpenBlocks . add ( Material . BLUE_ORCHID ) ;
safeOpenBlocks . add ( Material . ALLIUM ) ;
safeOpenBlocks . add ( Material . AZURE_BLUET ) ;
safeOpenBlocks . add ( Material . RED_TULIP ) ;
safeOpenBlocks . add ( Material . ORANGE_TULIP ) ;
safeOpenBlocks . add ( Material . WHITE_TULIP ) ;
safeOpenBlocks . add ( Material . PINK_TULIP ) ;
safeOpenBlocks . add ( Material . OXEYE_DAISY ) ;
safeOpenBlocks . add ( Material . BROWN_MUSHROOM ) ;
safeOpenBlocks . add ( Material . RED_MUSHROOM ) ;
safeOpenBlocks . add ( Material . TORCH ) ;
safeOpenBlocks . add ( Material . WALL_TORCH ) ;
safeOpenBlocks . add ( Material . REDSTONE_WIRE ) ;
safeOpenBlocks . add ( Material . WHEAT ) ;
safeOpenBlocks . add ( Material . LADDER ) ;
safeOpenBlocks . add ( Material . LEVER ) ;
safeOpenBlocks . add ( Material . LIGHT_WEIGHTED_PRESSURE_PLATE ) ;
safeOpenBlocks . add ( Material . HEAVY_WEIGHTED_PRESSURE_PLATE ) ;
safeOpenBlocks . add ( Material . STONE_PRESSURE_PLATE ) ;
safeOpenBlocks . add ( Material . OAK_PRESSURE_PLATE ) ;
safeOpenBlocks . add ( Material . SPRUCE_PRESSURE_PLATE ) ;
safeOpenBlocks . add ( Material . BIRCH_PRESSURE_PLATE ) ;
safeOpenBlocks . add ( Material . JUNGLE_PRESSURE_PLATE ) ;
safeOpenBlocks . add ( Material . ACACIA_PRESSURE_PLATE ) ;
safeOpenBlocks . add ( Material . DARK_OAK_PRESSURE_PLATE ) ;
safeOpenBlocks . add ( Material . REDSTONE_TORCH ) ;
safeOpenBlocks . add ( Material . REDSTONE_WALL_TORCH ) ;
safeOpenBlocks . add ( Material . STONE_BUTTON ) ;
safeOpenBlocks . add ( Material . SNOW ) ;
safeOpenBlocks . add ( Material . SUGAR_CANE ) ;
safeOpenBlocks . add ( Material . REPEATER ) ;
safeOpenBlocks . add ( Material . COMPARATOR ) ;
safeOpenBlocks . add ( Material . OAK_TRAPDOOR ) ;
safeOpenBlocks . add ( Material . SPRUCE_TRAPDOOR ) ;
safeOpenBlocks . add ( Material . BIRCH_TRAPDOOR ) ;
safeOpenBlocks . add ( Material . JUNGLE_TRAPDOOR ) ;
safeOpenBlocks . add ( Material . ACACIA_TRAPDOOR ) ;
safeOpenBlocks . add ( Material . DARK_OAK_TRAPDOOR ) ;
safeOpenBlocks . add ( Material . MELON_STEM ) ;
safeOpenBlocks . add ( Material . ATTACHED_MELON_STEM ) ;
safeOpenBlocks . add ( Material . PUMPKIN_STEM ) ;
safeOpenBlocks . add ( Material . ATTACHED_PUMPKIN_STEM ) ;
safeOpenBlocks . add ( Material . VINE ) ;
safeOpenBlocks . add ( Material . NETHER_WART ) ;
safeOpenBlocks . add ( Material . TRIPWIRE ) ;
safeOpenBlocks . add ( Material . TRIPWIRE_HOOK ) ;
safeOpenBlocks . add ( Material . CARROTS ) ;
safeOpenBlocks . add ( Material . POTATOES ) ;
2018-08-22 17:47:54 +02:00
safeOpenBlocks . add ( Material . OAK_BUTTON ) ;
safeOpenBlocks . add ( Material . SPRUCE_BUTTON ) ;
safeOpenBlocks . add ( Material . BIRCH_BUTTON ) ;
safeOpenBlocks . add ( Material . JUNGLE_BUTTON ) ;
safeOpenBlocks . add ( Material . ACACIA_BUTTON ) ;
safeOpenBlocks . add ( Material . DARK_OAK_BUTTON ) ;
safeOpenBlocks . add ( Material . SUNFLOWER ) ;
safeOpenBlocks . add ( Material . LILAC ) ;
safeOpenBlocks . add ( Material . ROSE_BUSH ) ;
safeOpenBlocks . add ( Material . PEONY ) ;
safeOpenBlocks . add ( Material . TALL_GRASS ) ;
safeOpenBlocks . add ( Material . LARGE_FERN ) ;
safeOpenBlocks . add ( Material . BEETROOTS ) ;
2019-05-24 02:48:54 +02:00
try
{ // signs in 1.14 can be different wood types
safeOpenBlocks . add ( Material . ACACIA_SIGN ) ;
safeOpenBlocks . add ( Material . ACACIA_WALL_SIGN ) ;
safeOpenBlocks . add ( Material . BIRCH_SIGN ) ;
safeOpenBlocks . add ( Material . BIRCH_WALL_SIGN ) ;
safeOpenBlocks . add ( Material . DARK_OAK_SIGN ) ;
safeOpenBlocks . add ( Material . DARK_OAK_WALL_SIGN ) ;
safeOpenBlocks . add ( Material . JUNGLE_SIGN ) ;
safeOpenBlocks . add ( Material . JUNGLE_WALL_SIGN ) ;
safeOpenBlocks . add ( Material . OAK_SIGN ) ;
safeOpenBlocks . add ( Material . OAK_WALL_SIGN ) ;
safeOpenBlocks . add ( Material . SPRUCE_SIGN ) ;
safeOpenBlocks . add ( Material . SPRUCE_WALL_SIGN ) ;
}
catch ( NoSuchFieldError ex ) { }
2018-08-22 07:20:04 +02:00
}
2011-04-01 20:04:08 +02:00
2011-12-14 13:03:00 +01:00
//these material IDs are ones we don't want to drop the player onto, like cactus or lava or fire or activated Ender portal
2018-08-22 07:20:04 +02:00
public static final EnumSet < Material > painfulBlocks = EnumSet . noneOf ( Material . class ) ;
static
{
painfulBlocks . add ( Material . LAVA ) ;
painfulBlocks . add ( Material . FIRE ) ;
painfulBlocks . add ( Material . CACTUS ) ;
painfulBlocks . add ( Material . END_PORTAL ) ;
painfulBlocks . add ( Material . MAGMA_BLOCK ) ;
}
2011-04-01 20:04:08 +02:00
// check if a particular spot consists of 2 breathable blocks over something relatively solid
2013-03-29 23:57:52 +01:00
private boolean isSafeSpot ( World world , int X , int Y , int Z , boolean flying )
2011-04-01 20:04:08 +02:00
{
2018-08-22 07:20:04 +02:00
boolean safe = safeOpenBlocks . contains ( world . getBlockAt ( X , Y , Z ) . getType ( ) ) // target block open and safe
& & safeOpenBlocks . contains ( world . getBlockAt ( X , Y + 1 , Z ) . getType ( ) ) ; // above target block open and safe
2013-03-29 23:57:52 +01:00
if ( ! safe | | flying )
return safe ;
2018-08-22 07:20:04 +02:00
Material below = world . getBlockAt ( X , Y - 1 , Z ) . getType ( ) ;
2013-03-29 23:57:52 +01:00
return ( safe
2018-08-22 07:20:04 +02:00
& & ( ! safeOpenBlocks . contains ( below ) | | below = = Material . WATER ) // below target block not open/breathable (so presumably solid), or is water
2013-03-29 23:57:52 +01:00
& & ! painfulBlocks . contains ( below ) // below target block not painful
2011-04-01 20:04:08 +02:00
) ;
}
2016-01-02 11:54:10 +01:00
private static final int limBot = 0 ;
2011-05-08 11:36:50 +02:00
2011-04-01 20:04:08 +02:00
// find closest safe Y position from the starting position
2013-03-29 23:57:52 +01:00
private double getSafeY ( World world , int X , int Y , int Z , boolean flying )
2011-04-01 20:04:08 +02:00
{
2012-10-25 08:04:23 +02:00
// artificial height limit of 127 added for Nether worlds since CraftBukkit still incorrectly returns 255 for their max height, leading to players sent to the "roof" of the Nether
2016-02-26 02:47:03 +01:00
final boolean isNether = world . getEnvironment ( ) = = World . Environment . NETHER ;
int limTop = isNether ? 125 : world . getMaxHeight ( ) - 2 ;
final int highestBlockBoundary = Math . min ( world . getHighestBlockYAt ( X , Z ) + 1 , limTop ) ;
// if Y is larger than the world can be and user can fly, return Y - Unless we are in the Nether, we might not want players on the roof
if ( flying & & Y > limTop & & ! isNether )
return ( double ) Y ;
// make sure Y values are within the boundaries of the world.
if ( Y > limTop )
{
if ( isNether )
Y = limTop ; // because of the roof, the nether can not rely on highestBlockBoundary, so limTop has to be used
else
{
if ( flying )
Y = limTop ;
else
Y = highestBlockBoundary ; // there will never be a save block to stand on for Y values > highestBlockBoundary
}
}
if ( Y < limBot )
Y = limBot ;
// for non Nether worlds we don't need to check upwards to the world-limit, it is enough to check up to the highestBlockBoundary, unless player is flying
if ( ! isNether & & ! flying )
limTop = highestBlockBoundary ;
2011-04-01 20:04:08 +02:00
// Expanding Y search method adapted from Acru's code in the Nether plugin
for ( int y1 = Y , y2 = Y ; ( y1 > limBot ) | | ( y2 < limTop ) ; y1 - - , y2 + + ) {
// Look below.
2011-12-14 13:03:00 +01:00
if ( y1 > limBot )
{
2013-03-29 23:57:52 +01:00
if ( isSafeSpot ( world , X , y1 , Z , flying ) )
2011-04-01 20:04:08 +02:00
return ( double ) y1 ;
}
// Look above.
2011-12-14 13:03:00 +01:00
if ( y2 < limTop & & y2 ! = y1 )
{
2013-03-29 23:57:52 +01:00
if ( isSafeSpot ( world , X , y2 , Z , flying ) )
2011-04-01 20:04:08 +02:00
return ( double ) y2 ;
}
}
return - 1 . 0 ; // no safe Y location?!?!? Must be a rare spot in a Nether world or something
}
2011-09-06 23:42:28 +02:00
@Override
public boolean equals ( Object obj )
{
if ( this = = obj )
return true ;
else if ( obj = = null | | obj . getClass ( ) ! = this . getClass ( ) )
return false ;
BorderData test = ( BorderData ) obj ;
2013-02-14 10:35:35 +01:00
return test . x = = this . x & & test . z = = this . z & & test . radiusX = = this . radiusX & & test . radiusZ = = this . radiusZ ;
2011-09-06 23:42:28 +02:00
}
@Override
public int hashCode ( )
{
2013-03-29 23:32:21 +01:00
return ( ( ( int ) ( this . x * 10 ) < < 4 ) + ( int ) this . z + ( this . radiusX < < 2 ) + ( this . radiusZ < < 3 ) ) ;
2011-09-06 23:42:28 +02:00
}
2013-04-03 22:19:51 +02:00
}