From 1264cdb240049a40132c11179de488ac711837ec Mon Sep 17 00:00:00 2001 From: asofold Date: Fri, 15 Feb 2013 13:59:36 +0100 Subject: [PATCH] [Bleeding] Add ray-tracing for passable check. By default this only checks for block-transitions and vclip down. --- .../utilities/BlockProperties.java | 94 +++++++++++---- .../utilities/PassableRayTracing.java | 113 ++++++++++++++++++ .../checks/moving/MovingConfig.java | 7 ++ .../nocheatplus/checks/moving/Passable.java | 17 ++- .../nocheatplus/config/ConfPaths.java | 4 + .../nocheatplus/config/DefaultConfig.java | 3 + 6 files changed, 216 insertions(+), 22 deletions(-) create mode 100644 NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/PassableRayTracing.java diff --git a/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/BlockProperties.java b/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/BlockProperties.java index fb2ff010..5660679e 100644 --- a/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/BlockProperties.java +++ b/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/BlockProperties.java @@ -1025,28 +1025,80 @@ public class BlockProperties { final double fy = y - by; final double fz = z - bz; // if (fx < block.minX || fx >= block.maxX || fy < block.minY || fy >= block.maxY || fz < block.minZ || fz >= block.maxZ) return true; - if (fx < bounds[0] || fx >= bounds[3] || fy < bounds[1] || fy >= bounds[4] || fz < bounds[2] || fz >= bounds[5]) return true; - else{ - // Workarounds (might get generalized some time). - if (isStairs(id)){ - if ((access.getData(bx, by, bz) & 0x4) != 0){ - if (fy < 0.5) return true; - } - else if (fy >= 0.5) return true; - } - else if (id == Material.SOUL_SAND.getId() && fy >= 0.875) return true; // 0.125 - else if (id == Material.IRON_FENCE.getId() || id == Material.THIN_GLASS.getId()){ - if (Math.abs(0.5 - fx) > 0.05 && Math.abs(0.5 - fz) > 0.05) return true; - } - else if (id == Material.FENCE_GATE.getId() && (access.getData(bx, by, bz) & 0x4)!= 0) return true; - else if (id == Material.CAKE_BLOCK.getId() && fy >= 0.4375) return true; // 0.0625 = 0.125 / 2 - else if (id == Material.CAULDRON.getId()){ - if (Math.abs(0.5 - fx) < 0.1 && Math.abs(0.5 - fz) < 0.1 && fy > 0.1) return true; - } - else if (id == Material.CACTUS.getId() && fy >= 0.9375) return true; - // Nothing found. - return false; + if (fx < bounds[0] || fx >= bounds[3] || fy < bounds[1] || fy >= bounds[4] || fz < bounds[2] || fz >= bounds[5]){ + return true; } + else{ + // TODO: Check f_itchy if/once exists. + return isPassableWorkaround(access, bx, by, bz, fx, fy, fz, id, 0, 0, 0, 0); + } + } + + /** + * Assuming the hit-box is hit (...) this checks for special blocks properties such as glass panes and similar.
+ * Ray-tracing version for passable-workarounds. + * @param access + * @param bx Block-coordinates. + * @param by + * @param bz + * @param fx Offset from block-coordinates in [0..1]. + * @param fy + * @param fz + * @param id Type-id of the block. + * @param dX Total ray distance for coordinated (see dT). + * @param dY + * @param dZ + * @param dT Time to cover from given position in [0..1], relating to dX, dY, dZ. + * @return + */ + public static final boolean isPassableWorkaround(final BlockCache access, final int bx, final int by, final int bz, final double fx, final double fy, final double fz, final int id, final double dX, final double dY, final double dZ, final double dT){ + final long flags = blockFlags[id]; + if ((flags & F_STAIRS) != 0){ + if ((access.getData(bx, by, bz) & 0x4) != 0){ + if (Math.max(fy, fy + dY * dT) < 0.5) return true; + } + else if (Math.min(fy, fy + dY * dT) >= 0.5) return true; + } + else if (id == Material.SOUL_SAND.getId()){ + if (Math.min(fy, fy + dY * dT) >= 0.875) return true; // 0.125 + } + else if (id == Material.IRON_FENCE.getId() || id == Material.THIN_GLASS.getId()){ + final double dFx = 0.5 - fx; + final double dFz = 0.5 - fz; + if (Math.abs(dFx) > 0.05 && Math.abs(dFz) > 0.05){ + // Check moving between quadrants. + final double dFx2 = 0.5 - (fx + dX * dT); + final double dFz2 = 0.5 - (fz + dZ * dT); + if (Math.abs(dFx2) > 0.05 && Math.abs(dFz2) > 0.05){ + if (dFx * dFx2 > 0.0 && dFz * dFz2 > 0.0){ + return true; + } + } + } + } + else if (id == Material.FENCE_GATE.getId()){ + if ((access.getData(bx, by, bz) & 0x4)!= 0) return true; + } + else if (id == Material.CAKE_BLOCK.getId()){ + if (Math.min(fy, fy + dY * dT) >= 0.4375) return true; // 0.0625 = 0.125 / 2 + } + else if (id == Material.CAULDRON.getId()){ + final double dFx = 0.5 - fx; + final double dFz = 0.5 - fz; + if (Math.min(fy, fy + dY * dT) > 0.1 && Math.abs(dFx) < 0.1 && Math.abs(dFz) < 0.1){ + // Check for moving through walls or floor. + final double dFx2 = 0.5 - (fx + dX * dT); + final double dFz2 = 0.5 - (fz + dZ * dT); + if (Math.abs(dFx2) < 0.1 && Math.abs(dFz2) < 0.1){ + return true; + } + } + } + else if (id == Material.CACTUS.getId()){ + if (Math.min(fy, fy + dY * dT) >= 0.9375) return true; + } + // Nothing found. + return false; } /** diff --git a/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/PassableRayTracing.java b/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/PassableRayTracing.java new file mode 100644 index 00000000..9d9fe898 --- /dev/null +++ b/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/PassableRayTracing.java @@ -0,0 +1,113 @@ +package fr.neatmonster.nocheatplus.utilities; + +public class PassableRayTracing extends RayTracing{ + + protected BlockCache blockCache = null; + + protected boolean collides = false; + + /** + * Empty constructor for setting other properties later. + */ + public PassableRayTracing() { + super(0, 0, 0, 0, 0, 0); + } + + + public BlockCache getBlockCache() { + return blockCache; + } + + + public void setBlockCache(BlockCache blockCache) { + this.blockCache = blockCache; + } + + /** + * Set from PlayerLocation instances. Currently takes BlockCache from the from-location. + * @param from + * @param to + */ + public void set(final PlayerLocation from, final PlayerLocation to){ + set(from.getX(), from.getY(), from.getZ(), to.getX(), to.getY(), to.getZ()); + setBlockCache(from.getBlockCache()); // TODO: This might better be done extra. + } + + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.utilities.RayTracing#set(double, double, double, double, double, double) + */ + @Override + public void set(double x0, double y0, double z0, double x1, double y1, double z1) { + super.set(x0, y0, z0, x1, y1, z1); + collides = false; + } + + public boolean collides(){ + return collides; + } + + + /** + * Remove reference to BlockCache. + */ + public void cleanup(){ + if (blockCache != null){ + blockCache = null; + } + } + + @Override + protected boolean step(final int blockX, final int blockY, final int blockZ, final double oX, final double oY, final double oZ, final double dT) { + final int id = blockCache.getTypeId(blockX, blockY, blockZ); + if (BlockProperties.isPassable(id)) return true; + double[] bounds = blockCache.getBounds(blockX, blockY, blockZ); + if (bounds == null) return true; + + // TODO: Other problem (forgot)... + + // Check if is already inside. + // TODO: This might be superfluous since below method used. + if (oX >= bounds[0] && oX < bounds[3] && oY >= bounds[1] && oY < bounds[4] && oZ >= bounds[2] && oZ < bounds[5]){ + if (!BlockProperties.isPassableWorkaround(blockCache, blockX, blockY, blockZ, oX, oY, oZ, id, 0, 0, 0, 0)){ + collides = true; + return true; + } + } + // Check extrapolation [all three intervals must be hit]. + if (dX < 0){ + if (oX < bounds[0]) return true; + else if (oX + dX * dT >= bounds[3]) return true; + } + else{ + if (oX >= bounds[3]) return true; + else if (oX + dX * dT < bounds[0]) return true; + } + if (dY < 0){ + if (oY < bounds[1]) return true; + else if (oY + dY * dT >= bounds[4]) return true; + } + else{ + if (oY >= bounds[4]) return true; + else if (oY + dY * dT < bounds[1]) return true; + } + if (dZ < 0){ + if (oZ < bounds[2]) return true; + else if (oZ + dZ * dT >= bounds[5]) return true; + } + else{ + if (oZ >= bounds[5]) return true; + else if (oZ + dZ * dT < bounds[2]) return true; + } + // Check for workarounds. + // TODO: check f_itchy once exists. + if (BlockProperties.isPassableWorkaround(blockCache, blockX, blockY, blockZ, oX, oY, oZ, id, dX, dY, dZ, dT)){ + return true; + } + // Does collide (most likely). + // TODO: This is not entirely accurate, needs further exclusion for smaller solid blocks. + // (Could allow start-end if passable + check first collision time or some estimate.) + collides = true; + return true; + } + +} diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingConfig.java b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingConfig.java index 7fbd1d59..094d00b7 100644 --- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingConfig.java +++ b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingConfig.java @@ -88,6 +88,10 @@ public class MovingConfig extends ACheckConfig { public final ActionList noFallActions; public final boolean passableCheck; + public final boolean passableRayTracingCheck; + public final boolean passableRayTracingBlockChangeOnly; + public final boolean passableRayTracingVclipOnly; + // TODO: passableAccuracy: also use if not using ray-tracing public final ActionList passableActions; public final boolean survivalFlyCheck; @@ -148,6 +152,9 @@ public class MovingConfig extends ACheckConfig { noFallActions = data.getOptimizedActionList(ConfPaths.MOVING_NOFALL_ACTIONS, Permissions.MOVING_NOFALL); passableCheck = data.getBoolean(ConfPaths.MOVING_PASSABLE_CHECK); + passableRayTracingCheck = data.getBoolean(ConfPaths.MOVING_PASSABLE_RAYTRACING_CHECK); + passableRayTracingBlockChangeOnly = data.getBoolean(ConfPaths.MOVING_PASSABLE_RAYTRACING_BLOCKCHANGEONLY); + passableRayTracingVclipOnly = data.getBoolean(ConfPaths.MOVING_PASSABLE_RAYTRACING_VCLIPONLY); passableActions = data.getOptimizedActionList(ConfPaths.MOVING_PASSABLE_ACTIONS, Permissions.MOVING_PASSABLE); survivalFlyCheck = data.getBoolean(ConfPaths.MOVING_SURVIVALFLY_CHECK); diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/moving/Passable.java b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/moving/Passable.java index 59bc952f..694f5f97 100644 --- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/moving/Passable.java +++ b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/moving/Passable.java @@ -10,9 +10,12 @@ import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; import fr.neatmonster.nocheatplus.utilities.BlockProperties; +import fr.neatmonster.nocheatplus.utilities.PassableRayTracing; import fr.neatmonster.nocheatplus.utilities.PlayerLocation; public class Passable extends Check { + + private final PassableRayTracing rayTracing = new PassableRayTracing(); public Passable() { super(CheckType.MOVING_PASSABLE); @@ -24,7 +27,19 @@ public class Passable extends Check { // TODO: account for actual bounding box. - if (to.isPassable()){ + boolean toPassable = to.isPassable(); + // TODO: Config settings, extra flag for further processing. + if (toPassable && cc.passableRayTracingCheck && (!cc.passableRayTracingVclipOnly || from.getY() > to.getY()) && (!cc.passableRayTracingBlockChangeOnly || from.getBlockX() != to.getBlockX() || from.getBlockY() != to.getBlockY() || from.getBlockZ() != to.getBlockZ())){ + rayTracing.set(from, to); + rayTracing.loop(); + if (rayTracing.collides()){ + toPassable = false; + } + // TODO: If accuracy is set, also check the head position (or bounding box right away). + rayTracing.cleanup(); + } + + if (toPassable){ // Quick return. // (Might consider if vl>=1: only decrease if from and loc are passable too, though micro...) data.passableVL *= 0.99; diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/config/ConfPaths.java b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/config/ConfPaths.java index 26faf5df..9dcf603d 100644 --- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/config/ConfPaths.java +++ b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/config/ConfPaths.java @@ -483,6 +483,10 @@ public abstract class ConfPaths { public static final String MOVING_PASSABLE = MOVING + "passable."; public static final String MOVING_PASSABLE_CHECK = MOVING_PASSABLE + "active"; + private static final String MOVING_PASSABLE_RAYTRACING = MOVING_PASSABLE + "raytracing."; + public static final String MOVING_PASSABLE_RAYTRACING_CHECK = MOVING_PASSABLE_RAYTRACING + "active"; + public static final String MOVING_PASSABLE_RAYTRACING_BLOCKCHANGEONLY= MOVING_PASSABLE_RAYTRACING + "blockchangeonly"; + public static final String MOVING_PASSABLE_RAYTRACING_VCLIPONLY = MOVING_PASSABLE_RAYTRACING + "vcliponly"; public static final String MOVING_PASSABLE_ACTIONS = MOVING_PASSABLE + "actions"; private static final String MOVING_SURVIVALFLY = MOVING + "survivalfly."; diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/config/DefaultConfig.java b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/config/DefaultConfig.java index 801ae7b6..beca2c2b 100644 --- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/config/DefaultConfig.java +++ b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/config/DefaultConfig.java @@ -378,6 +378,9 @@ public class DefaultConfig extends ConfigFile { set(ConfPaths.MOVING_NOFALL_ACTIONS, "log:nofall:0:5:if cancel vl>30 log:nofall:0:5:icf cancel"); set(ConfPaths.MOVING_PASSABLE_CHECK, true); + set(ConfPaths.MOVING_PASSABLE_RAYTRACING_CHECK, true); + set(ConfPaths.MOVING_PASSABLE_RAYTRACING_BLOCKCHANGEONLY, true); + set(ConfPaths.MOVING_PASSABLE_RAYTRACING_VCLIPONLY, true); set(ConfPaths.MOVING_PASSABLE_ACTIONS, "cancel vl>10 log:passable:0:5:if cancel vl>50 log:passable:0:5:icf cancel"); set(ConfPaths.MOVING_SURVIVALFLY_CHECK, true);