Search in sources :

Example 1 with MapLookPosition

use of com.bergerkiller.bukkit.common.map.util.MapLookPosition in project BKCommonLib by bergerhealer.

the class ItemFrameInfo method findLookPosition.

/**
 * Follows an eye ray to see if it lands on this item frame. If it does,
 * returns the exact coordinates on the display shown on this item frame.
 * If there is no map display being displayed, or the eye isn't looking at
 * this item frame, null is returned.<br>
 * <br>
 * Use {@link MapLookPosition#isWithinBounds()} to check whether the player is
 * looking within bounds of this item frame, or not.
 *
 * @param startPosition Start position of the eye ray
 * @param lookDirection Normalized direction vector of the eye ray
 * @return Map Look Position, or null if the eye ray doesn't land on this
 *         item frame, or this item frame isn't displaying a map display.
 */
public MapLookPosition findLookPosition(Vector startPosition, Vector lookDirection) {
    // If it shows no display, don't bother checking
    if (this.lastMapUUID == null) {
        return null;
    }
    // Check whether the item frame is invisible. If so, a different offset is used.
    boolean invisible = this.itemFrameHandle.getDataWatcher().getFlag(EntityHandle.DATA_FLAGS, EntityHandle.DATA_FLAG_INVISIBLE);
    // Offset from block face to canvas
    double FRAME_OFFSET = invisible ? 0.00625 : 0.0625;
    // Compare facing with the eye ray to calculate the eye distance to the item frame
    final double distance;
    boolean withinBounds = true;
    IntVector3 frameBlock = this.coordinates;
    BlockFace facing = this.itemFrameHandle.getFacing();
    switch(facing) {
        case NORTH:
            if (lookDirection.getZ() > 1e-10) {
                distance = (frameBlock.z + 1.0 - FRAME_OFFSET - startPosition.getZ()) / lookDirection.getZ();
            } else {
                withinBounds = false;
                distance = MathUtil.distance(frameBlock.x, frameBlock.y, frameBlock.z, startPosition.getX(), startPosition.getY(), startPosition.getZ());
            }
            break;
        case SOUTH:
            if (lookDirection.getZ() < -1e-10) {
                distance = (frameBlock.z + FRAME_OFFSET - startPosition.getZ()) / lookDirection.getZ();
            } else {
                withinBounds = false;
                distance = MathUtil.distance(frameBlock.x, frameBlock.y, frameBlock.z, startPosition.getX(), startPosition.getY(), startPosition.getZ());
            }
            break;
        case WEST:
            if (lookDirection.getX() > 1e-10) {
                distance = (frameBlock.x + 1.0 - FRAME_OFFSET - startPosition.getX()) / lookDirection.getX();
            } else {
                withinBounds = false;
                distance = MathUtil.distance(frameBlock.x, frameBlock.y, frameBlock.z, startPosition.getX(), startPosition.getY(), startPosition.getZ());
            }
            break;
        case EAST:
            if (lookDirection.getX() < -1e-10) {
                distance = (frameBlock.x + FRAME_OFFSET - startPosition.getX()) / lookDirection.getX();
            } else {
                withinBounds = false;
                distance = MathUtil.distance(frameBlock.x, frameBlock.y, frameBlock.z, startPosition.getX(), startPosition.getY(), startPosition.getZ());
            }
            break;
        case DOWN:
            if (lookDirection.getY() > 1e-10) {
                distance = (frameBlock.y + 1.0 - FRAME_OFFSET - startPosition.getY()) / lookDirection.getY();
            } else {
                withinBounds = false;
                distance = MathUtil.distance(frameBlock.x, frameBlock.y, frameBlock.z, startPosition.getX(), startPosition.getY(), startPosition.getZ());
            }
            break;
        case UP:
            if (lookDirection.getY() < -1e-10) {
                distance = (frameBlock.y + FRAME_OFFSET - startPosition.getY()) / lookDirection.getY();
            } else {
                withinBounds = false;
                distance = MathUtil.distance(frameBlock.x, frameBlock.y, frameBlock.z, startPosition.getX(), startPosition.getY(), startPosition.getZ());
            }
            break;
        default:
            throw new IllegalArgumentException("Invalid facing: " + facing);
    }
    // Add distance * lookDirection to startPosition and subtract item frame coordinates
    // to find the coordinates relative to the middle of the block that are looked at
    final double at_x = distance * lookDirection.getX() + startPosition.getX() - frameBlock.x - 0.5;
    final double at_y = distance * lookDirection.getY() + startPosition.getY() - frameBlock.y - 0.5;
    final double at_z = distance * lookDirection.getZ() + startPosition.getZ() - frameBlock.z - 0.5;
    // If outside range [-0.5 .. 0.5] then this item frame was not looked at
    double edgeDistance = Double.MAX_VALUE;
    if (withinBounds) {
        // Get distance from the edge of each coordinate space
        final Vector edge = new Vector(Math.max(0.0, Math.abs(at_x) - 0.5), Math.max(0.0, Math.abs(at_y) - 0.5), Math.max(0.0, Math.abs(at_z) - 0.5));
        edgeDistance = edge.length();
    }
    // Convert x/y/z into x/y using facing information
    double map_x, map_y;
    switch(facing) {
        case NORTH:
            map_x = 0.5 - at_x;
            map_y = 0.5 - at_y;
            break;
        case SOUTH:
            map_x = 0.5 + at_x;
            map_y = 0.5 - at_y;
            break;
        case WEST:
            map_x = 0.5 + at_z;
            map_y = 0.5 - at_y;
            break;
        case EAST:
            map_x = 0.5 - at_z;
            map_y = 0.5 - at_y;
            break;
        case DOWN:
            map_x = 0.5 + at_x;
            map_y = 0.5 - at_z;
            break;
        case UP:
            map_x = 0.5 + at_x;
            map_y = 0.5 + at_z;
            break;
        default:
            throw new IllegalArgumentException("Invalid facing: " + facing);
    }
    // Adjust the coordinates if a non-zero rotation is set
    switch(this.itemFrameHandle.getRotationOrdinal() & 0x3) {
        case 1:
            {
                double tmp = map_x;
                map_x = map_y;
                map_y = 1.0 - tmp;
                break;
            }
        case 2:
            {
                map_x = 1.0 - map_x;
                map_y = 1.0 - map_y;
                break;
            }
        case 3:
            {
                double tmp = map_x;
                map_x = 1.0 - map_y;
                map_y = tmp;
                break;
            }
        default:
            break;
    }
    // Change to pixel coordinates based on resolution and done!
    return new MapLookPosition(this, MapDisplayTile.RESOLUTION * (map_x + this.lastMapUUID.getTileX()), MapDisplayTile.RESOLUTION * (map_y + this.lastMapUUID.getTileY()), distance, edgeDistance);
}
Also used : MapLookPosition(com.bergerkiller.bukkit.common.map.util.MapLookPosition) BlockFace(org.bukkit.block.BlockFace) IntVector3(com.bergerkiller.bukkit.common.bases.IntVector3) Vector(org.bukkit.util.Vector)

