More skipping conditions for "set back on tick".

* The player is at the coordinates.
* The last received ACK for an outgoing teleport has been received on
packet level. This is experimental, to be confirmed to a) do something
b) not allow abuse.
This commit is contained in:
asofold 2017-04-07 16:31:02 +02:00
parent d06e658c7a
commit 718f991832
3 changed files with 64 additions and 1 deletions

View File

@ -45,6 +45,7 @@ import fr.neatmonster.nocheatplus.checks.workaround.WRPT;
import fr.neatmonster.nocheatplus.compat.blocks.changetracker.BlockChangeReference;
import fr.neatmonster.nocheatplus.components.data.ICanHandleTimeRunningBackwards;
import fr.neatmonster.nocheatplus.components.entity.IEntityAccessDimensions;
import fr.neatmonster.nocheatplus.components.location.IGetPosition;
import fr.neatmonster.nocheatplus.components.location.IPositionWithLook;
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
import fr.neatmonster.nocheatplus.utilities.TickTask;
@ -740,6 +741,20 @@ public class MovingData extends ACheckData {
return loc != null && teleported != null && TrigUtil.isSamePos(teleported, loc);
}
/**
* Check if the given location has the same coordinates like the
* 'teleported' (set back) location. This is more light-weight and more
* lenient than isTeleported, because world and yaw and pitch are all
* ignored.
*
* @param loc
* @return In case of either loc or teleported being null, false is
* returned, otherwise TrigUtil.isSamePos(pos, teleported).
*/
public boolean isTeleportedPosition(final IGetPosition pos) {
return pos != null && teleported != null && TrigUtil.isSamePos(pos, teleported);
}
/**
* Set teleport-to location to recognize NCP set backs. This copies the coordinates and world.
* @param loc

View File

@ -49,6 +49,7 @@ public class TeleportQueue {
private long maxAge = 4000; // TODO: configurable
private int maxQueueSize = 60; // TODO: configurable
private CountableLocation lastAck = null;
/**
* Maximum age in milliseconds, older entries expire.
@ -57,6 +58,10 @@ public class TeleportQueue {
public long getMaxAge() {
return maxAge;
}
public CountableLocation getLastAck() {
return lastAck;
}
/**
* Call for Bukkit events (expect this packet to be sent).
@ -64,6 +69,7 @@ public class TeleportQueue {
*/
public void onTeleportEvent(final double x, final double y, final double z, final float yaw, final float pitch) {
lock.lock();
lastAck = null;
expectOutgoing = new DataLocation(x, y, z, yaw, pitch);
lock.unlock();
}
@ -174,6 +180,7 @@ public class TeleportQueue {
if (--ref.count <= 0) { // (Lots of safety margin.)
expectIncoming.removeFirst(); // Do not use the iterator here.
}
lastAck = ref;
return AckResolution.ACK;
}
else {

View File

@ -26,6 +26,7 @@ import java.util.UUID;
import java.util.concurrent.locks.ReentrantLock;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
@ -33,7 +34,11 @@ import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.checks.access.ICheckData;
import fr.neatmonster.nocheatplus.checks.combined.Improbable;
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
import fr.neatmonster.nocheatplus.checks.moving.player.PlayerSetBackMethod;
import fr.neatmonster.nocheatplus.checks.net.NetData;
import fr.neatmonster.nocheatplus.checks.net.model.CountableLocation;
import fr.neatmonster.nocheatplus.compat.BridgeMisc;
import fr.neatmonster.nocheatplus.components.registry.feature.TickListener;
import fr.neatmonster.nocheatplus.logging.StaticLog;
@ -648,6 +653,10 @@ public class TickTask implements Runnable {
}
// Instance methods (meant private).
/** Temporary use only, beware of nesting. Cleanup with setWorld(null). */
private final Location useLoc = new Location(null, 0, 0, 0);
/**
*
* Notify all listeners. A copy of the listeners under lock, then processed without lock. Theoretically listeners can get processed though they have already been unregistered.
@ -693,11 +702,43 @@ public class TickTask implements Runnable {
}
continue;
}
if (!player.teleport(data.getTeleported(), BridgeMisc.TELEPORT_CAUSE_CORRECTION_OF_POSITION)) {
// (teleported is set.).
final Location loc = player.getLocation(useLoc);
if (data.isTeleportedPosition(loc)) {
// Skip redundant teleport.
if (data.debug) {
CheckUtils.debug(player, CheckType.MOVING, "Player set back on tick: Skip teleport, player is there, already.");
}
continue;
}
// (player is somewhere else.)
// TODO: Consider to skip packet level, if not available (plus optimize access to the information).
final PlayerSetBackMethod method = MovingConfig.getConfig(player).playerSetBackMethod;
if (method.shouldCancel() || method.shouldSetTo()) {
/*
* Another leniency option: Skip, if we have already received an
* ACK for this position on packet level.
*/
// (CANCEL + UPDATE_FROM mean a certain teleport to the set back, still could be repeated tp.)
final CountableLocation cl = ((NetData) CheckType.NET.getDataFactory().getData(player)).teleportQueue.getLastAck();
if (data.isTeleportedPosition(cl)) {
if (data.debug) {
CheckUtils.debug(player, CheckType.MOVING, "Player set back on tick: Skip teleport, having received an ACK for the teleport on packet level.");
}
continue;
}
}
// (No ACK received yet.)
final Location teleported = data.getTeleported();
if (!player.teleport(teleported, BridgeMisc.TELEPORT_CAUSE_CORRECTION_OF_POSITION)) {
if (data .debug) {
CheckUtils.debug(player, CheckType.MOVING, "Player set back on tick: Teleport failed.");
}
}
// Cleanup.
useLoc.setWorld(null);
// (Data resetting is done during PlayerTeleportEvent handling.)
}
// (There could be ids kept on errors !?)