From 3f7e2d44f1b5ae1b62882574b6aeab9a5a24dce7 Mon Sep 17 00:00:00 2001 From: asofold Date: Sun, 17 Feb 2013 17:33:14 +0100 Subject: [PATCH] Add heuristic InteractRayTracing. --- .../utilities/InteractRayTracing.java | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/InteractRayTracing.java diff --git a/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/InteractRayTracing.java b/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/InteractRayTracing.java new file mode 100644 index 00000000..4770ac2e --- /dev/null +++ b/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/InteractRayTracing.java @@ -0,0 +1,149 @@ +package fr.neatmonster.nocheatplus.utilities; + +import org.bukkit.Location; + +/** + * Rough ray-tracing for interaction with something. + * @author mc_dev + * + */ +public class InteractRayTracing extends RayTracing { + + private static final int[][] incr = new int[][]{ + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + {-1, 0, 0}, + {0, -1, 0}, + {0, 0, -1}, + }; + + protected BlockCache blockCache = null; + + protected boolean collides = false; + + protected boolean strict = false; + + protected int lastBx, lastBy, lastBz; + + protected int targetBx, targetBy, targetBz; + + public InteractRayTracing(){ + super(); + } + + public InteractRayTracing(boolean strict){ + super(); + this.strict = strict; + } + + public BlockCache getBlockCache() { + return blockCache; + } + + public void setBlockCache(BlockCache blockCache) { + this.blockCache = blockCache; + } + + /* (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; + lastBx = blockX; + lastBy = blockY; + lastBz = blockZ; + targetBx = Location.locToBlock(x1); + targetBy = Location.locToBlock(y1); + targetBz = Location.locToBlock(z1); + } + + public boolean collides(){ + return collides; + } + + /** + * Remove reference to BlockCache. + */ + public void cleanup(){ + if (blockCache != null){ + blockCache = null; + } + } + + /** + * Simplistic collision check (can interact through this block). + * @param blockX + * @param blockY + * @param blockZ + * @return + */ + private final boolean doesCollide(int blockX, int blockY, int blockZ){ + final int id = blockCache.getTypeId(blockX, blockY, blockZ); + final long flags = BlockProperties.getBlockFlags(id); + if ((flags & BlockProperties.F_SOLID) == 0){ + // Ignore non solid blocks anyway. + return false; + } + if ((flags & (BlockProperties.F_LIQUID | BlockProperties.F_IGN_PASSABLE | BlockProperties.F_STAIRS | BlockProperties.F_VARIABLE)) != 0){ + // Special cases. + // TODO: F_VARIABLE: Bounding boxes are roughly right ? + return false; + } + if (!blockCache.isFullBounds(blockX, blockY, blockZ)) return false; + return true; + } + + /** + * Check if the block may be interacted through by use of some workaround. + * @param blockX + * @param blockY + * @param blockZ + * @return + */ + private final boolean allowsWorkaround(final int blockX, final int blockY, final int blockZ) { + // TODO: This allows some bypasses for "strange" setups. + for (int i = 0; i < 6; i++){ + final int[] dir = incr[i]; + final int rX = lastBx + dir[0]; + if (Math.abs(blockX - rX) > 1) continue; + final int rY = lastBy + dir[1]; + if (Math.abs(blockY - rY) > 1) continue; + final int rZ = lastBz + dir[2]; + if (Math.abs(blockZ - rZ) > 1) continue; + if (!doesCollide(rX, rY, rZ)){ + // NOTE: Don't check "rX == targetBx && rZ == targetBz && rY == targetBy". + return true; + } + } + return false; + } + + @Override + protected boolean step(int blockX, int blockY, int blockZ, double oX, double oY, double oZ, double dT) { + // TODO: Make an optional, more precise check (like passable) ? + if (blockX == targetBx && blockZ == targetBz && blockY == targetBy || !doesCollide(blockX, blockY, blockZ)){ + lastBx = blockX; + lastBy = blockY; + lastBz = blockZ; + return true; + } + if (strict || blockX == lastBx && blockZ == lastBz && blockY == lastBy){ + collides = true; + return false; + } + // Check workarounds... + if (allowsWorkaround(blockX, blockY, blockZ)){ + lastBx = blockX; + lastBy = blockY; + lastBz = blockZ; + return true; + } + // No workaround found. + collides = true; + return false; + } + +}