Skip to content

Commit

Permalink
More skipping conditions for "set back on tick".
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
asofold committed Apr 7, 2017
1 parent d06e658 commit 718f991
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 1 deletion.
Expand Up @@ -45,6 +45,7 @@
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;
Expand Down Expand Up @@ -740,6 +741,20 @@ public boolean isTeleportedPosition(final Location loc) {
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
Expand Down
Expand Up @@ -49,6 +49,7 @@ public static enum AckResolution {
private long maxAge = 4000; // TODO: configurable
private int maxQueueSize = 60; // TODO: configurable

private CountableLocation lastAck = null;

/**
* Maximum age in milliseconds, older entries expire.
Expand All @@ -57,13 +58,18 @@ public static enum AckResolution {
public long getMaxAge() {
return maxAge;
}

public CountableLocation getLastAck() {
return lastAck;
}

/**
* Call for Bukkit events (expect this packet to be sent).
* @param packetData
*/
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();
}
Expand Down Expand Up @@ -174,6 +180,7 @@ else if (packetData.isSameLocation(ref)) {
if (--ref.count <= 0) { // (Lots of safety margin.)
expectIncoming.removeFirst(); // Do not use the iterator here.
}
lastAck = ref;
return AckResolution.ACK;
}
else {
Expand Down
Expand Up @@ -26,14 +26,19 @@
import java.util.concurrent.locks.ReentrantLock;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;

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;
Expand Down Expand Up @@ -648,6 +653,10 @@ public static void reset() {
}

// 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.
Expand Down Expand Up @@ -693,11 +702,43 @@ private void processPlayerSetBackIds() {
}
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 !?)
Expand Down

0 comments on commit 718f991

Please sign in to comment.