Example 2 with MapLookPosition

use of com.bergerkiller.bukkit.common.map.util.MapLookPosition in project BKCommonLib by bergerhealer.

the class CommonMapController method findLookingAt.

private LookAtSearchResult findLookingAt(Player player, ItemFrame itemFrame, Vector startPosition, Vector lookDirection) {
    MapDisplayInfo info = getInfo(itemFrame);
    if (info == null) {
        // no map here
        return null;
    }
    // Find the Display this player is sees on this map
    MapDisplayInfo.ViewStack stack = info.getViewStackByPlayerUUID(player.getUniqueId());
    if (stack == null || stack.stack.isEmpty()) {
        // no visible display for this player
        return null;
    }
    // Find the item frame metadata information
    ItemFrameInfo frameInfo = this.itemFrames.get(itemFrame.getEntityId());
    if (frameInfo == null) {
        // not tracked
        return null;
    }
    // Ask item frame to compute look-at information
    // If looking further than 16 map pixels away from the edge, fail
    MapLookPosition position = frameInfo.findLookPosition(startPosition, lookDirection);
    final double limit = 16.0;
    if (position == null || position.getEdgeDistance() > (limit / 128.0)) {
        return null;
    }
    // Keep position within bounds of the display
    // If very much out of bounds (>16 pixels) fail the looking-at check
    // This loose-ness allows for smooth clicking between frames without failures
    MapDisplay display = stack.stack.getLast();
    double new_x = position.getDoubleX();
    double new_y = position.getDoubleY();
    if (new_x < -limit || new_y < -limit || new_x > (display.getWidth() + limit) || new_y >= (display.getHeight() + limit)) {
        return null;
    } else if (new_x < 0.0 || new_y < 0.0 || new_x >= display.getWidth() || new_y >= display.getHeight()) {
        new_x = MathUtil.clamp(new_x, 0.0, (double) display.getWidth() - 1e-10);
        new_y = MathUtil.clamp(new_y, 0.0, (double) display.getHeight() - 1e-10);
        position = new MapLookPosition(position.getItemFrameInfo(), new_x, new_y, position.getDistance(), position.getEdgeDistance());
    }
    return new LookAtSearchResult(display, position);
}
Also used : MapDisplay(com.bergerkiller.bukkit.common.map.MapDisplay) MapDisplayInfo(com.bergerkiller.bukkit.common.map.binding.MapDisplayInfo) MapLookPosition(com.bergerkiller.bukkit.common.map.util.MapLookPosition) ItemFrameInfo(com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo)

Aggregations

MapLookPosition (com.bergerkiller.bukkit.common.map.util.MapLookPosition)2 IntVector3 (com.bergerkiller.bukkit.common.bases.IntVector3)1 MapDisplay (com.bergerkiller.bukkit.common.map.MapDisplay)1 ItemFrameInfo (com.bergerkiller.bukkit.common.map.binding.ItemFrameInfo)1 MapDisplayInfo (com.bergerkiller.bukkit.common.map.binding.MapDisplayInfo)1 BlockFace (org.bukkit.block.BlockFace)1 Vector (org.bukkit.util.Vector)1