Solved Determining Block Below Player & Subsequently Count of Blocks

Discussion in 'Spigot Plugin Development' started by WAS, May 3, 2017.

  1. WAS

    WAS

    What would be the lowest impact method to determine the block below a player and how many blocks there are while flying. Currently I am using the block iterator which I know in general you should try and avoid the iterator for loops.

    Code (Java):
          BlockIterator trace = new BlockIterator(f.getWorld(), f.toVector(),
               new Vector(BlockFace.DOWN.getModX(), BlockFace.DOWN.getModY(), BlockFace.DOWN.getModZ()), 0, 256);

           Block groundBlock = null;

           int toGround = 0;
           while (trace.hasNext()) {
             Block block = trace.next();
             if (!(block.getType().equals(Material.AIR))) {
               groundBlock = block;
               break;
             }
             toGround++;
           }
    Would it be less expensive to check blocks by location and use a simple for loop? And by locations something like

    Code (Java):
          for (int i = 0; i < f.getWorld().getMaxHeight(); i++) {
             Block block = f.add(0, -f.getY()-i, 0).getBlock();
             if (!(block.getType().equals(Material.AIR))) {
               groundBlock = block;
               toGround = i;
               break;
             }
           }
     
    #1 WAS, May 3, 2017
    Last edited: May 3, 2017
  2. Choco

    Moderator

    I see no reason to use a BlockIterator in a situation such as this. The only true purpose I could see for a BlockIterator for this would be if you require the last Block in the iteration, and the Vector was in an undetermined direction. In any other situation, it can be rather inefficient when there is a superior alternative (see BlockIterator's source code).

    I recommend instead using a while loop to determine where the next solid block is
    Code (Java):
    Location playerLoc = player.getLocation();

    int amount = 0;
    while (!playerLoc.subtract(0, 1, 0).getBlock().getType().isSolid()) {
        amount++;
    }
    I used Material#isSolid() just so water/lava (or any future liquids) don't count as solid blocks. They will essentially be considered as air. You're welcome to instead check if the material is not equal to air, however

    EDIT: You may also get creative with a for loop:
    Code (Java):
    Location playerLoc = player.getLocation();

    int count = 0;
    for (; !playerLoc.subtract(0, 1, 0).getBlock().getType().isSolid(); count++);
    (Hey look! A use for conditional statements without a body!)
     
    #2 Choco, May 3, 2017
    Last edited: May 3, 2017
    • Agree Agree x 1
  3. WAS

    WAS

    I came to same conclusion after doing some timing tests. I came up with this. Using the world height just in case there is instances where the nether is below. Course it'll count over by a margin in those circumstances, but better than going stray by some chance.

    Code (Java):
           Block lastBlock = null;
           Block groundBlock = null;
           int toGround = 0;
       
           for (int i = 0; i < f.getWorld().getMaxHeight(); i++) {
             if (lastBlock == null) {
               lastBlock = f.subtract(0, 1, 0).getBlock();
             } else {
               lastBlock = lastBlock.getLocation().subtract(0, 1, 0).getBlock();
             }
             if (!(lastBlock.getType().equals(Material.AIR))) {
               groundBlock = lastBlock;
               toGround = i;
               break;
             }
           }
     
  4. I would suggest if you're trying to optimize get the first block, get the x y z,
    The in your for loop
    for(i = y ; i > 0; i--)
    If(player.getWorld().getBlockTypeIdAt(x,i,z) == Material.AIR.ordinal()) {
    groundBlock = player.getWorld().getBlockAt(x,y,z);
    Return;
    }
    getBlockTypeIdAt is faster than getting the type and material.


    Sent from my iPhone using Tapatalk
     
  5. WAS

    WAS

    I'm not sure that's true in a negligible terms (citation needed), and is also deprecated.