diff --git a/src/main/java/com/wimbli/WorldBorder/BorderData.java b/src/main/java/com/wimbli/WorldBorder/BorderData.java index 8217363..1b015d1 100644 --- a/src/main/java/com/wimbli/WorldBorder/BorderData.java +++ b/src/main/java/com/wimbli/WorldBorder/BorderData.java @@ -406,8 +406,13 @@ public class BorderData // check if a particular spot consists of 2 breathable blocks over something relatively solid private boolean isSafeSpot(World world, int X, int Y, int Z, boolean flying) { - 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 + boolean safe = + // target block open and safe or is above maximum Y coordinate + (Y == world.getMaxHeight() + || (safeOpenBlocks.contains(world.getBlockAt(X, Y, Z).getType()) + // above target block open and safe or is above maximum Y coordinate + && (Y + 1 == world.getMaxHeight() + || safeOpenBlocks.contains(world.getBlockAt(X, Y + 1, Z).getType())))); if (!safe || flying) return safe; @@ -423,9 +428,10 @@ public class BorderData // find closest safe Y position from the starting position private double getSafeY(World world, int X, int Y, int Z, boolean flying) { - // 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 + // 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; we don't bother checking if Y = 126 or 127 are safe because they never will be unless there's a hole in the bedrock final boolean isNether = world.getEnvironment() == World.Environment.NETHER; - int limTop = isNether ? 125 : world.getMaxHeight() - 2; + int limTop = isNether ? 125 : world.getMaxHeight(); + // add 1 because getHighestBlockYAt() will give us the Y coordinate of a solid block, and we want the air block above it 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 @@ -448,12 +454,13 @@ public class BorderData 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 + // for non Nether worlds we don't need to check upwards to the world-limit, it is enough to check up to and including the highestBlockBoundary, unless player is flying if (!isNether && !flying) limTop = highestBlockBoundary; // 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++){ + // Note that we want to include limTop in the search - in the extreme case, world.getMaxHeight() should be included since the player can stand on top of the highest block + for(int y1 = Y, y2 = Y; (y1 > limBot) || (y2 <= limTop); y1--, y2++){ // Look below. if(y1 > limBot) { @@ -462,7 +469,7 @@ public class BorderData } // Look above. - if(y2 < limTop && y2 != y1) + if(y2 <= limTop && y2 != y1) { if (isSafeSpot(world, X, y2, Z, flying)) return (double)y2;