mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-09-27 14:13:11 +02:00
Let blockinteract.direction check queued packets. Unify loop (visible).
* Add a class to loop the flying queue with a block as target (look only). * Pass the flyingHandle to sub checks (doesn't necessarily make sense with reach - should probably re-check reach with the used flying queue state, but that's more complicated due to the possibility of split pos vs. look). * Use the loop class both for visible and direction (not reach). Likely similar has to be done with BlockPlace and BlockBreak - would be good to find a skipping heuristic for blockbreak.direction etc., so we know we have successfully checked that block from that exact position for this player and nothing has happened between (and so on, or a more relaxed heuristic).
This commit is contained in:
parent
970ed6b126
commit
180cf8a3c3
@ -33,6 +33,7 @@ import fr.neatmonster.nocheatplus.checks.combined.CombinedConfig;
|
||||
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
|
||||
import fr.neatmonster.nocheatplus.checks.moving.util.MovingUtil;
|
||||
import fr.neatmonster.nocheatplus.checks.net.FlyingQueueHandle;
|
||||
import fr.neatmonster.nocheatplus.checks.net.model.DataPacketFlying;
|
||||
import fr.neatmonster.nocheatplus.compat.Bridge1_9;
|
||||
import fr.neatmonster.nocheatplus.compat.BridgeHealth;
|
||||
import fr.neatmonster.nocheatplus.compat.BridgeMisc;
|
||||
@ -185,10 +186,27 @@ public class BlockInteractListener extends CheckListener {
|
||||
}
|
||||
else {
|
||||
data.subsequentCancel = 0;
|
||||
if (data.debug) {
|
||||
if (flyingHandle.isFlyingQueueFetched()) {
|
||||
// Log which entry was used.
|
||||
logUsedFlyingPacket(player, flyingHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
useLoc.setWorld(null);
|
||||
}
|
||||
|
||||
private void logUsedFlyingPacket(final Player player, final FlyingQueueHandle flyingHandle) {
|
||||
final DataPacketFlying[] queue = flyingHandle.getHandle();
|
||||
for (int i = 0; i < queue.length; i++) {
|
||||
final DataPacketFlying packet = queue[i];
|
||||
if (packet != null) {
|
||||
debug(player, "Flying packet queue used at index " + i + ": pitch=" + packet.getPitch() + ",yaw=" + packet.getYaw());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onCancelInteract(final Player player, final Block block, final BlockFace face,
|
||||
final PlayerInteractEvent event, final int previousLastTick, final boolean preventUseItem,
|
||||
final BlockInteractData data, final BlockInteractConfig cc) {
|
||||
|
@ -22,6 +22,7 @@ import org.bukkit.util.Vector;
|
||||
import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.net.FlyingQueueHandle;
|
||||
import fr.neatmonster.nocheatplus.checks.net.FlyingQueueLookBlockChecker;
|
||||
import fr.neatmonster.nocheatplus.utilities.collision.CollideRayVsAABB;
|
||||
import fr.neatmonster.nocheatplus.utilities.collision.ICollideRayVsAABB;
|
||||
import fr.neatmonster.nocheatplus.utilities.location.LocUtil;
|
||||
@ -31,7 +32,43 @@ import fr.neatmonster.nocheatplus.utilities.location.LocUtil;
|
||||
*/
|
||||
public class Direction extends Check {
|
||||
|
||||
private final class BoulderChecker extends FlyingQueueLookBlockChecker {
|
||||
// (Not static for convenience.)
|
||||
|
||||
private double minDistance;
|
||||
|
||||
@Override
|
||||
protected boolean check(final double x, final double y, final double z,
|
||||
final float yaw, final float pitch,
|
||||
final int blockX, final int blockY, final int blockZ) {
|
||||
final double distance = checkBoulder(x, y, z, yaw, pitch, blockX, blockY, blockZ);
|
||||
if (distance == Double.MAX_VALUE) {
|
||||
// minDistance is not updated, in case the information is interesting ever.
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
minDistance = Math.min(minDistance, distance);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkFlyingQueue(double x, double y, double z, float oldYaw, float oldPitch, int blockX,
|
||||
int blockY, int blockZ, FlyingQueueHandle flyingHandle) {
|
||||
minDistance = Double.MAX_VALUE;
|
||||
return super.checkFlyingQueue(x, y, z, oldYaw, oldPitch, blockX, blockY, blockZ, flyingHandle);
|
||||
}
|
||||
|
||||
public double getMinDistance() {
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final ICollideRayVsAABB boulder = new CollideRayVsAABB();
|
||||
private final Location useLoc = new Location(null, 0, 0, 0);
|
||||
|
||||
private final BoulderChecker checker = new BoulderChecker();
|
||||
|
||||
/**
|
||||
* Instantiates a new direction check.
|
||||
@ -53,20 +90,27 @@ public class Direction extends Check {
|
||||
final FlyingQueueHandle flyingHandle, final BlockInteractData data, final BlockInteractConfig cc) {
|
||||
|
||||
boolean cancel = false;
|
||||
|
||||
// How far "off" is the player with their aim.
|
||||
final Vector direction = loc.getDirection();
|
||||
// Initialize fully each time.
|
||||
boulder.setFindNearestPointIfNotCollide(true)
|
||||
.setRay(loc.getX(), loc.getY() + player.getEyeHeight(), loc.getZ(),
|
||||
direction.getX(), direction.getY(), direction.getZ())
|
||||
.setAABB(block.getX(), block.getY(), block.getZ(), 0.1)
|
||||
.loop();
|
||||
// TODO: if (boulder.collides()) { // Check flying queue.
|
||||
|
||||
if (!boulder.collides()) {
|
||||
final double distance = Math.sqrt(boulder.getClosestDistanceSquared());
|
||||
final double x = loc.getX();
|
||||
final double y = loc.getY() + player.getEyeHeight();
|
||||
final double z = loc.getZ();
|
||||
final int blockX = block.getX();
|
||||
final int blockY = block.getY();
|
||||
final int blockZ = block.getZ();
|
||||
// The distance is squared initially.
|
||||
double distance = checkBoulder(x, y, z, loc.getYaw(), loc.getPitch(), blockX, blockY, blockZ);
|
||||
if (distance != Double.MAX_VALUE) {
|
||||
if (checker.checkFlyingQueue(x, y, z, loc.getYaw(), loc.getPitch(),
|
||||
blockX, blockY, blockZ, flyingHandle)) {
|
||||
distance = Double.MAX_VALUE;
|
||||
}
|
||||
else {
|
||||
distance = Math.min(distance, checker.getMinDistance());
|
||||
}
|
||||
}
|
||||
|
||||
if (distance != Double.MAX_VALUE) {
|
||||
distance = Math.sqrt(distance);
|
||||
if (data.debug) {
|
||||
outputDebugFail(player, boulder, distance);
|
||||
}
|
||||
@ -83,10 +127,46 @@ public class Direction extends Check {
|
||||
// Player did likely nothing wrong, reduce violation counter to reward them.
|
||||
data.directionVL *= 0.9D;
|
||||
}
|
||||
|
||||
return cancel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check one configuration.
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param yaw
|
||||
* @param pitch
|
||||
* @param blockX
|
||||
* @param blockY
|
||||
* @param blockZ
|
||||
* @return Double.MAX_VALUE if this passes the check, otherwise the squared
|
||||
* violation distance (some measure).
|
||||
*/
|
||||
private double checkBoulder(final double x, final double y, final double z,
|
||||
final float yaw, final float pitch,
|
||||
final int blockX, final int blockY, final int blockZ) {
|
||||
useLoc.setYaw(yaw);
|
||||
useLoc.setPitch(pitch);
|
||||
final Vector dir = useLoc.getDirection(); // TODO: More efficient.
|
||||
final double dirX = dir.getX();
|
||||
final double dirY = dir.getY();
|
||||
final double dirZ = dir.getZ();
|
||||
// Initialize fully each time.
|
||||
boulder.setFindNearestPointIfNotCollide(true)
|
||||
.setRay(x, y, z, dirX, dirY, dirZ)
|
||||
.setAABB(blockX, blockY, blockZ, 0.1)
|
||||
.loop();
|
||||
// Interpret result.
|
||||
if (boulder.collides()) {
|
||||
return Double.MAX_VALUE;
|
||||
}
|
||||
else {
|
||||
return boulder.getClosestDistanceSquared();
|
||||
}
|
||||
}
|
||||
|
||||
private void outputDebugFail(Player player, ICollideRayVsAABB boulder, double distance) {
|
||||
debug(player, "Failed: collides: " + boulder.collides() + " , dist: " + distance + " , pos: " + LocUtil.simpleFormat(boulder));
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ public class Reach extends Check {
|
||||
|
||||
// Distance is calculated from eye location to center of targeted block. If the player is further away from their
|
||||
// target than allowed, the difference will be assigned to "distance".
|
||||
// TODO: On failure loop through flying queue, and do set not working entries to null (!).
|
||||
final double distance = TrigUtil.distance(loc.getX(), loc.getY() + player.getEyeHeight(), loc.getZ(), 0.5 + block.getX(), 0.5 + block.getY(), 0.5 + block.getZ()) - distanceLimit;
|
||||
|
||||
if (distance > 0) {
|
||||
|
@ -28,16 +28,69 @@ import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.ViolationData;
|
||||
import fr.neatmonster.nocheatplus.checks.net.FlyingQueueHandle;
|
||||
import fr.neatmonster.nocheatplus.checks.net.model.DataPacketFlying;
|
||||
import fr.neatmonster.nocheatplus.checks.net.FlyingQueueLookBlockChecker;
|
||||
import fr.neatmonster.nocheatplus.utilities.StringUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.collision.InteractRayTracing;
|
||||
import fr.neatmonster.nocheatplus.utilities.location.LocUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.location.TrigUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
|
||||
import fr.neatmonster.nocheatplus.utilities.map.WrapBlockCache;
|
||||
|
||||
public class Visible extends Check {
|
||||
|
||||
private final class RayChecker extends FlyingQueueLookBlockChecker {
|
||||
|
||||
private BlockFace face;
|
||||
private List<String> tags;
|
||||
private boolean debug;
|
||||
private Player player;
|
||||
|
||||
@Override
|
||||
protected boolean check(final double x, final double y, final double z,
|
||||
final float yaw, final float pitch,
|
||||
final int blockX, final int blockY, final int blockZ) {
|
||||
// Run ray-tracing again with updated pitch and yaw.
|
||||
useLoc.setPitch(pitch);
|
||||
useLoc.setYaw(yaw);
|
||||
final Vector direction = useLoc.getDirection(); // TODO: Better.
|
||||
tags.clear();
|
||||
if (checkRayTracing(x, y, z, direction.getX(), direction.getY(), direction.getZ(), blockX, blockY, blockZ, face, tags, debug)) {
|
||||
// Collision still.
|
||||
if (debug) {
|
||||
debug(player, "pitch=" + pitch + ",yaw=" + yaw + " tags=" + StringUtil.join(tags, "+"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean checkFlyingQueue(double x, double y, double z, float oldYaw, float oldPitch, int blockX,
|
||||
int blockY, int blockZ, FlyingQueueHandle flyingHandle,
|
||||
BlockFace face, List<String> tags, boolean debug, Player player) {
|
||||
this.face = face;
|
||||
this.tags = tags;
|
||||
this.debug = debug;
|
||||
this.player = player;
|
||||
return super.checkFlyingQueue(x, y, z, oldYaw, oldPitch, blockX, blockY, blockZ, flyingHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkFlyingQueue(double x, double y, double z, float oldYaw, float oldPitch, int blockX,
|
||||
int blockY, int blockZ, FlyingQueueHandle flyingHandle) {
|
||||
throw new UnsupportedOperationException("Use the other method.");
|
||||
}
|
||||
|
||||
public void cleanup () {
|
||||
this.player = null;
|
||||
this.face = null;
|
||||
this.debug = false;
|
||||
this.tags = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final WrapBlockCache wrapBlockCache;
|
||||
|
||||
/**
|
||||
@ -45,6 +98,8 @@ public class Visible extends Check {
|
||||
*/
|
||||
private final InteractRayTracing rayTracing = new InteractRayTracing(false);
|
||||
|
||||
private final RayChecker checker = new RayChecker();
|
||||
|
||||
private final List<String> tags = new ArrayList<String>();
|
||||
|
||||
/** For temporary use, no nested use, setWorld(null) after use, etc. */
|
||||
@ -86,52 +141,15 @@ public class Visible extends Check {
|
||||
if (collides) {
|
||||
// Debug output.
|
||||
if (data.debug) {
|
||||
debug(player, "pitch=" + loc.getPitch() + " yaw=" + loc.getYaw() + " tags=" + StringUtil.join(tags, "+"));
|
||||
debug(player, "pitch=" + loc.getPitch() + ",yaw=" + loc.getYaw() + " tags=" + StringUtil.join(tags, "+"));
|
||||
}
|
||||
// Re-check with flying packets.
|
||||
final DataPacketFlying[] flyingQueue = flyingHandle.getHandle();
|
||||
// TODO: Maybe just the latest one does (!).+
|
||||
LocUtil.set(useLoc, loc);
|
||||
final float oldPitch = useLoc.getPitch();
|
||||
final float oldYaw = useLoc.getYaw();
|
||||
// TODO: Specific max-recheck-count (likely doesn't equal packet count).
|
||||
for (int i = 0; i < flyingQueue.length; i++) {
|
||||
final DataPacketFlying packetData = flyingQueue[i];
|
||||
if (packetData == null) {
|
||||
// Other checks have pre-selected.
|
||||
continue;
|
||||
}
|
||||
// TODO: Allow if within threshold(s) of last move.
|
||||
// TODO: Confine by distance.
|
||||
// Abort/skipping conditions.
|
||||
// if (packetData.hasPos) {
|
||||
// break;
|
||||
// }
|
||||
if (!packetData.hasLook) {
|
||||
flyingQueue[i] = null;
|
||||
continue;
|
||||
}
|
||||
// TODO: Might skip last pitch+yaw as well.
|
||||
if (packetData.getPitch() == oldPitch && packetData.getYaw() == oldYaw) {
|
||||
flyingQueue[i] = null;
|
||||
continue;
|
||||
}
|
||||
// Run ray-tracing again with updated pitch and yaw.
|
||||
useLoc.setPitch(packetData.getPitch());
|
||||
useLoc.setYaw(packetData.getYaw());
|
||||
direction = useLoc.getDirection(); // TODO: Better.
|
||||
tags.clear();
|
||||
tags.add("flying(" + i + ")"); // Interesting if this gets through.
|
||||
collides = checkRayTracing(eyeX, eyeY, eyeZ, direction.getX(), direction.getY(), direction.getZ(), blockX, blockY, blockZ, face, tags, data.debug);
|
||||
if (!collides) {
|
||||
break;
|
||||
}
|
||||
flyingQueue[i] = null;
|
||||
// Debug output.
|
||||
if (data.debug) {
|
||||
debug(player, "pitch=" + loc.getPitch() + " yaw=" + loc.getYaw() + " tags=" + StringUtil.join(tags, "+"));
|
||||
}
|
||||
if (checker.checkFlyingQueue(eyeX, eyeY, eyeZ, useLoc.getYaw(), useLoc.getPitch(),
|
||||
blockX, blockY, blockZ, flyingHandle, face, tags, data.debug, player)) {
|
||||
// Check passed.
|
||||
collides = false;
|
||||
}
|
||||
checker.cleanup();
|
||||
useLoc.setWorld(null);
|
||||
}
|
||||
// Cleanup.
|
||||
@ -155,7 +173,7 @@ public class Visible extends Check {
|
||||
else {
|
||||
data.visibleVL *= 0.99;
|
||||
if (data.debug) {
|
||||
debug(player, "pitch=" + loc.getPitch() + " yaw=" + loc.getYaw() + " tags=" + StringUtil.join(tags, "+"));
|
||||
debug(player, "pitch=" + loc.getPitch() + ",yaw=" + loc.getYaw() + " tags=" + StringUtil.join(tags, "+"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,4 +31,8 @@ public class FlyingQueueHandle implements IHandle<DataPacketFlying[]> {
|
||||
return queue;
|
||||
}
|
||||
|
||||
public boolean isFlyingQueueFetched() {
|
||||
return queue != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,83 @@
|
||||
package fr.neatmonster.nocheatplus.checks.net;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.net.model.DataPacketFlying;
|
||||
|
||||
/**
|
||||
* A simple loop through checker for the flying queue feature.
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public abstract class FlyingQueueLookBlockChecker {
|
||||
|
||||
/**
|
||||
* Override to prevent setting elements that can't be used or for which
|
||||
* check returned false to null.
|
||||
*/
|
||||
protected boolean setUnusableToNull = true;
|
||||
|
||||
protected abstract boolean check(final double x, final double y, final double z,
|
||||
final float yaw, final float pitch,
|
||||
final int blockX, final int blockY, final int blockZ);
|
||||
|
||||
/**
|
||||
* Run check with the given start position (e.g. eye coordinates), but use
|
||||
* yaw and pitch from the flying queue. Non matching entries are nulled,
|
||||
* unless setUnusableToNull is set to false.
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param oldYaw
|
||||
* @param oldPitch
|
||||
* @param blockX
|
||||
* @param blockY
|
||||
* @param blockZ
|
||||
* @param flyingHandle
|
||||
* @return True, if check returned true (the first time is returned). False
|
||||
* if the queue is empty or check has not returned true for any
|
||||
* contained element. Special return values have to be set
|
||||
* elsewhere. An empty queue also yields false as return value.
|
||||
*/
|
||||
public boolean checkFlyingQueue(final double x, final double y, final double z,
|
||||
final float oldYaw, final float oldPitch,
|
||||
final int blockX, final int blockY, final int blockZ, final FlyingQueueHandle flyingHandle) {
|
||||
final DataPacketFlying[] queue = flyingHandle.getHandle();
|
||||
if (queue.length == 0) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < queue.length; i++) {
|
||||
final DataPacketFlying packetData = queue[i];
|
||||
if (packetData == null) {
|
||||
continue;
|
||||
}
|
||||
if (!packetData.hasLook) {
|
||||
if (setUnusableToNull) {
|
||||
queue[i] = null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
final float yaw = packetData.getYaw();
|
||||
final float pitch = packetData.getPitch();
|
||||
// Simple heuristic: reduce impact of checking by skipping redundant entries.
|
||||
// TODO: Other heuristic / what's typical?
|
||||
if (yaw == oldYaw && pitch == oldPitch) {
|
||||
if (setUnusableToNull) {
|
||||
queue[i] = null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// TODO: Consider support some other type of metric (possibly checking positions too?);
|
||||
if (check(x, y, z, yaw, pitch, blockX, blockY, blockZ)) {
|
||||
// TODO: Consider to remember index and entry as well?
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (setUnusableToNull) {
|
||||
queue[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user