mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2025-03-09 21:19:07 +01:00
Fixes, more tests and more to do for RayTracing.
* More tests for PassableRayTracing (room, rays from outside). * Alter InteractRayTracing to account for the block interacted with. * Added tests for InteractRayTracing. Problems: * RayTracing may end x-th digit off target, thus in the wrong block. Suggested fix is to keep correcting t by the absolute coordinates of the blocks, i.e. calculate the absolute position rather than adding up. * InteractRayTracing with strict set to false (like in the blockinteract.visible check) will be too lenient with 1-thick wall setups and fail test cases.
This commit is contained in:
parent
8856f68e55
commit
a5d6594591
@ -15,195 +15,207 @@ import fr.neatmonster.nocheatplus.utilities.BlockProperties;
|
||||
import fr.neatmonster.nocheatplus.utilities.InteractRayTracing;
|
||||
|
||||
public class Visible extends Check {
|
||||
|
||||
/** Offset from bounds to estimate some reference end position for ray-tracing. */
|
||||
private static final double offset = 0.0001;
|
||||
|
||||
private BlockCache blockCache;
|
||||
|
||||
private final InteractRayTracing rayTracing = new InteractRayTracing(false);
|
||||
|
||||
public Visible() {
|
||||
super(CheckType.BLOCKINTERACT_VISIBLE);
|
||||
blockCache = mcAccess.getBlockCache(null);
|
||||
rayTracing.setMaxSteps(60); // TODO: Configurable ?
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.neatmonster.nocheatplus.checks.Check#setMCAccess(fr.neatmonster.nocheatplus.compat.MCAccess)
|
||||
*/
|
||||
@Override
|
||||
public void setMCAccess(MCAccess mcAccess) {
|
||||
super.setMCAccess(mcAccess);
|
||||
// Renew the BlockCache instance.
|
||||
blockCache = mcAccess.getBlockCache(null);
|
||||
}
|
||||
|
||||
private static final double getEnd(final double[] bounds, final int index, final int mod){
|
||||
if (bounds == null){
|
||||
return 0.5 + (0.5 + offset) * mod;
|
||||
}
|
||||
if (mod == 0){
|
||||
// Middle.
|
||||
return (bounds[index] + bounds[index + 3]) / 2.0;
|
||||
}
|
||||
else if (mod == 1){
|
||||
// TODO: Slightly outside or dependent on exact position (inside, exact edge, outside)?
|
||||
return Math.min(1.0, bounds[index + 3]) + offset;
|
||||
}
|
||||
else if (mod == -1){
|
||||
// TODO: Slightly outside or dependent on exact position (inside, exact edge, outside)?
|
||||
return Math.max(0.0, bounds[index]) - offset;
|
||||
}
|
||||
else{
|
||||
throw new IllegalArgumentException("BlockFace.getModX|Y|Z must be 0, 1 or -1.");
|
||||
}
|
||||
}
|
||||
/** Offset from bounds to estimate some reference end position for ray-tracing. */
|
||||
private static final double offset = 0.0001;
|
||||
|
||||
public boolean check(final Player player, final Location loc, final Block block, final BlockFace face, final Action action, final BlockInteractData data, final BlockInteractConfig cc) {
|
||||
// TODO: This check might make parts of interact/blockbreak/... + direction (+?) obsolete.
|
||||
// TODO: Might confine what to check for (left/right-click, target blocks depending on item in hand, container blocks).
|
||||
final boolean collides;
|
||||
final int blockX = block.getX();
|
||||
final int blockY = block.getY();
|
||||
final int blockZ = block.getZ();
|
||||
final double eyeX = loc.getX();
|
||||
final double eyeY = loc.getY() + player.getEyeHeight();
|
||||
final double eyeZ = loc.getZ();
|
||||
|
||||
// TODO: Add tags for fail_passable, fail_raytracing, (fail_face).
|
||||
// TODO: Reachable face check ?
|
||||
|
||||
if (blockX == Location.locToBlock(eyeX) && blockZ == Location.locToBlock(eyeZ) && block.getY() == Location.locToBlock(eyeY)){
|
||||
// Player is interacting with the block their head is in.
|
||||
// TODO: Should the reachable-face-check be done here too (if it is added at all)?
|
||||
collides = false;
|
||||
}
|
||||
else{
|
||||
// Initialize.
|
||||
blockCache.setAccess(loc.getWorld());
|
||||
rayTracing.setBlockCache(blockCache);
|
||||
|
||||
collides = checkRayTracing(eyeX, eyeY, eyeZ, blockX, blockY, blockZ, face);
|
||||
|
||||
// Cleanup.
|
||||
rayTracing.cleanup();
|
||||
blockCache.cleanup();
|
||||
}
|
||||
|
||||
if (data.debug && player.hasPermission(Permissions.ADMINISTRATION_DEBUG)){
|
||||
// TODO: Tags
|
||||
player.sendMessage("Interact visible: " + (action == Action.RIGHT_CLICK_BLOCK ? "right" : "left") + " collide=" + rayTracing.collides());
|
||||
private BlockCache blockCache;
|
||||
|
||||
/**
|
||||
* Strict set to false, due to false positives.
|
||||
*/
|
||||
private final InteractRayTracing rayTracing = new InteractRayTracing(false);
|
||||
|
||||
public Visible() {
|
||||
super(CheckType.BLOCKINTERACT_VISIBLE);
|
||||
blockCache = mcAccess.getBlockCache(null);
|
||||
rayTracing.setMaxSteps(60); // TODO: Configurable ?
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.neatmonster.nocheatplus.checks.Check#setMCAccess(fr.neatmonster.nocheatplus.compat.MCAccess)
|
||||
*/
|
||||
@Override
|
||||
public void setMCAccess(MCAccess mcAccess) {
|
||||
super.setMCAccess(mcAccess);
|
||||
// Renew the BlockCache instance.
|
||||
blockCache = mcAccess.getBlockCache(null);
|
||||
}
|
||||
|
||||
private static final double getEnd(final double[] bounds, final int index, final int mod){
|
||||
if (bounds == null){
|
||||
return 0.5 + (0.5 + offset) * mod;
|
||||
}
|
||||
|
||||
// Actions ?
|
||||
boolean cancel = false;
|
||||
if (collides){
|
||||
data.visibleVL += 1;
|
||||
if (executeActions(player, data.visibleVL, 1, cc.visibleActions)){
|
||||
cancel = true;
|
||||
}
|
||||
}
|
||||
else{
|
||||
data.visibleVL *= 0.99;
|
||||
}
|
||||
|
||||
return cancel;
|
||||
}
|
||||
|
||||
private boolean checkRayTracing(final double eyeX, final double eyeY, final double eyeZ, final int blockX, final int blockY, final int blockZ, final BlockFace face){
|
||||
|
||||
// Estimated target-middle-position (does it for most cases).
|
||||
@SuppressWarnings("deprecation")
|
||||
final double[] bounds = BlockProperties.getCorrectedBounds(blockCache, blockX, blockY, blockZ);
|
||||
final int modX = face.getModX();
|
||||
final int modY = face.getModY();
|
||||
final int modZ = face.getModZ();
|
||||
final double estX = (double) blockX + getEnd(bounds, 0, modX);
|
||||
final double estY = (double) blockY + getEnd(bounds, 1, modY);
|
||||
final double estZ = (double) blockZ + getEnd(bounds, 2, modZ);
|
||||
final int bEstX = Location.locToBlock(estX);
|
||||
final int bEstY = Location.locToBlock(estY);
|
||||
final int bEstZ = Location.locToBlock(estZ);
|
||||
final int estId = blockCache.getTypeId(bEstX, bEstY, bEstZ);
|
||||
|
||||
// Ignore passable if the estimate is on the clicked block.
|
||||
final boolean skipPassable = blockX == bEstX && blockY == bEstY && blockZ == bEstZ;
|
||||
|
||||
// TODO: Might also use looking direction (test how accurate).
|
||||
return checkCollision(eyeX, eyeY, eyeZ, estX, estY, estZ, estId, bounds, modX, modY, modZ, skipPassable);
|
||||
|
||||
}
|
||||
if (mod == 0){
|
||||
// Middle.
|
||||
return (bounds[index] + bounds[index + 3]) / 2.0;
|
||||
}
|
||||
else if (mod == 1){
|
||||
// TODO: Slightly outside or dependent on exact position (inside, exact edge, outside)?
|
||||
return Math.min(1.0, bounds[index + 3]) + offset;
|
||||
}
|
||||
else if (mod == -1){
|
||||
// TODO: Slightly outside or dependent on exact position (inside, exact edge, outside)?
|
||||
return Math.max(0.0, bounds[index]) - offset;
|
||||
}
|
||||
else{
|
||||
throw new IllegalArgumentException("BlockFace.getModX|Y|Z must be 0, 1 or -1.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively check alternate positions.
|
||||
* @param eyeX
|
||||
* @param eyeY
|
||||
* @param eyeZ
|
||||
* @param estX
|
||||
* @param estY
|
||||
* @param estZ
|
||||
* @param estId
|
||||
* @param modX
|
||||
* @param modY
|
||||
* @param modZ
|
||||
* @param skipPassable
|
||||
* @return
|
||||
*/
|
||||
private boolean checkCollision(final double eyeX, final double eyeY, final double eyeZ, final double estX, final double estY, final double estZ, final int estId, final double[] bounds, final int modX, final int modY, final int modZ, final boolean skipPassable) {
|
||||
// Check current position.
|
||||
if (skipPassable || BlockProperties.isPassable(blockCache, estX, estY, estZ, estId)){
|
||||
// Perform ray-tracing.
|
||||
rayTracing.set(eyeX, eyeY, eyeZ, estX, estY, estZ);
|
||||
rayTracing.loop();
|
||||
if (!rayTracing.collides() && rayTracing.getStepsDone() < rayTracing.getMaxSteps()){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Note: Center of bounds is used for mod == 0.
|
||||
// TODO: Could "sort" positions by setting signum of d by which is closer to the player.
|
||||
// TODO: Could consider slightly in-set positions.
|
||||
if (modX == 0){
|
||||
// TODO: Might ensure to check if it is the same block?
|
||||
final double d = bounds == null ? 0.5 : (bounds[3] - bounds[0]) / 2.0;
|
||||
if (d >= 0.05){
|
||||
// Recursion with adapted x position (if differs enough from bounds.
|
||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX - d, estY, estZ, estId, bounds, 1, modY, modZ, skipPassable)){
|
||||
return false;
|
||||
}
|
||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX + d, estY, estZ, estId, bounds, 1, modY, modZ, skipPassable)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (modZ == 0){
|
||||
// TODO: Might ensure to check if it is the same block?
|
||||
final double d = bounds == null ? 0.5 : (bounds[5] - bounds[2]) / 2.0;
|
||||
if (d >= 0.05){
|
||||
// Recursion with adapted x position (if differs enough from bounds.
|
||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY, estZ - d, estId, bounds, 1, modY, 1, skipPassable)){
|
||||
return false;
|
||||
}
|
||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY, estZ + d, estId, bounds, 1, modY, 1, skipPassable)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (modY == 0){
|
||||
// TODO: Might ensure to check if it is the same block?
|
||||
final double d = bounds == null ? 0.5 : (bounds[4] - bounds[1]) / 2.0;
|
||||
if (d >= 0.05){
|
||||
// Recursion with adapted x position (if differs enough from bounds.
|
||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY - d, estZ, estId, bounds, 1, 1, 1, skipPassable)){
|
||||
return false;
|
||||
}
|
||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY + d, estZ, estId, bounds, 1, 1, 1, skipPassable)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public boolean check(final Player player, final Location loc, final Block block, final BlockFace face, final Action action, final BlockInteractData data, final BlockInteractConfig cc) {
|
||||
// TODO: This check might make parts of interact/blockbreak/... + direction (+?) obsolete.
|
||||
// TODO: Might confine what to check for (left/right-click, target blocks depending on item in hand, container blocks).
|
||||
final boolean collides;
|
||||
final int blockX = block.getX();
|
||||
final int blockY = block.getY();
|
||||
final int blockZ = block.getZ();
|
||||
final double eyeX = loc.getX();
|
||||
final double eyeY = loc.getY() + player.getEyeHeight();
|
||||
final double eyeZ = loc.getZ();
|
||||
|
||||
// TODO: Add tags for fail_passable, fail_raytracing, (fail_face).
|
||||
// TODO: Reachable face check ?
|
||||
|
||||
if (blockX == Location.locToBlock(eyeX) && blockZ == Location.locToBlock(eyeZ) && block.getY() == Location.locToBlock(eyeY)){
|
||||
// Player is interacting with the block their head is in.
|
||||
// TODO: Should the reachable-face-check be done here too (if it is added at all)?
|
||||
collides = false;
|
||||
}
|
||||
else{
|
||||
// Initialize.
|
||||
blockCache.setAccess(loc.getWorld());
|
||||
rayTracing.setBlockCache(blockCache);
|
||||
|
||||
collides = checkRayTracing(eyeX, eyeY, eyeZ, blockX, blockY, blockZ, face);
|
||||
|
||||
// Cleanup.
|
||||
rayTracing.cleanup();
|
||||
blockCache.cleanup();
|
||||
}
|
||||
|
||||
if (data.debug && player.hasPermission(Permissions.ADMINISTRATION_DEBUG)){
|
||||
// TODO: Tags
|
||||
player.sendMessage("Interact visible: " + (action == Action.RIGHT_CLICK_BLOCK ? "right" : "left") + " collide=" + rayTracing.collides());
|
||||
}
|
||||
|
||||
// Actions ?
|
||||
boolean cancel = false;
|
||||
if (collides){
|
||||
data.visibleVL += 1;
|
||||
if (executeActions(player, data.visibleVL, 1, cc.visibleActions)){
|
||||
cancel = true;
|
||||
}
|
||||
}
|
||||
else{
|
||||
data.visibleVL *= 0.99;
|
||||
}
|
||||
|
||||
return cancel;
|
||||
}
|
||||
|
||||
private boolean checkRayTracing(final double eyeX, final double eyeY, final double eyeZ, final int blockX, final int blockY, final int blockZ, final BlockFace face){
|
||||
|
||||
/*
|
||||
* TODO: Always use the exact looking direction first (calculate where
|
||||
* it hits the target block, and which faces are exposed then, estimate
|
||||
* alternative positions based on that, get rid of the workaround).
|
||||
*/
|
||||
/*
|
||||
* TODO: Consider using (slightly less than) full block bounds always ?
|
||||
* (alt: 2,3 classes of size)
|
||||
*/
|
||||
// Estimated target-middle-position (does it for most cases).
|
||||
@SuppressWarnings("deprecation")
|
||||
final double[] bounds = BlockProperties.getCorrectedBounds(blockCache, blockX, blockY, blockZ);
|
||||
final int modX = face.getModX();
|
||||
final int modY = face.getModY();
|
||||
final int modZ = face.getModZ();
|
||||
final double estX = (double) blockX + getEnd(bounds, 0, modX);
|
||||
final double estY = (double) blockY + getEnd(bounds, 1, modY);
|
||||
final double estZ = (double) blockZ + getEnd(bounds, 2, modZ);
|
||||
final int bEstX = Location.locToBlock(estX);
|
||||
final int bEstY = Location.locToBlock(estY);
|
||||
final int bEstZ = Location.locToBlock(estZ);
|
||||
final int estId = blockCache.getTypeId(bEstX, bEstY, bEstZ);
|
||||
|
||||
// Ignore passable if the estimate is on the clicked block.
|
||||
final boolean skipPassable = blockX == bEstX && blockY == bEstY && blockZ == bEstZ;
|
||||
|
||||
// TODO: Might also use looking direction (test how accurate).
|
||||
return checkCollision(eyeX, eyeY, eyeZ, estX, estY, estZ, estId, bounds, modX, modY, modZ, skipPassable, blockX, blockY, blockZ);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively check alternate positions.
|
||||
* @param eyeX
|
||||
* @param eyeY
|
||||
* @param eyeZ
|
||||
* @param estX
|
||||
* @param estY
|
||||
* @param estZ
|
||||
* @param estId
|
||||
* @param modX
|
||||
* @param modY
|
||||
* @param modZ
|
||||
* @param skipPassable
|
||||
* @return
|
||||
*/
|
||||
private boolean checkCollision(final double eyeX, final double eyeY, final double eyeZ, final double estX, final double estY, final double estZ, final int estId, final double[] bounds, final int modX, final int modY, final int modZ, final boolean skipPassable, final int clickedX, final int clickedY, final int clickedZ) {
|
||||
// Check current position.
|
||||
if (skipPassable || BlockProperties.isPassable(blockCache, estX, estY, estZ, estId)){
|
||||
// Perform ray-tracing.
|
||||
rayTracing.set(eyeX, eyeY, eyeZ, estX, estY, estZ, clickedX, clickedY, clickedZ);
|
||||
rayTracing.loop();
|
||||
if (!rayTracing.collides() && rayTracing.getStepsDone() < rayTracing.getMaxSteps()){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Note: Center of bounds is used for mod == 0.
|
||||
// TODO: Could "sort" positions by setting signum of d by which is closer to the player.
|
||||
// TODO: Could consider slightly in-set positions.
|
||||
if (modX == 0){
|
||||
// TODO: Might ensure to check if it is the same block?
|
||||
final double d = bounds == null ? 0.5 : (bounds[3] - bounds[0]) / 2.0;
|
||||
if (d >= 0.05){
|
||||
// Recursion with adapted x position (if differs enough from bounds.
|
||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX - d, estY, estZ, estId, bounds, 1, modY, modZ, skipPassable, clickedX, clickedY, clickedZ)){
|
||||
return false;
|
||||
}
|
||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX + d, estY, estZ, estId, bounds, 1, modY, modZ, skipPassable, clickedX, clickedY, clickedZ)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (modZ == 0){
|
||||
// TODO: Might ensure to check if it is the same block?
|
||||
final double d = bounds == null ? 0.5 : (bounds[5] - bounds[2]) / 2.0;
|
||||
if (d >= 0.05){
|
||||
// Recursion with adapted x position (if differs enough from bounds.
|
||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY, estZ - d, estId, bounds, 1, modY, 1, skipPassable, clickedX, clickedY, clickedZ)){
|
||||
return false;
|
||||
}
|
||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY, estZ + d, estId, bounds, 1, modY, 1, skipPassable, clickedX, clickedY, clickedZ)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (modY == 0){
|
||||
// TODO: Might ensure to check if it is the same block?
|
||||
final double d = bounds == null ? 0.5 : (bounds[4] - bounds[1]) / 2.0;
|
||||
if (d >= 0.05){
|
||||
// Recursion with adapted x position (if differs enough from bounds.
|
||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY - d, estZ, estId, bounds, 1, 1, 1, skipPassable, clickedX, clickedY, clickedZ)){
|
||||
return false;
|
||||
}
|
||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY + d, estZ, estId, bounds, 1, 1, 1, skipPassable, clickedX, clickedY, clickedZ)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -88,6 +88,52 @@ public class FakeBlockCache extends BlockCache {
|
||||
}
|
||||
}
|
||||
|
||||
public void fill(int x1, int y1, int z1, int x2, int y2, int z2, Material type) {
|
||||
fill(x1, y1, z1, x2, y2, z2, BlockProperties.getId(type), 0, new double[]{0.0, 0.0, 0.0, 1.0, 1.0, 1.0});
|
||||
}
|
||||
|
||||
public void fill(int x1, int y1, int z1, int x2, int y2, int z2, int typeId, int data, double[] bounds) {
|
||||
for (int x = x1; x <= x2; x++) {
|
||||
for (int y = y1; y <= y2; y ++) {
|
||||
for (int z = z1; z <= z2; z++) {
|
||||
set(x, y, z, typeId, data, bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void walls(int x1, int y1, int z1, int x2, int y2, int z2, Material type) {
|
||||
walls(x1, y1, z1, x2, y2, z2, BlockProperties.getId(type), 0, new double[]{0.0, 0.0, 0.0, 1.0, 1.0, 1.0});
|
||||
}
|
||||
|
||||
public void walls(int x1, int y1, int z1, int x2, int y2, int z2, int typeId, int data, double[] bounds) {
|
||||
for (int x = x1; x <= x2; x++) {
|
||||
for (int y = y1; y <= y2; y ++) {
|
||||
for (int z = z1; z <= z2; z++) {
|
||||
if (x == x1 || x == x2 || z == z1 || z == z2) {
|
||||
set(x, y, z, typeId, data, bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void room(int x1, int y1, int z1, int x2, int y2, int z2, Material type) {
|
||||
room(x1, y1, z1, x2, y2, z2, BlockProperties.getId(type), 0, new double[]{0.0, 0.0, 0.0, 1.0, 1.0, 1.0});
|
||||
}
|
||||
|
||||
public void room(int x1, int y1, int z1, int x2, int y2, int z2, int typeId, int data, double[] bounds) {
|
||||
for (int x = x1; x <= x2; x++) {
|
||||
for (int y = y1; y <= y2; y ++) {
|
||||
for (int z = z1; z <= z2; z++) {
|
||||
if (x == x1 || x == x2 || z == z1 || z == z2 || y == y1 || y == y2) {
|
||||
set(x, y, z, typeId, data, bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAccess(World world) {
|
||||
// Ignore.
|
||||
@ -123,7 +169,7 @@ public class FakeBlockCache extends BlockCache {
|
||||
@Override
|
||||
public boolean standsOnEntity(Entity entity, double minX, double minY,
|
||||
double minZ, double maxX, double maxY, double maxZ) {
|
||||
// TODO: Consider adding blocks where this might be the case.
|
||||
// TODO: Consider adding cuboids which mean "ground" if the foot location is inside.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
package fr.neatmonster.nocheatplus.utilities;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rough ray-tracing for interaction with something. This does not do any smart end-point guessing.
|
||||
@ -25,11 +28,13 @@ public class InteractRayTracing extends RayTracing {
|
||||
|
||||
protected int lastBx, lastBy, lastBz;
|
||||
|
||||
public InteractRayTracing(){
|
||||
protected int targetX, targetY, targetZ;
|
||||
|
||||
public InteractRayTracing() {
|
||||
super();
|
||||
}
|
||||
|
||||
public InteractRayTracing(boolean strict){
|
||||
public InteractRayTracing(boolean strict) {
|
||||
super();
|
||||
this.strict = strict;
|
||||
}
|
||||
@ -42,27 +47,43 @@ public class InteractRayTracing extends RayTracing {
|
||||
this.blockCache = blockCache;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see fr.neatmonster.nocheatplus.utilities.RayTracing#set(double, double, double, double, double, double)
|
||||
*/
|
||||
@Override
|
||||
public void set(double x0, double y0, double z0, double x1, double y1, double z1) {
|
||||
set(x0, y0, z0, x1, y1, z1, Location.locToBlock(x1), Location.locToBlock(y1), Location.locToBlock(z1));
|
||||
// Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param x0
|
||||
* @param y0
|
||||
* @param z0
|
||||
* @param x1
|
||||
* @param y1
|
||||
* @param z1
|
||||
* @param targetX The block clicked/interacted with (can be different to the end point of ray-tracing, or ignored with Integer.MAX_VALUE).
|
||||
* @param targetY
|
||||
* @param targetZ
|
||||
*/
|
||||
public void set(double x0, double y0, double z0, double x1, double y1, double z1, int targetX, int targetY, int targetZ) {
|
||||
super.set(x0, y0, z0, x1, y1, z1);
|
||||
collides = false;
|
||||
lastBx = blockX;
|
||||
lastBy = blockY;
|
||||
lastBz = blockZ;
|
||||
this.targetX = targetX;
|
||||
this.targetY = targetY;
|
||||
this.targetZ = targetZ;
|
||||
}
|
||||
|
||||
public boolean collides(){
|
||||
public boolean collides() {
|
||||
return collides;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove reference to BlockCache.
|
||||
*/
|
||||
public void cleanup(){
|
||||
if (blockCache != null){
|
||||
public void cleanup() {
|
||||
if (blockCache != null) {
|
||||
blockCache = null;
|
||||
}
|
||||
}
|
||||
@ -74,49 +95,75 @@ public class InteractRayTracing extends RayTracing {
|
||||
* @param blockZ
|
||||
* @return
|
||||
*/
|
||||
private final boolean doesCollide(int blockX, int blockY, int blockZ){
|
||||
private final boolean doesCollide(final int blockX, final int blockY, final int blockZ) {
|
||||
final int id = blockCache.getTypeId(blockX, blockY, blockZ);
|
||||
final long flags = BlockProperties.getBlockFlags(id);
|
||||
if ((flags & BlockProperties.F_SOLID) == 0){
|
||||
if ((flags & BlockProperties.F_SOLID) == 0) {
|
||||
// Ignore non solid blocks anyway.
|
||||
return false;
|
||||
}
|
||||
if ((flags & (BlockProperties.F_LIQUID | BlockProperties.F_IGN_PASSABLE | BlockProperties.F_STAIRS | BlockProperties.F_VARIABLE)) != 0){
|
||||
if ((flags & (BlockProperties.F_LIQUID | BlockProperties.F_IGN_PASSABLE | BlockProperties.F_STAIRS | BlockProperties.F_VARIABLE)) != 0) {
|
||||
// Special cases.
|
||||
// TODO: F_VARIABLE: Bounding boxes are roughly right ?
|
||||
return false;
|
||||
}
|
||||
if (!blockCache.isFullBounds(blockX, blockY, blockZ)) return false;
|
||||
if (!blockCache.isFullBounds(blockX, blockY, blockZ)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the primary line is on the block interacted with (may be a
|
||||
* different one that the end point of ray-tracing).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isTargetBlock() {
|
||||
return targetX != Integer.MAX_VALUE && blockX == targetX && blockY == targetY && blockZ == targetZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the block may be interacted through by use of some workaround.
|
||||
*
|
||||
* @param blockX
|
||||
* @param blockY
|
||||
* @param blockZ
|
||||
* @return
|
||||
*/
|
||||
private final boolean allowsWorkaround(final int blockX, final int blockY, final int blockZ) {
|
||||
// TODO: This allows some bypasses for "strange" setups.
|
||||
|
||||
// TODO: Recode this/other.
|
||||
|
||||
// TODO: This could allow some bypasses for "strange" setups.
|
||||
// TODO: Consider using distance to target as heuristic ? [should not get smaller !?]
|
||||
// TODO: Consider (min/max) offset for distance.
|
||||
final int dX = blockX - lastBx;
|
||||
final int dY = blockY - lastBy;
|
||||
final int dZ = blockZ - lastBz;
|
||||
final double dSq = dX * dX + dY * dY + dZ * dZ;
|
||||
for (int i = 0; i < 6; i++){
|
||||
// TODO: Limit distance more here !?
|
||||
for (int i = 0; i < 6; i++) {
|
||||
final int[] dir = incr[i];
|
||||
final int rX = blockX + dir[0];
|
||||
if (Math.abs(lastBx - rX) > 1) continue;
|
||||
if (Math.abs(lastBx - rX) > 1) {
|
||||
continue;
|
||||
}
|
||||
final int rY = blockY + dir[1];
|
||||
if (Math.abs(lastBy - rY) > 1) continue;
|
||||
if (Math.abs(lastBy - rY) > 1) {
|
||||
continue;
|
||||
}
|
||||
final int rZ = blockZ + dir[2];
|
||||
if (Math.abs(lastBz - rZ) > 1) continue;
|
||||
if (Math.abs(lastBz - rZ) > 1) {
|
||||
continue;
|
||||
}
|
||||
final int dRx = rX - lastBx;
|
||||
final int dRy = rY - lastBy;
|
||||
final int dRz = rZ - lastBz;
|
||||
if (dRx * dRx + dRy * dRy + dRz * dRz <= dSq) continue;
|
||||
if (!doesCollide(rX, rY, rZ)){
|
||||
if (dRx * dRx + dRy * dRy + dRz * dRz <= dSq) {
|
||||
continue;
|
||||
}
|
||||
if (!doesCollide(rX, rY, rZ)) {
|
||||
// NOTE: Don't check "rX == targetBx && rZ == targetBz && rY == targetBy".
|
||||
return true;
|
||||
}
|
||||
@ -125,22 +172,24 @@ public class InteractRayTracing extends RayTracing {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean step(int blockX, int blockY, int blockZ, double oX, double oY, double oZ, double dT, final boolean isPrimary) {
|
||||
protected boolean step(final int blockX, final int blockY, final int blockZ, final double oX, final double oY, final double oZ, final double dT, final boolean isPrimary) {
|
||||
// TODO: Make an optional, more precise check (like passable) ?
|
||||
// TODO: Account for primary line vs. secondary.
|
||||
// TODO: isEndBlock -> blockInteractedWith, because the offset edge might be on the next block.
|
||||
if (isEndBlock() || !doesCollide(blockX, blockY, blockZ)){
|
||||
lastBx = blockX;
|
||||
lastBy = blockY;
|
||||
lastBz = blockZ;
|
||||
// TODO: isTargetBlock checks the primary line (!, might be ok.).
|
||||
if (isTargetBlock() || !doesCollide(blockX, blockY, blockZ)) {
|
||||
if (isPrimary) {
|
||||
lastBx = blockX;
|
||||
lastBy = blockY;
|
||||
lastBz = blockZ;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (strict || blockX == lastBx && blockZ == lastBz && blockY == lastBy){
|
||||
if (strict || blockX == lastBx && blockZ == lastBz && blockY == lastBy) {
|
||||
collides = true;
|
||||
return false;
|
||||
}
|
||||
// Check workarounds...
|
||||
if (allowsWorkaround(blockX, blockY, blockZ)){
|
||||
if (isPrimary && allowsWorkaround(blockX, blockY, blockZ)) {
|
||||
lastBx = blockX;
|
||||
lastBy = blockY;
|
||||
lastBz = blockZ;
|
||||
|
@ -111,7 +111,7 @@ public class MCAccessFactory {
|
||||
};
|
||||
// TEMP END //
|
||||
|
||||
// 1.7.10
|
||||
// 1.7.10
|
||||
try{
|
||||
return new MCAccessCB3100();
|
||||
}
|
||||
|
@ -0,0 +1,145 @@
|
||||
package fr.neatmonster.nocheatplus.test;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.neatmonster.nocheatplus.logging.StaticLog;
|
||||
import fr.neatmonster.nocheatplus.utilities.FakeBlockCache;
|
||||
import fr.neatmonster.nocheatplus.utilities.InteractRayTracing;
|
||||
import fr.neatmonster.nocheatplus.utilities.build.BuildParameters;
|
||||
|
||||
public class TestInteractRayTracing {
|
||||
|
||||
public final class CenteredInteractRayTracing extends InteractRayTracing {
|
||||
private int centerX, centerY, centerZ;
|
||||
public CenteredInteractRayTracing(boolean strict, int centerX, int centerY, int centerZ) {
|
||||
super(strict);
|
||||
this.centerX = centerX;
|
||||
this.centerY = centerY;
|
||||
this.centerZ = centerZ;
|
||||
}
|
||||
@Override
|
||||
public void set(double x0, double y0, double z0, double x1, double y1, double z1) {
|
||||
super.set(x0, y0, z0, x1, y1, z1, centerX, centerY, centerZ);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Blunt copy and paste from TestPassableRayTracing, add something that makes sense.
|
||||
|
||||
public TestInteractRayTracing() {
|
||||
StaticLog.setUseLogManager(false);
|
||||
BlockTests.initBlockProperties();
|
||||
StaticLog.setUseLogManager(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAir() {
|
||||
FakeBlockCache bc = new FakeBlockCache();
|
||||
InteractRayTracing rt = new InteractRayTracing();
|
||||
rt.setBlockCache(bc);
|
||||
double[] coords = new double[]{0.5, 0.5, -0.5, 0.5, 0.5, 1.5};
|
||||
rt.set(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
|
||||
rt.loop();
|
||||
if (rt.collides()) {
|
||||
TestRayTracing.doFail("Expect not to collide with air.", coords);
|
||||
}
|
||||
if (rt.getStepsDone() > 4) {
|
||||
TestRayTracing.doFail("Expect less than 4 steps for moving straight through a block of air.", coords);
|
||||
}
|
||||
rt.cleanup();
|
||||
bc.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moving diagonally through an "empty corner", seen from above:<br>
|
||||
* ox<br>
|
||||
* xo
|
||||
*/
|
||||
@Test
|
||||
public void testEmptyCorner() {
|
||||
FakeBlockCache bc = new FakeBlockCache();
|
||||
// The "empty corner" setup.
|
||||
for (int y = 70 ; y < 73; y ++) {
|
||||
bc.set(10, y, 10, Material.STONE);
|
||||
bc.set(11, y, 11, Material.STONE);
|
||||
}
|
||||
// Ground.
|
||||
for (int x = 9; x < 13; x++) {
|
||||
for (int z = 9; z < 13; z++) {
|
||||
bc.set(x, 69, z, Material.STONE);
|
||||
}
|
||||
}
|
||||
// TODO: Make work with strict set to false.
|
||||
InteractRayTracing rt = new InteractRayTracing(true);
|
||||
//InteractRayTracing rt = new InteractRayTracing(false);
|
||||
rt.setBlockCache(bc);
|
||||
// TODO: More Directions, also just behind the corner.
|
||||
double[][] setups = new double[][] {
|
||||
// Slightly off the middle (11, y, 11)
|
||||
{11.4, 70.0, 10.4, 10.6, 70.0, 11.4},
|
||||
// Going exactly through the middle (11, y, 11)
|
||||
{11.4, 70.0, 10.6, 10.6, 70.0, 11.4},
|
||||
{11.5, 70.0, 10.5, 10.5, 70.0, 11.5},
|
||||
};
|
||||
TestRayTracing.runCoordinates(rt, setups, true, false, 3.0, true);
|
||||
rt.cleanup();
|
||||
bc.cleanup();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWall() {
|
||||
FakeBlockCache bc = new FakeBlockCache();
|
||||
// Wall using full blocks.
|
||||
bc.walls(0, 65, 0, 16, 67, 0, Material.STONE);
|
||||
// Ground using full blocks (roughly 16 margin to each side).
|
||||
bc.fill(-16, 64, -16, 32, 64, 16, Material.STONE);
|
||||
// TODO: Test chest like bounds for target blocks.
|
||||
InteractRayTracing rt = new InteractRayTracing(false);
|
||||
rt.setBlockCache(bc);
|
||||
// TODO: More cases, head inside block itself, angles, ...
|
||||
double[][] noCollision = new double[][] {
|
||||
{8.5, 66.75, 1.2 , 8.5, 65.8, 1.0},
|
||||
{8.5, 66.75, 1.2 , 8.5, 69.0, 0.0}, // "Above enough".
|
||||
};
|
||||
TestRayTracing.runCoordinates(rt, noCollision, false, true, 3.0, true);
|
||||
double[][] shouldCollide = new double[][] {
|
||||
{8.5, 66.75, 1.2 , 8.5, 65.8, 0.0},
|
||||
{8.5, 66.75, 1.2 , 8.5, 65.8, -0.2},
|
||||
};
|
||||
TestRayTracing.runCoordinates(rt, shouldCollide, true, false, 3.0, true);
|
||||
rt.cleanup();
|
||||
bc.cleanup();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoom() {
|
||||
// TODO: Test for differing middle points (negative to positive range, random, selected rays).
|
||||
FakeBlockCache bc = new FakeBlockCache();
|
||||
bc.room(-1, 64, -1, 1, 66, 1, Material.STONE);
|
||||
// Note that reversed checks are slightly different with the centered version, but start + end blocks are air anyway.
|
||||
double[] middle = new double[] {0.5, 65.5, 0.5}; // Free spot.
|
||||
// TODO: Must work with strict set to false.
|
||||
//CenteredInteractRayTracing rt = new CenteredInteractRayTracing(false, 0, 65, 0);
|
||||
CenteredInteractRayTracing rt = new CenteredInteractRayTracing(true, 0, 65, 0);
|
||||
rt.setBlockCache(bc);
|
||||
double[][] pastFailures = new double[][] {
|
||||
{2.1393379885667643, 67.18197661625649, 1.7065201483677281 , 0.0, 65.0, 0.0},
|
||||
{2.7915547712543676, 66.65545738305906, 1.310222428430474 , 0.0, 65.0, 0.0},
|
||||
{0.0, 65.0, 4.5 , 0.0, 65.0, 1.0}, // strict is false.
|
||||
{-3.5, 61.5, -3.5 , 0.0, 65.0, 0.0} // strict is false.
|
||||
};
|
||||
TestRayTracing.runCoordinates(rt, pastFailures, true, false, 3, true);
|
||||
boolean intense = BuildParameters.testLevel > 1;
|
||||
for (double x = -0.5; x < 1.0; x += 0.5) {
|
||||
for (double y = -0.5; y < 1.0; y += 0.5) {
|
||||
for (double z = -0.5; z < 1.0; z += 0.5) {
|
||||
double add = Math.abs(x) + Math.abs(y) + Math.abs(z);
|
||||
TestRayTracing.runCenterRays(rt, middle[0] + x, middle[1] + y, middle[2] + z, 2.0 + add, intense ? 10000 : 1000, true, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
rt.cleanup();
|
||||
bc.cleanup();
|
||||
}
|
||||
|
||||
}
|
@ -6,22 +6,23 @@ import org.junit.Test;
|
||||
import fr.neatmonster.nocheatplus.logging.StaticLog;
|
||||
import fr.neatmonster.nocheatplus.utilities.FakeBlockCache;
|
||||
import fr.neatmonster.nocheatplus.utilities.PassableRayTracing;
|
||||
import fr.neatmonster.nocheatplus.utilities.build.BuildParameters;
|
||||
|
||||
public class TestPassableRayTracing {
|
||||
|
||||
|
||||
// TODO: Moving into a block,
|
||||
// TODO: Moving out of a block
|
||||
// TODO: Moving horizontally on various kinds of ground (normal, half blocks)
|
||||
// TODO: Moving up stairs etc ?
|
||||
// TODO: From ground and onto ground moves, onto-edge moves (block before edge, into block, etc).
|
||||
// TODO: Randomized tests (Collide with inner sphere, not collide with outer sphere).
|
||||
|
||||
|
||||
public TestPassableRayTracing() {
|
||||
StaticLog.setUseLogManager(false);
|
||||
BlockTests.initBlockProperties();
|
||||
StaticLog.setUseLogManager(true);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAir() {
|
||||
FakeBlockCache bc = new FakeBlockCache();
|
||||
@ -39,7 +40,7 @@ public class TestPassableRayTracing {
|
||||
rt.cleanup();
|
||||
bc.cleanup();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testThroughOneBlock() {
|
||||
FakeBlockCache bc = new FakeBlockCache();
|
||||
@ -47,26 +48,26 @@ public class TestPassableRayTracing {
|
||||
PassableRayTracing rt = new PassableRayTracing();
|
||||
rt.setBlockCache(bc);
|
||||
double[][] setups = new double[][] {
|
||||
// Through the middle of the block.
|
||||
{0.5, 0.5, -0.5, 0.5, 0.5, 1.5},
|
||||
{-0.5, 0.5, 0.5, 1.5, 0.5, 0.5},
|
||||
{0.5, -0.5, 0.5, 0.5, 1.5, 0.5},
|
||||
// Along the edges.
|
||||
{0.5, 0.0, -0.5, 0.5, 0.0, 1.5},
|
||||
{-0.5, 0.0, 0.5, 1.5, 0.0, 0.5},
|
||||
// Exactly diagonal.
|
||||
{-0.5, -0.5, -0.5, 1.5, 1.5, 1.5}, // 3d
|
||||
{-0.5, 0.0, -0.5, 1.5, 0.0, 1.5}, // 2d
|
||||
// Through a corner.
|
||||
{1.2, 0.5, 0.5, 0.5, 0.5, 1.2},
|
||||
|
||||
// TODO: More of each and other... + generic set-ups?
|
||||
// Through the middle of the block.
|
||||
{0.5, 0.5, -0.5, 0.5, 0.5, 1.5},
|
||||
{-0.5, 0.5, 0.5, 1.5, 0.5, 0.5},
|
||||
{0.5, -0.5, 0.5, 0.5, 1.5, 0.5},
|
||||
// Along the edges.
|
||||
{0.5, 0.0, -0.5, 0.5, 0.0, 1.5},
|
||||
{-0.5, 0.0, 0.5, 1.5, 0.0, 0.5},
|
||||
// Exactly diagonal.
|
||||
{-0.5, -0.5, -0.5, 1.5, 1.5, 1.5}, // 3d
|
||||
{-0.5, 0.0, -0.5, 1.5, 0.0, 1.5}, // 2d
|
||||
// Through a corner.
|
||||
{1.2, 0.5, 0.5, 0.5, 0.5, 1.2},
|
||||
|
||||
// TODO: More of each and other... + generic set-ups?
|
||||
};
|
||||
TestRayTracing.runCoordinates(rt, setups, true, false, 3.0, true);
|
||||
rt.cleanup();
|
||||
bc.cleanup();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Moving diagonally through an "empty corner", seen from above:<br>
|
||||
* ox<br>
|
||||
@ -88,17 +89,18 @@ public class TestPassableRayTracing {
|
||||
rt.setBlockCache(bc);
|
||||
// TODO: More Directions, over a corner, sides, etc.
|
||||
double[][] setups = new double[][] {
|
||||
// Slightly off the middle (11, y, 11)
|
||||
{11.4, 70.0, 10.4, 10.6, 70.0, 11.4},
|
||||
// Going exactly through the middle (11, y, 11)
|
||||
{11.4, 70.0, 10.6, 10.6, 70.0, 11.4},
|
||||
{11.5, 70.0, 10.5, 10.5, 70.0, 11.5},
|
||||
// Slightly off the middle (11, y, 11)
|
||||
{11.4, 70.0, 10.4, 10.6, 70.0, 11.4},
|
||||
// Going exactly through the middle (11, y, 11)
|
||||
{11.4, 70.0, 10.6, 10.6, 70.0, 11.4},
|
||||
{11.5, 70.0, 10.5, 10.5, 70.0, 11.5},
|
||||
//{11.5, 70.0, 10.5, 10.99999999999, 70.0, 11.00000000001}, // TODO: Craft something here
|
||||
};
|
||||
TestRayTracing.runCoordinates(rt, setups, true, false, 3.0, true);
|
||||
rt.cleanup();
|
||||
bc.cleanup();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGround() {
|
||||
FakeBlockCache bc = new FakeBlockCache();
|
||||
@ -112,21 +114,21 @@ public class TestPassableRayTracing {
|
||||
rt.setBlockCache(bc);
|
||||
// TODO: More Directions, also from air underneath to ground).
|
||||
double[][] noCollision = new double[][] {
|
||||
{1.3, 66.0, 2.43, 5.25, 66.0, 7.12},
|
||||
{1.3, 66.0, 2.43, 5.25, 66.0, 7.12},
|
||||
};
|
||||
TestRayTracing.runCoordinates(rt, noCollision, false, true, 3.0, true);
|
||||
double[][] shouldCollide = new double[][] {
|
||||
{1.3, 65.1, 2.43, 2.3, 65.1, 4.43},
|
||||
{1.3, 65.0, 2.43, 2.3, 65.0, 4.43},
|
||||
{1.3, 66.0, 2.43, 1.3, 65.9, 2.43},
|
||||
{1.3, 66.0, 2.43, 5.25, 65.9, 7.12},
|
||||
{1.3, 65.4, 2.43, 1.3, 65.4, 2.43}, // No distance.
|
||||
{1.3, 65.1, 2.43, 2.3, 65.1, 4.43},
|
||||
{1.3, 65.0, 2.43, 2.3, 65.0, 4.43},
|
||||
{1.3, 66.0, 2.43, 1.3, 65.9, 2.43},
|
||||
{1.3, 66.0, 2.43, 5.25, 65.9, 7.12},
|
||||
{1.3, 65.4, 2.43, 1.3, 65.4, 2.43}, // No distance.
|
||||
};
|
||||
TestRayTracing.runCoordinates(rt, shouldCollide, true, false, 3.0, true);
|
||||
rt.cleanup();
|
||||
bc.cleanup();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGroundSteps() {
|
||||
FakeBlockCache bc = new FakeBlockCache();
|
||||
@ -142,19 +144,39 @@ public class TestPassableRayTracing {
|
||||
rt.setBlockCache(bc);
|
||||
// TODO: More Directions, also from air underneath to ground).
|
||||
double[][] noCollision = new double[][] {
|
||||
{1.3, 65.5, 2.43, 5.25, 65.5, 7.12},
|
||||
{1.3, 65.5, 2.43, 5.25, 65.5, 7.12},
|
||||
};
|
||||
TestRayTracing.runCoordinates(rt, noCollision, false, true, 3.0, true);
|
||||
double[][] shouldCollide = new double[][] {
|
||||
{1.3, 65.1, 2.43, 2.3, 65.1, 7.43},
|
||||
{1.3, 65.0, 2.43, 2.3, 65.0, 7.43},
|
||||
{1.3, 65.5, 2.43, 1.3, 65.4, 2.43},
|
||||
{1.3, 65.5, 2.43, 5.25, 65.4, 7.12},
|
||||
{1.3, 65.4, 2.43, 1.3, 65.4, 2.43}, // No distance.
|
||||
{1.3, 65.1, 2.43, 2.3, 65.1, 7.43},
|
||||
{1.3, 65.0, 2.43, 2.3, 65.0, 7.43},
|
||||
{1.3, 65.5, 2.43, 1.3, 65.4, 2.43},
|
||||
{1.3, 65.5, 2.43, 5.25, 65.4, 7.12},
|
||||
{1.3, 65.4, 2.43, 1.3, 65.4, 2.43}, // No distance.
|
||||
};
|
||||
TestRayTracing.runCoordinates(rt, shouldCollide, true, false, 3.0, true);
|
||||
rt.cleanup();
|
||||
bc.cleanup();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRoom() {
|
||||
FakeBlockCache bc = new FakeBlockCache();
|
||||
bc.room(-1, 64, -1, 1, 66, 1, Material.STONE);
|
||||
double[] middle = new double[] {0.5, 65.5, 0.5}; // Free spot.
|
||||
PassableRayTracing rt = new PassableRayTracing();
|
||||
rt.setBlockCache(bc);
|
||||
boolean intense = BuildParameters.testLevel > 1;
|
||||
for (double x = -0.5; x < 1.0; x += 0.5) {
|
||||
for (double y = -0.5; y < 1.0; y += 0.5) {
|
||||
for (double z = -0.5; z < 1.0; z += 0.5) {
|
||||
double add = Math.abs(x) + Math.abs(y) + Math.abs(z);
|
||||
TestRayTracing.runCenterRays(rt, middle[0] + x, middle[1] + y, middle[2] + z, 2.0 + add, intense ? 10000 : 1000, true, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
rt.cleanup();
|
||||
bc.cleanup();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import static org.junit.Assert.fail;
|
||||
import java.util.Random;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.junit.Test;
|
||||
|
||||
import fr.neatmonster.nocheatplus.utilities.RayTracing;
|
||||
@ -259,6 +260,16 @@ public class TestRayTracing {
|
||||
// TODO: Add tests for typical coordinates a with interact, passable.
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param rt
|
||||
* @param setup
|
||||
* @param expectCollide
|
||||
* @param expectNotCollide
|
||||
* @param stepsManhattan
|
||||
* @param reverse If set to true, end points will be exchanged for this run (not in addition).
|
||||
* @param tag
|
||||
*/
|
||||
public static void runCoordinates(RayTracing rt, double[] setup, boolean expectCollide, boolean expectNotCollide, double stepsManhattan, boolean reverse, String tag) {
|
||||
if (reverse) {
|
||||
rt.set(setup[3], setup [4], setup[5], setup[0], setup[1], setup[2]);
|
||||
@ -291,7 +302,7 @@ public class TestRayTracing {
|
||||
* @param expectCollide
|
||||
* @param expectNotCollide
|
||||
* @param stepsManhattan
|
||||
* @param testReversed
|
||||
* @param testReversed If to test the each ray with reversed end points in addition.
|
||||
*/
|
||||
public static void runCoordinates(RayTracing rt, double[][] setups, boolean expectCollide, boolean expectNotCollide, double stepsManhattan, boolean testReversed) {
|
||||
for (int i = 0; i < setups.length; i++) {
|
||||
@ -304,4 +315,61 @@ public class TestRayTracing {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run (some) standard directions towards the center.
|
||||
* @param rt
|
||||
* @param cX
|
||||
* @param cY
|
||||
* @param cZ
|
||||
* @param length Rough length of the rays (might be applied per-axis including an additum).
|
||||
* @param nRandom Test a number of random rays as well.
|
||||
* @param expectCollide
|
||||
* @param expectNotCollide
|
||||
* @param testReversed If to test the each ray with reversed end points in addition.
|
||||
*/
|
||||
public static void runCenterRays(RayTracing rt, double cX, double cY, double cZ, double length, int nRandom, boolean expectCollide, boolean expectNotCollide, boolean testReversed) {
|
||||
double[] mult = new double[] {-1.0, 0.0, 1.0};
|
||||
for (int ix = 0; ix < 3; ix ++) {
|
||||
for (int iy = 0; iy < 3; iy++) {
|
||||
for (int iz = 0; iz < 3; iz++) {
|
||||
if (ix == 1 && iy == 1 && iz == 1) {
|
||||
// Skip the center itself.
|
||||
continue;
|
||||
}
|
||||
double[] coords = new double[] {
|
||||
cX + length * mult[ix],
|
||||
cY + length * mult[iy],
|
||||
cZ + length * mult[iz],
|
||||
cX,
|
||||
cY,
|
||||
cZ
|
||||
};
|
||||
// TODO: Generate differing target points on/near middle as well.
|
||||
TestRayTracing.runCoordinates(rt, coords, true, false, 3.0, false, "");
|
||||
if (testReversed) {
|
||||
TestRayTracing.runCoordinates(rt, coords, true, false, 3.0, true, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Consider running block coordinates with larger radius (potentially all within some radius?).
|
||||
for (int n = 0; n < nRandom; n ++) {
|
||||
// TODO: Check if normalize is necessary.
|
||||
// One totally random vector.
|
||||
Vector vec = Vector.getRandom().normalize().multiply(length);
|
||||
double[] coords = new double[] {
|
||||
cX + vec.getX(),
|
||||
cY + vec.getY(),
|
||||
cZ + vec.getZ(),
|
||||
cX,
|
||||
cY,
|
||||
cZ
|
||||
};
|
||||
TestRayTracing.runCoordinates(rt, coords, true, false, 3.0, false, "random");
|
||||
if (testReversed) {
|
||||
TestRayTracing.runCoordinates(rt, coords, true, false, 3.0, true, "random");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user