/**
  * Checks if the player is on a ladder or vine.
  *
  * @return If so.
  */
 public boolean isOnClimbable() {
   if (onClimbable == null) {
     // Climbable blocks.
     if (blockFlags != null && (blockFlags.longValue() & BlockProperties.F_CLIMBABLE) == 0) {
       onClimbable = false;
       return false;
     }
     onClimbable = (BlockProperties.getBlockFlags(getTypeId()) & BlockProperties.F_CLIMBABLE) != 0;
     // TODO: maybe use specialized bounding box.
     //          final double d = 0.1d;
     //          onClimbable = BlockProperties.collides(getBlockAccess(), minX - d, minY - d, minZ
     // - d, maxX + d, minY + 1.0, maxZ + d, BlockProperties.F_CLIMBABLE);
   }
   return onClimbable;
 }
 /**
  * Checks if the player is on ground, including entities such as Minecart, Boat.
  *
  * @return true, if the player is on ground
  */
 public boolean isOnGround() {
   if (onGround != null) {
     return onGround;
   }
   // Check cached values and simplifications.
   if (notOnGroundMaxY >= yOnGround) onGround = false;
   else if (onGroundMinY <= yOnGround) onGround = true;
   else {
     // Shortcut check (currently needed for being stuck + sf).
     if (blockFlags == null || (blockFlags.longValue() & BlockProperties.F_GROUND) != 0) {
       // TODO: Consider dropping this shortcut.
       final int bY = Location.locToBlock(y - yOnGround);
       final int id =
           bY == blockY
               ? getTypeId()
               : (bY == blockY - 1 ? getTypeIdBelow() : blockCache.getTypeId(blockX, bY, blockZ));
       final long flags = BlockProperties.getBlockFlags(id);
       // TODO: Might remove check for variable ?
       if ((flags & BlockProperties.F_GROUND) != 0 && (flags & BlockProperties.F_VARIABLE) == 0) {
         final double[] bounds = blockCache.getBounds(blockX, bY, blockZ);
         // Check collision if not inside of the block. [Might be a problem for cauldron or similar
         // + something solid above.]
         // TODO: Might need more refinement.
         if (bounds != null
             && y - bY >= bounds[4]
             && BlockProperties.collidesBlock(
                 blockCache,
                 x,
                 minY - yOnGround,
                 z,
                 x,
                 minY,
                 z,
                 blockX,
                 bY,
                 blockZ,
                 id,
                 bounds,
                 flags)) {
           // TODO: BlockHeight is needed for fences, use right away (above)?
           if (!BlockProperties.isPassableWorkaround(
                   blockCache,
                   blockX,
                   bY,
                   blockZ,
                   minX - blockX,
                   minY - yOnGround - bY,
                   minZ - blockZ,
                   id,
                   maxX - minX,
                   yOnGround,
                   maxZ - minZ,
                   1.0)
               || (flags & BlockProperties.F_GROUND_HEIGHT) != 0
                   && BlockProperties.getGroundMinHeight(
                           blockCache, blockX, bY, blockZ, id, bounds, flags)
                       <= y - bY) {
             //
             // NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, "***
             // onground SHORTCUT");
             onGround = true;
           }
         }
       }
       if (onGround == null) {
         //
         // NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, "*** fetch
         // onground std");
         // Full on-ground check (blocks).
         // Note: Might check for half-block height too (getTypeId), but that is much more seldom.
         onGround =
             BlockProperties.isOnGround(
                 blockCache, minX, minY - yOnGround, minZ, maxX, minY, maxZ, 0L);
       }
     } else onGround = false;
   }
   if (onGround) onGroundMinY = Math.min(onGroundMinY, yOnGround);
   else {
     //          NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, "***
     // onground check entities");
     // TODO: further confine this ?
     notOnGroundMaxY = Math.max(notOnGroundMaxY, yOnGround);
     final double d1 = 0.25D;
     onGround =
         blockCache.standsOnEntity(
             player,
             minX - d1,
             minY - yOnGround - d1,
             minZ - d1,
             maxX + d1,
             minY + 0.25 + d1,
             maxZ + d1);
   }
   return onGround;
 }
 /**
  * Checks if the player is above a ladder or vine.<br>
  * Does not save back value to field.
  *
  * @return If so.
  */
 public boolean isAboveLadder() {
   if (blockFlags != null && (blockFlags.longValue() & BlockProperties.F_CLIMBABLE) == 0)
     return false;
   // TODO: bounding box ?
   return (BlockProperties.getBlockFlags(getTypeIdBelow()) & BlockProperties.F_CLIMBABLE) != 0;
 }