Add /tracemask. (#474)

Allows setting a mask used for block traces. This allows brush tools to
pass through various materials, such as water (e.g. `/tracemask #solid`
or `/tracemask !air,water`) before starting to build.
By default, a null mask is equivalent to #existing (original behavior).

https://gfycat.com/ImmaculateFrayedCockatiel
This commit is contained in:
wizjany
2019-05-23 21:12:31 -04:00
committed by GitHub
parent d0ef56326a
commit 7b47d9a945
9 changed files with 150 additions and 37 deletions

View File

@ -20,10 +20,15 @@
package com.sk89q.worldedit.util;
import com.sk89q.worldedit.entity.Player;
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 com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
/**
* This class uses an inefficient method to figure out what block a player
* is looking towards.
@ -33,7 +38,8 @@ import com.sk89q.worldedit.world.World;
*/
public class TargetBlock {
private World world;
private final World world;
private int maxDistance;
private double checkDistance, curDistance;
private BlockVector3 targetPos = BlockVector3.ZERO;
@ -41,6 +47,11 @@ public class TargetBlock {
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
*
@ -50,6 +61,8 @@ public class TargetBlock {
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);
}
/**
@ -62,6 +75,36 @@ public class TargetBlock {
public TargetBlock(Player player, 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);
}
/**
* 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;
}
}
/**
@ -79,7 +122,7 @@ public class TargetBlock {
this.checkDistance = checkDistance;
this.curDistance = 0;
xRotation = (xRotation + 90) % 360;
yRotation = yRotation * -1;
yRotation *= -1;
double h = (checkDistance * Math.cos(Math.toRadians(yRotation)));
@ -102,15 +145,15 @@ public class TargetBlock {
boolean searchForLastBlock = true;
Location lastBlock = null;
while (getNextBlock() != null) {
if (world.getBlock(targetPos).getBlockType().getMaterial().isAir()) {
if (stopMask.test(targetPos)) {
break;
} else {
if (searchForLastBlock) {
lastBlock = getCurrentBlock();
if (lastBlock.getBlockY() <= 0 || lastBlock.getBlockY() >= world.getMaxY()) {
searchForLastBlock = false;
}
}
} else {
break;
}
}
Location currentBlock = getCurrentBlock();
@ -124,7 +167,8 @@ public class TargetBlock {
* @return Block
*/
public Location getTargetBlock() {
while (getNextBlock() != null && world.getBlock(targetPos).getBlockType().getMaterial().isAir()) ;
//noinspection StatementWithEmptyBody
while (getNextBlock() != null && !stopMask.test(targetPos)) ;
return getCurrentBlock();
}
@ -135,7 +179,8 @@ public class TargetBlock {
* @return Block
*/
public Location getSolidTargetBlock() {
while (getNextBlock() != null && !world.getBlock(targetPos).getBlockType().getMaterial().isMovementBlocker()) ;
//noinspection StatementWithEmptyBody
while (getNextBlock() != null && !solidMask.test(targetPos)) ;
return getCurrentBlock();
}