Fix various cases with velocity around lava (swimup, vdistrel).

This commit is contained in:
asofold 2016-01-06 10:31:37 +01:00
parent 1c580c1b08
commit 6b1277e981
2 changed files with 118 additions and 18 deletions

View File

@ -137,6 +137,34 @@ public class Magic {
return yDistance <= frictDist + extraGravity && yDistance > frictDist - GRAVITY_SPAN - extraGravity;
}
/**
* Friction envelope testing, with a different kind of leniency (relate
* off-amount to decreased amount), testing if 'friction' has been accounted
* for in a sufficient but not necessarily exact way.<br>
* In the current shape this method is meant for higher speeds rather (needs
* a twist for low speed comparison).
*
* @param thisMove
* @param lastMove
* @param friction
* Friction factor to apply.
* @param minGravity
* Amount to subtract from frictDist by default.
* @param maxOff
* Amount yDistance may be off the friction distance.
* @param decreaseByOff
* Factor, how many times the amount being off friction distance
* must fit into the decrease from lastMove to thisMove.
* @return
*/
static boolean enoughFrictionEnvelope(final MoveData thisMove, final MoveData lastMove, final double friction,
final double minGravity, final double maxOff, final double decreaseByOff) {
// TODO: Elaborate... could have one method to test them all?
final double frictDist = lastMove.yDistance * friction - minGravity;
final double off = Math.abs(thisMove.yDistance - frictDist);
return off <= maxOff && thisMove.yDistance - lastMove.yDistance <= off * decreaseByOff;
}
/**
* Jump after leaving the liquid near ground or jumping through liquid
* (rather friction envelope, problematic). Needs last move data.
@ -154,11 +182,17 @@ public class Magic {
return
// 0: Falling slightly too fast (velocity/special).
yDistDiffEx < 0.0 && (
// 2: Friction issue (bad).
// 2: Friction issues (bad).
// TODO: Velocity jump phase isn't exact on that account, but shouldn't hurt.
// TODO: Water-bound or not?
// TODO: Liquid-bound or not?
(data.liftOffEnvelope != LiftOffEnvelope.NORMAL || data.isVelocityJumpPhase())
&& fallingEnvelope(yDistance, lastMove.yDistance, data.lastFrictionVertical, GRAVITY_ODD / 2.0)
&& ( //
fallingEnvelope(yDistance, lastMove.yDistance, data.lastFrictionVertical, GRAVITY_ODD / 2.0)
// Moving out of lava with velocity.
// TODO: Generalize / fix friction there (max/min!?)
|| lastMove.from.extraPropertiesValid && lastMove.from.inLava
&& enoughFrictionEnvelope(data.thisMove, lastMove, FRICTION_MEDIUM_LAVA, 0.0, 2.0 * GRAVITY_MAX, 4.0)
)
)
// 0: Not normal envelope.
// TODO: Water-bound or not?
@ -324,11 +358,13 @@ public class Magic {
// Use past move data for two moves.
return !thisMove.touchedGround && thisMove.from.inWater && !thisMove.to.resetCond // Out of water.
&& !lastMove.touchedGround && !lastMove.from.resetCond && lastMove.to.inWater // Into water.
&& excludeStaticSpeed(thisMove) && excludeStaticSpeed(lastMove)
;
}
/**
* Fully in-air move.
*
* @param thisMove
* Not strictly the latest move in MovingData.
* @return
@ -337,17 +373,49 @@ public class Magic {
return !thisMove.touchedGround && !thisMove.from.resetCond && !thisMove.to.resetCond;
}
/**
* A liquid -> liquid move. Exclude web and climbable.
*
* @param thisMove
* @return
*/
private static boolean inLiquid(final MoveData thisMove) {
return thisMove.from.inLiquid && thisMove.to.inLiquid && excludeStaticSpeed(thisMove);
}
/**
* Moving out of liquid, might move onto ground. Exclude web and climbable.
*
* @param thisMove
* @return
*/
private static boolean leavingLiquid(final MoveData thisMove) {
return thisMove.from.inLiquid && !thisMove.to.inLiquid && excludeStaticSpeed(thisMove);
}
/**
* Exclude moving from/to blocks with static (vertical) speed, such as web
* or climbable.
*
* @param thisMove
* @return
*/
private static boolean excludeStaticSpeed(final MoveData thisMove) {
return !thisMove.from.inWeb && !thisMove.to.inWeb
&& !thisMove.from.onClimbable && !thisMove.to.onClimbable;
}
/**
* Odd behavior with moving up or (slightly) down, not like the ordinary
* friction mechanics, accounting for more than one past move. Only for too
* high decrease.
* friction mechanics, accounting for more than one past move. Needs
* lastMove to be valid.
*
* @param yDistance
* @param lastMove
* @param data
* @return
*/
static boolean oddFriction(final double yDistance, final MoveData lastMove, final MovingData data) {
static boolean oddFriction(final double yDistance, final double yDistDiffEx, final MoveData lastMove, final MovingData data) {
// Use past move data for two moves.
final MoveData pastMove1 = data.moveData.get(1);
if (!lastMove.to.extraPropertiesValid || !pastMove1.toIsValid || !pastMove1.to.extraPropertiesValid) {
@ -355,20 +423,34 @@ public class Magic {
}
final MoveData thisMove = data.thisMove;
return
// 0: Odd speed decrease bumping into a block sideways somehow, having moved through water.
// 0: First move into air, moving out of liquid.
// (These should probably be oddLiquid cases, might pull pastMove1 to vDistAir later.)
data.sfJumpPhase == 1
&& (data.liftOffEnvelope == LiftOffEnvelope.LIMIT_NEAR_GROUND || data.liftOffEnvelope == LiftOffEnvelope.LIMIT_LIQUID)
&& inAir(thisMove) && splashMove(lastMove, pastMove1)
(data.liftOffEnvelope == LiftOffEnvelope.LIMIT_NEAR_GROUND || data.liftOffEnvelope == LiftOffEnvelope.LIMIT_LIQUID)
&& data.sfJumpPhase == 1 && inAir(thisMove)
&& pastMove1.yDistance > lastMove.yDistance - GRAVITY_MAX // Some speed decrease.
&& lastMove.yDistance > yDistance + GRAVITY_MAX && lastMove.yDistance > 0.0 // Positive speed. TODO: rather > 1.0 (!).
&& (
// 1: Odd too high decrease, after middle move being within friction envelope.
yDistance > lastMove.yDistance / 5.0
// 1: Two times about the same decrease (e.g. near 1.0), ending up near zero distance.
|| yDistance > -GRAVITY_MAX
&& Math.abs(pastMove1.yDistance - lastMove.yDistance - (lastMove.yDistance - thisMove.yDistance)) < GRAVITY_MAX
// 1: Odd speed decrease bumping into a block sideways somehow, having moved through water.
yDistDiffEx < 0.0 && splashMove(lastMove, pastMove1)
&& (
// 2: Odd too high decrease, after middle move being within friction envelope.
yDistance > lastMove.yDistance / 5.0
// 2: Two times about the same decrease (e.g. near 1.0), ending up near zero distance.
|| yDistance > -GRAVITY_MAX
&& Math.abs(pastMove1.yDistance - lastMove.yDistance - (lastMove.yDistance - thisMove.yDistance)) < GRAVITY_MAX
)
// 1: Almost keep speed (gravity only), moving out of lava with (high) velocity.
// (Needs jump phase == 1, to confine decrease from pastMove1 to lastMove.)
// TODO: Never seems to apply.
// TODO: Might explicitly demand (lava) friction decrease from pastMove1 to lastMove.
|| inLiquid(pastMove1) && leavingLiquid(lastMove) && lastMove.yDistance > 4.0 * GRAVITY_MAX
// TODO: Store applicable or used friction in MoveData and use enoughFrictionEnvelope?
&& yDistance < lastMove.yDistance - Magic.GRAVITY_MAX
&& yDistance > lastMove.yDistance - 2.0 * Magic.GRAVITY_MAX
&& Math.abs(lastMove.yDistance - pastMove1.yDistance) > 4.0 * GRAVITY_MAX
)
;
}

View File

@ -939,6 +939,9 @@ public class SurvivalFly extends Check {
else if (Magic.oddSlope(to, yDistance, maxJumpGain, yDistDiffEx, lastMove, data)) {
// Odd decrease after lift-off.
}
else if (Magic.oddFriction(yDistance, yDistDiffEx, lastMove, data)) {
// Odd behavior with moving up or (slightly) down, accounting for more than one past move.
}
else {
// Violation.
vDistRelVL = true;
@ -973,7 +976,7 @@ public class SurvivalFly extends Check {
else if (data.thisMove.headObstructed || lastMove.toIsValid && lastMove.headObstructed && lastMove.yDistance >= 0.0) {
// Head is blocked, thus a shorter move.
}
else if (lastMove.toIsValid && Magic.oddFriction(yDistance, lastMove, data)) {
else if (lastMove.toIsValid && Magic.oddFriction(yDistance, yDistDiffEx, lastMove, data)) {
// Odd behavior with moving up or (slightly) down, accounting for more than one past move.
}
else {
@ -1016,7 +1019,7 @@ public class SurvivalFly extends Check {
&& (data.thisMove.headObstructed || lastMove.toIsValid && lastMove.headObstructed && lastMove.yDistance >= 0.0)) {
// Head was blocked, thus faster decrease than expected.
}
else if (lastMove.toIsValid && Magic.oddFriction(yDistance, lastMove, data)) {
else if (lastMove.toIsValid && Magic.oddFriction(yDistance, yDistDiffEx, lastMove, data)) {
// Odd behavior with moving up or (slightly) down, accounting for more than one past move.
}
else {
@ -1138,13 +1141,19 @@ public class SurvivalFly extends Check {
tags.add("data_missing");
}
double vAllowedDistance;
if (thisMove.from.onGround) {
if (thisMove.yDistance > - Magic.GRAVITY_MAX && thisMove.yDistance < 0.0) {
// Allow falling.
vAllowedDistance = thisMove.yDistance;
}
else if (thisMove.from.onGround) {
// Allow jumping.
vAllowedDistance = maxJumpGain + jumpGainMargin;
if (thisMove.to.onGround) {
vAllowedDistance = Math.max(cc.sfStepHeight, vAllowedDistance);
}
}
else if (Magic.skipPaper(thisMove, lastMove, data)) {
// Double arithmetics, moving up after join/teleport/respawn.
vAllowedDistance = Magic.PAPER_DIST;
tags.add("skip_paper");
}
@ -1609,6 +1618,15 @@ public class SurvivalFly extends Check {
}
}
if (lastMove.toIsValid) {
// Lenient on marginal violation if speed decreases by 'enough'.
// (Observed on 'dirty' phase.)
if (Math.abs(frictDist - yDistance) <= 2.0 * Magic.GRAVITY_MAX
&& yDistance < lastMove.yDistance - 4.0 * Math.abs(frictDist - yDistance)
) {
return new double[]{yDistance, 0.0};
}
}
}
// Otherwise, only if last move is available.
else if (lastMove.toIsValid) {