com.sk89q.worldedit.util.TargetBlock Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of FastAsyncWorldEdit-Core Show documentation
Show all versions of FastAsyncWorldEdit-Core Show documentation
Blazingly fast Minecraft world manipulation for artists, builders and everyone else.
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package com.sk89q.worldedit.util;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import javax.annotation.Nullable;
/**
* This class uses an inefficient method to figure out what block a player
* is looking towards.
*
* Originally written by toi. It was ported to WorldEdit and trimmed down by
* sk89q. Thanks to Raphfrk for optimization of toi's original class.
*/
public class TargetBlock {
//FAWE start - Extent > World
private final Extent world;
//FAWE end
private int maxDistance;
private double checkDistance;
private double curDistance;
private BlockVector3 targetPos = BlockVector3.ZERO;
private Vector3 targetPosDouble = Vector3.ZERO;
private BlockVector3 prevPos = BlockVector3.ZERO;
private Vector3 offset = Vector3.ZERO;
// the mask which dictates when to stop a trace - defaults to stopping at non-air blocks
private Mask stopMask;
// the mask which dictates when to stop a solid block trace - default to BlockMaterial#isMovementBlocker
private Mask solidMask;
/**
* Constructor requiring a player, uses default values.
*
* @param player player to work with
*/
public TargetBlock(Player player) {
this.world = player.getWorld();
this.setValues(player.getLocation().toVector(), player.getLocation().getYaw(), player.getLocation().getPitch(),
300, 1.65, 0.2
);
this.stopMask = new ExistingBlockMask(world);
this.solidMask = new SolidBlockMask(world);
}
/**
* Constructor requiring a player, max distance and a checking distance.
*
* @param player Player to work with
* @param maxDistance how far it checks for blocks
* @param checkDistance how often to check for blocks, the smaller the more precise
*/
public TargetBlock(Player player, int maxDistance, double checkDistance) {
//FAWE start
this(player, player.getWorld(), maxDistance, checkDistance);
//FAWE end
}
//FAWE start - Extend > World
public TargetBlock(Player player, Extent extent, int maxDistance, double checkDistance) {
this.world = player.getWorld();
this.setValues(
player.getLocation().toVector(),
player.getLocation().getYaw(),
player.getLocation().getPitch(),
maxDistance,
1.65,
checkDistance
);
this.stopMask = new ExistingBlockMask(world);
this.solidMask = new SolidBlockMask(world);
}
//FAWE end
/**
* Set the mask used for determine where to stop traces.
* Setting to null will restore the default.
*
* @param stopMask the mask used to stop traces
*/
public void setStopMask(@Nullable Mask stopMask) {
if (stopMask == null) {
this.stopMask = new ExistingBlockMask(world);
} else {
this.stopMask = stopMask;
}
}
/**
* Set the mask used for determine where to stop solid block traces.
* Setting to null will restore the default.
*
* @param solidMask the mask used to stop solid block traces
*/
public void setSolidMask(@Nullable Mask solidMask) {
if (solidMask == null) {
this.solidMask = new SolidBlockMask(world);
} else {
this.solidMask = solidMask;
}
}
/**
* Set the values, all constructors uses this function.
*
* @param loc location of the view
* @param rotationX the X rotation
* @param rotationY the Y rotation
* @param maxDistance how far it checks for blocks
* @param viewHeight where the view is positioned in y-axis
* @param checkDistance how often to check for blocks, the smaller the more precise
*/
private void setValues(
Vector3 loc,
double rotationX,
double rotationY,
int maxDistance,
double viewHeight,
double checkDistance
) {
this.maxDistance = maxDistance;
this.checkDistance = checkDistance;
this.curDistance = 0;
rotationX = (rotationX + 90) % 360;
rotationY *= -1;
double h = (checkDistance * Math.cos(Math.toRadians(rotationY)));
offset = Vector3.at(
(h * Math.cos(Math.toRadians(rotationX))),
(checkDistance * Math.sin(Math.toRadians(rotationY))),
(h * Math.sin(Math.toRadians(rotationX)))
);
targetPosDouble = loc.add(0, viewHeight, 0);
targetPos = targetPosDouble.toBlockPoint();
prevPos = targetPos;
}
/**
* Returns any block at the sight. Returns null if out of range or if no
* viable target was found. Will try to return the last valid air block it finds.
*
* @return Block
*/
public Location getAnyTargetBlock() {
Location lastBlock = null;
while (getNextBlock() != null) {
if (stopMask.test(targetPos)) {
break;
} else {
lastBlock = getCurrentBlock();
if (lastBlock.getBlockY() < world.getMinY()
|| lastBlock.getBlockY() > world.getMaxY()) {
return null;
}
}
}
Location currentBlock = getCurrentBlock();
return (currentBlock != null ? currentBlock : lastBlock);
}
/**
* Returns the block at the sight. Returns null if out of range or if no
* viable target was found
*
* @return Block
*/
@SuppressWarnings("StatementWithEmptyBody")
public Location getTargetBlock() {
while (getNextBlock() != null && !stopMask.test(targetPos)) {
}
return getCurrentBlock();
}
/**
* Returns the block at the sight. Returns null if out of range or if no
* viable target was found
*
* @return Block
*/
@SuppressWarnings("StatementWithEmptyBody")
public Location getSolidTargetBlock() {
while (getNextBlock() != null && !solidMask.test(targetPos)) {
}
return getCurrentBlock();
}
/**
* Get next block.
*
* @return next block position
*/
public Location getNextBlock() {
prevPos = targetPos;
do {
curDistance += checkDistance;
targetPosDouble = offset.add(
targetPosDouble.getX(),
targetPosDouble.getY(),
targetPosDouble.getZ()
);
targetPos = targetPosDouble.toBlockPoint();
} while (curDistance <= maxDistance
&& targetPos.getBlockX() == prevPos.getBlockX()
&& targetPos.getBlockY() == prevPos.getBlockY()
&& targetPos.getBlockZ() == prevPos.getBlockZ());
if (curDistance > maxDistance) {
return null;
}
return new Location(world, targetPos.toVector3());
}
/**
* Returns the current block along the line of vision.
*
* @return block position
*/
public Location getCurrentBlock() {
if (curDistance > maxDistance) {
return null;
} else {
return new Location(world, targetPos.toVector3());
}
}
/**
* Returns the previous block in the aimed path.
*
* @return block position
*/
public Location getPreviousBlock() {
return new Location(world, prevPos.toVector3());
}
public Location getAnyTargetBlockFace() {
getAnyTargetBlock();
Location current = getCurrentBlock();
if (current != null) {
return current.setDirection(current.toVector().subtract(getPreviousBlock().toVector()));
} else {
return new Location(world, targetPos.toVector3(), Float.NaN, Float.NaN);
}
}
public Location getTargetBlockFace() {
getTargetBlock();
if (getCurrentBlock() == null) {
return null;
}
return getCurrentBlock().setDirection(getCurrentBlock().toVector().subtract(getPreviousBlock().toVector()));
}
}