Bleeding: Add "passable" check (~vclip).

This commit is contained in:
asofold 2012-09-28 03:08:34 +02:00
parent 791dca6048
commit 23e6d9b1be
13 changed files with 217 additions and 33 deletions

View File

@ -22,6 +22,7 @@ package fr.neatmonster.nocheatplus.actions;
*/
public enum ParameterName {
CHECK("check"),
BLOCK_ID("blockid"),
DISTANCE("distance"),
FALL_DISTANCE("falldistance"),
FOOD("food"),

View File

@ -92,6 +92,7 @@ public enum CheckType {
MOVING_MOREPACKETS(MOVING, Permissions.MOVING_MOREPACKETS),
MOVING_MOREPACKETSVEHICLE(MOVING, Permissions.MOVING_MOREPACKETSVEHICLE),
MOVING_NOFALL(MOVING, Permissions.MOVING_NOFALL),
MOVING_PASSABLE(MOVING, Permissions.MOVING_PASSABLE),
MOVING_SURVIVALFLY(MOVING, Permissions.MOVING_SURVIVALFLY),
UNKNOWN;

View File

@ -145,5 +145,9 @@ public class ViolationData {
final String value = parameters.get(parameterName);
return(value == null) ? ("<?" + parameterName + ">") : value;
}
public void setParameter(final ParameterName parameterName, String value){
if (parameters != null) parameters.put(parameterName, value);
}
}

View File

@ -80,6 +80,9 @@ public class MovingConfig extends ACheckConfig {
public final boolean noFallCheck;
public final ActionList noFallActions;
public final boolean passableCheck;
public final ActionList passableActions;
public final boolean survivalFlyCheck;
public final int survivalFlyBlockingSpeed;
@ -121,6 +124,9 @@ public class MovingConfig extends ACheckConfig {
noFallCheck = data.getBoolean(ConfPaths.MOVING_NOFALL_CHECK);
noFallActions = data.getActionList(ConfPaths.MOVING_NOFALL_ACTIONS, Permissions.MOVING_NOFALL);
passableCheck = data.getBoolean(ConfPaths.MOVING_PASSABLE_CHECK);
passableActions = data.getActionList(ConfPaths.MOVING_PASSABLE_ACTIONS, Permissions.MOVING_PASSABLE);
survivalFlyCheck = data.getBoolean(ConfPaths.MOVING_SURVIVALFLY_CHECK);
// Default values are specified here because this settings aren't showed by default into the configuration file.
@ -149,6 +155,8 @@ public class MovingConfig extends ACheckConfig {
return noFallCheck;
case MOVING_SURVIVALFLY:
return survivalFlyCheck;
case MOVING_PASSABLE:
return passableCheck;
case MOVING_MOREPACKETS:
return morePacketsCheck;
case MOVING_MOREPACKETSVEHICLE:

View File

@ -95,6 +95,9 @@ public class MovingData extends ACheckData {
public double noFallFallDistance;
public boolean noFallOnGround;
public boolean noFallWasOnGround;
// Passable check.
public double passableVL;
// Data of the survival fly check.
public int survivalFlyJumpPhase;

View File

@ -75,6 +75,8 @@ public class MovingListener implements Listener {
/** The survival fly check. */
private final SurvivalFly survivalFly = new SurvivalFly();
private final Passable passable = new Passable();
/**
* A workaround for players placing blocks below them getting pushed off the block by NoCheatPlus.
@ -352,8 +354,11 @@ public class MovingListener implements Listener {
Location newTo = null;
if (passable.isEnabled(player)) newTo = passable.check(player, data.from, data.to, data, cc);
// Optimized checking, giving creativefly permission precedence over survivalfly.
if (!player.hasPermission(Permissions.MOVING_CREATIVEFLY)){
if (newTo != null);
else if (!player.hasPermission(Permissions.MOVING_CREATIVEFLY)){
// Either survivalfly or speed check.
if ((cc.ignoreCreative || player.getGameMode() != GameMode.CREATIVE) && (cc.ignoreAllowFlight || !player.getAllowFlight())
&& cc.survivalFlyCheck && !NCPExemptionManager.isExempted(player, CheckType.MOVING_SURVIVALFLY) && !player.hasPermission(Permissions.MOVING_SURVIVALFLY)){

View File

@ -0,0 +1,55 @@
package fr.neatmonster.nocheatplus.checks.moving;
import java.util.Map;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.actions.ParameterName;
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.PlayerLocation;
public class Passable extends Check {
public Passable() {
super(CheckType.MOVING_PASSABLE);
}
public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc){
// Simple check.
final int toId = to.getTypeId();
if (!BlockProperties.isPassable(to.getBlockAccess(), to.getX(), to.getY(), to.getZ(), toId)){
// Allow moving into the same block.
if (from.isSameBlock(to)){
if (!BlockProperties.isPassable(from.getBlockAccess(), from.getX(), from.getY(), from.getZ(), from.getTypeId())) return null;
}
// Return the reset position.
data.passableVL += 1d;
final ViolationData vd = new ViolationData(this, player, data.passableVL, 1, cc.passableActions);
vd.setParameter(ParameterName.BLOCK_ID, "" + toId);
if (executeActions(vd)){
final Location newTo = from.getLocation();
newTo.setYaw(to.getYaw());
newTo.setPitch(to.getPitch());
return newTo;
}
}
else{
data.passableVL *= 0.99;
}
return null;
}
@Override
protected Map<ParameterName, String> getParameterMap(final ViolationData violationData) {
// TODO Auto-generated method stub
return super.getParameterMap(violationData);
}
}

View File

@ -223,7 +223,7 @@ public class SurvivalFly extends Check {
// Slowly reduce the level with each event.
data.survivalFlyVL *= 0.95D;
// System.out.println("vertical freedom: " + data.verticalFreedom + " ("+data.verticalVelocity+"/"+data.verticalVelocityCounter+")");
// Did the player move in unexpected ways?
if (result > 0D) {
// Increment violation counter.

View File

@ -450,6 +450,10 @@ public abstract class ConfPaths {
private static final String MOVING_NOFALL = MOVING + "nofall.";
public static final String MOVING_NOFALL_CHECK = MOVING_NOFALL + "active";
public static final String MOVING_NOFALL_ACTIONS = MOVING_NOFALL + "actions";
public static final String MOVING_PASSABLE = MOVING + "passable.";
public static final String MOVING_PASSABLE_CHECK = MOVING_PASSABLE + "active";
public static final String MOVING_PASSABLE_ACTIONS = MOVING_PASSABLE + "actions";
private static final String MOVING_SURVIVALFLY = MOVING + "survivalfly.";
public static final String MOVING_SURVIVALFLY_CHECK = MOVING_SURVIVALFLY + "active";

View File

@ -342,6 +342,9 @@ public class DefaultConfig extends ConfigFile {
set(ConfPaths.MOVING_NOFALL_CHECK, true);
set(ConfPaths.MOVING_NOFALL_ACTIONS, "cancel vl>0 log:nofall:0:5:if cancel vl>6 log:nofall:0:5:icf cancel");
set(ConfPaths.MOVING_PASSABLE_CHECK, true);
set(ConfPaths.MOVING_PASSABLE_ACTIONS, "cancel vl>5 log:passable:0:5:if cancel vl>50 log:passable:0:5:icf cancel");
set(ConfPaths.MOVING_SURVIVALFLY_CHECK, true);
// The settings aren't enabled by default. Simply write them yourself in the configuration file.
@ -408,6 +411,7 @@ public class DefaultConfig extends ConfigFile {
set(ConfPaths.STRINGS + ".nofall", start + "tried to avoid fall damage for ~[falldistance] block(s)" + end);
set(ConfPaths.STRINGS + ".nopwnage", start + "acted like spamming (IP: [ip])" + end);
set(ConfPaths.STRINGS + ".noswing", start + "didn't swing arm" + end);
set(ConfPaths.STRINGS + ".passable", start + "moved into a block([blockid])" + end);
set(ConfPaths.STRINGS + ".tellglchat", tell + "&cNCP: &eChat can by annoying at times...");
set(ConfPaths.STRINGS + ".tempkick1", "ncp tempkick [player] 1 Wait a minute!");
set(ConfPaths.STRINGS + ".tempkick5", "ncp tempkick [player] 5 You have five minutes to think about it!");

View File

@ -164,6 +164,7 @@ public class Permissions {
public static final String MOVING_MOREPACKETS = MOVING + ".morepackets";
public static final String MOVING_MOREPACKETSVEHICLE = MOVING + ".morepacketsvehicle";
public static final String MOVING_NOFALL = MOVING + ".nofall";
public static final String MOVING_PASSABLE = MOVING + ".passable";
public static final String MOVING_SURVIVALFLY = MOVING + ".survivalfly";
public static final String MOVING_SURVIVALFLY_BLOCKING = MOVING_SURVIVALFLY + ".blocking";
public static final String MOVING_SURVIVALFLY_SNEAKING = MOVING_SURVIVALFLY + ".sneaking";

View File

@ -7,6 +7,7 @@ import java.util.List;
import java.util.Map;
import net.minecraft.server.Block;
import net.minecraft.server.IBlockAccess;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -236,8 +237,10 @@ public class BlockProperties {
protected static final long[] blockFlags = new long[maxBlocks];
/** Flag position for stairs. */
public static final int F_STAIRS = 0x1;
public static final int F_LIQUID = 0x2;
public static final int F_STAIRS = 0x1;
public static final int F_LIQUID = 0x2;
public static final int F_SOLID = 0x4;
public static final int F_IGN_SOLID = 0x8;
static{
try{
@ -283,11 +286,19 @@ public class BlockProperties {
for (int i = 0; i <maxBlocks; i++){
blocks[i] = null;
blockFlags[i] = 0;
final net.minecraft.server.Block block = net.minecraft.server.Block.byId[i];
if (block != null){
if (block.material != null){
final net.minecraft.server.Material material = block.material;
if (material.isSolid()) blockFlags[i] |= F_SOLID;
if (material.isLiquid()) blockFlags[i] |= F_LIQUID;
}
}
}
// Stairs.
for (final Material mat : new Material[] {Material.WOOD_STAIRS, Material.COBBLESTONE_STAIRS,
Material.BRICK_STAIRS, Material.SMOOTH_STAIRS, Material.NETHER_BRICK_STAIRS, Material.SANDSTONE_STAIRS,
Material.SPRUCE_WOOD_STAIRS, Material.BIRCH_WOOD_STAIRS, Material.JUNGLE_WOOD_STAIRS}){
for (final Material mat : new Material[] {Material.NETHER_BRICK_STAIRS,
Material.COBBLESTONE_STAIRS, Material.SMOOTH_STAIRS, Material.BRICK_STAIRS, Material.SANDSTONE_STAIRS,
Material.WOOD_STAIRS, Material.SPRUCE_WOOD_STAIRS, Material.BIRCH_WOOD_STAIRS, Material.JUNGLE_WOOD_STAIRS}){
blockFlags[mat.getId()] |= F_STAIRS;
}
// Liquid.
@ -295,7 +306,13 @@ public class BlockProperties {
Material.LAVA, Material.STATIONARY_LAVA,
Material.STATIONARY_WATER, Material.WATER,
}) {
blockFlags[mat.getId()] |= F_LIQUID;
blockFlags[mat.getId()] |= F_LIQUID; // TODO: This might already be handled above now.
}
for (final Material mat : new Material[]{
Material.WOOD_PLATE, Material.STONE_PLATE,
Material.WALL_SIGN, Material.SIGN_POST,
}){
blockFlags[mat.getId()] |= F_IGN_SOLID;
}
// Instantly breakable.
for (final Material mat : instantMat){
@ -534,30 +551,6 @@ public class BlockProperties {
return getBreakingDuration(blockId, itemInHand, onGround, inWater, helmet != null && helmet.containsEnchantment(Enchantment.WATER_WORKER));
}
public static boolean isInWater(final int blockId) {
if (blockId == Material.STATIONARY_WATER.getId() || blockId == Material.STATIONARY_LAVA.getId()) return true;
// TODO: count in water height ?
// TODO: lava ?
return false;
}
/**
* Heavy but ...
* @param world
* @param x
* @param y
* @param z
* @return
*/
public static boolean isOnGround(Player player, Location location) {
// return blockId != 0 && net.minecraft.server.Block.byId[blockId].//.c();// d();
final PlayerLocation loc = new PlayerLocation();
// Bit fat workaround, maybe put the object through from check listener ?
loc.set(location, player, 0.3);
return loc.isOnGround();
}
/**
* Get the normal breaking duration, including enchantments, and tool properties.
@ -724,6 +717,29 @@ public class BlockProperties {
blockProps.validate();
BlockProperties.defaultBlockProps = blockProps;
}
public static boolean isInWater(final int blockId) {
if (blockId == Material.STATIONARY_WATER.getId() || blockId == Material.STATIONARY_LAVA.getId()) return true;
// TODO: count in water height ?
// TODO: lava ?
return false;
}
/**
* Heavy but ...
* @param world
* @param x
* @param y
* @param z
* @return
*/
public static boolean isOnGround(Player player, Location location) {
// return blockId != 0 && net.minecraft.server.Block.byId[blockId].//.c();// d();
final PlayerLocation loc = new PlayerLocation();
// Bit fat workaround, maybe put the object through from check listener ?
loc.set(location, player, 0.3);
return loc.isOnGround();
}
/**
* Hiding the API access here.<br>
@ -734,14 +750,82 @@ public class BlockProperties {
public static final boolean i(final int id) {
return Block.i(id);
}
public static final long getBLockFlags(final int id){
return blockFlags[id];
}
public static final void setBlockFlags(final int id, final long flags){
blockFlags[id] = flags;
}
public static final boolean isStairs(final int id) {
return (blockFlags[id] & F_STAIRS) != 0;
}
public static boolean isLiquid(final int id) {
public static final boolean isLiquid(final int id) {
return (blockFlags[id] & F_LIQUID) != 0;
}
/**
* Might hold true for liquids too.
* @param id
* @return
*/
public static final boolean isSolid(final int id){
return (blockFlags[id] & F_SOLID) != 0;
}
/**
* Just check if a position is not inside of a block that has a bounding box.<br>
* This is an inaccurate check, it also returns false for doors etc.
* @param id
* @return
*/
public static final boolean isPassable(final int id){
if ((blockFlags[id] & (F_LIQUID | F_IGN_SOLID)) != 0) return true;
else return (blockFlags[id] & F_SOLID) == 0;
}
/**
* Test if a position can be passed through.<br>
* NOTE: This is experimental.
* @param world
* @param x
* @param y
* @param z
* @param id
* @return
*/
public static final boolean isPassable(final IBlockAccess blockAccess, final double x, final double y, final double z, final int id){
// Simple exclusion check first.
if (isPassable(id)) return true;
// Check if the position is inside of a bounding box.
final int bx = Location.locToBlock(x);
final int by = Location.locToBlock(y);
final int bz = Location.locToBlock(z);
final net.minecraft.server.Block block = net.minecraft.server.Block.byId[id];
if (block == null) return true;
block.updateShape(blockAccess, bx, by, bz);
final double fx = x - bx;
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;
else{
// Workarounds.
if (isStairs(id)){
if ((blockAccess.getData(bx, by, bz) & 0x4) == 1){
if (fy < 0.5) return true;
}
else if (fy >= 0.5) return true;
}
else if ((id == Material.IRON_FENCE.getId() || id == Material.THIN_GLASS.getId()) && block.maxX == 1.0){
if (Math.abs(0.5 - fx) > 0.1 && Math.abs(0.5 - fz) > 0.1) return true;
}
// Nothing found.
return false;
}
}
}

View File

@ -2,6 +2,7 @@ package fr.neatmonster.nocheatplus.utilities;
import net.minecraft.server.AxisAlignedBB;
import net.minecraft.server.EntityPlayer;
import net.minecraft.server.IBlockAccess;
import net.minecraft.server.WorldServer;
import org.bukkit.Location;
@ -300,4 +301,17 @@ public class PlayerLocation {
return typeIdBelow;
}
public final boolean isSameBlock(final PlayerLocation other) {
// Maybe make block coordinate fields later.
return Location.locToBlock(x) == Location.locToBlock(other.getX()) && Location.locToBlock(y) == Location.locToBlock(other.getY()) && Location.locToBlock(z) == Location.locToBlock(other.getZ());
}
/**
* TODO: temp maybe
* @return
*/
public final IBlockAccess getBlockAccess() {
return world;
}
}