Skip to content

Commit

Permalink
[BLEEDING, INSTABLE] Switch horizontal velocity to a new method.
Browse files Browse the repository at this point in the history
This method remembers (currently) each velocity added and only uses it
when it is needed not to generate a violation. Further (currently
simple) activation and invalidation logics are applied. With this method
latency will be much less of a problem, though stacking of queued
entries (especially for rocket-boots style flying) and more
merging of entries and more invalidation logics are required, thus
bleeding+instable.

On the long term this should make cheating much more difficult, possible
steps are:
1. Use method for vertical velocity too (only positive)
2. Distinguish positive and negative vertical velocity (opens a way to
control the speed downwards in any medium!).
3. Per-axis velocity (either absolute or pos/neg with more invalidation
logic on direction changes).
  • Loading branch information
asofold committed Mar 8, 2013
1 parent 24c1599 commit 5dd09d4
Show file tree
Hide file tree
Showing 9 changed files with 280 additions and 46 deletions.
Expand Up @@ -83,7 +83,23 @@ public Location check(final Player player, final PlayerLocation from, final Play
final double limitH = cc.creativeFlyHorizontalSpeed / 100D * HORIZONTAL_SPEED * fSpeed;

// Finally, determine how far the player went beyond the set limits.
double resultH = Math.max(0.0D, hDistance - data.horizontalFreedom - limitH);
// double resultH = Math.max(0.0D, hDistance - data.horizontalFreedom - limitH);
double resultH = Math.max(0.0D, hDistance - limitH);

// Check velocity.
if (resultH > 0){
double hFreedom = data.getHorizontalFreedom();
if (hFreedom < resultH){
// Use queued velocity if possible.
hFreedom += data.useHorizontalVelocity(resultH - hFreedom);
}
if (hFreedom > 0.0){
resultH = Math.max(0.0, resultH - hFreedom);
}
}
else{
data.hVelActive.clear(); // TODO: test/check !
}

final boolean sprinting = player.isSprinting() && player.getFoodLevel() > 5;

Expand Down
Expand Up @@ -119,6 +119,7 @@ public static MovingConfig getConfig(final Player player) {
// Special tolerance values:
/** This is not strictly ticks, but packets, for now.*/
public final int velocityGraceTicks;
public final int velocityActivationCounter;
public final double noFallyOnGround;
public final double yOnGround;
public final double yStep;
Expand Down Expand Up @@ -183,6 +184,7 @@ public MovingConfig(final ConfigFile config) {
sfHoverViolation = config.getDouble(ConfPaths.MOVING_SURVIVALFLY_HOVER_SFVIOLATION);

velocityGraceTicks = config.getInt(ConfPaths.MOVING_VELOCITY_GRACETICKS);
velocityActivationCounter = config.getInt(ConfPaths.MOVING_VELOCITY_ACTIVATIONCOUNTER);
yOnGround = config.getDouble(ConfPaths.MOVING_YONGROUND, 0.001, 2.0, 0.0626); // sqrt(1/256), see: NetServerHandler.
noFallyOnGround = config.getDouble(ConfPaths.MOVING_NOFALL_YONGROUND, 0.001, 2.0, yOnGround);
// ystep is set to 0.45 by default, for stairs / steps.
Expand Down
@@ -1,6 +1,9 @@
package fr.neatmonster.nocheatplus.checks.moving;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.bukkit.Location;
Expand Down Expand Up @@ -90,10 +93,14 @@ public static void clear(){
public int verticalVelocityCounter;
public double verticalFreedom;
public double verticalVelocity;
public int verticalVelocityUsed = 0;
public int horizontalVelocityCounter;
public double horizontalFreedom;
public int horizontalVelocityUsed = 0;
public int verticalVelocityUsed = 0;
/** Active velocity entries (horizontal distance). */
public final List<Velocity> hVelActive = new LinkedList<Velocity>();
/** Queued velocity entries (horizontal distance). */
public final List<Velocity> hVelQueued = new LinkedList<Velocity>();
// public int horizontalVelocityCounter;
// public double horizontalFreedom;
// public int horizontalVelocityUsed = 0;

// Coordinates.
/** Last from coordinates. */
Expand Down Expand Up @@ -176,6 +183,7 @@ public void clearFlyData() {
fromX = toX = Double.MAX_VALUE;
clearAccounting();
clearNoFallData();
removeAllVelocity();
sfHorizontalBuffer = 0;
sfHBufExtra = 0;
toWasReset = fromWasReset = false; // TODO: true maybe
Expand Down Expand Up @@ -211,6 +219,7 @@ public void onSetBack(final Location setBack) {
sfHoverTicks = -1;
sfDirty = false;
mediumLiftOff = defaultMediumLiftOff;
removeAllVelocity();
}

/**
Expand Down Expand Up @@ -403,5 +412,98 @@ public final void setTo(final Location to) {
toY = to.getY();
toZ = to.getZ();
}

/**
* Add horizontal velocity (distance). <br>
* Since velocity is seldom an access method should be better. Flying players are expensive anyway, so this should not matter too much.
* @param vel
*/
public void addHorizontalVelocity(final Velocity vel) {
// TODO: Might merge entries !
hVelQueued.add(vel);
}

/**
* Currently only applies to horizontal velocity.
*/
public void removeAllVelocity(){
hVelActive.clear();
hVelQueued.clear();
}

/**
* Remove all velocity entries that are invalid. Checks both active and queued.
* <br>(This does not catch invalidation by speed / direction changing.)
*/
public void removeInvalidVelocity() {
// TODO: Also merge entries here, or just on adding?
Iterator<Velocity> it;
// Active.
it = hVelActive.iterator();
while (it.hasNext()){
final Velocity vel = it.next();
// TODO: 0.001 can be stretched somewhere else, most likely...
if (vel.valCount <= 0 || vel.value <= 0.001) it.remove();
}
// Queued.
it = hVelQueued.iterator();
while (it.hasNext()){
final Velocity vel = it.next();
if (vel.actCount <= 0) it.remove();
}
}

/**
* Called for moving events, increase age of velocity.
*/
public void velocityTick(){
// Increase counts for active.
for (final Velocity vel : hVelActive){
vel.actCount --;
vel.sum += vel.value;
vel.value *= 0.9; // TODO: Actual friction.
}
// Increase counts for queued.
final Iterator<Velocity> it = hVelQueued.iterator();
while (it.hasNext()){
it.next().actCount --;
}
}

/**
* Get effective amount of all used velocity.
* @return
*/
public double getHorizontalFreedom() {
// TODO: model/calculate it as accurate as possible...
double f = 0;
for (final Velocity vel : hVelActive){
f += vel.value;
}
return f;
}

/**
* Use all queued velocity until at least amount is matched.
* Amount is the horizontal distance that is to be covered by velocity (active has already been checked).
* <br>
* If the modeling changes (max instead of sum or similar), then this will be affected.
* @param amount The amount used.
* @return
*/
public double useHorizontalVelocity(final double amount) {
final Iterator<Velocity> it = hVelQueued.iterator();
double used = 0;
while (it.hasNext()){
final Velocity vel = it.next();
used += vel.value;
hVelActive.add(vel);
it.remove();
if (used >= amount){
break;
}
}
return used;
}

}
Expand Up @@ -455,6 +455,7 @@ public void onPlayerMove(final PlayerMoveEvent event) {
if (player.isInsideVehicle()){
// Workaround for pigs !
data.sfHoverTicks = -1;
data.removeAllVelocity();
final Entity vehicle = player.getVehicle();
if (vehicle != null && (vehicle instanceof Pig)){
onVehicleMove(new VehicleMoveEvent((Vehicle) vehicle, event.getFrom(), event.getFrom()));
Expand Down Expand Up @@ -518,22 +519,24 @@ public void onPlayerMove(final PlayerMoveEvent event) {
// Just try to estimate velocities over time. Not very precise, but works good enough most of the time. Do
// general data modifications one for each event.
// TODO: Rework to queued velocity entries: activation + invalidation
// Horizontal velocity.
if (data.horizontalVelocityCounter > 0D){
data.horizontalVelocityUsed ++;
data.horizontalVelocityCounter--;
data.horizontalFreedom = Math.max(0.0, data.horizontalFreedom - 0.09);
}
else if (data.horizontalFreedom > 0.001D){
if (data.verticalVelocityUsed == 1 && data.verticalVelocity > 0.5){
data.horizontalVelocityUsed = 0;
data.horizontalFreedom = 0;
}
else{
data.horizontalVelocityUsed ++;
data.horizontalFreedom *= 0.90D;
}
}
data.removeInvalidVelocity();
data.velocityTick();
// // Horizontal velocity.
// if (data.horizontalVelocityCounter > 0D){
// data.horizontalVelocityUsed ++;
// data.horizontalVelocityCounter--;
// data.horizontalFreedom = Math.max(0.0, data.horizontalFreedom - 0.09);
// }
// else if (data.horizontalFreedom > 0.001D){
// if (data.verticalVelocityUsed == 1 && data.verticalVelocity > 0.5){
// data.horizontalVelocityUsed = 0;
// data.horizontalFreedom = 0;
// }
// else{
// data.horizontalVelocityUsed ++;
// data.horizontalFreedom *= 0.90D;
// }
// }
// Vertical velocity.
if (data.verticalVelocity <= 0.09D){
data.verticalVelocityUsed ++;
Expand Down Expand Up @@ -951,6 +954,8 @@ public void onPlayerVelocity(final PlayerVelocityEvent event) {

if (cc.debug) System.out.println(event.getPlayer().getName() + " new velocity: " + velocity);

// TODO: Check for vehicles ?

double newVal = velocity.getY();
if (newVal >= 0D) {
if (data.verticalFreedom <= 0.001 && data.verticalVelocityCounter >= 0){
Expand All @@ -964,9 +969,12 @@ public void onPlayerVelocity(final PlayerVelocityEvent event) {

newVal = Math.sqrt(velocity.getX() * velocity.getX() + velocity.getZ() * velocity.getZ());
if (newVal > 0D) {
data.horizontalFreedom += newVal;
data.horizontalVelocityCounter = Math.min(100, Math.max(data.horizontalVelocityCounter, cc.velocityGraceTicks ) + 1 + (int) Math.round(newVal * 10.0)); // 30;
data.horizontalVelocityUsed = 0;
final Velocity vel = new Velocity(newVal, cc.velocityActivationCounter, 1 + (int) Math.round(newVal * 10.0));
data.removeInvalidVelocity();
data.addHorizontalVelocity(vel);
// data.horizontalFreedom += newVal;
// data.horizontalVelocityCounter = Math.min(100, Math.max(data.horizontalVelocityCounter, cc.velocityGraceTicks ) + 1 + (int) Math.round(newVal * 10.0)); // 30;
// data.horizontalVelocityUsed = 0;
}

// Set dirty flag here.
Expand Down Expand Up @@ -1121,6 +1129,7 @@ public void onPlayerJoin(final PlayerJoinEvent event) {
final MovingData data = MovingData.getData(player);
// TODO: on existing set back: detect world changes and loss of world on join (+ set up some paradigm).
data.clearMorePacketsData();
data.removeAllVelocity();
final Location loc = player.getLocation();

// Correct set-back on world changes.
Expand Down Expand Up @@ -1167,7 +1176,8 @@ public void onPlayerQuit(final PlayerQuitEvent event){
private void onLeave(final Player player) {
survivalFly.setReallySneaking(player, false);
noFall.onLeave(player);

final MovingData data = MovingData.getData(player);
data.removeAllVelocity();
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
Expand Down Expand Up @@ -1199,9 +1209,11 @@ private final void onPlayerVehicleLeave(final Player player){
data.resetPositions(loc);
data.setSetBack(loc);
// Experiment: add some velocity (fake).
data.horizontalVelocityCounter = 1;
data.horizontalFreedom = 0.9;
data.horizontalVelocityUsed = 0;
// data.horizontalVelocityCounter = 1;
// data.horizontalFreedom = 0.9;
// data.horizontalVelocityUsed = 0;
data.removeAllVelocity();
data.addHorizontalVelocity(new Velocity(0.9, 1, 1));
data.verticalVelocityCounter = 1;
data.verticalFreedom = 1.2;
data.verticalVelocity = 0.15;
Expand Down

0 comments on commit 5dd09d4

Please sign in to comment.