Get highest y block not returning highest block.

Discussion in 'Spigot Plugin Development' started by G0ldManPox, Jun 12, 2016.

  1. I have been working on this problem for hours. When I call getHighestBlockYAt(x , z), it actually doesn't consider trees.
    For example, when I teleport a player to this location, they actually are teleported into a leaf block. Apparently, in 1.8.8, this causes them to be teleported into the ground and take suffocation damage. Is there a work around for this? I believe this happens because the chunk doesn't populate correctly or they actually fall through the leaf blocks while they are being teleported. Any advice would be helpful.
    I believe my method for checking the location is airtight.
    Code (Text):
    private boolean validate(Location loc){
            boolean valid = true;
            Block landBlock = loc.clone().add(0, -1, 0).getBlock();
            Block oneAboveLand = loc.clone().getBlock();
            Block twoAboveLand = loc.clone().add(0, 1, 0).getBlock();


            checkLoop:
                for(BlockFace face : faces){

                    if(VALID_SPAWN_BLOCKS.contains(landBlock.getRelative(face).getType())==false){
                        valid=false;
                        break checkLoop;
                    }

                    else if(oneAboveLand.getRelative(face).getType()!=(Material.AIR)){
                        valid=false;
                        break checkLoop;
                    }

                    else if(twoAboveLand.getRelative(face).getType()!=(Material.AIR)){
                        valid = false;
                        break checkLoop;
                    }

                }


            return valid;
        }

    private final Set<Material> VALID_SPAWN_BLOCKS = ImmutableSet.of(
                Material.GRASS,
                Material.SAND
                );
    private BlockFace[] faces = new BlockFace[] {
                BlockFace.SELF, BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH,
                BlockFace.WEST, BlockFace.NORTH_EAST, BlockFace.SOUTH_EAST, BlockFace.SOUTH_WEST, BlockFace.NORTH_WEST};


     
     
  2. The highest block is loaded when the chunk loads, so it's not that accurate. You could create a custom method that goes from y 255 to 0 to check the highest block manually.
     
  3. You're teleporting to the highest block, so of course you're inside it. One above #getHighestBlock is what you teleport to.

    Code (Java):
    Block oneAboveLand = loc.clone().getBlock();
    If `loc` is from #getHighestBlock, you are mistaken in thinking that this is one above it.
     
  4. Tried that, I made a method that did that, and it still did not work correctly. I still ran into the same issue of the trees not populating. Also, I tried using nms and listening for a chunk load and then getting the highest block, but that also did not work.

    Incorrect, I checked. highestYBlock actually does return the air block above the land block. No need to add 1 to it. Besides I have tried that, but still did not fix the leaf issue. Thanks though.
     
  5. Not incorrect, it's literally right in the documentation:
    http://docs.codelanx.com/Bukkit/1.8/org/bukkit/World.html#getHighestBlockAt-int-int-

    Note non-empty, aka it is not air.
     
    • Agree Agree x 1
  6. The documentation might say so, but in real testing, that is not the case.
    As evidence, I added this piece of code: Bukkit.broadcastMessage(oneAboveLand.getType().toString());

    It returned this:
    Code (Text):
    12.06 17:14:09 [Server] INFO AIR
    12.06 17:14:09 [Server] INFO AIR
    12.06 17:14:05 [Server] INFO AIR
    12.06 17:14:03 [Server] INFO AIR
    12.06 17:14:02 [Server] INFO AIR
    12.06 17:13:58 [Server] INFO AIR
    12.06 17:13:55 [Server] INFO LONG_GRASS
    12.06 17:13:55 [Server] INFO AIR
    12.06 17:13:52 [Server] INFO AIR
    12.06 17:13:49 [Server] INFO AIR
    12.06 17:13:49 [Server] INFO AIR
    12.06 17:13:45 [Server] INFO AIR
    12.06 17:13:42 [Server] INFO AIR
     
    • Agree Agree x 1
  7. Then show more code.
     
  8. Code (Java):
    if(cmd.getName().equalsIgnoreCase("getHighestBlock")){
        if(sender instanceof Player){
            Location loc = ((Player)sender).getLocation();
            Block block = loc.getWorld().getHighestBlockAt(loc);
            sender.sendMessage(ChatColor.translateAlternateColorCodes('&', " The highest block at your location is &a"+block.getType()+"&8 (&7"+block.getX()+"&8,&7 "+block.getY()+"&8,&7 "+block.getZ()+"&8)"));
        }
        return true;
    }
    [​IMG]
     
  9. Seems to be a spigot bug then, should report it on their JIRA.
     
  10. I am on 1.8.8. Interesting how leaves are ignored in that regard.

    However I found a non-elegant (dangerous) solution if anyone is interested.
    The idea is, after teleporting the player, call this function to clear the blocks around them (so they don't suffocate in a block). In case they aren't online then add them to list. When they login, call the function again. Again, not a very pretty solution.
    Code (Text):
    private void safeCheck(OfflinePlayer p){

            new BukkitRunnable() {

                @Override
                public void run() {

                    if(p.isOnline()){
                        Player target = (Player) p;
                        Block atLand = target.getLocation().clone().add(0, -1, 0).getBlock();
                        Block oneAboveLand = target.getLocation().getBlock();
                        Block twoAboveLand = target.getLocation().clone().add(0, 1, 0).getBlock();
                        Block threeAboveLand = target.getLocation().clone().add(0, 2, 0).getBlock();

                        for(BlockFace face : faces){
                            atLand.getRelative(face).setType(Material.GLASS);
                            oneAboveLand.getRelative(face).setType(Material.AIR);
                            twoAboveLand.getRelative(face).setType(Material.AIR);
                            threeAboveLand.getRelative(face).setType(Material.AIR);
                        }
                    }
                    else{
                        lateSafeCheck.add(p.getUniqueId());
                    }


                }
            }.runTaskLater(plugin, 5L);
        }
     
  11. getHighestBlockY gets a value from the chunk heightmap, which utterly ignores anything added by biome decorators, players or other modification.
     
  12. Code (Text):
    public Location getHighestBock(World world, int x, int z){
       int i = 255;
       while(i>0){
          if(new Location(world, x, i, z).getBlock().getType()!=Material.AIR)
             return new Location(world, x, i, z).add(0,1,0);
          i--;
       }
       return new Location(world, x, 1, z);
    }