mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-07-05 10:44:40 +02:00
Keep adjusting time and offsets in raytracing.
* Not actually a fix for anything we encountered. * Nailed down blockinteract.visible raytracing issues to bad end-points for raytracing. * Also test/prepare logging test-cases for raytracing in general. Not enabled, because we should have some flag/permission/command to check before logging ~ 5KB per interact event.
This commit is contained in:
parent
ab88b98704
commit
14049200a2
|
@ -188,7 +188,8 @@ public class Visible extends Check {
|
|||
* Consider using a configuration setting for extended debugging
|
||||
* (e.g. make DEBUG_LEVEL accessible by API and config).
|
||||
*/
|
||||
// TODO: public static void InteractRayTracing.logTestCase(...).
|
||||
// TEST: Log as a false positive (!).
|
||||
//NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, "blockinteract.visible test case:\n" + rayTracing.getTestCase(1.05, false));
|
||||
}
|
||||
return collides;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package fr.neatmonster.nocheatplus.utilities;
|
|||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
@ -26,6 +27,42 @@ public class FakeBlockCache extends BlockCache {
|
|||
/** Cached shape values. */
|
||||
private final CoordMap<double[]> boundsMapStored = new CoordMap<double[]>(23);
|
||||
|
||||
/**
|
||||
* Convenience method to copy a cuboid region given by two endpoints without any order specified.
|
||||
* @param other
|
||||
* @param x0
|
||||
* @param y0
|
||||
* @param z0
|
||||
* @param x1
|
||||
* @param y1
|
||||
* @param z1
|
||||
* @param margin
|
||||
*/
|
||||
public void set(BlockCache other, double x0, double y0, double z0, double x1, double y1, double z1, double margin) {
|
||||
set(other, Location.locToBlock(Math.min(x0, x1) - margin), Location.locToBlock(Math.min(y0, y1) - margin), Location.locToBlock(Math.min(z0, z1) - margin),
|
||||
Location.locToBlock(Math.max(x0, x1) + margin), Location.locToBlock(Math.max(y0, y1) + margin), Location.locToBlock(Math.max(z0, z1) + margin));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a cuboid region from the other BlockCache instance.
|
||||
* @param other
|
||||
* @param minX
|
||||
* @param minY
|
||||
* @param minZ
|
||||
* @param maxX
|
||||
* @param maxY
|
||||
* @param maxZ
|
||||
*/
|
||||
public void set(BlockCache other, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int y = minY; y <= maxY; y ++) {
|
||||
for (int z = minZ; z <= maxZ; z ++) {
|
||||
set(x, y, z, other.getTypeId(x, y, z), other.getData(x, y, z), other.getBounds(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set with data=0 and bounds=full.
|
||||
* @param x
|
||||
|
@ -79,7 +116,7 @@ public class FakeBlockCache extends BlockCache {
|
|||
* @param z
|
||||
* @param typeId
|
||||
* @param data
|
||||
* @param bounds
|
||||
* @param bounds Stores the given bounds directly.
|
||||
*/
|
||||
public void set(int x, int y, int z, int typeId, int data, double[] bounds) {
|
||||
idMapStored.put(x, y, z, typeId);
|
||||
|
@ -219,9 +256,17 @@ public class FakeBlockCache extends BlockCache {
|
|||
* Return a line of java code to construct a new FakeBlockCache with the same content (no newlines).
|
||||
* @param builder
|
||||
* @param fbcName Variable name of the FakeBlockCache instance.
|
||||
* @param boundsPrefix A prefix for bounds variables for the case of repeated content. If set to null, no optimization will be performed.
|
||||
*/
|
||||
public void toJava(final StringBuilder builder, final String fbcName) {
|
||||
public void toJava(final StringBuilder builder, final String fbcName, final String boundsPrefix) {
|
||||
builder.append("FakeBlockCache " + fbcName + " = new FakeBlockCache();");
|
||||
final String fullBounds;
|
||||
if (boundsPrefix != null) {
|
||||
fullBounds = boundsPrefix + "_fb";
|
||||
builder.append(" double[] " + fullBounds + " = new double[]{0.0, 0.0, 0.0, 1.0, 1.0, 1.0};" );
|
||||
} else {
|
||||
fullBounds = null;
|
||||
}
|
||||
// Assume id is always set.
|
||||
final Iterator<Entry<Integer>> it = idMapStored.iterator();
|
||||
final int airId = BlockProperties.getId(Material.AIR);
|
||||
|
@ -233,16 +278,22 @@ public class FakeBlockCache extends BlockCache {
|
|||
final Integer id = entry.getValue();
|
||||
if (id == airId) {
|
||||
builder.append(fbcName + ".set(" + x + ", " + y + ", " + z + ", " + id + ");");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
final Integer data = dataMapStored.get(x, y, z);
|
||||
final double[] bounds = boundsMapStored.get(x, y, z);
|
||||
if (bounds == null) {
|
||||
if (data == null) { // Consider 0 too.
|
||||
builder.append(fbcName + ".set(" + x + ", " + y + ", " + z + ", " + id + ");");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder.append(fbcName + ".set(" + x + ", " + y + ", " + z + ", " + id + ", " + data + ");");
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else if (boundsPrefix != null && BlockCache.isFullBounds(bounds)) {
|
||||
builder.append(fbcName + ".set(" + x + ", " + y + ", " + z + ", " + id + ", " + data + ", " + fullBounds + ");");;
|
||||
}
|
||||
else {
|
||||
builder.append(fbcName + ".set(" + x + ", " + y + ", " + z + ", " + id + ", " + data + ", ");
|
||||
DebugUtil.toJava(bounds, builder);
|
||||
builder.append(");");
|
||||
|
|
|
@ -24,19 +24,20 @@ public class InteractRayTracing extends RayTracing {
|
|||
|
||||
protected boolean collides = false;
|
||||
|
||||
protected boolean strict = false;
|
||||
protected final boolean strict;
|
||||
|
||||
protected int lastBx, lastBy, lastBz;
|
||||
|
||||
protected int targetX, targetY, targetZ;
|
||||
|
||||
public InteractRayTracing() {
|
||||
super();
|
||||
this(false);
|
||||
}
|
||||
|
||||
public InteractRayTracing(boolean strict) {
|
||||
super();
|
||||
this.strict = strict;
|
||||
this.forceStepEndPos = false; // Not needed here.
|
||||
}
|
||||
|
||||
public BlockCache getBlockCache() {
|
||||
|
@ -200,4 +201,27 @@ public class InteractRayTracing extends RayTracing {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a directly usable test case (in a closure), for copy and paste to TestInteractRayTracing.
|
||||
* @param captureMargin
|
||||
* @param expectCollide
|
||||
* @return
|
||||
*/
|
||||
public String getTestCase(double captureMargin, boolean expectCollide) {
|
||||
FakeBlockCache recorder = new FakeBlockCache();
|
||||
recorder.set(this.blockCache, x0, y0, z0, x0 + dX, y0 + dY, z0 + dZ, captureMargin);
|
||||
StringBuilder builder = new StringBuilder(10000);
|
||||
// Add everything inside a closure for direct copy and paste.
|
||||
builder.append('{');
|
||||
// Set up the block cache.
|
||||
recorder.toJava(builder, "fbc", "");
|
||||
// Add the test case code.
|
||||
builder.append("InteractRayTracing rt = new CenteredInteractRayTracing(false, " + targetX + ", " + targetY + ", " + targetZ + "); rt.setBlockCache(fbc);");
|
||||
builder.append("TestRayTracing.runCoordinates(rt, new double[]{" + x0 + ", " + y0 + ", " + z0 + ", " + (x0 + dX) + ", " + (y0 + dY) + ", " + (z0 + dZ) + "}, " + expectCollide + ", " + !expectCollide + ", 0.0, false, \"ingame\");");
|
||||
builder.append("rt.cleanup(); fbc.cleanup();");
|
||||
builder.append('}');
|
||||
recorder.cleanup();
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.bukkit.Location;
|
|||
public abstract class RayTracing {
|
||||
|
||||
// /** End point coordinates (from, to) */
|
||||
// protected double x0, y0, z0, x1, y1, z1;
|
||||
protected double x0, y0, z0; // x1, y1, z1;
|
||||
|
||||
// /** Total distance between end points. */
|
||||
// protected double d;
|
||||
|
@ -33,6 +33,9 @@ public abstract class RayTracing {
|
|||
/** Tolerance for time, for checking the abort condition: 1.0 - t <= tol . */
|
||||
protected double tol = 0.0;
|
||||
|
||||
/** Force calling step at the end position, for the case it is reached with block transitions. */
|
||||
protected boolean forceStepEndPos = true;
|
||||
|
||||
/**
|
||||
* Counting the number of steps along the primary line. Step is incremented
|
||||
* before calling step(), and is 0 after set(...). Checking this from within
|
||||
|
@ -65,9 +68,9 @@ public abstract class RayTracing {
|
|||
* @param z1
|
||||
*/
|
||||
public void set(double x0, double y0, double z0, double x1, double y1, double z1) {
|
||||
// this.x0 = x0;
|
||||
// this.y0 = y0;
|
||||
// this.z0 = z0;
|
||||
this.x0 = x0;
|
||||
this.y0 = y0;
|
||||
this.z0 = z0;
|
||||
// this.x1 = x1;
|
||||
// this.y1 = y1;
|
||||
// this.z1 = z1;
|
||||
|
@ -136,7 +139,7 @@ public abstract class RayTracing {
|
|||
* "off by x-th digit" or "t=0 transition"). Consider correcting t on
|
||||
* base of the block coordinates in use.
|
||||
*/
|
||||
while (1.0 - t > tol) {
|
||||
while (t + tol < 1.0) {
|
||||
// Determine smallest time to block edge, per axis.
|
||||
tX = tDiff(dX, oX, blockX == endBlockX);
|
||||
tY = tDiff(dY, oY, blockY == endBlockY);
|
||||
|
@ -167,7 +170,7 @@ public abstract class RayTracing {
|
|||
}
|
||||
|
||||
// Abort if arrived.
|
||||
if (t + tMin >= 1.0 - tol && isEndBlock()) {
|
||||
if (t + tMin + tol >= 1.0 && isEndBlock()) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -201,10 +204,18 @@ public abstract class RayTracing {
|
|||
if (!handleTransitions(transitions, transX, transY, transZ, tMin)) {
|
||||
break;
|
||||
}
|
||||
// Check conditions for abort/end.
|
||||
if (forceStepEndPos && t + tol >= 1.0) {
|
||||
// Reached the end with transitions, ensure we check the end block.
|
||||
step(blockX, blockY, blockZ, oX, oY, oZ, 0.0, true);
|
||||
break;
|
||||
}
|
||||
|
||||
// Abort if done or exceeded maxSteps.
|
||||
if (transitions == 0 || step >= maxSteps) {
|
||||
} else {
|
||||
// No transitions, finished.
|
||||
break;
|
||||
}
|
||||
// Ensure not to go beyond maxSteps.
|
||||
if (step >= maxSteps) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -228,36 +239,48 @@ public abstract class RayTracing {
|
|||
}
|
||||
|
||||
// Apply all transitions to the primary line.
|
||||
double tcMin = 1.0; // Corrected absolute time to reach the resulting block position.
|
||||
if (transX) {
|
||||
if (dX > 0.0) {
|
||||
blockX ++;
|
||||
oX = 0.0;
|
||||
tcMin = Math.min(tcMin, ((double) blockX - x0) / dX);
|
||||
}
|
||||
else {
|
||||
blockX --;
|
||||
oX = 1.0;
|
||||
tcMin = Math.min(tcMin, (1.0 + (double) blockX - x0) / dX);
|
||||
}
|
||||
}
|
||||
if (transY) {
|
||||
if (dY > 0.0) {
|
||||
blockY ++;
|
||||
oY = 0.0;
|
||||
tcMin = Math.min(tcMin, ((double) blockY - y0) / dY);
|
||||
}
|
||||
else {
|
||||
blockY --;
|
||||
oY = 1.0;
|
||||
tcMin = Math.min(tcMin, (1.0 + (double) blockY - y0) / dY);
|
||||
}
|
||||
}
|
||||
if (transZ) {
|
||||
if (dZ > 0.0) {
|
||||
blockZ ++;
|
||||
oZ = 0.0;
|
||||
tcMin = Math.min(tcMin, ((double) blockZ - z0) / dZ);
|
||||
}
|
||||
else {
|
||||
blockZ --;
|
||||
oZ = 1.0;
|
||||
tcMin = Math.min(tcMin, (1.0 + (double) blockZ - z0) / dZ);
|
||||
}
|
||||
}
|
||||
// Correct time and offsets based on tcMin.
|
||||
oX = x0 + tcMin * dX - (double) blockX;
|
||||
oY = y0 + tcMin * dY - (double) blockY;
|
||||
oZ = z0 + tcMin * dZ - (double) blockZ;
|
||||
t = tcMin;
|
||||
return true; // Continue loop.
|
||||
}
|
||||
|
||||
|
|
|
@ -142,4 +142,14 @@ public class TestInteractRayTracing {
|
|||
bc.cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cases taken from ingame logging.
|
||||
*/
|
||||
@Test
|
||||
public void testIngame() {
|
||||
// Circle around the corners of 4 blocks with left button pressed down (random sample).
|
||||
// Bad end coords (should fail):
|
||||
{FakeBlockCache fbc = new FakeBlockCache(); double[] _fb = new double[]{0.0, 0.0, 0.0, 1.0, 1.0, 1.0};fbc.set(142, 67, 221, 3, 0, _fb);fbc.set(142, 67, 217, 3, 0, _fb);fbc.set(142, 69, 219, 0);fbc.set(142, 68, 218, 2, 0, _fb);fbc.set(142, 70, 220, 0);fbc.set(142, 71, 217, 0);fbc.set(142, 71, 221, 0);fbc.set(143, 67, 218, 3, 0, _fb);fbc.set(143, 68, 217, 2, 0, _fb);fbc.set(143, 68, 221, 2, 0, _fb);fbc.set(143, 69, 220, 0);fbc.set(143, 70, 219, 0);fbc.set(143, 71, 218, 0);fbc.set(144, 67, 219, 3, 0, _fb);fbc.set(144, 68, 220, 2, 0, _fb);fbc.set(144, 69, 217, 0);fbc.set(144, 69, 221, 31, 1, new double[] {0.09999999403953552, 0.0, 0.09999999403953552, 0.8999999761581421, 0.800000011920929, 0.8999999761581421});fbc.set(144, 70, 218, 0);fbc.set(144, 71, 219, 0);fbc.set(145, 67, 220, 3, 0, _fb);fbc.set(145, 68, 219, 2, 0, _fb);fbc.set(145, 69, 218, 0);fbc.set(145, 70, 217, 0);fbc.set(145, 70, 221, 0);fbc.set(145, 71, 220, 0);fbc.set(142, 68, 217, 2, 0, _fb);fbc.set(142, 68, 221, 2, 0, _fb);fbc.set(142, 67, 218, 3, 0, _fb);fbc.set(142, 69, 220, 0);fbc.set(142, 70, 219, 0);fbc.set(142, 71, 218, 0);fbc.set(143, 67, 217, 3, 0, _fb);fbc.set(143, 67, 221, 3, 0, _fb);fbc.set(143, 68, 218, 49, 0, _fb);fbc.set(143, 69, 219, 0);fbc.set(143, 70, 220, 0);fbc.set(143, 71, 217, 0);fbc.set(143, 71, 221, 0);fbc.set(144, 67, 220, 3, 0, _fb);fbc.set(144, 68, 219, 49, 0, _fb);fbc.set(144, 69, 218, 0);fbc.set(144, 70, 217, 0);fbc.set(144, 70, 221, 0);fbc.set(144, 71, 220, 0);fbc.set(145, 67, 219, 3, 0, _fb);fbc.set(145, 68, 220, 2, 0, _fb);fbc.set(145, 69, 217, 0);fbc.set(145, 69, 221, 50, 5, new double[] {0.4000000059604645, 0.0, 0.4000000059604645, 0.6000000238418579, 0.6000000238418579, 0.6000000238418579});fbc.set(145, 70, 218, 0);fbc.set(145, 71, 219, 0);fbc.set(142, 67, 219, 3, 0, _fb);fbc.set(142, 70, 218, 0);fbc.set(142, 69, 221, 31, 1, new double[] {0.09999999403953552, 0.0, 0.09999999403953552, 0.8999999761581421, 0.800000011920929, 0.8999999761581421});fbc.set(142, 69, 217, 0);fbc.set(142, 68, 220, 2, 0, _fb);fbc.set(142, 71, 219, 0);fbc.set(143, 67, 220, 3, 0, _fb);fbc.set(143, 68, 219, 49, 0, _fb);fbc.set(143, 69, 218, 0);fbc.set(143, 70, 217, 0);fbc.set(143, 70, 221, 0);fbc.set(143, 71, 220, 0);fbc.set(144, 67, 217, 3, 0, _fb);fbc.set(144, 67, 221, 3, 0, _fb);fbc.set(144, 68, 218, 49, 0, _fb);fbc.set(144, 69, 219, 0);fbc.set(144, 70, 220, 0);fbc.set(144, 71, 217, 0);fbc.set(144, 71, 221, 0);fbc.set(145, 67, 218, 3, 0, _fb);fbc.set(145, 68, 217, 2, 0, _fb);fbc.set(145, 68, 221, 2, 0, _fb);fbc.set(145, 69, 220, 0);fbc.set(145, 70, 219, 0);fbc.set(145, 71, 218, 0);fbc.set(142, 68, 219, 2, 0, _fb);fbc.set(142, 70, 217, 0);fbc.set(142, 67, 220, 3, 0, _fb);fbc.set(142, 69, 218, 31, 1, new double[] {0.09999999403953552, 0.0, 0.09999999403953552, 0.8999999761581421, 0.800000011920929, 0.8999999761581421});fbc.set(142, 70, 221, 0);fbc.set(142, 71, 220, 0);fbc.set(143, 67, 219, 3, 0, _fb);fbc.set(143, 68, 220, 2, 0, _fb);fbc.set(143, 69, 217, 0);fbc.set(143, 69, 221, 0);fbc.set(143, 70, 218, 0);fbc.set(143, 71, 219, 0);fbc.set(144, 67, 218, 3, 0, _fb);fbc.set(144, 68, 217, 2, 0, _fb);fbc.set(144, 68, 221, 2, 0, _fb);fbc.set(144, 69, 220, 0);fbc.set(144, 70, 219, 0);fbc.set(144, 71, 218, 0);fbc.set(145, 67, 217, 3, 0, _fb);fbc.set(145, 67, 221, 3, 0, _fb);fbc.set(145, 68, 218, 2, 0, _fb);fbc.set(145, 69, 219, 0);fbc.set(145, 70, 220, 0);fbc.set(145, 71, 217, 0);fbc.set(145, 71, 221, 0);InteractRayTracing rt = new CenteredInteractRayTracing(false, 144, 68, 218); rt.setBlockCache(fbc);TestRayTracing.runCoordinates(rt, new double[]{144.01901074886095, 70.62, 220.1221052415879, 144.07776715103876, 68.99423513239826, 219.0}, true, false, 0.0, false, "ingame");rt.cleanup(); fbc.cleanup();}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -111,16 +111,16 @@ public class TestRayTracing {
|
|||
doFail("dT < 0 at t = " + StringUtil.fdec3.format(t), coords);
|
||||
}
|
||||
|
||||
// TODO: Check if this check makes sense at all (dT=0 happens during multi-transitions.)l.
|
||||
// TODO: Check if this check makes sense at all (dT=0 happens during multi-transitions).
|
||||
// if (dT == 0.0 && 1.0 - (t + dT) > tol) {
|
||||
// if (!ignEdge(oX, dX) && !ignEdge(oY, dY) && !ignEdge(oZ, dZ)) {
|
||||
// doFail("Premature dT = 0 at t = " + StringUtil.fdec3.format(t), coords);
|
||||
// }
|
||||
// }
|
||||
|
||||
checkOffset(oX, "x");
|
||||
checkOffset(oY, "y");
|
||||
checkOffset(oZ, "z");
|
||||
// checkOffset(oX, "x");
|
||||
// checkOffset(oY, "y");
|
||||
// checkOffset(oZ, "z");
|
||||
|
||||
// TODO: check with last block coordinates
|
||||
if (lbx == blockX && lby == blockY && lbz == blockZ) {
|
||||
|
@ -143,11 +143,11 @@ public class TestRayTracing {
|
|||
return true;
|
||||
}
|
||||
|
||||
private void checkOffset(double offset, String name) {
|
||||
if (offset < 0.0 || offset > 1.0) {
|
||||
doFail("Bad " + name + "-offset: " + offset, coords);
|
||||
}
|
||||
}
|
||||
// private void checkOffset(double offset, String name) {
|
||||
// if (offset < 0.0 || offset > 1.0) {
|
||||
// doFail("Bad " + name + "-offset: " + offset, coords);
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void loop() {
|
||||
|
@ -193,17 +193,17 @@ public class TestRayTracing {
|
|||
return crt;
|
||||
}
|
||||
|
||||
public static void dump(int blockX, int blockY, int blockZ, double oX, double oY, double oZ, double t, double dT) {
|
||||
public static void dump(int blockX, int blockY, int blockZ, double oX, double oY, double oZ, double t, double dT, boolean isPrimary) {
|
||||
String sdt = StringUtil.fdec3.format(dT);
|
||||
if ("0".equals(sdt) && dT > 0) sdt = "0.X";
|
||||
System.out.println(StringUtil.fdec3.format(t) + " (+" + sdt + "): " + blockX + ", "+blockY + ", " + blockZ + " / " + StringUtil.fdec3.format(oX) + ", " + StringUtil.fdec3.format(oY)+ ", " + StringUtil.fdec3.format(oZ));
|
||||
System.out.println(StringUtil.fdec3.format(t) + " (+" + sdt + "): " + blockX + ", "+blockY + ", " + blockZ + " / " + StringUtil.fdec3.format(oX) + ", " + StringUtil.fdec3.format(oY)+ ", " + StringUtil.fdec3.format(oZ) + (isPrimary ? " (primary)" : ""));
|
||||
}
|
||||
|
||||
public static RayTracing dumpRawRayTracing(final double[] coords) {
|
||||
RayTracing rt = new RayTracing(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]) {
|
||||
@Override
|
||||
protected boolean step(int blockX, int blockY, int blockZ, double oX, double oY, double oZ, double dT, boolean isPrimary) {
|
||||
dump(blockX, blockY, blockZ, oX, oY, oZ, t, dT);
|
||||
dump(blockX, blockY, blockZ, oX, oY, oZ, t, dT, isPrimary);
|
||||
if (step > maxSteps(dX, dY, dZ)) {
|
||||
System.out.println("[WARNING] Max steps exceeded: " + maxSteps(dX, dY, dZ));
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue
Block a user