diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/Passable.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/Passable.java index 8a91ec07..bad8b92c 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/Passable.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/player/Passable.java @@ -40,6 +40,7 @@ public class Passable extends Check { // TODO: Configuration. // TODO: Test cases. private static boolean rt_legacy = false; + // TODO: Should keep an eye on passable vs. on-ground, when checking with reduced margins. // TODO: rt_xzFactor = 1.0; // Problems: Doors, fences. private static double rt_xzFactor = 0.98; // TODO: Test bumping head into things. @@ -57,126 +58,71 @@ public class Passable extends Check { } // TODO: Store both and select on check (with config then). - private final ICollidePassable rayTracing = rt_legacy ? new PassableRayTracing() : new PassableAxisTracing(); + private final ICollidePassable rayTracingLegacy = new PassableRayTracing(); + private final ICollidePassable rayTracingActual = new PassableAxisTracing(); public Passable() { super(CheckType.MOVING_PASSABLE); - rayTracing.setMaxSteps(60); // TODO: Configurable ? + // TODO: Configurable maxSteps? + rayTracingLegacy.setMaxSteps(60); + rayTracingActual.setMaxSteps(60); } - public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc) - { - // TODO: WAT: if (!from.isSameCoords(loc)) {...check passable for loc -> from !?... + sf etc too?} - + public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, + final MovingData data, final MovingConfig cc) { + if (rt_legacy) { + return checkLegacy(player, from, to, data, cc); + } + else { + return checkActual(player, from, to, data, cc); + } + } + private Location checkActual(final Player player, final PlayerLocation from, final PlayerLocation to, + final MovingData data, final MovingConfig cc) { // TODO: Distinguish feet vs. box. - String tags = ""; // Block distances (sum, max) for from-to (not for loc!). final int manhattan = from.manhattan(to); - if (rt_legacy) { - // Skip moves inside of ignored blocks right away [works as long as we only check between foot-locations]. - if (manhattan <= 1 && BlockProperties.isPassable(from.getTypeId())) { - // TODO: Monitor: BlockProperties.isPassable checks slightly different than before. - if (manhattan == 0){ - return null; - } else { - // manhattan == 1 - if (BlockProperties.isPassable(to.getTypeId())) { - return null; - } - } - } - } - - boolean toPassable = to.isPassable(); // General condition check for using ray-tracing. - if ((!rt_legacy || toPassable) && cc.passableRayTracingCheck - && (!cc.passableRayTracingBlockChangeOnly || manhattan > 0)) { - final String newTag; - if (rt_legacy) { - newTag = checkRayTracingLegacy(player, from, to, manhattan, data, cc); - if (newTag != null) { - toPassable = false; - tags = newTag; - } - } - else { - newTag = checkRayTracing(player, from, to, manhattan, data, cc); - if (newTag != null) { - // Direct return. - return potentialViolation(player, from, to, manhattan, tags, data, cc); - } + if (cc.passableRayTracingCheck && (!cc.passableRayTracingBlockChangeOnly || manhattan > 0)) { + final String newTag = checkRayTracing(player, from, to, manhattan, data, cc); + if (newTag != null) { + // Direct return. + return potentialViolation(player, from, to, manhattan, newTag, data, cc); } } - - // TODO: Checking order: If loc is not the same as from, a quick return here might not be wanted. - if (toPassable) { + if (to.isPassable()) { // Quick return. // (Might consider if vl>=1: only decrease if from and loc are passable too, though micro...) data.passableVL *= 0.99; return null; } else { - return potentialViolationLegacy(player, from, to, manhattan, tags, data, cc); + return potentialViolationLegacy(player, from, to, manhattan, "", data, cc); } - } private String checkRayTracing(final Player player, final PlayerLocation from, final PlayerLocation to, final int manhattan, final MovingData data, final MovingConfig cc) { String tags = null; - setNormalMargins(rayTracing, from); - rayTracing.set(from, to); - rayTracing.setIgnoreInitiallyColliding(true); + setNormalMargins(rayTracingActual, from); + rayTracingActual.set(from, to); + rayTracingActual.setIgnoreInitiallyColliding(true); //rayTracing.setCutOppositeDirectionMargin(true); - rayTracing.loop(); - rayTracing.setIgnoreInitiallyColliding(false); + rayTracingActual.loop(); + rayTracingActual.setIgnoreInitiallyColliding(false); //rayTracing.setCutOppositeDirectionMargin(false); - if (rayTracing.collides()) { + if (rayTracingActual.collides()) { tags = "raytracing_collide_"; } - else if (rayTracing.getStepsDone() >= rayTracing.getMaxSteps()) { + else if (rayTracingActual.getStepsDone() >= rayTracingActual.getMaxSteps()) { tags = "raytracing_maxsteps_"; } if (data.debug) { - debugExtraCollisionDetails(player, rayTracing, "std"); + debugExtraCollisionDetails(player, rayTracingActual, "std"); } - rayTracing.cleanup(); - return tags; - } - - private String checkRayTracingLegacy(final Player player, final PlayerLocation from, final PlayerLocation to, - final int manhattan, final MovingData data, final MovingConfig cc) { - setNormalMargins(rayTracing, from); - rayTracing.set(from, to); - rayTracing.loop(); - String tags = null; - if (rayTracing.collides() || rayTracing.getStepsDone() >= rayTracing.getMaxSteps()) { - if (data.debug) { - debugExtraCollisionDetails(player, rayTracing, "legacy"); - } - final int maxBlockDist = manhattan <= 1 ? manhattan : from.maxBlockDist(to); - if (maxBlockDist <= 1 && rayTracing.getStepsDone() == 1 && !from.isPassable()) { - // Redo ray-tracing for moving out of blocks. - if (collidesIgnoreFirst(from, to)) { - tags = "raytracing_2x_"; - if (data.debug) { - debugExtraCollisionDetails(player, rayTracing, "ingoreFirst"); - } - } - else if (data.debug) { - debug(player, "Allow moving out of a block."); - } - } - else{ - if (!allowsSplitMove(from, to, manhattan, data)) { - tags = "raytracing_"; - } - } - } - // TODO: Future: If accuracy is demanded, also check the head position (or bounding box right away). - rayTracing.cleanup(); + rayTracingActual.cleanup(); return tags; } @@ -210,6 +156,146 @@ public class Passable extends Check { return actualViolation(player, from, to, tags, data, cc); } + private Location actualViolation(final Player player, final PlayerLocation from, final PlayerLocation to, + final String tags, final MovingData data, final MovingConfig cc) { + Location setBackLoc = null; // Alternative to from.getLocation(). + + // Prefer the set-back location from the data. + if (data.hasSetBack()) { + setBackLoc = data.getSetBack(to);; + if (data.debug) { + debug(player, "Using set-back location for passable."); + } + } + + // Return the reset position. + data.passableVL += 1d; + final ViolationData vd = new ViolationData(this, player, data.passableVL, 1, cc.passableActions); + if (data.debug || vd.needsParameters()) { + vd.setParameter(ParameterName.LOCATION_FROM, String.format(Locale.US, "%.2f, %.2f, %.2f", from.getX(), from.getY(), from.getZ())); + vd.setParameter(ParameterName.LOCATION_TO, String.format(Locale.US, "%.2f, %.2f, %.2f", to.getX(), to.getY(), to.getZ())); + vd.setParameter(ParameterName.DISTANCE, String.format(Locale.US, "%.2f", TrigUtil.distance(from, to))); + // TODO: Consider adding from.getTypeId() too, if blocks differ and non-air. + vd.setParameter(ParameterName.BLOCK_ID, "" + to.getTypeId()); + if (!tags.isEmpty()) { + vd.setParameter(ParameterName.TAGS, tags); + } + } + if (executeActions(vd).willCancel()) { + // TODO: Consider another set back position for this, also keeping track of players moving around in blocks. + final Location newTo; + if (setBackLoc != null) { + // Ensure the given location is cloned. + newTo = LocUtil.clone(setBackLoc); + } else { + newTo = from.getLocation(); + if (data.debug) { + debug(player, "Using from location for passable."); + } + } + newTo.setYaw(to.getYaw()); + newTo.setPitch(to.getPitch()); + return newTo; + } + else{ + // No cancel action set. + return null; + } + } + + /** + * Debug only if colliding. + * + * @param player + * @param rayTracing + * @param tag + */ + private void debugExtraCollisionDetails(Player player, ICollidePassable rayTracing, String tag) { + if (rayTracing.collides()) { + debug(player, "Raytracing collision (" + tag + "): " + rayTracing.getCollidingAxis()); + } + else if (rayTracing.getStepsDone() >= rayTracing.getMaxSteps()) { + debug(player, "Raytracing max steps exceeded (" + tag + "): "+ rayTracing.getCollidingAxis()); + } + } + + private Location checkLegacy(final Player player, final PlayerLocation from, final PlayerLocation to, + final MovingData data, final MovingConfig cc) { + // TODO: Distinguish feet vs. box. + + String tags = ""; + // Block distances (sum, max) for from-to (not for loc!). + final int manhattan = from.manhattan(to); + + // Skip moves inside of ignored blocks right away [works as long as we only check between foot-locations]. + if (manhattan <= 1 && BlockProperties.isPassable(from.getTypeId())) { + // TODO: Monitor: BlockProperties.isPassable checks slightly different than before. + if (manhattan == 0){ + return null; + } else { + // manhattan == 1 + if (BlockProperties.isPassable(to.getTypeId())) { + return null; + } + } + } + + boolean toPassable = to.isPassable(); + // General condition check for using ray-tracing. + if (toPassable && cc.passableRayTracingCheck + && (!cc.passableRayTracingBlockChangeOnly || manhattan > 0)) { + final String newTag = checkRayTracingLegacy(player, from, to, manhattan, data, cc); + if (newTag != null) { + toPassable = false; + tags = newTag; + } + } + + // TODO: Checking order: If loc is not the same as from, a quick return here might not be wanted. + if (toPassable) { + // Quick return. + // (Might consider if vl>=1: only decrease if from and loc are passable too, though micro...) + data.passableVL *= 0.99; + return null; + } else { + return potentialViolationLegacy(player, from, to, manhattan, tags, data, cc); + } + } + + private String checkRayTracingLegacy(final Player player, final PlayerLocation from, final PlayerLocation to, + final int manhattan, final MovingData data, final MovingConfig cc) { + setNormalMargins(rayTracingLegacy, from); + rayTracingLegacy.set(from, to); + rayTracingLegacy.loop(); + String tags = null; + if (rayTracingLegacy.collides() || rayTracingLegacy.getStepsDone() >= rayTracingLegacy.getMaxSteps()) { + if (data.debug) { + debugExtraCollisionDetails(player, rayTracingLegacy, "legacy"); + } + final int maxBlockDist = manhattan <= 1 ? manhattan : from.maxBlockDist(to); + if (maxBlockDist <= 1 && rayTracingLegacy.getStepsDone() == 1 && !from.isPassable()) { + // Redo ray-tracing for moving out of blocks. + if (collidesIgnoreFirst(from, to)) { + tags = "raytracing_2x_"; + if (data.debug) { + debugExtraCollisionDetails(player, rayTracingLegacy, "ingoreFirst"); + } + } + else if (data.debug) { + debug(player, "Allow moving out of a block."); + } + } + else{ + if (!allowsSplitMove(from, to, manhattan, data)) { + tags = "raytracing_"; + } + } + } + // TODO: Future: If accuracy is demanded, also check the head position (or bounding box right away). + rayTracingLegacy.cleanup(); + return tags; + } + /** * Legacy skipping conditions, before triggering an actual violation. * @@ -266,53 +352,6 @@ public class Passable extends Check { return actualViolation(player, from, to, tags, data, cc); } - private Location actualViolation(final Player player, final PlayerLocation from, final PlayerLocation to, - final String tags, final MovingData data, final MovingConfig cc) { - Location setBackLoc = null; // Alternative to from.getLocation(). - - // Prefer the set-back location from the data. - if (data.hasSetBack()) { - setBackLoc = data.getSetBack(to);; - if (data.debug) { - debug(player, "Using set-back location for passable."); - } - } - - // Return the reset position. - data.passableVL += 1d; - final ViolationData vd = new ViolationData(this, player, data.passableVL, 1, cc.passableActions); - if (data.debug || vd.needsParameters()) { - vd.setParameter(ParameterName.LOCATION_FROM, String.format(Locale.US, "%.2f, %.2f, %.2f", from.getX(), from.getY(), from.getZ())); - vd.setParameter(ParameterName.LOCATION_TO, String.format(Locale.US, "%.2f, %.2f, %.2f", to.getX(), to.getY(), to.getZ())); - vd.setParameter(ParameterName.DISTANCE, String.format(Locale.US, "%.2f", TrigUtil.distance(from, to))); - // TODO: Consider adding from.getTypeId() too, if blocks differ and non-air. - vd.setParameter(ParameterName.BLOCK_ID, "" + to.getTypeId()); - if (!tags.isEmpty()) { - vd.setParameter(ParameterName.TAGS, tags); - } - } - if (executeActions(vd).willCancel()) { - // TODO: Consider another set back position for this, also keeping track of players moving around in blocks. - final Location newTo; - if (setBackLoc != null) { - // Ensure the given location is cloned. - newTo = LocUtil.clone(setBackLoc); - } else { - newTo = from.getLocation(); - if (data.debug) { - debug(player, "Using from location for passable."); - } - } - newTo.setYaw(to.getYaw()); - newTo.setPitch(to.getPitch()); - return newTo; - } - else{ - // No cancel action set. - return null; - } - } - /** * Test collision with ignoring the first block. * @param from @@ -320,15 +359,13 @@ public class Passable extends Check { * @return */ private boolean collidesIgnoreFirst(PlayerLocation from, PlayerLocation to) { - // TODO: Set (and reset?) margins? - // TODO: rayTracing.setIgnoreInitiallyColliding(true); - rayTracing.set(from, to); - rayTracing.setIgnoreInitiallyColliding(true); - rayTracing.setCutOppositeDirectionMargin(true); - rayTracing.loop(); - rayTracing.setIgnoreInitiallyColliding(false); - rayTracing.setCutOppositeDirectionMargin(false); - return rayTracing.collides() || rayTracing.getStepsDone() >= rayTracing.getMaxSteps(); + rayTracingLegacy.set(from, to); + rayTracingLegacy.setIgnoreInitiallyColliding(true); + rayTracingLegacy.setCutOppositeDirectionMargin(true); + rayTracingLegacy.loop(); + rayTracingLegacy.setIgnoreInitiallyColliding(false); + rayTracingLegacy.setCutOppositeDirectionMargin(false); + return rayTracingLegacy.collides() || rayTracingLegacy.getStepsDone() >= rayTracingLegacy.getMaxSteps(); } /** @@ -339,17 +376,17 @@ public class Passable extends Check { * @return */ private boolean allowsSplitMove(final PlayerLocation from, final PlayerLocation to, final int manhattan, final MovingData data) { - if (!rayTracing.mightNeedSplitAxisHandling()) { + if (!rayTracingLegacy.mightNeedSplitAxisHandling()) { return false; } // Always check y first. - rayTracing.set(from.getX(), from.getY(), from.getZ(), from.getX(), to.getY(), from.getZ()); - rayTracing.loop(); - if (!rayTracing.collides() && rayTracing.getStepsDone() < rayTracing.getMaxSteps()) { + rayTracingLegacy.set(from.getX(), from.getY(), from.getZ(), from.getX(), to.getY(), from.getZ()); + rayTracingLegacy.loop(); + if (!rayTracingLegacy.collides() && rayTracingLegacy.getStepsDone() < rayTracingLegacy.getMaxSteps()) { // horizontal second. - rayTracing.set(from.getX(), to.getY(), from.getZ(), to.getX(), to.getY(), to.getZ()); - rayTracing.loop(); - if (!rayTracing.collides() && rayTracing.getStepsDone() < rayTracing.getMaxSteps()) { + rayTracingLegacy.set(from.getX(), to.getY(), from.getZ(), to.getX(), to.getY(), to.getZ()); + rayTracingLegacy.loop(); + if (!rayTracingLegacy.collides() && rayTracingLegacy.getStepsDone() < rayTracingLegacy.getMaxSteps()) { return true; } } @@ -361,13 +398,13 @@ public class Passable extends Check { // if (data.debug) { // DebugUtil.debug(from.getPlayer().getName() + " passable - Test horizontal move first."); // } - // rayTracing.set(from.getX(), from.getY(), from.getZ(), to.getX(), from.getY(), to.getZ()); - // rayTracing.loop(); - // if (!rayTracing.collides() && rayTracing.getStepsDone() < rayTracing.getMaxSteps()) { + // rayTracingLegacy.set(from.getX(), from.getY(), from.getZ(), to.getX(), from.getY(), to.getZ()); + // rayTracingLegacy.loop(); + // if (!rayTracingLegacy.collides() && rayTracingLegacy.getStepsDone() < rayTracingLegacy.getMaxSteps()) { // // y second. - // rayTracing.set(to.getX(), from.getY(), to.getZ(), to.getX(), to.getY(), to.getZ()); - // rayTracing.loop(); - // if (!rayTracing.collides() && rayTracing.getStepsDone() < rayTracing.getMaxSteps()) { + // rayTracingLegacy.set(to.getX(), from.getY(), to.getZ(), to.getX(), to.getY(), to.getZ()); + // rayTracingLegacy.loop(); + // if (!rayTracingLegacy.collides() && rayTracingLegacy.getStepsDone() < rayTracingLegacy.getMaxSteps()) { // return true; // } // } @@ -378,20 +415,4 @@ public class Passable extends Check { return false; } - /** - * Debug only if colliding. - * - * @param player - * @param rayTracing - * @param tag - */ - private void debugExtraCollisionDetails(Player player, ICollidePassable rayTracing, String tag) { - if (rayTracing.collides()) { - debug(player, "Raytracing collision (" + tag + "): " + rayTracing.getCollidingAxis()); - } - else if (rayTracing.getStepsDone() >= rayTracing.getMaxSteps()) { - debug(player, "Raytracing max steps exceeded (" + tag + "): "+ rayTracing.getCollidingAxis()); - } - } - }