Store if head is obstructed for past moves and make use of it.

Also:
* Rename the walkSpeed constant to WALK_SPEED (nuisance to mix up).
* Alter conditions slightly in some places by using
thisMove/lastMove.headObstructed.

Issues remaining:
* Moderate speed increase with yDist 0 and hDist like 0.35 -> 0.45.
* Transitions head blocked -> not, can trigger hspeed violations.
This commit is contained in:
asofold 2015-12-13 23:12:36 +01:00
parent cfc2db97f3
commit 98df033a7c
2 changed files with 102 additions and 69 deletions

View File

@ -40,32 +40,32 @@ public class SurvivalFly extends Check {
private static final String DOUBLE_BUNNY = "doublebunny";
// Horizontal speeds/modifiers.
public static final double walkSpeed = 0.221D;
public static final double WALK_SPEED = 0.221D;
public static final double modSneak = 0.13D / walkSpeed;
public static final double modSneak = 0.13D / WALK_SPEED;
// public static final double modSprint = 0.29D / walkSpeed; // TODO: without bunny 0.29 / practical is 0.35
public static final double modBlock = 0.16D / walkSpeed;
public static final double modSwim = 0.115D / walkSpeed;
public static final double modBlock = 0.16D / WALK_SPEED;
public static final double modSwim = 0.115D / WALK_SPEED;
public static final double[] modDepthStrider = new double[] {
1.0,
0.1645 / modSwim / walkSpeed,
0.1995 / modSwim / walkSpeed,
0.1645 / modSwim / WALK_SPEED,
0.1995 / modSwim / WALK_SPEED,
1.0 / modSwim, // Results in walkspeed.
};
public static final double modWeb = 0.105D / walkSpeed; // TODO: walkingSpeed * 0.15D; <- does not work
public static final double modWeb = 0.105D / WALK_SPEED; // TODO: walkingSpeed * 0.15D; <- does not work
public static final double modIce = 2.5D; //
/** Faster moving down stream (water mainly). */
public static final double modDownStream = 0.19 / (walkSpeed * modSwim);
public static final double modDownStream = 0.19 / (WALK_SPEED * modSwim);
/** Maximal horizontal buffer. It can be higher, but normal resetting should keep this limit. */
public static final double hBufMax = 1.0;
// Vertical speeds/modifiers.
public static final double climbSpeed = walkSpeed * 1.3; // TODO: Check if the factor is needed!
public static final double climbSpeed = WALK_SPEED * 1.3; // TODO: Check if the factor is needed!
// Other.
/** Bunny-hop delay. */
@ -171,7 +171,7 @@ public class SurvivalFly extends Check {
if (data.lostSprintCount > 0) {
// Sprint got toggled off, though the client is still (legitimately) moving at sprinting speed.
// NOTE: This could extend the "sprinting grace" period, theoretically, until on ground.
if (resetTo && (fromOnGround || from.isResetCond()) || hDistance <= walkSpeed) {
if (resetTo && (fromOnGround || from.isResetCond()) || hDistance <= WALK_SPEED) {
// Invalidate.
data.lostSprintCount = 0;
tags.add("invalidate_lostsprint");
@ -206,7 +206,7 @@ public class SurvivalFly extends Check {
// Use the player-specific walk speed.
// TODO: Might get from listener.
// TODO: Use in lostground?
final double walkSpeed = SurvivalFly.walkSpeed * ((double) data.walkSpeed / 0.2);
final double walkSpeed = SurvivalFly.WALK_SPEED * ((double) data.walkSpeed / 0.2);
setNextFriction(from, to, data, cc);
@ -249,6 +249,13 @@ public class SurvivalFly extends Check {
tags.add("dirty");
}
// Check if head is obstructed.
if (!resetFrom || !resetTo) {
data.thisMove.headObstructed = (yDistance > 0.0 ? from.isHeadObstructedMax(yDistance) : from.isHeadObstructed())
// || to.isHeadObstructed() // Best not have this one.
;
}
//////////////////////
// Horizontal move.
//////////////////////
@ -809,6 +816,7 @@ public class SurvivalFly extends Check {
// Y-distance for normal jumping, like in air.
double vAllowedDistance = 0.0;
double vDistanceAboveLimit = 0.0;
final MoveData lastMove = data.moveData.get(0);
// Change seen from last yDistance.
final double yDistChange = data.lastYDist == Double.MAX_VALUE ? Double.MAX_VALUE : yDistance - data.lastYDist;
@ -952,7 +960,7 @@ public class SurvivalFly extends Check {
// Too strong decrease with velocity.
// TODO: Observed when moving off water, might be confined by that.
}
else if (to.isHeadObstructed() || from.isHeadObstructedMax(yDistance)) {
else if (data.thisMove.headObstructed || lastMove.valid && lastMove.headObstructed && lastMove.yDistance >= 0.0) {
// Head is blocked, thus a shorter move.
}
else {
@ -990,7 +998,8 @@ public class SurvivalFly extends Check {
else if (oddLiquid(yDistance, yDistDiffEx, maxJumpGain, resetTo, data)) {
// Just having left liquid.
}
else if (data.lastYDist >= 0.0 && yDistance <= 0.0 && yDistance > -GRAVITY_MAX - GRAVITY_SPAN && from.isHeadObstructed()) {
else if (lastMove.valid && yDistance <= 0.0 && yDistance > -GRAVITY_MAX - GRAVITY_SPAN
&& (data.thisMove.headObstructed || lastMove.valid && lastMove.headObstructed && lastMove.yDistance >= 0.0)) {
// Head was blocked, thus faster decrease than expected.
}
else {
@ -1254,7 +1263,8 @@ public class SurvivalFly extends Check {
// TODO: Can all cases be reduced to change sign with max. neg. gain of max + span ?
|| data.lastYDist <= GRAVITY_MAX + GRAVITY_MIN && data.lastYDist > GRAVITY_ODD
&& yDistance < GRAVITY_ODD && yDistance > -2.0 * GRAVITY_MAX - GRAVITY_ODD / 2.0
// 1: Head is obstructed. TODO: Cover this in a more generic way elsewhere (<= friction envelope + obstructed).
// 1: Head is obstructed.
// TODO: Cover this in a more generic way elsewhere (<= friction envelope + obstructed).
|| data.lastYDist >= 0.0 && (from.isHeadObstructed(from.getyOnGround()) || data.fromWasReset && from.isHeadObstructed())
// 1: Break the block underneath.
|| data.lastYDist < 0.0 && data.toWasReset // TODO: Also assumeGround? Should have more precise flags.
@ -1279,7 +1289,8 @@ public class SurvivalFly extends Check {
// 1: Odd decrease less near zero.
|| yDistChange > -GRAVITY_MIN && yDistChange < -GRAVITY_ODD
&& data.lastYDist < 0.5 && data.lastYDist > 0.4
// 1: Small decrease after high edge. TODO: Consider min <-> span, generic.
// 1: Small decrease after high edge.
// TODO: Consider min <-> span, generic.
|| data.lastYDist == 0.0 && yDistance > -GRAVITY_MIN && yDistance < -GRAVITY_ODD
)
// 0: Small distance to set.back. .
@ -1297,7 +1308,8 @@ public class SurvivalFly extends Check {
|| data.jumpAmplifier > 0 && data.lastYDist < GRAVITY_MAX + GRAVITY_MIN / 2.0 && data.lastYDist > -2.0 * GRAVITY_MAX - 0.5 * GRAVITY_MIN
&& yDistance > -2.0 * GRAVITY_MAX - 2.0 * GRAVITY_MIN && yDistance < GRAVITY_MIN
&& yDistChange < -GRAVITY_SPAN
// 0: Another near 0 yDistance case. TODO: Inaugurate into some more generic envelope.
// 0: Another near 0 yDistance case.
// TODO: Inaugurate into some more generic envelope.
|| data.lastYDist > -GRAVITY_MAX && data.lastYDist < GRAVITY_MIN && !data.toWasReset
&& yDistance < data.lastYDist - GRAVITY_MIN / 2.0 && yDistance > data.lastYDist - GRAVITY_MAX - 0.5 * GRAVITY_MIN
// 0: Reduced jumping envelope.
@ -1462,10 +1474,8 @@ public class SurvivalFly extends Check {
}
if (setBackYDistance < estimate) {
// Low jump, further check if there might have been a reason for low jumping.
if (yDistance >= 0.0 && from.isHeadObstructedMax(yDistance)
|| yDistance < 0.0 && from.isHeadObstructed()
|| to.isHeadObstructed() // TODO: Not sure this should count at all (should with 1st on might be multiple?).
) {
final MoveData lastMove = data.moveData.get(0);
if (data.thisMove.headObstructed || yDistance <= 0.0 && lastMove.valid && lastMove.headObstructed && lastMove.yDistance >= 0.0) {
// Exempt.
tags.add("nolowjump_ceil");
}
@ -1576,7 +1586,8 @@ public class SurvivalFly extends Check {
// TODO: A more state-machine like modeling (hop, slope, states, low-edge).
// Fly phase.
if (data.lastHDist != Double.MAX_VALUE && data.bunnyhopDelay > 0 && hDistance > walkSpeed) { // * modSprint) {
// TODO: Walk speed (static or not) is not a good reference, switch to need normal/base speed instead.
if (data.lastHDist != Double.MAX_VALUE && data.bunnyhopDelay > 0 && hDistance > WALK_SPEED) { // * modSprint) {
// (lastHDist may be reset on commands.)
allowHop = false; // Magic!
final int hopTime = bunnyHopMax - data.bunnyhopDelay;
@ -1621,7 +1632,8 @@ public class SurvivalFly extends Check {
}
// 2x horizontal speed increase detection.
if (!allowHop && data.lastHDist != Double.MAX_VALUE && hDistance - data.lastHDist >= walkSpeed * 0.5 && hopTime == 1) {
// TODO: Walk speed (static or not) is not a good reference, switch to need normal/base speed instead.
if (!allowHop && data.lastHDist != Double.MAX_VALUE && hDistance - data.lastHDist >= WALK_SPEED * 0.5 && hopTime == 1) {
if (data.lastYDist >= -GRAVITY_MAX / 2.0 && data.lastYDist <= 0.0 && (data.fromWasReset || data.toWasReset) && yDistance >= 0.4) {
// TODO: Confine to increasing set back y ?
tags.add(DOUBLE_BUNNY);
@ -1631,7 +1643,8 @@ public class SurvivalFly extends Check {
// Allow hop for special cases.
if (!allowHop && (from.isOnGround() || data.noFallAssumeGround)) {
if (data.bunnyhopDelay <= 6 || yDistance >= 0.0 && from.isHeadObstructed() || to.isHeadObstructed()) {
// TODO: Better reset delay in this case ?
if (data.bunnyhopDelay <= 6 || yDistance >= 0.0 && data.thisMove.headObstructed) { // || to.isHeadObstructed()) {
// TODO: headObstructed: check always and set a flag in data + consider regain buffer?
tags.add("ediblebunny");
allowHop = true;
@ -1641,23 +1654,29 @@ public class SurvivalFly extends Check {
// Check hop (singular peak up to roughly two times the allowed distance).
// TODO: Needs better modeling.
if (allowHop && hDistance >= walkSpeed
// TODO: Walk speed (static or not) is not a good reference, switch to need normal/base speed instead.
if (allowHop && hDistance >= WALK_SPEED
&& (hDistance > (((data.lastHDist == Double.MAX_VALUE || data.lastHDist == 0.0 && data.lastYDist == 0.0) ? 1.11 : 1.314)) * hAllowedDistance)
&& hDistance < 2.15 * hAllowedDistance
|| (yDistance > from.getyOnGround() || hDistance < 2.6 * walkSpeed) && data.lastHDist != Double.MAX_VALUE && hDistance > 1.314 * data.lastHDist && hDistance < 2.15 * data.lastHDist
// TODO: Walk speed (static or not) is not a good reference, switch to need normal/base speed instead.
|| (yDistance > from.getyOnGround() || hDistance < 2.6 * WALK_SPEED) && data.lastHDist != Double.MAX_VALUE && hDistance > 1.314 * data.lastHDist && hDistance < 2.15 * data.lastHDist
) { // if (sprinting) {
// TODO: Test bunny spike over all sorts of speeds + attributes.
// TODO: Allow slightly higher speed on lost ground?
// TODO: LiftOffEnvelope.allowBunny ?
final MoveData lastMove = data.moveData.get(0);
if (data.liftOffEnvelope == LiftOffEnvelope.NORMAL
&& (!data.sfLowJump || data.sfNoLowJump)
// 0: Y-distance envelope.
&& yDistance >= 0.0
&& (
// 1: Normal jumping.
yDistance > 0.0
&& yDistance > data.liftOffEnvelope.getMinJumpGain(data.jumpAmplifier) - GRAVITY_SPAN
|| from.isHeadObstructedMax(yDistance)
// TODO: (2nd below) demand try next jump.
// 1: Too short with head obstructed.
|| data.thisMove.headObstructed || lastMove.valid && lastMove.headObstructed && lastMove.yDistance <= 0.0
// 1: Hop without y distance increase at moderate h-speed.
// TODO: 2nd below: demand next move to jump. Relate to stored past moves.
|| (cc.sfGroundHop || yDistance == 0.0 && !data.fromWasReset)
&& hAllowedDistance > 0.0 && hDistance / hAllowedDistance < 1.35
)
@ -1699,7 +1718,7 @@ public class SurvivalFly extends Check {
private static double swimBaseSpeedV() {
// TODO: Does this have to be the dynamic walk speed (refactoring)?
return walkSpeed * modSwim + 0.02;
return WALK_SPEED * modSwim + 0.02;
}
/**
@ -1754,7 +1773,7 @@ public class SurvivalFly extends Check {
// TODO: What now !?
|| !to.isInLiquid()
|| (toOnGround || data.lastYDist != Double.MAX_VALUE && data.lastYDist - yDistance >= 0.010 || to.isAboveStairs())) {
double vAllowedDistance = walkSpeed * modSwim + 0.5;
double vAllowedDistance = baseSpeed + 0.5;
double vDistanceAboveLimit = yDistance - vAllowedDistance;
if (vDistanceAboveLimit <= 0.0) {
return new double[]{vAllowedDistance, 0.0};

View File

@ -12,62 +12,87 @@ import fr.neatmonster.nocheatplus.utilities.TrigUtil;
public class MoveData {
/////////////////////////////
// Guaranteed to be set.
/////////////////////////////
//////////////////////////////////////////
// Guaranteed to be initialized with set.
//////////////////////////////////////////
/**
* Indicate if data has been set. Likely there will be sets of properties
* with a flag for each such set.
*/
public boolean valid = false;
/** Double.MAX_VALUE if not available, e.g. after a teleport. */
public double yDistance = Double.MAX_VALUE;
/** Double.MAX_VALUE if not available, e.g. after a teleport. */
public double hDistance = Double.MAX_VALUE;
// TODO: Last coords,
// TODO: Velocity used, fly check, ...
/////////////////////////////
// Not guaranteed to be set.
/////////////////////////////
//////////////////////////////////////////////////////////
// Reset with set, could be lazily initialized.
//////////////////////////////////////////////////////////
/**
* Head is obstructed. Should expect descending next move, if in air. <br>
* Set at the beginning of SurvivalFly.check, if either end point is not on ground.
*/
public boolean headObstructed = false;
// TODO: ground/reset/web/...
/**
*
* @param fromX
* @param fromY
* @param fromZ
* @param fromYaw
* @param fromPitch
* @param toX
* @param toY
* @param toZ
* @param toYaw
* @param toPitch
*/
private void setPositions(final double fromX, final double fromY, final double fromZ, final float fromYaw, final float fromPitch,
final double toX, final double toY, final double toZ, final float toYaw, final float toPitch) {
yDistance = toY - fromY;
hDistance = TrigUtil.distance(fromX, fromZ, toX, toZ);
}
/**
* Set the minimal properties, likely to be used.
* Set with join / teleport / set-back.
* @param x
* @param y
* @param z
* @param yaw
* @param pitch
*/
private void setPositions(final double x, final double y, final double z, final float yaw, final float pitch) {
yDistance = Double.MAX_VALUE;
hDistance = Double.MAX_VALUE;
}
private void resetBase() {
headObstructed = false;
valid = true;
}
/**
* Set some basic data and reset all other properties properly.
*
* @param from
* @param to
*/
public void set(final PlayerLocation from, final PlayerLocation to) {
set(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch(),
setPositions(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch(),
to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch());
resetBase();
}
/**
* Set some basic move edge data and reset all other properties properly.
* @param fromX
* @param fromY
* @param fromZ
* @param toX
* @param toY
* @param toZ
*/
public void set(final double fromX, final double fromY, final double fromZ, final float fromYaw, final float fromPitch,
final double toX, final double toY, final double toZ, final float toYaw, final float toPitch) {
yDistance = toY - fromY;
hDistance = TrigUtil.distance(fromX, fromZ, toX, toZ);
headObstructed = false;
// Set Valid last.
valid = true;
}
/**
* Set with teleport / set-back.
* Set with join / teleport / set-back.
* @param x
* @param y
* @param z
@ -75,10 +100,8 @@ public class MoveData {
* @param pitch
*/
public void set(final double x, final double y, final double z, final float yaw, final float pitch) {
yDistance = Double.MAX_VALUE; // TODO: 0 ?
hDistance = Double.MAX_VALUE; // TODO: 0 ?
headObstructed = false;
valid = true;
setPositions(x, y, z, yaw, pitch);
resetBase();
}
/**
@ -88,13 +111,4 @@ public class MoveData {
valid = false;
}
// public void reset() {
// // TODO: Might not need this method: it's always set(...) or set invalid to true.
// valid = false;
// // Reset properties after resetting valid.
// yDistance = Double.MAX_VALUE;
// hDistance = Double.MAX_VALUE;
// headObstructed = false;
// }
}