[BREAKING] Unify block (interact/place/break) direction checks.

Might break configurations.
This commit is contained in:
asofold 2017-05-03 00:40:37 +02:00
parent 2cca81f39a
commit 73f420527c
6 changed files with 336 additions and 292 deletions

View File

@ -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;
}
}
}
/**

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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));
}
}