[BLEEDING] Testing: ender-pearl glitch use (first sketch, read details).

* This method is "hard-coded" and not configurable yet.
* Prevent throwing and teleporting into blocks directly, prevent
the second throw on glitching into a one thick ceiling (might lead to
lots of passable violations at present).
* If stuck in a block with the feet (not sand/gravel) without being on
ground, throwing is prevented.
* Some dependencies were updated, hopefully without conflicts for
backwards compatibility (untested).
This commit is contained in:
asofold 2013-04-22 21:46:49 +02:00
parent 3b4352c044
commit 22ffb43ddf
17 changed files with 312 additions and 69 deletions

View File

@ -1,5 +1,6 @@
package fr.neatmonster.nocheatplus.compat;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.entity.Entity;
@ -135,5 +136,12 @@ public interface MCAccess {
* @return Long.MIN_VALUE if not possible.
*/
public long getKeepAliveTime(Player player);
/**
* Usually sand and gravel. Not for fastest access.
* @param type
* @return
*/
public boolean hasGravity(Material type);
}

View File

@ -1546,6 +1546,24 @@ public class BlockProperties {
return res;
}
/**
* Normal ray tracing.
* @param from
* @param to
* @return
*/
public static final boolean isPassable(final Location from, final Location to){
blockCache.setAccess(from.getWorld());
PassableRayTracing rt = new PassableRayTracing();
rt.setBlockCache(blockCache);
rt.set(from.getX(), from.getY(), from.getZ(), to.getX(), to.getY(), to.getZ());
rt.loop();
final boolean collides = rt.collides();
blockCache.cleanup();
rt.cleanup();
return !collides;
}
/**
* Convenience method to allow using an already fetched or prepared IBlockAccess.
* @param access

View File

@ -22,7 +22,7 @@
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.4.7-R1.0</version>
<version>1.5.1-R0.2</version>
</dependency>
</dependencies>

View File

@ -198,4 +198,20 @@ public class MCAccessBukkit implements MCAccess, BlockPropertiesSetup{
return Long.MIN_VALUE;
}
@Override
public boolean hasGravity(final Material mat) {
try{
return mat.hasGravity();
}
catch(Throwable t){
switch(mat){
case SAND:
case GRAVEL:
return true;
default:
return false;
}
}
}
}

View File

@ -8,6 +8,7 @@ import net.minecraft.server.EntityPlayer;
import net.minecraft.server.MobEffectList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.craftbukkit.CraftServer;
@ -160,5 +161,16 @@ public class MCAccessCB2511 implements MCAccess {
// TODO: Implement if possible.
return Long.MIN_VALUE;
}
@Override
public boolean hasGravity(final Material mat) {
switch(mat){
case SAND:
case GRAVEL:
return true;
default:
return false;
}
}
}

View File

@ -8,6 +8,7 @@ import net.minecraft.server.v1_4_5.EntityPlayer;
import net.minecraft.server.v1_4_5.MobEffectList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.craftbukkit.v1_4_5.CraftServer;
@ -159,4 +160,15 @@ public class MCAccessCB2512 implements MCAccess{
return Long.MIN_VALUE;
}
@Override
public boolean hasGravity(final Material mat) {
switch(mat){
case SAND:
case GRAVEL:
return true;
default:
return false;
}
}
}

View File

@ -8,6 +8,7 @@ import net.minecraft.server.v1_4_6.EntityPlayer;
import net.minecraft.server.v1_4_6.MobEffectList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.craftbukkit.v1_4_6.CraftServer;
@ -159,4 +160,15 @@ public class MCAccessCB2545 implements MCAccess{
return Long.MIN_VALUE;
}
@Override
public boolean hasGravity(final Material mat) {
switch(mat){
case SAND:
case GRAVEL:
return true;
default:
return false;
}
}
}

View File

@ -8,6 +8,7 @@ import net.minecraft.server.v1_4_R1.EntityPlayer;
import net.minecraft.server.v1_4_R1.MobEffectList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.craftbukkit.v1_4_R1.CraftServer;
@ -160,4 +161,16 @@ public class MCAccessCB2602 implements MCAccess{
return Long.MIN_VALUE;
}
@Override
public boolean hasGravity(final Material mat) {
switch(mat){
case SAND:
case GRAVEL:
return true;
default:
return false;
}
}
}

View File

@ -8,6 +8,7 @@ import net.minecraft.server.v1_5_R1.EntityPlayer;
import net.minecraft.server.v1_5_R1.MobEffectList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.craftbukkit.v1_5_R1.CraftServer;
@ -157,4 +158,15 @@ public class MCAccessCB2645 implements MCAccess{
return Long.MIN_VALUE;
}
@Override
public boolean hasGravity(final Material mat) {
switch(mat){
case SAND:
case GRAVEL:
return true;
default:
return false;
}
}
}

View File

@ -22,7 +22,7 @@
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.5.1-R0.2</version>
<version>1.5.1-R0.3-SNAPSHOT</version>
</dependency>
</dependencies>

View File

@ -8,6 +8,7 @@ import net.minecraft.server.v1_5_R2.EntityPlayer;
import net.minecraft.server.v1_5_R2.MobEffectList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.craftbukkit.v1_5_R2.CraftServer;
@ -157,4 +158,15 @@ public class MCAccessCB2691 implements MCAccess{
return Long.MIN_VALUE;
}
@Override
public boolean hasGravity(final Material mat) {
switch(mat){
case SAND:
case GRAVEL:
return true;
default:
return false;
}
}
}

View File

@ -8,6 +8,7 @@ import net.minecraft.server.v1_5_R2.EntityPlayer;
import net.minecraft.server.v1_5_R2.MobEffectList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.craftbukkit.v1_5_R2.CraftServer;
@ -157,4 +158,15 @@ public class MCAccessCBDev implements MCAccess{
return Long.MIN_VALUE;
}
@Override
public boolean hasGravity(final Material mat) {
switch(mat){
case SAND:
case GRAVEL:
return true;
default:
return false;
}
}
}

View File

@ -1,6 +1,7 @@
package fr.neatmonster.nocheatplus.checks.blockinteract;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
@ -9,9 +10,11 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import fr.neatmonster.nocheatplus.checks.CheckListener;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
/*
* M#"""""""'M dP dP M""M dP dP
@ -60,7 +63,7 @@ public class BlockInteractListener extends CheckListener {
* the event
*/
@EventHandler(
ignoreCancelled = true, priority = EventPriority.LOWEST)
ignoreCancelled = false, priority = EventPriority.LOWEST)
protected void onPlayerInteract(final PlayerInteractEvent event) {
/*
* ____ _ ___ _ _
@ -71,21 +74,33 @@ public class BlockInteractListener extends CheckListener {
* |___/
*/
// TODO: Cancelled events: might still have to check for use of blocks etc?
final Player player = event.getPlayer();
final Action action = event.getAction();
if (action != Action.LEFT_CLICK_BLOCK && action != Action.RIGHT_CLICK_BLOCK){
return;
}
final Block block = event.getClickedBlock();
// TODO: Re-arrange for interact spam, possibly move ender pearl stuff to a method.
final Action action = event.getAction();
final Block block = event.getClickedBlock();
if (block == null){
return;
}
final Player player = event.getPlayer();
switch(action){
case LEFT_CLICK_BLOCK:
break;
case RIGHT_CLICK_BLOCK:
final ItemStack stack = player.getItemInHand();
if (stack != null && stack.getTypeId() == Material.ENDER_PEARL.getId()){
if (!BlockProperties.isPassable(block.getTypeId())){
event.setUseItemInHand(Result.DENY);
}
}
break;
default:
return;
}
if (event.isCancelled()){
return;
}
final BlockInteractData data = BlockInteractData.getData(player);
final BlockInteractConfig cc = BlockInteractConfig.getConfig(player);

View File

@ -4,7 +4,10 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
@ -19,6 +22,7 @@ import fr.neatmonster.nocheatplus.checks.CheckListener;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.combined.Combined;
import fr.neatmonster.nocheatplus.checks.combined.Improbable;
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager;
import fr.neatmonster.nocheatplus.permissions.Permissions;
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
@ -275,11 +279,14 @@ public class BlockPlaceListener extends CheckListener {
* |__/
*/
// The shooter needs to be a player.
if (!(event.getEntity().getShooter() instanceof Player))
final Projectile entity = event.getEntity();
final Entity shooter = entity.getShooter();
if (!(shooter instanceof Player))
return;
// And the projectile must be one the following:
switch (event.getEntityType()) {
EntityType type = event.getEntityType();
switch (type) {
case ENDER_PEARL:
break;
case ENDER_SIGNAL:
@ -296,25 +303,56 @@ public class BlockPlaceListener extends CheckListener {
return;
}
final Player player = (Player) event.getEntity().getShooter();
final Player player = (Player) shooter;
// Do the actual check...
boolean cancel = false;
if (speed.isEnabled(player)){
final long now = System.currentTimeMillis();
final Location loc = player.getLocation();
if (Combined.checkYawRate(player, loc.getYaw(), now, loc.getWorld().getName())){
// Yawrate (checked extra).
event.setCancelled(true);
cancel = true;
}
if (speed.check(player)){
// If the check was positive, cancel the event.
event.setCancelled(true);
cancel = true;
}
else if (Improbable.check(player, 0.6f, now, "blockplace.speed")){
// Combined fighting speed.
event.setCancelled(true);
cancel = true;
}
}
// Ender pearl glitch (ab-) use.
if (!cancel && type == EntityType.ENDER_PEARL){
if (!BlockProperties.isPassable(entity.getLocation())){
// Launch into a block.
// TODO: This might be a general check later.
cancel = true;
}
else{
if (!BlockProperties.isPassable(player.getEyeLocation(), entity.getLocation())){
// Something between player
// TODO: This might be a general check later.
cancel = true;
}
else{
final Material mat = player.getLocation().getBlock().getType();
final long flags = BlockProperties.F_CLIMBABLE | BlockProperties.F_LIQUID | BlockProperties.F_IGN_PASSABLE;
if (mat != Material.AIR && (BlockProperties.getBlockFlags(mat.getId()) & flags) == 0 && !mcAccess.hasGravity(mat)){
// Still fails on piston traps etc.
if (!BlockProperties.isPassable(player.getLocation(), entity.getLocation()) && !BlockProperties.isOnGroundOrResetCond(player, player.getLocation(), MovingConfig.getConfig(player).yOnGround)){
cancel = true;
}
}
}
}
}
// Cancelled ?
if (cancel){
event.setCancelled(true);
}
}
}

View File

@ -0,0 +1,47 @@
package fr.neatmonster.nocheatplus.checks.moving;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.compat.MCAccess;
import fr.neatmonster.nocheatplus.utilities.BlockCache;
import fr.neatmonster.nocheatplus.utilities.PlayerLocation;
/**
* Coupling from and to PlayerLocation objects with a block cache for easy storage and reuse.
* @author mc_dev
*
*/
public class MoveInfo {
public final BlockCache cache;
public final PlayerLocation from;
public final PlayerLocation to;
public MoveInfo(final MCAccess mcAccess){
cache = mcAccess.getBlockCache(null);
from = new PlayerLocation(mcAccess, null);
to = new PlayerLocation(mcAccess, null);
}
/**
* Demands at least setting from.
* @param player
* @param from
* @param to
* @param yOnGround
*/
public final void set(final Player player, final Location from, final Location to, final double yOnGround){
this.from.set(from, player, yOnGround);
this.cache.setAccess(from.getWorld());
this.from.setBlockCache(cache);
if (to != null){
this.to.set(to, player, yOnGround);
this.to.setBlockCache(cache);
}
}
public final void cleanup(){
from.cleanup();
to.cleanup();
cache.cleanup();
}
}

View File

@ -535,5 +535,20 @@ public class MovingData extends ACheckData {
// TODO: Add to sum.
return used;
}
/**
* Test if the location is the same, ignoring pitch and yaw.
* @param loc
* @return
*/
public boolean isSetBack(final Location loc) {
if (loc == null || setBack == null){
return false;
}
if (!loc.getWorld().getName().equals(setBack.getWorld().getName())){
return false;
}
return loc.getX() == setBack.getX() && loc.getY() == setBack.getY() && loc.getZ() == setBack.getZ();
}
}

View File

@ -45,7 +45,6 @@ import fr.neatmonster.nocheatplus.checks.combined.BedLeave;
import fr.neatmonster.nocheatplus.checks.combined.Combined;
import fr.neatmonster.nocheatplus.checks.combined.CombinedData;
import fr.neatmonster.nocheatplus.command.INotifyReload;
import fr.neatmonster.nocheatplus.compat.MCAccess;
import fr.neatmonster.nocheatplus.components.IData;
import fr.neatmonster.nocheatplus.components.IHaveCheckType;
import fr.neatmonster.nocheatplus.components.INeedConfig;
@ -59,7 +58,6 @@ import fr.neatmonster.nocheatplus.logging.DebugUtil;
import fr.neatmonster.nocheatplus.logging.LogUtil;
import fr.neatmonster.nocheatplus.permissions.Permissions;
import fr.neatmonster.nocheatplus.players.DataManager;
import fr.neatmonster.nocheatplus.utilities.BlockCache;
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
import fr.neatmonster.nocheatplus.utilities.PlayerLocation;
@ -92,45 +90,6 @@ import fr.neatmonster.nocheatplus.utilities.build.BuildParameters;
*/
public class MovingListener extends CheckListener implements TickListener, IRemoveData, IHaveCheckType, INotifyReload, INeedConfig, JoinLeaveListener{
/**
* Coupling from and to PlayerLocation objects with a block cache for easy storage and reuse.
* @author mc_dev
*
*/
private static final class MoveInfo{
public final BlockCache cache;
public final PlayerLocation from;
public final PlayerLocation to;
public MoveInfo(final MCAccess mcAccess){
cache = mcAccess.getBlockCache(null);
from = new PlayerLocation(mcAccess, null);
to = new PlayerLocation(mcAccess, null);
}
/**
* Demands at least setting from.
* @param player
* @param from
* @param to
* @param yOnGround
*/
public final void set(final Player player, final Location from, final Location to, final double yOnGround){
this.from.set(from, player, yOnGround);
this.cache.setAccess(from.getWorld());
this.from.setBlockCache(cache);
if (to != null){
this.to.set(to, player, yOnGround);
this.to.setBlockCache(cache);
}
}
public final void cleanup(){
from.cleanup();
to.cleanup();
cache.cleanup();
}
}
/**
* Determine "some jump amplifier": 1 is jump boost, 2 is jump boost II. <br>
* NOTE: This is not the original amplifier value (use mcAccess for that).
@ -907,11 +866,15 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Detect small distance teleports.
boolean smallRange = false;
boolean cancel = false;
// boolean pass = false;
final double margin = 0.67;
final Location from = event.getFrom();
if (event.getCause() == TeleportCause.UNKNOWN){
final TeleportCause cause = event.getCause();
if (cause == TeleportCause.UNKNOWN){
// Check special small range teleports (moved too quickly).
if (from != null && from.getWorld().equals(to.getWorld())){
if (CheckUtils.distance(from, to) < margin){
@ -925,10 +888,46 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
}
}
else if (cause == TeleportCause.ENDER_PEARL){
if (!BlockProperties.isPassable(to)){ // || !BlockProperties.isOnGroundOrResetCond(player, to, 1.0)){
// Not check on-ground: Check the second throw.
cancel = true;
}
else{
// pass = true;
}
}
if (smallRange){
// if (pass){
// ref = to;
// }
// else
if (cancel){
// Cancel!
if (data.hasSetBack() && !data.hasSetBackWorldChanged(to)){
ref = data.getSetBack(to);
event.setTo(ref);
}
else{
ref = from;
event.setCancelled(true);
}
}
else if (smallRange){
// Very small range teleport, keep set back etc.
ref = to;
// if (data.hasSetBack() && !data.hasSetBackWorldChanged(to)){
// final Location setBack = data.getSetBack(from);
// Bukkit.getScheduler().scheduleSyncDelayedTask(this.plugin, new Runnable() {
// @Override
// public void run() {
// if (!data.hasSetBackWorldChanged(setBack)){ // && data.isSetBack(setBack)){
// player.sendMessage("SETBACK FROM MC DERP.");
// player.teleport(setBack);
// }
// }
// });
// }
}
else{
// "real" teleport
@ -954,7 +953,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
if (cc.debug && BuildParameters.debugLevel > 0){
System.out.println(player.getName() + " TP" + (smallRange ? " (small-range)" : "") + ": " + to);
System.out.println(player.getName() + " TP" + (smallRange ? " (small-range)" : "") + (cancel ? " (cancelled)" : "") + ": " + to);
}
}
else{
@ -1160,13 +1159,17 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final float fallDistance = player.getFallDistance();
final int damage = event.getDamage();
final float yDiff = (float) (data.noFallMaxY - loc.getY());
if (cc.debug) System.out.println(player.getName() + " damage(FALL): " + damage + " / dist=" + player.getFallDistance() + " nf=" + data.noFallFallDistance + " yDiff=" + yDiff);
if (cc.debug){
System.out.println(player.getName() + " damage(FALL): " + damage + " / dist=" + player.getFallDistance() + " nf=" + data.noFallFallDistance + " yDiff=" + yDiff);
}
// Fall-back check.
final int maxD = NoFall.getDamage(Math.max(yDiff, Math.max(data.noFallFallDistance, fallDistance))) + (allowReset ? 0 : 3);
if (maxD > damage){
// TODO: respect dealDamage ?
event.setDamage(maxD);
if (cc.debug) System.out.println(player.getName() + " Adjust fall damage to: " + maxD);
if (cc.debug){
System.out.println(player.getName() + " Adjust fall damage to: " + maxD);
}
}
if (allowReset){
// Normal fall damage, reset data.
@ -1258,8 +1261,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final Entity entity = event.getExited();
if (!(entity instanceof Player)) return;
onPlayerVehicleLeave((Player) entity);
// System.out.println("Vehicle: " + event.getVehicle().getLocation());
// System.out.println("Player: " + entity.getLocation());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)