[BLEEDING] Fixes and refactoring for vertical velocity handling.

This is not the thing (lots of yet), but it is a small step.

Refactor:
* Use access methods for several details on vertical velocity.

Fixes:
* Dont reset the current jump phase if there is vertical freedom left,
because the next jump might then cause a violation.
* Fix clearActiveVerVel (remainder used to clear hVel, yet unused).
* Clear vertical velocity on removeAllVelocity (!).
* Keep setting sfDirty if velocity is found, to prevent premature reset.

Missing:
* Some resetting conditions for sfDirty might be missing.
* Implement an error counter increasing with velocity-add by 1.0 or
slightly more , decreasing with violations, but undo violations if count
is > 0.0. Use at least for vertical accounting, in order to go stricter
on cheating with velocity.
* Revise setting sfDirty on horizontal velocity as well.
* Switch to AxisVelocity (vertical), accounting for + and -.
This commit is contained in:
asofold 2015-03-28 23:06:30 +01:00
parent 4180d3b20b
commit 1510f01144
5 changed files with 137 additions and 48 deletions

View File

@ -58,9 +58,9 @@ public class Critical extends Check {
if (mcFallDistance > 0.0 && !player.isInsideVehicle() && !player.hasPotionEffect(PotionEffectType.BLINDNESS)) {
// Might be a violation.
final MovingData dataM = MovingData.getData(player);
// TODO: Skip near the highest jump height (needs check if head collided with something solid, which also detects low jump).
if (!dataM.sfDirty && (dataM.sfLowJump && !dataM.sfNoLowJump && dataM.mediumLiftOff == MediumLiftOff.GROUND
if (!dataM.isVelocityJumpPhase() && (dataM.sfLowJump && !dataM.sfNoLowJump && dataM.mediumLiftOff == MediumLiftOff.GROUND
|| mcFallDistance < cc.criticalFallDistance && !BlockProperties.isResetCond(player, loc, mCc.yOnGround))) {
final MovingConfig ccM = MovingConfig.getConfig(player);
if (MovingUtil.shouldCheckSurvivalFly(player, dataM, ccM)) {

View File

@ -143,11 +143,12 @@ public class CreativeFly extends Check {
// final double resultV = (vDistanceAboveLimit - limitV) * 100D;
// final double result = Math.max(0.0, resultH) + Math.max(0D, resultV);
// Old handling.
final double resultV = (yDistance - data.verticalFreedom - limitV) * 100D;
final double verticalFreedom = data.getVerticalFreedom();
final double resultV = (yDistance - verticalFreedom - limitV) * 100D;
final double result = Math.max(0.0, resultH) + Math.max(0D, resultV);
if (cc.debug) {
outpuDebugMove(player, hDistance, limitH, yDistance, data.verticalFreedom, limitV);
outpuDebugMove(player, hDistance, limitH, yDistance, verticalFreedom, limitV);
}
// The player went to far, either horizontal or vertical.

View File

@ -15,6 +15,7 @@ import fr.neatmonster.nocheatplus.logging.Streams;
import fr.neatmonster.nocheatplus.utilities.ActionAccumulator;
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
import fr.neatmonster.nocheatplus.utilities.PlayerLocation;
import fr.neatmonster.nocheatplus.utilities.StringUtil;
import fr.neatmonster.nocheatplus.utilities.TickTask;
/**
@ -118,10 +119,10 @@ public class MovingData extends ACheckData {
// TODO: consider resetting these with clearFlyData and onSetBack.
/** Vertical velocity modeled as an axis (positive and negative possible) */
//private final AxisVelocity verVel = new AxisVelocity();
public int verticalVelocityCounter;
public double verticalFreedom;
public double verticalVelocity;
public int verticalVelocityUsed = 0;
private int verticalVelocityCounter;
private double verticalFreedom;
private double verticalVelocity;
private int verticalVelocityUsed = 0;
/** Horizontal velocity modeled as an axis (always positive) */
private final AxisVelocity horVel = new AxisVelocity();
@ -182,7 +183,7 @@ public class MovingData extends ACheckData {
public int lostSprintCount = 0;
public int sfJumpPhase = 0;
/** "Dirty" flag, for receiving velocity and similar while in air. */
public boolean sfDirty = false;
private boolean sfDirty = false;
/** Indicate low jumping descending phase (likely cheating). */
public boolean sfLowJump = false;
@ -561,7 +562,8 @@ public class MovingData extends ACheckData {
*/
public void removeAllVelocity() {
horVel.clear();
// verVel.clear();
clearActiveVerVel(); // Until we have a better method.
sfDirty = false;
}
/**
@ -581,13 +583,6 @@ public class MovingData extends ACheckData {
horVel.clearActive();
}
/**
* Clear only active horizontal velocity.
*/
public void clearActiveVerVel() {
horVel.clearActive();
}
public boolean hasActiveHorVel() {
return horVel.hasActive();
}
@ -596,6 +591,16 @@ public class MovingData extends ACheckData {
return horVel.hasQueued();
}
/**
* Clear active vertical velocity (until recoded, this will remove all vertical velocity).
*/
public void clearActiveVerVel() {
verticalFreedom = 0.0;
verticalVelocity = 0.0;
verticalVelocityCounter = 0;
verticalVelocityUsed = 0;
}
// public boolean hasActiveVerVel() {
// return verVel.hasActive();
// }
@ -635,6 +640,10 @@ public class MovingData extends ACheckData {
verticalFreedom *= 0.93D;
}
}
if (horVel.hasActive() || horVel.hasQueued() || verticalFreedom > 0.001) {
// Renew the dirty phase.
sfDirty = true;
}
}
/**
@ -851,4 +860,84 @@ public class MovingData extends ACheckData {
// TODO: clear accounting here ?
}
/**
* Refactoring stage: Test if velocity has affected the in-air
* jumping phase. Use clearActiveVerVel to force end velocity jump phase.
*
* @return
*/
public boolean isVelocityJumpPhase() {
return sfDirty;
}
/**
* Refactoring state: Get the classic verticalFreedom.
* @return
*/
public double getVerticalFreedom() {
return verticalFreedom;
}
/**
* Refactoring stage: Fake/override vertical velocity.
* @param velocity
* @param freedom
* @param counter
*/
public void fakeVerticalFreedom(final double velocity, final double freedom, final int counter) {
verticalVelocity = velocity;
verticalFreedom = freedom;
verticalVelocityCounter = counter;
verticalVelocityUsed = 0;
}
/**
* Refactoring stage: Test which value sfDirty should have and set
* accordingly. This should only be called, if the player reached ground.
*
* @return If the velocity jump phase is still active (sfDirty).
*/
public boolean resetVelocityJumpPhase() {
if (verticalFreedom > 0.001 || horVel.hasActive() || horVel.hasQueued()) {
sfDirty = true;
} else {
sfDirty = false;
}
return sfDirty;
}
/**
* Add to builder with a leading newline, if counter or counter or freedom
* is above threshold (0 / 0.001).
*
* @param builder
*/
public void logVerticalFreedom(StringBuilder builder) {
if (verticalVelocityCounter > 0 || verticalFreedom >= 0.001) {
builder.append("\n vertical freedom: " + StringUtil.fdec3.format(verticalFreedom) + " (vel=" + StringUtil.fdec3.format(verticalVelocity) + "/counter=" + verticalVelocityCounter +"/used=" + verticalVelocityUsed);
}
}
/**
* Refactoring stage: Invalidate vertical velocity based on checking vs.
* configured grace ticks.
*
* @param velocityGraceTicks Ticks to check used ticks vs.
* @param removeFreedom If to reset verticalFreedom and use count as well.
* @return If actually reset.
*/
public boolean invalidateVerVelGrace(final int velocityGraceTicks, final boolean removeFreedom) {
if (verticalVelocityUsed > velocityGraceTicks) {
verticalVelocityCounter = 0;
verticalVelocity = 0;
if (removeFreedom) {
verticalVelocityUsed = 0;
verticalFreedom = 0;
}
return true;
} else {
return false;
}
}
}

View File

@ -1482,10 +1482,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Give some freedom to allow the "exiting move".
data.removeAllVelocity();
data.addHorizontalVelocity(new Velocity(0.9, 1, 1));
data.verticalVelocityCounter = 1;
data.verticalFreedom = 1.2;
data.verticalVelocity = 0.15;
data.verticalVelocityUsed = 0;
data.fakeVerticalFreedom(0.15, 1.2, 1);
useLoc.setWorld(null);
}

View File

@ -261,6 +261,10 @@ public class SurvivalFly extends Check {
}
}
} else {
/*
* TODO: Consider to log and/or remember when this was last time
* cleared [add time distance to tags/log on violations].
*/
data.clearActiveHorVel();
}
@ -270,14 +274,18 @@ public class SurvivalFly extends Check {
//////////////////////////
// Account for "dirty"-flag (allow less for normal jumping).
if (data.sfDirty) {
if (resetFrom || resetTo) {
// Not resetting for data.noFallAssumeOnGround, currently.
data.sfDirty = false;
}
else{
final boolean sfDirty;
if (data.isVelocityJumpPhase()) {
if (!resetFrom && !resetTo || data.resetVelocityJumpPhase()) {
// TODO: If resetTo && !resetfrom -> too early reset ?
sfDirty = true;
tags.add("dirty");
}
else {
sfDirty = false;
}
} else {
sfDirty = false;
}
// Calculate the vertical speed limit based on the current jump phase.
@ -297,11 +305,11 @@ public class SurvivalFly extends Check {
return data.getSetBack(to);
}
}
else if (data.verticalFreedom <= 0.001 && from.isOnClimbable()) {
else if (!sfDirty && from.isOnClimbable()) {
// Ladder types.
vDistanceAboveLimit = vDistClimbable(from, fromOnGround, toOnGround, yDistance, data);
}
else if (data.verticalFreedom <= 0.001 && from.isInLiquid() && (Math.abs(yDistance) > 0.2 || to.isInLiquid())) {
else if (!sfDirty && from.isInLiquid() && (Math.abs(yDistance) > 0.2 || to.isInLiquid())) {
// Swimming...
final double[] res = vDistLiquid(from, to, toOnGround, yDistance, data);
vAllowedDistance = res[0];
@ -310,7 +318,7 @@ public class SurvivalFly extends Check {
else{
// Check y-distance for normal jumping, like in air.
// TODO: Can it be easily transformed to a more accurate max. absolute height?
vAllowedDistance = 1.35D + data.verticalFreedom;
vAllowedDistance = 1.35D + data.getVerticalFreedom();
int maxJumpPhase;
if (data.mediumLiftOff == MediumLiftOff.LIMIT_JUMP) {
// TODO: In normal water this is 0. Could set higher for special cases only (needs efficient data + flags collection?).
@ -327,7 +335,7 @@ public class SurvivalFly extends Check {
else {
maxJumpPhase = 6;
}
if (data.sfJumpPhase > maxJumpPhase && data.verticalVelocityCounter <= 0 && !data.sfDirty) {
if (data.sfJumpPhase > maxJumpPhase && data.getVerticalFreedom() <= 0 && !data.isVelocityJumpPhase()) {
if (yDistance < 0) {
// Ignore falling, and let accounting deal with it.
}
@ -453,11 +461,10 @@ public class SurvivalFly extends Check {
// Invalidation of vertical velocity.
// TODO: This invalidation is wrong in case of already jumped higher (can not be repaired?).
if (data.verticalVelocityUsed > cc.velocityGraceTicks && yDistance <= 0 && data.sfLastYDist > 0 && data.sfLastYDist != Double.MAX_VALUE) {
// data.verticalFreedom = 0; // TODO: <- why?
data.verticalVelocityCounter = 0;
data.verticalVelocity = 0;
tags.add("invalidate_vvel"); // TODO: Test / validate by logs.
if (yDistance <= 0 && data.sfLastYDist > 0 && data.sfLastYDist != Double.MAX_VALUE
&& data.invalidateVerVelGrace(cc.velocityGraceTicks, false)) {
// (Only prevent counting further up, leaves the freedom.)
tags.add("cap_vvel"); // TODO: Test / validate by logs.
}
// Apply reset conditions.
@ -470,11 +477,8 @@ public class SurvivalFly extends Check {
tags.add("resetbunny");
}
// TODO: Experimental: reset vertical velocity.
if (data.verticalVelocityUsed > cc.velocityGraceTicks && yDistance < 0) {
data.verticalVelocityCounter = 0;
data.verticalFreedom = 0;
data.verticalVelocity = 0;
data.verticalVelocityUsed = 0;
if (yDistance < 0.0 && data.invalidateVerVelGrace(cc.velocityGraceTicks, true)) {
tags.add("rem_vvel");
}
}
// Reset data.
@ -538,7 +542,7 @@ public class SurvivalFly extends Check {
// multiple times if necessary.
double hAllowedDistance = 0D;
final boolean sfDirty = data.sfDirty;
final boolean sfDirty = data.isVelocityJumpPhase();
if (from.isInWeb()) {
data.sfOnIce = 0;
@ -694,7 +698,7 @@ public class SurvivalFly extends Check {
// Allow adding 0.
data.vDistAcc.add((float) yDistance);
}
else if (data.verticalFreedom <= 0.001D) {
else if (!data.isVelocityJumpPhase()) {
// Here yDistance can be negative and positive.
if (yDistance != 0D) {
data.vDistAcc.add((float) yDistance);
@ -786,7 +790,7 @@ public class SurvivalFly extends Check {
}
else {
// Moving upwards after falling without having touched the ground.
if (data.verticalFreedom <= 0.001 && data.bunnyhopDelay < 9 && !(data.fromWasReset && data.sfLastYDist == 0D)) {
if (!data.isVelocityJumpPhase() && data.bunnyhopDelay < 9 && !(data.fromWasReset && data.sfLastYDist == 0D)) {
// TODO: adjust limit for bunny-hop.
vDistanceAboveLimit = Math.max(vDistanceAboveLimit, Math.abs(yDistance));
tags.add("ychincfly");
@ -801,7 +805,7 @@ public class SurvivalFly extends Check {
tags.add("ychdec");
// Detect low jumping.
// TODO: sfDirty: Account for actual velocity (demands consuming queued for dir-change(!))!
if (!data.sfNoLowJump && !data.sfDirty && data.mediumLiftOff == MediumLiftOff.GROUND) {
if (!data.sfNoLowJump && data.mediumLiftOff == MediumLiftOff.GROUND && !data.isVelocityJumpPhase()) {
final double setBackYDistance = to.getY() - data.getSetBackY();
if (setBackYDistance > 0.0) {
// Only count it if the player has actually been jumping (higher than setback).
@ -1455,9 +1459,7 @@ public class SurvivalFly extends Check {
builder.append(player.getName() + " SurvivalFly\nground: " + (data.noFallAssumeGround ? "(assumeonground) " : "") + (fromOnGround ? "onground -> " : (resetFrom ? "resetcond -> " : "--- -> ")) + (toOnGround ? "onground" : (resetTo ? "resetcond" : "---")) + ", jumpphase: " + data.sfJumpPhase);
final String dHDist = (BuildParameters.debugLevel > 0 && data.sfLastHDist != Double.MAX_VALUE && Math.abs(data.sfLastHDist - hDistance) > 0.0005) ? ("(" + (hDistance > data.sfLastHDist ? "+" : "") + StringUtil.fdec3.format(hDistance - data.sfLastHDist) + ")") : "";
builder.append("\n" + " hDist: " + StringUtil.fdec3.format(hDistance) + dHDist + " / " + StringUtil.fdec3.format(hAllowedDistance) + hBuf + lostSprint + hVelUsed + " , vDist: " + StringUtil.fdec3.format(yDistance) + " (" + StringUtil.fdec3.format(to.getY() - data.getSetBackY()) + " / " + StringUtil.fdec3.format(vAllowedDistance) + "), sby=" + (data.hasSetBack() ? data.getSetBackY() : "?"));
if (data.verticalVelocityCounter > 0 || data.verticalFreedom >= 0.001) {
builder.append("\n" + " vertical freedom: " + StringUtil.fdec3.format(data.verticalFreedom) + " (vel=" + StringUtil.fdec3.format(data.verticalVelocity) + "/counter=" + data.verticalVelocityCounter +"/used="+data.verticalVelocityUsed);
}
data.logVerticalFreedom(builder);
// if (data.horizontalVelocityCounter > 0 || data.horizontalFreedom >= 0.001) {
// builder.append("\n" + player.getName() + " horizontal freedom: " + StringUtil.fdec3.format(data.horizontalFreedom) + " (counter=" + data.horizontalVelocityCounter +"/used="+data.horizontalVelocityUsed);
// }