mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-09-05 03:31:09 +02: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
|
@ -21,6 +21,9 @@ public class Visible extends Check {
|
||||||
|
|
||||||
private BlockCache blockCache;
|
private BlockCache blockCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strict set to false, due to false positives.
|
||||||
|
*/
|
||||||
private final InteractRayTracing rayTracing = new InteractRayTracing(false);
|
private final InteractRayTracing rayTracing = new InteractRayTracing(false);
|
||||||
|
|
||||||
public Visible() {
|
public Visible() {
|
||||||
|
@ -113,6 +116,15 @@ public class Visible extends Check {
|
||||||
|
|
||||||
private boolean checkRayTracing(final double eyeX, final double eyeY, final double eyeZ, final int blockX, final int blockY, final int blockZ, final BlockFace face){
|
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).
|
// Estimated target-middle-position (does it for most cases).
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
final double[] bounds = BlockProperties.getCorrectedBounds(blockCache, blockX, blockY, blockZ);
|
final double[] bounds = BlockProperties.getCorrectedBounds(blockCache, blockX, blockY, blockZ);
|
||||||
|
@ -131,7 +143,7 @@ public class Visible extends Check {
|
||||||
final boolean skipPassable = blockX == bEstX && blockY == bEstY && blockZ == bEstZ;
|
final boolean skipPassable = blockX == bEstX && blockY == bEstY && blockZ == bEstZ;
|
||||||
|
|
||||||
// TODO: Might also use looking direction (test how accurate).
|
// TODO: Might also use looking direction (test how accurate).
|
||||||
return checkCollision(eyeX, eyeY, eyeZ, estX, estY, estZ, estId, bounds, modX, modY, modZ, skipPassable);
|
return checkCollision(eyeX, eyeY, eyeZ, estX, estY, estZ, estId, bounds, modX, modY, modZ, skipPassable, blockX, blockY, blockZ);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,11 +162,11 @@ public class Visible extends Check {
|
||||||
* @param skipPassable
|
* @param skipPassable
|
||||||
* @return
|
* @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) {
|
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.
|
// Check current position.
|
||||||
if (skipPassable || BlockProperties.isPassable(blockCache, estX, estY, estZ, estId)){
|
if (skipPassable || BlockProperties.isPassable(blockCache, estX, estY, estZ, estId)){
|
||||||
// Perform ray-tracing.
|
// Perform ray-tracing.
|
||||||
rayTracing.set(eyeX, eyeY, eyeZ, estX, estY, estZ);
|
rayTracing.set(eyeX, eyeY, eyeZ, estX, estY, estZ, clickedX, clickedY, clickedZ);
|
||||||
rayTracing.loop();
|
rayTracing.loop();
|
||||||
if (!rayTracing.collides() && rayTracing.getStepsDone() < rayTracing.getMaxSteps()){
|
if (!rayTracing.collides() && rayTracing.getStepsDone() < rayTracing.getMaxSteps()){
|
||||||
return false;
|
return false;
|
||||||
|
@ -168,10 +180,10 @@ public class Visible extends Check {
|
||||||
final double d = bounds == null ? 0.5 : (bounds[3] - bounds[0]) / 2.0;
|
final double d = bounds == null ? 0.5 : (bounds[3] - bounds[0]) / 2.0;
|
||||||
if (d >= 0.05){
|
if (d >= 0.05){
|
||||||
// Recursion with adapted x position (if differs enough from bounds.
|
// 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)){
|
if (!checkCollision(eyeX, eyeY, eyeZ, estX - d, estY, estZ, estId, bounds, 1, modY, modZ, skipPassable, clickedX, clickedY, clickedZ)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX + d, estY, estZ, estId, bounds, 1, modY, modZ, skipPassable)){
|
if (!checkCollision(eyeX, eyeY, eyeZ, estX + d, estY, estZ, estId, bounds, 1, modY, modZ, skipPassable, clickedX, clickedY, clickedZ)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,10 +193,10 @@ public class Visible extends Check {
|
||||||
final double d = bounds == null ? 0.5 : (bounds[5] - bounds[2]) / 2.0;
|
final double d = bounds == null ? 0.5 : (bounds[5] - bounds[2]) / 2.0;
|
||||||
if (d >= 0.05){
|
if (d >= 0.05){
|
||||||
// Recursion with adapted x position (if differs enough from bounds.
|
// 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)){
|
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY, estZ - d, estId, bounds, 1, modY, 1, skipPassable, clickedX, clickedY, clickedZ)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY, estZ + d, estId, bounds, 1, modY, 1, skipPassable)){
|
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY, estZ + d, estId, bounds, 1, modY, 1, skipPassable, clickedX, clickedY, clickedZ)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,10 +206,10 @@ public class Visible extends Check {
|
||||||
final double d = bounds == null ? 0.5 : (bounds[4] - bounds[1]) / 2.0;
|
final double d = bounds == null ? 0.5 : (bounds[4] - bounds[1]) / 2.0;
|
||||||
if (d >= 0.05){
|
if (d >= 0.05){
|
||||||
// Recursion with adapted x position (if differs enough from bounds.
|
// 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)){
|
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY - d, estZ, estId, bounds, 1, 1, 1, skipPassable, clickedX, clickedY, clickedZ)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY + d, estZ, estId, bounds, 1, 1, 1, skipPassable)){
|
if (!checkCollision(eyeX, eyeY, eyeZ, estX, estY + d, estZ, estId, bounds, 1, 1, 1, skipPassable, clickedX, clickedY, clickedZ)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
@Override
|
||||||
public void setAccess(World world) {
|
public void setAccess(World world) {
|
||||||
// Ignore.
|
// Ignore.
|
||||||
|
@ -123,7 +169,7 @@ public class FakeBlockCache extends BlockCache {
|
||||||
@Override
|
@Override
|
||||||
public boolean standsOnEntity(Entity entity, double minX, double minY,
|
public boolean standsOnEntity(Entity entity, double minX, double minY,
|
||||||
double minZ, double maxX, double maxY, double maxZ) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package fr.neatmonster.nocheatplus.utilities;
|
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.
|
* 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;
|
protected int lastBx, lastBy, lastBz;
|
||||||
|
|
||||||
public InteractRayTracing(){
|
protected int targetX, targetY, targetZ;
|
||||||
|
|
||||||
|
public InteractRayTracing() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public InteractRayTracing(boolean strict){
|
public InteractRayTracing(boolean strict) {
|
||||||
super();
|
super();
|
||||||
this.strict = strict;
|
this.strict = strict;
|
||||||
}
|
}
|
||||||
|
@ -42,27 +47,43 @@ public class InteractRayTracing extends RayTracing {
|
||||||
this.blockCache = blockCache;
|
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) {
|
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);
|
super.set(x0, y0, z0, x1, y1, z1);
|
||||||
collides = false;
|
collides = false;
|
||||||
lastBx = blockX;
|
lastBx = blockX;
|
||||||
lastBy = blockY;
|
lastBy = blockY;
|
||||||
lastBz = blockZ;
|
lastBz = blockZ;
|
||||||
|
this.targetX = targetX;
|
||||||
|
this.targetY = targetY;
|
||||||
|
this.targetZ = targetZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean collides(){
|
public boolean collides() {
|
||||||
return collides;
|
return collides;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove reference to BlockCache.
|
* Remove reference to BlockCache.
|
||||||
*/
|
*/
|
||||||
public void cleanup(){
|
public void cleanup() {
|
||||||
if (blockCache != null){
|
if (blockCache != null) {
|
||||||
blockCache = null;
|
blockCache = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,49 +95,75 @@ public class InteractRayTracing extends RayTracing {
|
||||||
* @param blockZ
|
* @param blockZ
|
||||||
* @return
|
* @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 int id = blockCache.getTypeId(blockX, blockY, blockZ);
|
||||||
final long flags = BlockProperties.getBlockFlags(id);
|
final long flags = BlockProperties.getBlockFlags(id);
|
||||||
if ((flags & BlockProperties.F_SOLID) == 0){
|
if ((flags & BlockProperties.F_SOLID) == 0) {
|
||||||
// Ignore non solid blocks anyway.
|
// Ignore non solid blocks anyway.
|
||||||
return false;
|
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.
|
// Special cases.
|
||||||
// TODO: F_VARIABLE: Bounding boxes are roughly right ?
|
// TODO: F_VARIABLE: Bounding boxes are roughly right ?
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!blockCache.isFullBounds(blockX, blockY, blockZ)) return false;
|
if (!blockCache.isFullBounds(blockX, blockY, blockZ)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
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.
|
* Check if the block may be interacted through by use of some workaround.
|
||||||
|
*
|
||||||
* @param blockX
|
* @param blockX
|
||||||
* @param blockY
|
* @param blockY
|
||||||
* @param blockZ
|
* @param blockZ
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private final boolean allowsWorkaround(final int blockX, final int blockY, final int blockZ) {
|
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 using distance to target as heuristic ? [should not get smaller !?]
|
||||||
|
// TODO: Consider (min/max) offset for distance.
|
||||||
final int dX = blockX - lastBx;
|
final int dX = blockX - lastBx;
|
||||||
final int dY = blockY - lastBy;
|
final int dY = blockY - lastBy;
|
||||||
final int dZ = blockZ - lastBz;
|
final int dZ = blockZ - lastBz;
|
||||||
final double dSq = dX * dX + dY * dY + dZ * dZ;
|
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[] dir = incr[i];
|
||||||
final int rX = blockX + dir[0];
|
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];
|
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];
|
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 dRx = rX - lastBx;
|
||||||
final int dRy = rY - lastBy;
|
final int dRy = rY - lastBy;
|
||||||
final int dRz = rZ - lastBz;
|
final int dRz = rZ - lastBz;
|
||||||
if (dRx * dRx + dRy * dRy + dRz * dRz <= dSq) continue;
|
if (dRx * dRx + dRy * dRy + dRz * dRz <= dSq) {
|
||||||
if (!doesCollide(rX, rY, rZ)){
|
continue;
|
||||||
|
}
|
||||||
|
if (!doesCollide(rX, rY, rZ)) {
|
||||||
// NOTE: Don't check "rX == targetBx && rZ == targetBz && rY == targetBy".
|
// NOTE: Don't check "rX == targetBx && rZ == targetBz && rY == targetBy".
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -125,22 +172,24 @@ public class InteractRayTracing extends RayTracing {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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: 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.
|
// TODO: isEndBlock -> blockInteractedWith, because the offset edge might be on the next block.
|
||||||
if (isEndBlock() || !doesCollide(blockX, blockY, blockZ)){
|
// TODO: isTargetBlock checks the primary line (!, might be ok.).
|
||||||
|
if (isTargetBlock() || !doesCollide(blockX, blockY, blockZ)) {
|
||||||
|
if (isPrimary) {
|
||||||
lastBx = blockX;
|
lastBx = blockX;
|
||||||
lastBy = blockY;
|
lastBy = blockY;
|
||||||
lastBz = blockZ;
|
lastBz = blockZ;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (strict || blockX == lastBx && blockZ == lastBz && blockY == lastBy){
|
if (strict || blockX == lastBx && blockZ == lastBz && blockY == lastBy) {
|
||||||
collides = true;
|
collides = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Check workarounds...
|
// Check workarounds...
|
||||||
if (allowsWorkaround(blockX, blockY, blockZ)){
|
if (isPrimary && allowsWorkaround(blockX, blockY, blockZ)) {
|
||||||
lastBx = blockX;
|
lastBx = blockX;
|
||||||
lastBy = blockY;
|
lastBy = blockY;
|
||||||
lastBz = blockZ;
|
lastBz = blockZ;
|
||||||
|
|
|
@ -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,6 +6,7 @@ import org.junit.Test;
|
||||||
import fr.neatmonster.nocheatplus.logging.StaticLog;
|
import fr.neatmonster.nocheatplus.logging.StaticLog;
|
||||||
import fr.neatmonster.nocheatplus.utilities.FakeBlockCache;
|
import fr.neatmonster.nocheatplus.utilities.FakeBlockCache;
|
||||||
import fr.neatmonster.nocheatplus.utilities.PassableRayTracing;
|
import fr.neatmonster.nocheatplus.utilities.PassableRayTracing;
|
||||||
|
import fr.neatmonster.nocheatplus.utilities.build.BuildParameters;
|
||||||
|
|
||||||
public class TestPassableRayTracing {
|
public class TestPassableRayTracing {
|
||||||
|
|
||||||
|
@ -93,6 +94,7 @@ public class TestPassableRayTracing {
|
||||||
// Going exactly through the middle (11, y, 11)
|
// Going exactly through the middle (11, y, 11)
|
||||||
{11.4, 70.0, 10.6, 10.6, 70.0, 11.4},
|
{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.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);
|
TestRayTracing.runCoordinates(rt, setups, true, false, 3.0, true);
|
||||||
rt.cleanup();
|
rt.cleanup();
|
||||||
|
@ -157,4 +159,24 @@ public class TestPassableRayTracing {
|
||||||
bc.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 java.util.Random;
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import fr.neatmonster.nocheatplus.utilities.RayTracing;
|
import fr.neatmonster.nocheatplus.utilities.RayTracing;
|
||||||
|
@ -259,6 +260,16 @@ public class TestRayTracing {
|
||||||
// TODO: Add tests for typical coordinates a with interact, passable.
|
// 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) {
|
public static void runCoordinates(RayTracing rt, double[] setup, boolean expectCollide, boolean expectNotCollide, double stepsManhattan, boolean reverse, String tag) {
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
rt.set(setup[3], setup [4], setup[5], setup[0], setup[1], setup[2]);
|
rt.set(setup[3], setup [4], setup[5], setup[0], setup[1], setup[2]);
|
||||||
|
@ -291,7 +302,7 @@ public class TestRayTracing {
|
||||||
* @param expectCollide
|
* @param expectCollide
|
||||||
* @param expectNotCollide
|
* @param expectNotCollide
|
||||||
* @param stepsManhattan
|
* @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) {
|
public static void runCoordinates(RayTracing rt, double[][] setups, boolean expectCollide, boolean expectNotCollide, double stepsManhattan, boolean testReversed) {
|
||||||
for (int i = 0; i < setups.length; i++) {
|
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