[BREAKING] Unify block (interact/place/break) direction checks.
Might break configurations.
This commit is contained in:
parent
2cca81f39a
commit
73f420527c
|
@ -15,6 +15,7 @@
|
|||
package fr.neatmonster.nocheatplus.checks.blockbreak;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
|
@ -36,6 +37,8 @@ import fr.neatmonster.nocheatplus.checks.blockinteract.BlockInteractData;
|
|||
import fr.neatmonster.nocheatplus.checks.blockinteract.BlockInteractListener;
|
||||
import fr.neatmonster.nocheatplus.checks.inventory.Items;
|
||||
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.AlmostBoolean;
|
||||
import fr.neatmonster.nocheatplus.compat.Bridge1_9;
|
||||
import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager;
|
||||
|
@ -74,6 +77,9 @@ public class BlockBreakListener extends CheckListener {
|
|||
private final Counters counters = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Counters.class);
|
||||
private final int idCancelDIllegalItem = counters.registerKey("illegalitem");
|
||||
|
||||
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
|
||||
private final Location useLoc = new Location(null, 0, 0, 0);
|
||||
|
||||
public BlockBreakListener(){
|
||||
super(CheckType.BLOCKBREAK);
|
||||
}
|
||||
|
@ -149,26 +155,36 @@ public class BlockBreakListener extends CheckListener {
|
|||
cancelled = true;
|
||||
}
|
||||
|
||||
// Is the block really in reach distance?
|
||||
if (!cancelled) {
|
||||
if (isInteractBlock && bdata.isPassedCheck(CheckType.BLOCKINTERACT_REACH)) {
|
||||
skippedRedundantChecks ++;
|
||||
final FlyingQueueHandle flyingHandle;
|
||||
if (cc.reachCheck || cc.directionCheck) {
|
||||
flyingHandle = new FlyingQueueHandle(player);
|
||||
final Location loc = player.getLocation(useLoc);
|
||||
// Is the block really in reach distance?
|
||||
if (!cancelled) {
|
||||
if (isInteractBlock && bdata.isPassedCheck(CheckType.BLOCKINTERACT_REACH)) {
|
||||
skippedRedundantChecks ++;
|
||||
}
|
||||
else if (reach.isEnabled(player) && reach.check(player, block, data)) {
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
else if (reach.isEnabled(player) && reach.check(player, block, data)) {
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Did the player look at the block at all?
|
||||
// TODO: Skip if checks were run on this block (all sorts of hashes/conditions).
|
||||
if (!cancelled) {
|
||||
if (isInteractBlock && (bdata.isPassedCheck(CheckType.BLOCKINTERACT_DIRECTION)
|
||||
|| bdata.isPassedCheck(CheckType.BLOCKINTERACT_VISIBLE))) {
|
||||
skippedRedundantChecks ++;
|
||||
}
|
||||
else if (direction.isEnabled(player) && direction.check(player, block, data)) {
|
||||
cancelled = true;
|
||||
// Did the player look at the block at all?
|
||||
// TODO: Skip if checks were run on this block (all sorts of hashes/conditions).
|
||||
if (!cancelled) {
|
||||
if (isInteractBlock && (bdata.isPassedCheck(CheckType.BLOCKINTERACT_DIRECTION)
|
||||
|| bdata.isPassedCheck(CheckType.BLOCKINTERACT_VISIBLE))) {
|
||||
skippedRedundantChecks ++;
|
||||
}
|
||||
else if (direction.isEnabled(player) && direction.check(player, loc, block, flyingHandle,
|
||||
data, cc)) {
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
useLoc.setWorld(null);
|
||||
}
|
||||
else {
|
||||
flyingHandle = null;
|
||||
}
|
||||
|
||||
// Destroying liquid blocks.
|
||||
|
@ -192,7 +208,7 @@ public class BlockBreakListener extends CheckListener {
|
|||
// data.clickedX = Integer.MAX_VALUE;
|
||||
// Debug log (only if not cancelled, to avoid spam).
|
||||
if (data.debug) {
|
||||
debugBlockBreakResult(player, block, skippedRedundantChecks);
|
||||
debugBlockBreakResult(player, block, skippedRedundantChecks, flyingHandle);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,13 +225,22 @@ public class BlockBreakListener extends CheckListener {
|
|||
isInstaBreak = AlmostBoolean.NO;
|
||||
}
|
||||
|
||||
private void debugBlockBreakResult(final Player player, final Block block, final int skippedRedundantChecks) {
|
||||
private void debugBlockBreakResult(final Player player, final Block block, final int skippedRedundantChecks,
|
||||
final FlyingQueueHandle flyingHandle) {
|
||||
debug(player, "Block break(" + block.getType() + "): " + block.getX() + ", " + block.getY() + ", " + block.getZ());
|
||||
BlockInteractListener.debugBlockVSBlockInteract(player, checkType, block, "onBlockBreak",
|
||||
Action.LEFT_CLICK_BLOCK);
|
||||
if (skippedRedundantChecks > 0) {
|
||||
debug(player, "Skipped redundant checks: " + skippedRedundantChecks);
|
||||
}
|
||||
if (flyingHandle != null && flyingHandle.isFlyingQueueFetched()) {
|
||||
final int flyingIndex = flyingHandle.getFirstIndexWithContentIfFetched();
|
||||
final DataPacketFlying packet = flyingHandle.getIfFetched(flyingIndex);
|
||||
if (packet != null) {
|
||||
debug(player, "Flying packet queue used at index " + flyingIndex + ": pitch=" + packet.getPitch() + ",yaw=" + packet.getYaw());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,23 +14,17 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.checks.blockbreak;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.actions.ActionList;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.utilities.collision.CollisionUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.location.TrigUtil;
|
||||
import fr.neatmonster.nocheatplus.checks.generic.block.AbstractBlockDirectionCheck;
|
||||
|
||||
/**
|
||||
* The Direction check will find out if a player tried to interact with something that's not in their field of view.
|
||||
* The Direction check will find out if a player tried to interact with
|
||||
* something that's not in their field of view.
|
||||
*/
|
||||
public class Direction extends Check {
|
||||
|
||||
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
|
||||
private final Location useLoc = new Location(null, 0, 0, 0);
|
||||
public class Direction extends AbstractBlockDirectionCheck<BlockBreakData, BlockBreakConfig> {
|
||||
|
||||
/**
|
||||
* Instantiates a new direction check.
|
||||
|
@ -39,41 +33,20 @@ public class Direction extends Check {
|
|||
super(CheckType.BLOCKBREAK_DIRECTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a player.
|
||||
*
|
||||
* @param player
|
||||
* the player
|
||||
* @param location
|
||||
* the location
|
||||
* @return true, if successful
|
||||
*/
|
||||
public boolean check(final Player player, final Block block, final BlockBreakData data) {
|
||||
|
||||
boolean cancel = false;
|
||||
|
||||
// How far "off" is the player with their aim. We calculate from the players eye location and view direction to
|
||||
// the center of the target block. If the line of sight is more too far off, "off" will be bigger than 0.
|
||||
final Location loc = player.getLocation(useLoc);
|
||||
final Vector direction = loc.getDirection();
|
||||
final double off = CollisionUtil.directionCheck(loc, player.getEyeHeight(), direction, block, TrigUtil.DIRECTION_PRECISION);
|
||||
|
||||
if (off > 0.1D) {
|
||||
// Player failed the check. Let's try to guess how far they were from looking directly to the block...
|
||||
final Vector blockEyes = new Vector(0.5 + block.getX() - loc.getX(), 0.5 + block.getY() - loc.getY() - player.getEyeHeight(), 0.5 + block.getZ() - loc.getZ());
|
||||
final double distance = blockEyes.crossProduct(direction).length() / direction.length();
|
||||
|
||||
// Add the overall violation level of the check.
|
||||
data.directionVL += distance;
|
||||
|
||||
// Execute whatever actions are associated with this check and the violation level and find out if we should
|
||||
// cancel the event.
|
||||
cancel = executeActions(player, data.directionVL, distance, BlockBreakConfig.getConfig(player).directionActions).willCancel();
|
||||
} else {
|
||||
// Player did likely nothing wrong, reduce violation counter to reward them.
|
||||
data.directionVL *= 0.9D;
|
||||
}
|
||||
useLoc.setWorld(null);
|
||||
return cancel;
|
||||
@Override
|
||||
protected double addVL(Player player, double distance, BlockBreakData data, BlockBreakConfig cc) {
|
||||
data.directionVL += distance;
|
||||
return data.directionVL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ActionList getActions(BlockBreakConfig cc) {
|
||||
return cc.directionActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cooldown(Player player, BlockBreakData data, BlockBreakConfig cc) {
|
||||
data.directionVL *= 0.9D;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,61 +14,17 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.checks.blockinteract;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.actions.ActionList;
|
||||
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;
|
||||
import fr.neatmonster.nocheatplus.checks.generic.block.AbstractBlockDirectionCheck;
|
||||
|
||||
/**
|
||||
* The Direction check will find out if a player tried to interact with something that's not in their field of view.
|
||||
* The Direction check will find out if a player tried to interact with
|
||||
* something that's not in their field of view.
|
||||
*/
|
||||
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();
|
||||
public class Direction extends AbstractBlockDirectionCheck<BlockInteractData, BlockInteractConfig> {
|
||||
|
||||
/**
|
||||
* Instantiates a new direction check.
|
||||
|
@ -77,99 +33,21 @@ public class Direction extends Check {
|
|||
super(CheckType.BLOCKINTERACT_DIRECTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a player.
|
||||
*
|
||||
* @param player
|
||||
* the player
|
||||
* @param blockLocation
|
||||
* the location
|
||||
* @return true, if successful
|
||||
*/
|
||||
public boolean check(final Player player, final Location loc, final Block block,
|
||||
final FlyingQueueHandle flyingHandle, final BlockInteractData data, final BlockInteractConfig cc) {
|
||||
|
||||
boolean cancel = false;
|
||||
// How far "off" is the player with their aim.
|
||||
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);
|
||||
}
|
||||
|
||||
// Add the overall violation level of the check.
|
||||
data.directionVL += distance;
|
||||
|
||||
// TODO: Set distance parameter.
|
||||
|
||||
// Execute whatever actions are associated with this check and the violation level and find out if we should
|
||||
// cancel the event.
|
||||
cancel = executeActions(player, data.directionVL, distance, cc.directionActions).willCancel();
|
||||
} else {
|
||||
// Player did likely nothing wrong, reduce violation counter to reward them.
|
||||
data.directionVL *= 0.9D;
|
||||
data.addPassedCheck(this.type);
|
||||
}
|
||||
return cancel;
|
||||
@Override
|
||||
protected double addVL(Player player, double distance, BlockInteractData data, BlockInteractConfig cc) {
|
||||
data.directionVL += distance;
|
||||
return data.directionVL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
@Override
|
||||
protected ActionList getActions(BlockInteractConfig cc) {
|
||||
return cc.directionActions;
|
||||
}
|
||||
|
||||
private void outputDebugFail(Player player, ICollideRayVsAABB boulder, double distance) {
|
||||
debug(player, "Failed: collides: " + boulder.collides() + " , dist: " + distance + " , pos: " + LocUtil.simpleFormat(boulder));
|
||||
@Override
|
||||
protected void cooldown(Player player, BlockInteractData data, BlockInteractConfig cc) {
|
||||
data.directionVL *= 0.9D;
|
||||
data.addPassedCheck(this.type);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ import fr.neatmonster.nocheatplus.checks.combined.CombinedConfig;
|
|||
import fr.neatmonster.nocheatplus.checks.combined.Improbable;
|
||||
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
|
||||
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.BridgeMisc;
|
||||
import fr.neatmonster.nocheatplus.permissions.Permissions;
|
||||
|
@ -197,24 +199,33 @@ public class BlockPlaceListener extends CheckListener {
|
|||
cancelled = true;
|
||||
}
|
||||
|
||||
// Reach check (distance).
|
||||
if (!cancelled && !shouldSkipSome) {
|
||||
if (isInteractBlock && bdata.isPassedCheck(CheckType.BLOCKINTERACT_REACH)) {
|
||||
skippedRedundantChecks ++;
|
||||
final FlyingQueueHandle flyingHandle;
|
||||
if (cc.reachCheck || cc.directionCheck) {
|
||||
flyingHandle = new FlyingQueueHandle(player);
|
||||
final Location loc = player.getLocation(useLoc);
|
||||
// Reach check (distance).
|
||||
if (!cancelled && !shouldSkipSome) {
|
||||
if (isInteractBlock && bdata.isPassedCheck(CheckType.BLOCKINTERACT_REACH)) {
|
||||
skippedRedundantChecks ++;
|
||||
}
|
||||
else if (reach.isEnabled(player) && reach.check(player, block, data, cc)) {
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
else if (reach.isEnabled(player) && reach.check(player, block, data, cc)) {
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Direction check.
|
||||
if (!cancelled && !shouldSkipSome) {
|
||||
if (isInteractBlock && bdata.isPassedCheck(CheckType.BLOCKINTERACT_DIRECTION)) {
|
||||
skippedRedundantChecks ++;
|
||||
}
|
||||
else if (direction.isEnabled(player) && direction.check(player, block, blockAgainst, data, cc)) {
|
||||
cancelled = true;
|
||||
// Direction check.
|
||||
if (!cancelled && !shouldSkipSome) {
|
||||
if (isInteractBlock && bdata.isPassedCheck(CheckType.BLOCKINTERACT_DIRECTION)) {
|
||||
skippedRedundantChecks ++;
|
||||
}
|
||||
else if (direction.isEnabled(player) && direction.check(player, loc, block, flyingHandle, data, cc)) {
|
||||
cancelled = true;
|
||||
}
|
||||
}
|
||||
useLoc.setWorld(null);
|
||||
}
|
||||
else {
|
||||
flyingHandle = null;
|
||||
}
|
||||
|
||||
// Surrounding material.
|
||||
|
@ -229,7 +240,7 @@ public class BlockPlaceListener extends CheckListener {
|
|||
else {
|
||||
// Debug log (only if not cancelled, to avoid spam).
|
||||
if (data.debug) {
|
||||
debugBlockPlace(player, placedMat, block, blockAgainst, skippedRedundantChecks);
|
||||
debugBlockPlace(player, placedMat, block, blockAgainst, skippedRedundantChecks, flyingHandle);
|
||||
}
|
||||
}
|
||||
// Cleanup
|
||||
|
@ -238,13 +249,21 @@ public class BlockPlaceListener extends CheckListener {
|
|||
|
||||
private void debugBlockPlace(final Player player, final Material placedMat,
|
||||
final Block block, final Block blockAgainst,
|
||||
final int skippedRedundantChecks) {
|
||||
final int skippedRedundantChecks, final FlyingQueueHandle flyingHandle) {
|
||||
debug(player, "Block place(" + placedMat + "): " + block.getX() + ", " + block.getY() + ", " + block.getZ());
|
||||
BlockInteractListener.debugBlockVSBlockInteract(player, checkType, blockAgainst, "onBlockInteract(blockAgainst)",
|
||||
Action.RIGHT_CLICK_BLOCK);
|
||||
if (skippedRedundantChecks > 0) {
|
||||
debug(player, "Skipped redundant checks: " + skippedRedundantChecks);
|
||||
}
|
||||
if (flyingHandle != null && flyingHandle.isFlyingQueueFetched()) {
|
||||
final int flyingIndex = flyingHandle.getFirstIndexWithContentIfFetched();
|
||||
final DataPacketFlying packet = flyingHandle.getIfFetched(flyingIndex);
|
||||
if (packet != null) {
|
||||
debug(player, "Flying packet queue used at index " + flyingIndex + ": pitch=" + packet.getPitch() + ",yaw=" + packet.getYaw());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
|
|
|
@ -14,23 +14,17 @@
|
|||
*/
|
||||
package fr.neatmonster.nocheatplus.checks.blockplace;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.actions.ActionList;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.utilities.collision.CollisionUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.location.TrigUtil;
|
||||
import fr.neatmonster.nocheatplus.checks.generic.block.AbstractBlockDirectionCheck;
|
||||
|
||||
/**
|
||||
* The Direction check will find out if a player tried to interact with something that's not in their field of view.
|
||||
* The Direction check will find out if a player tried to interact with
|
||||
* something that's not in their field of view.
|
||||
*/
|
||||
public class Direction extends Check {
|
||||
|
||||
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
|
||||
private final Location useLoc = new Location(null, 0, 0, 0);
|
||||
public class Direction extends AbstractBlockDirectionCheck<BlockPlaceData, BlockPlaceConfig> {
|
||||
|
||||
/**
|
||||
* Instantiates a new direction check.
|
||||
|
@ -39,65 +33,20 @@ public class Direction extends Check {
|
|||
super(CheckType.BLOCKPLACE_DIRECTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a player.
|
||||
*
|
||||
* @param player
|
||||
* the player
|
||||
* @param data
|
||||
* @param cc
|
||||
* @param location
|
||||
* the location
|
||||
* @return true, if successful
|
||||
*/
|
||||
public boolean check(final Player player, final Block placed, final Block against, final BlockPlaceData data, final BlockPlaceConfig cc) {
|
||||
|
||||
boolean cancel = false;
|
||||
|
||||
// How far "off" is the player with their aim. We calculate from the players eye location and view direction to
|
||||
// the center of the target block. If the line of sight is more too far off, "off" will be bigger than 0.
|
||||
final Location loc = player.getLocation(useLoc);
|
||||
final Vector direction = loc.getDirection();
|
||||
double off = CollisionUtil.directionCheck(loc, player.getEyeHeight(), direction, against, TrigUtil.DIRECTION_PRECISION);
|
||||
|
||||
// Now check if the player is looking at the block from the correct side.
|
||||
double off2 = 0.0D;
|
||||
|
||||
// Find out against which face the player tried to build, and if they
|
||||
// stood on the correct side of it
|
||||
if (placed.getX() > against.getX())
|
||||
off2 = against.getX() + 0.5D - loc.getX();
|
||||
else if (placed.getX() < against.getX())
|
||||
off2 = -(against.getX() + 0.5D - loc.getX());
|
||||
else if (placed.getY() > against.getY())
|
||||
off2 = against.getY() + 0.5D - loc.getY() - player.getEyeHeight();
|
||||
else if (placed.getY() < against.getY())
|
||||
off2 = -(against.getY() + 0.5D - loc.getY() - player.getEyeHeight());
|
||||
else if (placed.getZ() > against.getZ())
|
||||
off2 = against.getZ() + 0.5D - loc.getZ();
|
||||
else if (placed.getZ() < against.getZ())
|
||||
off2 = -(against.getZ() + 0.5D - loc.getZ());
|
||||
|
||||
// If they weren't on the correct side, add that to the "off" value
|
||||
if (off2 > 0.0D)
|
||||
off += off2;
|
||||
|
||||
if (off > 0.1D) {
|
||||
// Player failed the check. Let's try to guess how far they were from looking directly to the block...
|
||||
final Vector blockEyes = new Vector(0.5 + placed.getX() - loc.getX(), 0.5 + placed.getY() - loc.getY() - player.getEyeHeight(), 0.5 + placed.getZ() - loc.getZ());
|
||||
final double distance = blockEyes.crossProduct(direction).length() / direction.length();
|
||||
|
||||
// Add the overall violation level of the check.
|
||||
data.directionVL += distance;
|
||||
|
||||
// Execute whatever actions are associated with this check and the violation level and find out if we should
|
||||
// cancel the event.
|
||||
cancel = executeActions(player, data.directionVL, distance, cc.directionActions).willCancel();
|
||||
} else {
|
||||
// Player did likely nothing wrong, reduce violation counter to reward them.
|
||||
data.directionVL *= 0.9D;
|
||||
}
|
||||
useLoc.setWorld(null);
|
||||
return cancel;
|
||||
@Override
|
||||
protected double addVL(Player player, double distance, BlockPlaceData data, BlockPlaceConfig cc) {
|
||||
data.directionVL += distance;
|
||||
return data.directionVL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ActionList getActions(BlockPlaceConfig cc) {
|
||||
return cc.directionActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cooldown(Player player, BlockPlaceData data, BlockPlaceConfig cc) {
|
||||
data.directionVL *= 0.9D;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
package fr.neatmonster.nocheatplus.checks.generic.block;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import fr.neatmonster.nocheatplus.actions.ActionList;
|
||||
import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.access.ICheckConfig;
|
||||
import fr.neatmonster.nocheatplus.checks.access.ICheckData;
|
||||
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;
|
||||
|
||||
/**
|
||||
* A first made-abstract version of a direction-towards-a-block-check.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
* @param <D>
|
||||
* @param <C>
|
||||
*/
|
||||
public abstract class AbstractBlockDirectionCheck<D extends ICheckData, C extends ICheckConfig> 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.
|
||||
*/
|
||||
public AbstractBlockDirectionCheck(CheckType checkType) {
|
||||
super(checkType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the distance to the VL, return the resulting violation level.
|
||||
*
|
||||
* @param distance
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
protected abstract double addVL(Player player, double distance, D data, C cc);
|
||||
|
||||
/**
|
||||
* Fetch the actions from the config.
|
||||
* @param cc
|
||||
* @return
|
||||
*/
|
||||
protected abstract ActionList getActions(C cc);
|
||||
|
||||
|
||||
/**
|
||||
* Called on passing the check (cooldown vl, debug log, ...).
|
||||
*
|
||||
* @param player
|
||||
* @param datam
|
||||
* @param cc
|
||||
*/
|
||||
protected abstract void cooldown(Player player, D data, C cc);
|
||||
|
||||
/**
|
||||
* The actual checking method.
|
||||
*
|
||||
* @param player
|
||||
* @param loc
|
||||
* Location of the player.
|
||||
* @param block
|
||||
* The block the player is supposed to be looking at.
|
||||
* @param flyingHandle
|
||||
* @param data
|
||||
* @param cc
|
||||
* @return True, if the check has been failed.
|
||||
*/
|
||||
public boolean check(final Player player, final Location loc, final Block block,
|
||||
final FlyingQueueHandle flyingHandle, final D data, final C cc) {
|
||||
|
||||
boolean cancel = false;
|
||||
// How far "off" is the player with their aim.
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Consider a protected field with a tolerance value.
|
||||
if (distance != Double.MAX_VALUE) {
|
||||
distance = Math.sqrt(distance);
|
||||
if (data.getDebug()) {
|
||||
outputDebugFail(player, boulder, distance);
|
||||
}
|
||||
|
||||
// Add the overall violation level of the check.
|
||||
final double vl = addVL(player, distance, data, cc);
|
||||
|
||||
// TODO: Set distance parameter.
|
||||
|
||||
// Execute whatever actions are associated with this check and the violation level and find out if we should
|
||||
// cancel the event.
|
||||
cancel = executeActions(player, vl, distance, getActions(cc)).willCancel();
|
||||
} else {
|
||||
// Player did likely nothing wrong, reduce violation counter to reward them.
|
||||
cooldown(player, data, cc);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue