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);
}
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);
}
Aggregations