Is there a (safe) Bukkit alternative for this?

Discussion in 'Plugin Development' started by bergerkiller, May 11, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    bergerkiller

    So I wanted to interact with rails properly, but found that getTarget sees all blocks as full, 1x1 blocks. As a result, it could not obtain the 'actual, visual' block a player clicked. So I had to write my own method using the rayTrace method in NMS:

    Code:
        /*
        * The below code will be moved to BKCommonLib during 1.5.2 - DO NOT FORGET!
        */
        private static final ClassTemplate<?> movingObjectPosTemplate = NMSClassTemplate.create("MovingObjectPosition");
        private static final Class<?> vec3DClass = CommonUtil.getNMSClass("Vec3D");
        private static final MethodAccessor<Object> worldRayTrace = WorldRef.TEMPLATE.getMethod("rayTrace", vec3DClass, vec3DClass, boolean.class);
        private static final FieldAccessor<Integer> mobObjPosX = movingObjectPosTemplate.getField("b");
        private static final FieldAccessor<Integer> mobObjPosY = movingObjectPosTemplate.getField("c");
        private static final FieldAccessor<Integer> mobObjPosZ = movingObjectPosTemplate.getField("d");
        private static final MethodAccessor<Float> entityPlayerGetheadHeight = EntityPlayerRef.TEMPLATE.getMethod("getHeadHeight");
     
        public static Block rayTrace(World world, double startX, double startY, double startZ, double endX, double endY, double endZ) {
            Object startVec = VectorRef.newVec(startX, startY, startZ);
            Object endVec = VectorRef.newVec(endX, endY, endZ);
            Object movingObjectPosition = worldRayTrace.invoke(Conversion.toWorldHandle.convert(world), startVec, endVec, false);
            if (movingObjectPosition == null) {
                return null;
            }
            return world.getBlockAt(mobObjPosX.get(movingObjectPosition), mobObjPosY.get(movingObjectPosition), mobObjPosZ.get(movingObjectPosition));
        }
     
        public static Block rayTrace(Location startLocation, Vector direction, double maxLength) {
            final double startX = startLocation.getX();
            final double startY = startLocation.getY();
            final double startZ = startLocation.getZ();
            final double endX = startX + direction.getX() * maxLength;
            final double endY = startY + direction.getY() * maxLength;
            final double endZ = startZ + direction.getZ() * maxLength;
            return rayTrace(startLocation.getWorld(), startX, startY, startZ, endX, endY, endZ);
        }
     
        public static Block rayTrace(Location startLocation, double maxLength) {
            return rayTrace(startLocation, startLocation.getDirection(), maxLength);
        }
     
        public static Block rayTrace(Player player) {
            return rayTrace(player.getLocation().add(0.0, entityPlayerGetheadHeight.invoke(Conversion.toEntityHandle.convert(player)), 0.0), 5.0);
        }
    Now before I include this cancer-ridden monstrosity into BKCommonLib: is there some sort of safer Bukkit alternative to rayTrace? Or is the functionality really that poor that only 1x1 block scanning is possible?

    The same applies to getting the head height of a player, or obtaining the location of the 'eyes' of a player. I could not find it.

    Oh well I guess not then. Added it to WorldUtil.

    Code:
        /**
        * Performs a ray tracing operation from one point to the other, and obtains the (first) block hit
        *
        * @param world to ray trace in
        * @param startX to start ray tracing from
        * @param startY to start ray tracing from
        * @param startZ to start ray tracing from
        * @param endX to stop ray tracing (outer limit)
        * @param endY to stop ray tracing (outer limit)
        * @param endZ to stop ray tracing (outer limit)
        * @return the hit Block, or null if none was found (AIR)
        */
        public static Block rayTraceBlock(org.bukkit.World world, double startX, double startY, double startZ, double endX, double endY, double endZ) {
            MovingObjectPosition mop = CommonNMS.getNative(world).rayTrace(CommonNMS.newVec3D(startX, startY, startZ),
                    CommonNMS.newVec3D(endX, endY, endZ), false);
            return mop == null ? null : world.getBlockAt(mop.b, mop.c, mop.d);
        }
     
        /**
        * Performs a ray tracing operation from one point to the other, and obtains the (first) block hit
        *
        * @param startLocation to start ray tracing from
        * @param direction to which to ray trace
        * @param maxLength limit of ray tracing
        * @return the hit Block, or null if none was found (AIR)
        */
        public static Block rayTraceBlock(Location startLocation, Vector direction, double maxLength) {
            final double startX = startLocation.getX();
            final double startY = startLocation.getY();
            final double startZ = startLocation.getZ();
            final double endX = startX + direction.getX() * maxLength;
            final double endY = startY + direction.getY() * maxLength;
            final double endZ = startZ + direction.getZ() * maxLength;
            return rayTraceBlock(startLocation.getWorld(), startX, startY, startZ, endX, endY, endZ);
        }
     
        /**
        * Performs a ray tracing operation from one point to the other, and obtains the (first) block hit
        *
        * @param startLocation to start ray tracing from, direction from Location is used
        * @param maxLength limit of ray tracing
        * @return the hit Block, or null if none was found (AIR)
        */
        public static Block rayTraceBlock(Location startLocation, double maxLength) {
            return rayTraceBlock(startLocation, startLocation.getDirection(), maxLength);
        }
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 1, 2016
  2. Offline

    Comphenix

    You can specify which blocks to treat as transparent blocks in getTargetBlock(), but it won't perform a proper collision test. A block is either an air block, or a solid block.

    I've used player.getEyeLocation() for that, and it seems to work.
     
  3. Offline

    bergerkiller

    Hmn ok so there is no alternative. You see, the issue with player.getTarget is that it treats rails as solid blocks. So when I stand on top of a rail and click on a rail a bit further away, it treats the rail I stand on as a solid block, and returns that instead. getTarget is only really useful for very long distances where this doesn't matter I think.

    I could not find getEyeLocation in the Player class, neither getHeadLocation...so I'll stick to my getHeadLocation method I added in ExtendedEntity in BKC.
     
  4. bergerkiller likes this.
  5. Offline

    bergerkiller

    Digi
    Ah thanks, so there it is :)
     
Thread Status:
Not open for further replies.

Share This Page