[Bleeding] Add ray-tracing for passable check.

By default this only checks for block-transitions and vclip down.
This commit is contained in:
asofold 2013-02-15 13:59:36 +01:00
parent 9f7d3c6cfc
commit 1264cdb240
6 changed files with 216 additions and 22 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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.";

View File

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