Skip to content

Commit

Permalink
Alter FlyingFrequency to match redundancy vs. MovingData (toX, ...).
Browse files Browse the repository at this point in the history
First attempt to detect if a moving event would fire. This might not be
100% accurate, as a) we can'T really know and b) lastTo is not minitored
in the most reliable way (e.g. teleport on highest priority, resetting
logic favors set-backs).
  • Loading branch information
asofold committed Jan 21, 2015
1 parent f79cda4 commit f8cbe40
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 126 deletions.
Expand Up @@ -13,13 +13,16 @@
import com.comphenix.protocol.events.PacketEvent;

import fr.neatmonster.nocheatplus.NCPAPIProvider;
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
import fr.neatmonster.nocheatplus.components.JoinLeaveListener;
import fr.neatmonster.nocheatplus.logging.Streams;
import fr.neatmonster.nocheatplus.net.NetConfig;
import fr.neatmonster.nocheatplus.net.NetConfigCache;
import fr.neatmonster.nocheatplus.stats.Counters;
import fr.neatmonster.nocheatplus.time.monotonic.Monotonic;
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
import fr.neatmonster.nocheatplus.utilities.TrigUtil;

/**
* Prevent extremely fast ticking by just sending packets that don't do anything
Expand All @@ -30,6 +33,10 @@
*/
public class FlyingFrequency extends PacketAdapter implements JoinLeaveListener {

public static final double minMoveDistSq = 1f / 256; // PlayerConnection magic.

public static final float minLookChange = 10f;

// TODO: Most efficient registration + optimize (primary thread or asynchronous).

private class FFData {
Expand All @@ -39,10 +46,7 @@ private class FFData {
public static final int indexhasLook = 2;

public final ActionFrequency all;
// Last move.
public final double[] doubles = new double[3]; // x, y, z
public final float[] floats = new float[2]; // yaw, pitch
//public final boolean[] booleans = new boolean[3]; // ground, hasPos, hasLook
// Last move on-ground.
public boolean onGround = false;
public long timeOnGround = 0;
public long timeNotOnGround = 0;
Expand Down Expand Up @@ -117,55 +121,34 @@ public void onPacketReceiving(final PacketEvent event) {
}

// Cancel redundant packets, when frequency is high anyway.
if (cancelRedundant && cc.flyingFrequencyCancelRedundant && checkRedundantPackets(event, allScore, data, cc)) {
if (cancelRedundant && cc.flyingFrequencyCancelRedundant && checkRedundantPackets(player, event, allScore, data, cc)) {
event.setCancelled(true);
}

}

private boolean checkRedundantPackets(final PacketEvent event, final float allScore, final FFData data, final NetConfig cc) {
// TODO: Check vs. MovingData last-to.
private boolean checkRedundantPackets(final Player player, final PacketEvent event, final float allScore, final FFData data, final NetConfig cc) {
// TODO: Consider quick return conditions.
// TODO: Debug logging (better with integration into DataManager).
// TODO: Consider to compare to moving data directly, skip keeping track extra.

boolean redundant = true;
final PacketContainer packet = event.getPacket();
final List<Boolean> booleans = packet.getBooleans().getValues();
if (booleans.size() != FFData.numBooleans) {
return packetMismatch();
}
final boolean onGround = booleans.get(FFData.indexOnGround).booleanValue();
final boolean hasPos = booleans.get(FFData.indexhasPos);
final boolean hasLook = booleans.get(FFData.indexhasLook);

if (hasPos) {
final List<Double> doubles = packet.getDoubles().getValues();
if (doubles.size() != data.doubles.length) {
return packetMismatch();
}
for (int i = 0; i < data.doubles.length; i++) {
final double val = doubles.get(i).doubleValue();
if (val != data.doubles[i]) {
redundant = false;
data.doubles[i] = val;
}
}
}

if (hasLook) {
final List<Float> floats = packet.getFloat().getValues();
if (floats.size() != data.floats.length) {
return packetMismatch();
}
for (int i = 0; i < data.floats.length; i++) {
final float val = floats.get(i).floatValue();
if (val != data.floats[i]) {
redundant = false;
data.floats[i] = val;
}
}
final MovingData mData = MovingData.getData(player);
if (mData.toX == Double.MAX_VALUE && mData.toYaw == Float.MAX_VALUE) {
// Can not check.
return false;
}
final boolean hasPos = booleans.get(FFData.indexhasPos);
final boolean hasLook = booleans.get(FFData.indexhasLook);
final boolean onGround = booleans.get(FFData.indexOnGround).booleanValue();
boolean onGroundSkip = false;

// Allow at least one on-ground change per second.
// TODO: Consider to verify on ground somehow (could tell MovingData the state).
if (onGround != data.onGround) {
// Regard as not redundant only if sending the same state happened at least a second ago.
Expand All @@ -178,20 +161,58 @@ private boolean checkRedundantPackets(final PacketEvent event, final float allSc
lastTime = data.timeNotOnGround;
data.timeNotOnGround = time;
}
// Only invalidate if there is no look/pos.
if (time - lastTime < 1000) {
redundant = false;
onGroundSkip = true;
}
}
data.onGround = onGround;

if (redundant) {
// TODO: Could check first bucket or even just 50 ms to last packet.
if (allScore / cc.flyingFrequencySeconds > 20f) {
counters.add(idRedundant, 1);
if (hasPos) {
final List<Double> doubles = packet.getDoubles().getValues();
if (doubles.size() != 3) {
return packetMismatch();
}
final double x = doubles.get(0).doubleValue();
final double y = doubles.get(1).doubleValue();
final double z = doubles.get(2).doubleValue();
if (CheckUtils.isBadCoordinate(x, y, z)) {
// TODO: Alert, counters, kick.
return true;
}
if (TrigUtil.distanceSquared(x, y, z, mData.toX, mData.toY, mData.toZ) > minMoveDistSq) {
return false;
}
}

if (hasLook) {
final List<Float> floats = packet.getFloat().getValues();
if (floats.size() != 2) {
return packetMismatch();
}
final float yaw = floats.get(0).floatValue();
final float pitch = floats.get(1).floatValue();
// TODO: Consider to detect bad pitch too.
if (CheckUtils.isBadCoordinate(yaw, pitch)) {
// TODO: Alert, counters, kick.
return true;
}
if (Math.abs(TrigUtil.yawDiff(yaw, mData.toYaw)) > minLookChange || Math.abs(TrigUtil.yawDiff(pitch, mData.toPitch)) > minLookChange) {
return false;
}
}

if (onGroundSkip) {
return false;
}

// TODO: Could check first bucket or even just 50 ms to last packet.
if (allScore / cc.flyingFrequencySeconds > 20f) {
counters.add(idRedundant, 1);
return true;
} else {
return false;
}
return false;
}

/**
Expand Down
Expand Up @@ -130,7 +130,9 @@ public static void onReload() {
/** Last from coordinates. X is at Double.MAX_VALUE, if not set. */
public double fromX = Double.MAX_VALUE, fromY, fromZ;
/** Last to coordinates. X is at Double.MAX_VALUE, if not set. */
public double toX = Double.MAX_VALUE, toY, toZ;
public double toX = Double.MAX_VALUE, toY, toZ;
/** Last to looking direction. Yaw is at Float.MAX_VALUE if not set. */
public float toYaw = Float.MAX_VALUE, toPitch ;
/** Moving trace (to-positions, use tick as time). This is initialized on "playerJoins, i.e. MONITOR, and set to null on playerLeaves." */
private LocationTrace trace = null;

Expand Down Expand Up @@ -225,6 +227,7 @@ public void clearFlyData() {
setBack = null;
sfLastYDist = sfLastHDist = Double.MAX_VALUE;
fromX = toX = Double.MAX_VALUE;
toYaw = Float.MAX_VALUE;
clearAccounting();
clearNoFallData();
removeAllVelocity();
Expand Down Expand Up @@ -290,10 +293,10 @@ public void prepareSetBack(final Location loc) {
*/
public void resetPositions(final Location loc) {
if (loc == null) {
resetPositions(Double.MAX_VALUE, 0, 0);
resetPositions();
}
else {
resetPositions(loc.getX(), loc.getY(), loc.getZ());
resetPositions(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
}
}

Expand All @@ -303,23 +306,32 @@ public void resetPositions(final Location loc) {
*/
public void resetPositions(PlayerLocation loc) {
if (loc == null) {
resetPositions(Double.MAX_VALUE, 0, 0);
resetPositions();
}
else {
resetPositions(loc.getX(), loc.getY(), loc.getZ());
resetPositions(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
}
}

/**
* Reset the "last locations" to "not set".
*/
public void resetPositions() {
resetPositions(Double.MAX_VALUE, 0.0, 0.0, Float.MAX_VALUE, 0f);
}

/**
* Just reset the "last locations" references.
* @param x
* @param y
* @param z
*/
public void resetPositions(final double x, final double y, final double z) {
public void resetPositions(final double x, final double y, final double z, final float yaw, final float pitch) {
fromX = toX = x;
fromY = toY = y;
fromZ = toZ = z;
toYaw = yaw;
toPitch = pitch;
sfLastYDist = sfLastHDist = Double.MAX_VALUE;
sfDirty = false;
sfLowJump = false;
Expand All @@ -328,6 +340,22 @@ public void resetPositions(final double x, final double y, final double z) {
// No reset of vehicleConsistency.
}

/**
* Set positions according to a move (just to and from).
* @param from
* @param to
*/
public void setPositions(final Location from, final Location to) {
fromX = from.getX();
fromY = from.getY();
fromZ = from.getZ();
toX = to.getX();
toY = to.getY();
toZ = to.getZ();
toYaw = to.getYaw();
toPitch = to.getPitch();
}

/**
* Clear accounting data.
*/
Expand Down Expand Up @@ -516,6 +544,8 @@ public final void setTo(final Location to) {
toX = to.getX();
toY = to.getY();
toZ = to.getZ();
toYaw = to.getYaw();
toPitch = to.getPitch();
}

/**
Expand Down
Expand Up @@ -609,12 +609,7 @@ else if (checkCf) {
if (newTo == null) {
// Set positions.
// TODO: Consider setting in Monitor (concept missing for changing coordinates, could double-check).
data.fromX = from.getX();
data.fromY = from.getY();
data.fromZ = from.getZ();
data.toX = to.getX();
data.toY = to.getY();
data.toZ = to.getZ();
data.setPositions(from, to);
}
else {
// Set-back handling.
Expand Down

0 comments on commit f8cbe40

Please sign in to comment.