diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/CreativeFly.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/CreativeFly.java index 930dd4a1..e88f8c88 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/CreativeFly.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/CreativeFly.java @@ -12,6 +12,7 @@ import fr.neatmonster.nocheatplus.actions.ParameterName; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; +import fr.neatmonster.nocheatplus.checks.moving.magic.Magic; import fr.neatmonster.nocheatplus.checks.moving.model.ModelFlying; import fr.neatmonster.nocheatplus.checks.moving.model.MoveData; import fr.neatmonster.nocheatplus.compat.BridgeMisc; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingData.java index 0c26b859..c5ad46b3 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingData.java @@ -16,6 +16,7 @@ import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory; import fr.neatmonster.nocheatplus.checks.access.ICheckData; import fr.neatmonster.nocheatplus.checks.moving.locations.LocUtil; import fr.neatmonster.nocheatplus.checks.moving.locations.LocationTrace; +import fr.neatmonster.nocheatplus.checks.moving.magic.Magic; import fr.neatmonster.nocheatplus.checks.moving.model.LiftOffEnvelope; import fr.neatmonster.nocheatplus.checks.moving.model.MoveConsistency; import fr.neatmonster.nocheatplus.checks.moving.model.MoveData; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java index b24556bc..951547a1 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java @@ -60,6 +60,7 @@ import fr.neatmonster.nocheatplus.checks.combined.CombinedData; import fr.neatmonster.nocheatplus.checks.moving.locations.LocUtil; import fr.neatmonster.nocheatplus.checks.moving.locations.MoveInfo; import fr.neatmonster.nocheatplus.checks.moving.locations.VehicleSetBack; +import fr.neatmonster.nocheatplus.checks.moving.magic.Magic; import fr.neatmonster.nocheatplus.checks.moving.model.MoveConsistency; import fr.neatmonster.nocheatplus.checks.moving.model.MoveData; import fr.neatmonster.nocheatplus.checks.moving.util.MovingUtil; diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/SurvivalFly.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/SurvivalFly.java index bdd0fbc7..4c7309bf 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/SurvivalFly.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/SurvivalFly.java @@ -16,6 +16,9 @@ import fr.neatmonster.nocheatplus.actions.ParameterName; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; +import fr.neatmonster.nocheatplus.checks.moving.magic.Magic; +import fr.neatmonster.nocheatplus.checks.moving.magic.MagicAir; +import fr.neatmonster.nocheatplus.checks.moving.magic.MagicLiquid; import fr.neatmonster.nocheatplus.checks.moving.model.LiftOffEnvelope; import fr.neatmonster.nocheatplus.checks.moving.model.MoveData; import fr.neatmonster.nocheatplus.checks.workaround.WRPT; @@ -813,7 +816,7 @@ public class SurvivalFly extends Check { // Hacks. final boolean envelopeHack; - if (!resetFrom && !resetTo && Magic.venvHacks(from, to, yDistance, yDistChange, lastMove, data)) { + if (!resetFrom && !resetTo && MagicAir.venvHacks(from, to, yDistance, yDistChange, lastMove, data)) { envelopeHack = true; tags.add("hack_venv"); } @@ -930,7 +933,7 @@ public class SurvivalFly extends Check { && yDistance < lastMove.yDistance - 0.001) { // Odd decrease with water. } - else if (lastMove.toIsValid && Magic.oddJunction(from, to, yDistance, yDistChange, yDistDiffEx, maxJumpGain, resetTo, lastMove, data, cc)) { + else if (lastMove.toIsValid && MagicAir.oddJunction(from, to, yDistance, yDistChange, yDistDiffEx, maxJumpGain, resetTo, lastMove, data, cc)) { // Several types of odd in-air moves, mostly with gravity near maximum, friction, medium change. } else { @@ -958,7 +961,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.oddJunction(from, to, yDistance, yDistChange, yDistDiffEx, maxJumpGain, resetTo, lastMove, data, cc)) { + else if (lastMove.toIsValid && MagicAir.oddJunction(from, to, yDistance, yDistChange, yDistDiffEx, maxJumpGain, resetTo, lastMove, data, cc)) { // Several types of odd in-air moves, mostly with gravity near maximum, friction, medium change. } else { @@ -994,7 +997,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.oddJunction(from, to, yDistance, yDistChange, yDistDiffEx, maxJumpGain, resetTo, lastMove, data, cc)) { + else if (lastMove.toIsValid && MagicAir.oddJunction(from, to, yDistance, yDistChange, yDistDiffEx, maxJumpGain, resetTo, lastMove, data, cc)) { // Several types of odd in-air moves, mostly with gravity near maximum, friction, medium change. } else { @@ -1580,91 +1583,11 @@ public class SurvivalFly extends Check { // ("== 0.0" is covered by the minimal speed check above.) } - // Special cases. - if (yDistance >= 0) { - // TODO: liftOffEnvelope: refine conditions (general) , should be near water level. - // TODO: 1.5 high blocks ? - // TODO: Conditions seem warped. - if (yDistance <= 0.5) { - if (lastMove.toIsValid && yDistance < lastMove.yDistance - && lastMove.yDistance - yDistance > Math.max(0.001, yDistance - baseSpeed)) { - // Decrease more than difference to baseSpeed. - return new double[]{yDistance, 0.0}; - } - if (yDistance <= data.liftOffEnvelope.getMaxJumpGain(data.jumpAmplifier) && !BlockProperties.isLiquid(from.getTypeIdAbove()) - // TODO: What now !? - || !to.isInLiquid() // TODO: impossible !? - || (toOnGround || lastMove.toIsValid && lastMove.yDistance - yDistance >= 0.010 || to.isAboveStairs())) { - double vAllowedDistance = baseSpeed + 0.5; - double vDistanceAboveLimit = yDistance - vAllowedDistance; - if (vDistanceAboveLimit <= 0.0) { - return new double[]{vAllowedDistance, 0.0}; - } - } - } - - 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}; - } - // Jumping with velocity into water from below, just slightly more decrease than gravity, twice. - if (yDistance > frictDist && yDistance < lastMove.yDistance - Magic.GRAVITY_MAX && data.insideMediumCount <= 1) { - // (Should be able to do without aw-ww-ww confinement.) - // (dirty seems to be set/kept reliably) - return new double[]{yDistance, 0.0}; - } - } + // Workarounds for special cases. + final Double wRes = MagicLiquid.liquidWorkarounds(from, to, baseSpeed, frictDist, lastMove, data); + if (wRes != null) { + return new double[]{wRes, 0.0}; } - // Otherwise, only if last move is available. - else if (lastMove.toIsValid) { - // Falling into water, mid-speed (second move after diving in). - if (yDistance > -0.9 && yDistance < lastMove.yDistance - && Math.abs(yDistance - lastMove.yDistance) <= Magic.GRAVITY_MAX + Magic.GRAVITY_MIN - && yDistance - lastMove.yDistance < -Magic.GRAVITY_MIN - //&& !BlockProperties.isLiquid(to.getTypeId(to.getBlockX(), Location.locToBlock(to.getY() + to.getEyeHeight()), to.getBlockZ())) - ) { - return new double[]{lastMove.yDistance - Magic.GRAVITY_MAX - Magic.GRAVITY_MIN, 0.0}; - } - // Increase speed slightly on second in-medium move (dirty flag may have been reset). - else if (data.insideMediumCount <= 1 && lastMove.yDistance < 0.8 - && yDistance < lastMove.yDistance - Magic.GRAVITY_ODD / 2.0 && yDistance > lastMove.yDistance - Magic.GRAVITY_MAX - ) { - return new double[]{yDistance, 0.0}; - } - // In-water rough near-0-inversion from allowed speed to a negative amount, little more than allowed (magic -0.2 roughly). - else if (lastMove.yDistance >= Magic.GRAVITY_MAX / 2.0 && lastMove.yDistance <= Magic.GRAVITY_MAX + Magic.GRAVITY_MIN / 2.0 - && yDistance < 0.0 && yDistance > -2.0 * Magic.GRAVITY_MAX - Magic.GRAVITY_MIN / 2.0 - && data.isVelocityJumpPhase() && to.isInLiquid() // TODO: Might skip the liquid check, though. - && lastMove.from.inLiquid && lastMove.to.extraPropertiesValid && lastMove.to.inLiquid // TODO: in water only? - ) { - return new double[]{yDistance, 0.0}; - } - // Lava rather. - else if (data.lastFrictionVertical < 0.65 // (Random, but smaller than water.) - && ( - // Moving downstream. - lastMove.yDistance < 0.0 && yDistance > -0.5 && yDistance < lastMove.yDistance - && lastMove.yDistance - yDistance < Magic.GRAVITY_MIN && BlockProperties.isDownStream(from, to) - // Mix of gravity and base speed [careful: relates to water base speed]. - || lastMove.yDistance < 0.0 && yDistance > -baseSpeed - Magic.GRAVITY_MAX && yDistance < lastMove.yDistance - && lastMove.yDistance - yDistance > Magic.GRAVITY_SPAN - && Math.abs(lastMove.yDistance + baseSpeed) < 0.25 * baseSpeed - // Falling slightly too fast in lava. - || data.insideMediumCount == 1 || data.insideMediumCount == 2 - && lastMove.yDistance < 0.0 && yDistance < lastMove.yDistance - && yDistance - lastMove.yDistance > -Magic.GRAVITY_MIN && yDistance > -0.65 - ) - ) { - return new double[]{yDistance, 0.0}; - } - } - - // TODO: Also DOWNSTREAM !? - // Try to use velocity for compensation. if (data.getOrUseVerticalVelocity(yDistance) != null) { diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/magic/Magic.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/magic/Magic.java new file mode 100644 index 00000000..a5e04f56 --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/magic/Magic.java @@ -0,0 +1,251 @@ +package fr.neatmonster.nocheatplus.checks.moving.magic; + +import fr.neatmonster.nocheatplus.checks.moving.MovingData; +import fr.neatmonster.nocheatplus.checks.moving.model.MoveData; + +/** + * Keeping some of the magic confined in here. + * + * @author asofold + * + */ +public class Magic { + + // Gravity. + public static final double GRAVITY_MAX = 0.0834; + public static final double GRAVITY_MIN = 0.0624; // TODO: Special cases go down to 0.05. + public static final double GRAVITY_SPAN = GRAVITY_MAX - GRAVITY_MIN; + public static final double GRAVITY_ODD = 0.05; // 19; // TODO: This should probably be min. / cleanup. + /** Assumed minimal average decrease per move, suitable for regarding 3 moves. */ + public static final float GRAVITY_VACC = (float) (GRAVITY_MIN * 0.6); + + // Friction factor by medium (move inside of). + public static final double FRICTION_MEDIUM_AIR = 0.98; + /** Friction for water (default). */ + public static final double FRICTION_MEDIUM_WATER = 0.89; + /** Friction for lava. */ + public static final double FRICTION_MEDIUM_LAVA = 0.535; + + // Horizontal speeds/modifiers. + public static final double WALK_SPEED = 0.221D; + public static final double modSneak = 0.13D / WALK_SPEED; + // public static final double modSprint = 0.29 / walkSpeed; // TODO: without bunny 0.29 / practical is 0.35 + 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 / WALK_SPEED, + 0.1995 / modSwim / WALK_SPEED, + 1.0 / modSwim, // Results in walkspeed. + }; + 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 / (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 = WALK_SPEED * 1.3; // TODO: Check if the factor is needed! + + // Other constants. + public static final double PAPER_DIST = 0.01; + /** + * Extreme move check threshold (Actual like 3.9 upwards with velocity, + * velocity downwards may be like -1.835 max., but falling will be near 3 + * too.) + */ + public static final double EXTREME_MOVE_DIST_VERTICAL = 4.0; + public static final double EXTREME_MOVE_DIST_HORIZONTAL = 22.0; + + /** + * The absolute per-tick base speed for swimming vertically. + * + * @return + */ + public static double swimBaseSpeedV() { + // TODO: Does this have to be the dynamic walk speed (refactoring)? + return WALK_SPEED * modSwim + 0.02; + } + + /** + * Test if the player is (well) within in-air falling envelope. + * @param yDistance + * @param lastYDist + * @param extraGravity Extra amount to fall faster. + * @return + */ + public static boolean fallingEnvelope(final double yDistance, final double lastYDist, final double lastFrictionVertical, final double extraGravity) { + if (yDistance >= lastYDist) { + return false; + } + // TODO: data.lastFrictionVertical (see vDistAir). + final double frictDist = lastYDist * lastFrictionVertical - GRAVITY_MIN; + // TODO: Extra amount: distinguish pos/neg? + 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.
+ * 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 + */ + public 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; + } + + /** + * Test for a specific move in-air -> water, then water -> in-air. + * + * @param thisMove + * Not strictly the latest move in MovingData. + * @param lastMove + * Move before thisMove. + * @return + */ + static boolean splashMove(final MoveData thisMove, final MoveData lastMove) { + // 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) + ; + } + + /** + * Test for a specific move ground/in-air -> water, then water -> in-air. + * + * @param thisMove + * Not strictly the latest move in MovingData. + * @param lastMove + * Move before thisMove. + * @return + */ + static boolean splashMoveNonStrict(final MoveData thisMove, final MoveData lastMove) { + // Use past move data for two moves. + return !thisMove.touchedGround && thisMove.from.inWater && !thisMove.to.resetCond // Out of water. + && !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 + */ + static boolean inAir(final MoveData thisMove) { + return !thisMove.touchedGround && !thisMove.from.resetCond && !thisMove.to.resetCond; + } + + /** + * A liquid -> liquid move. Exclude web and climbable. + * + * @param thisMove + * @return + */ + static boolean inLiquid(final MoveData thisMove) { + return thisMove.from.inLiquid && thisMove.to.inLiquid && excludeStaticSpeed(thisMove); + } + + /** + * Test if either point is in reset condition (liquid, web, ladder). + * + * @param thisMove + * @return + */ + static boolean resetCond(final MoveData thisMove) { + return thisMove.from.resetCond || thisMove.to.resetCond; + } + + /** + * Moving out of liquid, might move onto ground. Exclude web and climbable. + * + * @param thisMove + * @return + */ + static boolean leavingLiquid(final MoveData thisMove) { + return thisMove.from.inLiquid && !thisMove.to.inLiquid && excludeStaticSpeed(thisMove); + } + + /** + * Moving into liquid., might move onto ground. Exclude web and climbable. + * + * @param thisMove + * @return + */ + static boolean intoLiquid(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 + */ + static boolean excludeStaticSpeed(final MoveData thisMove) { + return !thisMove.from.inWeb && !thisMove.to.inWeb + && !thisMove.from.onClimbable && !thisMove.to.onClimbable; + } + + /** + * First move after set-back / teleport. Originally has been found with + * PaperSpigot for MC 1.7.10, however it also does occur on Spigot for MC + * 1.7.10. + * + * @param thisMove + * @param lastMove + * @param data + * @return + */ + public static boolean skipPaper(final MoveData thisMove, final MoveData lastMove, final MovingData data) { + // TODO: Confine to from at block level (offset 0)? + final double setBackYDistance = thisMove.to.y - data.getSetBackY(); + return !lastMove.toIsValid && data.sfJumpPhase == 0 && thisMove.mightBeMultipleMoves + && setBackYDistance > 0.0 && setBackYDistance < PAPER_DIST + && thisMove.yDistance > 0.0 && thisMove.yDistance < PAPER_DIST && inAir(thisMove); + } + + /** + * Disregarding this move, test if all the way falling after head being + * obstructed. + * + * @param data + * @return + */ + public static boolean fallAfterHeadObstructed(final MovingData data, int limit) { + limit = Math.min(limit, data.moveData.size()); + for (int i = 0; i < limit; i++) { + final MoveData move = data.moveData.get(i); + if (!move.toIsValid || move.yDistance >= 0.0) { + return false; + } + else if (move.headObstructed) { + return true; + } + } + return false; + } + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/Magic.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/magic/MagicAir.java similarity index 53% rename from NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/Magic.java rename to NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/magic/MagicAir.java index b5a2db62..7f73fc1d 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/Magic.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/magic/MagicAir.java @@ -1,74 +1,13 @@ -package fr.neatmonster.nocheatplus.checks.moving; +package fr.neatmonster.nocheatplus.checks.moving.magic; +import fr.neatmonster.nocheatplus.checks.moving.MovingConfig; +import fr.neatmonster.nocheatplus.checks.moving.MovingData; import fr.neatmonster.nocheatplus.checks.moving.model.LiftOffEnvelope; import fr.neatmonster.nocheatplus.checks.moving.model.MoveData; import fr.neatmonster.nocheatplus.checks.workaround.WRPT; import fr.neatmonster.nocheatplus.utilities.PlayerLocation; -/** - * Keeping some of the magic confined in here. - * - * @author asofold - * - */ -public class Magic { - - // Gravity. - public static final double GRAVITY_MAX = 0.0834; - public static final double GRAVITY_MIN = 0.0624; // TODO: Special cases go down to 0.05. - public static final double GRAVITY_SPAN = GRAVITY_MAX - GRAVITY_MIN; - public static final double GRAVITY_ODD = 0.05; // 19; // TODO: This should probably be min. / cleanup. - /** Assumed minimal average decrease per move, suitable for regarding 3 moves. */ - public static final float GRAVITY_VACC = (float) (GRAVITY_MIN * 0.6); - - // Friction factor by medium (move inside of). - public static final double FRICTION_MEDIUM_AIR = 0.98; - /** Friction for water (default). */ - public static final double FRICTION_MEDIUM_WATER = 0.89; - /** Friction for lava. */ - public static final double FRICTION_MEDIUM_LAVA = 0.535; - - // Horizontal speeds/modifiers. - public static final double WALK_SPEED = 0.221D; - public static final double modSneak = 0.13D / WALK_SPEED; - // public static final double modSprint = 0.29 / walkSpeed; // TODO: without bunny 0.29 / practical is 0.35 - 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 / WALK_SPEED, - 0.1995 / modSwim / WALK_SPEED, - 1.0 / modSwim, // Results in walkspeed. - }; - 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 / (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 = WALK_SPEED * 1.3; // TODO: Check if the factor is needed! - - // Other constants. - public static final double PAPER_DIST = 0.01; - /** - * Extreme move check threshold (Actual like 3.9 upwards with velocity, - * velocity downwards may be like -1.835 max., but falling will be near 3 - * too.) - */ - public static final double EXTREME_MOVE_DIST_VERTICAL = 4.0; - public static final double EXTREME_MOVE_DIST_HORIZONTAL = 22.0; - - /** - * The absolute per-tick base speed for swimming vertically. - * - * @return - */ - static double swimBaseSpeedV() { - // TODO: Does this have to be the dynamic walk speed (refactoring)? - return WALK_SPEED * modSwim + 0.02; - } +public class MagicAir { /** * Vertical envelope "hacks". Directly check for certain transitions, on @@ -80,7 +19,7 @@ public class Magic { * @param data * @return If to skip those sub-checks. */ - static boolean venvHacks(final PlayerLocation from, final PlayerLocation to, final double yDistance, final double yDistChange, final MoveData lastMove, final MovingData data) { + public static boolean venvHacks(final PlayerLocation from, final PlayerLocation to, final double yDistance, final double yDistChange, final MoveData lastMove, final MovingData data) { return // 0: Intended for cobweb. // TODO: Bounding box issue ? @@ -89,11 +28,11 @@ public class Magic { lastMove.toIsValid && lastMove.yDistance < 0.0 && ( // 2: Switch to 0 y-Dist on early jump phase. - yDistance == 0.0 && lastMove.yDistance < -GRAVITY_ODD / 3.0 && lastMove.yDistance > -GRAVITY_MIN + yDistance == 0.0 && lastMove.yDistance < -Magic.GRAVITY_ODD / 3.0 && lastMove.yDistance > -Magic.GRAVITY_MIN // 2: Decrease too few. - || yDistChange < -GRAVITY_MIN / 3.0 && yDistChange > -GRAVITY_MAX + || yDistChange < -Magic.GRAVITY_MIN / 3.0 && yDistChange > -Magic.GRAVITY_MAX // 2: Keep negative y-distance (very likely a player height issue). - || yDistChange == 0.0 && lastMove.yDistance > -GRAVITY_MAX && lastMove.yDistance < -GRAVITY_ODD / 3.0 + || yDistChange == 0.0 && lastMove.yDistance > -Magic.GRAVITY_MAX && lastMove.yDistance < -Magic.GRAVITY_ODD / 3.0 ) // 1: Keep yDist == 0.0 on first falling. // TODO: Do test if hdist == 0.0 or something small can be assumed. @@ -119,7 +58,7 @@ public class Magic { */ private static boolean oddSlope(final PlayerLocation to, final double yDistance, final double maxJumpGain, final double yDistDiffEx, final MoveData lastMove, final MovingData data) { return data.sfJumpPhase == 1 //&& data.fromWasReset - && Math.abs(yDistDiffEx) < 2.0 * GRAVITY_SPAN + && Math.abs(yDistDiffEx) < 2.0 * Magic.GRAVITY_SPAN && lastMove.yDistance > 0.0 && yDistance < lastMove.yDistance && to.getY() - data.getSetBackY() <= data.liftOffEnvelope.getMaxJumpHeight(data.jumpAmplifier) && ( @@ -128,55 +67,10 @@ public class Magic { //&& fallingEnvelope(yDistance, lastMove.yDistance, 2.0 * GRAVITY_SPAN) // Decrease more after going through liquid (but normal ground envelope). || lastMove.yDistance > 0.5 * maxJumpGain && lastMove.yDistance < 0.84 * maxJumpGain - && lastMove.yDistance - yDistance <= GRAVITY_MAX + GRAVITY_SPAN + && lastMove.yDistance - yDistance <= Magic.GRAVITY_MAX + Magic.GRAVITY_SPAN ); } - /** - * Test if the player is (well) within in-air falling envelope. - * @param yDistance - * @param lastYDist - * @param extraGravity Extra amount to fall faster. - * @return - */ - static boolean fallingEnvelope(final double yDistance, final double lastYDist, final double lastFrictionVertical, final double extraGravity) { - if (yDistance >= lastYDist) { - return false; - } - // TODO: data.lastFrictionVertical (see vDistAir). - final double frictDist = lastYDist * lastFrictionVertical - GRAVITY_MIN; - // TODO: Extra amount: distinguish pos/neg? - 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.
- * 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. @@ -199,11 +93,11 @@ public class Magic { // TODO: Liquid-bound or not? (data.liftOffEnvelope != LiftOffEnvelope.NORMAL || data.isVelocityJumpPhase()) && ( // - fallingEnvelope(yDistance, lastMove.yDistance, data.lastFrictionVertical, GRAVITY_ODD / 2.0) + Magic.fallingEnvelope(yDistance, lastMove.yDistance, data.lastFrictionVertical, Magic.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) + && Magic.enoughFrictionEnvelope(data.thisMove, lastMove, Magic.FRICTION_MEDIUM_LAVA, 0.0, 2.0 * Magic.GRAVITY_MAX, 4.0) ) ) // 0: Not normal envelope. @@ -212,33 +106,33 @@ public class Magic { && ( // 1: Jump or decrease falling speed after a small gain (could be bounding box?). yDistDiffEx > 0.0 && yDistance > lastMove.yDistance && yDistance < 0.84 * maxJumpGain - && lastMove.yDistance >= -GRAVITY_MAX - GRAVITY_MIN && lastMove.yDistance < GRAVITY_MAX + GRAVITY_SPAN + && lastMove.yDistance >= -Magic.GRAVITY_MAX - Magic.GRAVITY_MIN && lastMove.yDistance < Magic.GRAVITY_MAX + Magic.GRAVITY_SPAN ) // 0: Moving out of water somehow. || (data.liftOffEnvelope == LiftOffEnvelope.LIMIT_LIQUID || data.liftOffEnvelope == LiftOffEnvelope.LIMIT_NEAR_GROUND) && ( // 1: Too few decrease on first moves out of water (upwards). - lastMove.yDistance > 0.0 && yDistance < lastMove.yDistance - GRAVITY_MAX && yDistDiffEx > 0.0 && yDistDiffEx < GRAVITY_MAX + GRAVITY_ODD + lastMove.yDistance > 0.0 && yDistance < lastMove.yDistance - Magic.GRAVITY_MAX && yDistDiffEx > 0.0 && yDistDiffEx < Magic.GRAVITY_MAX + Magic.GRAVITY_ODD // 1: Odd decrease of speed as if still in water, moving out of water (downwards). // TODO: data.lastFrictionVertical might not catch it (jump phase 0 -> next = air). // TODO: Could not reproduce since first time (use DebugUtil.debug(String, boolean)). - || lastMove.yDistance < -2.0 * GRAVITY_MAX && data.sfJumpPhase == 1 - && yDistance < -GRAVITY_MAX && yDistance > lastMove.yDistance - && Math.abs(yDistance - lastMove.yDistance * data.lastFrictionVertical) < GRAVITY_MAX + || lastMove.yDistance < -2.0 * Magic.GRAVITY_MAX && data.sfJumpPhase == 1 + && yDistance < -Magic.GRAVITY_MAX && yDistance > lastMove.yDistance + && Math.abs(yDistance - lastMove.yDistance * data.lastFrictionVertical) < Magic.GRAVITY_MAX // 1: Falling too slow, keeping roughly gravity-once speed. || data.sfJumpPhase == 1 - && lastMove.yDistance < -GRAVITY_ODD && lastMove.yDistance > -GRAVITY_MAX - GRAVITY_MIN - && Math.abs(lastMove.yDistance - yDistance) < GRAVITY_SPAN - && (yDistance < lastMove.yDistance || yDistance < GRAVITY_MIN) + && lastMove.yDistance < -Magic.GRAVITY_ODD && lastMove.yDistance > -Magic.GRAVITY_MAX - Magic.GRAVITY_MIN + && Math.abs(lastMove.yDistance - yDistance) < Magic.GRAVITY_SPAN + && (yDistance < lastMove.yDistance || yDistance < Magic.GRAVITY_MIN) // 1: Falling slightly too slow. || yDistDiffEx > 0.0 && ( // 2: Falling too slow around 0 yDistance. - lastMove.yDistance > -2.0 * GRAVITY_MAX - GRAVITY_ODD - && yDistance < lastMove.yDistance && lastMove.yDistance - yDistance < GRAVITY_MAX - && lastMove.yDistance - yDistance > GRAVITY_MIN / 4.0 + lastMove.yDistance > -2.0 * Magic.GRAVITY_MAX - Magic.GRAVITY_ODD + && yDistance < lastMove.yDistance && lastMove.yDistance - yDistance < Magic.GRAVITY_MAX + && lastMove.yDistance - yDistance > Magic.GRAVITY_MIN / 4.0 // 2: Moving out of liquid with velocity. - || yDistance > 0.0 && data.sfJumpPhase == 1 && yDistDiffEx < 4.0 * GRAVITY_MAX - && yDistance < lastMove.yDistance - GRAVITY_MAX && data.isVelocityJumpPhase() + || yDistance > 0.0 && data.sfJumpPhase == 1 && yDistDiffEx < 4.0 * Magic.GRAVITY_MAX + && yDistance < lastMove.yDistance - Magic.GRAVITY_MAX && data.isVelocityJumpPhase() ) ) ; // (return) @@ -264,61 +158,61 @@ public class Magic { // || from.isHeadObstructed(from.getyOnGround()) || data.fromWasReset && from.isHeadObstructed()) return // 0: Any envelope (supposedly normal) near 0 yDistance. - yDistance > -2.0 * GRAVITY_MAX - GRAVITY_MIN && yDistance < 2.0 * GRAVITY_MAX + GRAVITY_MIN + yDistance > -2.0 * Magic.GRAVITY_MAX - Magic.GRAVITY_MIN && yDistance < 2.0 * Magic.GRAVITY_MAX + Magic.GRAVITY_MIN && ( // 1: Too big chunk of change, but within reasonable bounds (should be contained in some other generic case?). - lastMove.yDistance < 3.0 * GRAVITY_MAX + GRAVITY_MIN && yDistChange < -GRAVITY_MIN && yDistChange > -2.5 * GRAVITY_MAX -GRAVITY_MIN + lastMove.yDistance < 3.0 * Magic.GRAVITY_MAX + Magic.GRAVITY_MIN && yDistChange < -Magic.GRAVITY_MIN && yDistChange > -2.5 * Magic.GRAVITY_MAX -Magic.GRAVITY_MIN // Transition to 0.0 yDistance. - || lastMove.yDistance > GRAVITY_ODD / 2.0 && lastMove.yDistance < GRAVITY_MIN && yDistance == 0.0 + || lastMove.yDistance > Magic.GRAVITY_ODD / 2.0 && lastMove.yDistance < Magic.GRAVITY_MIN && yDistance == 0.0 // 1: yDist inversion near 0 (almost). TODO: This actually happens near liquid, but NORMAL env!? // lastYDist < Gravity max + min happens with dirty phase (slimes),. previously: max + span // TODO: Can all cases be reduced to change sign with max. neg. gain of max + span ? - || lastMove.yDistance <= GRAVITY_MAX + GRAVITY_MIN && lastMove.yDistance > GRAVITY_ODD - && yDistance < GRAVITY_ODD && yDistance > -2.0 * GRAVITY_MAX - GRAVITY_ODD / 2.0 + || lastMove.yDistance <= Magic.GRAVITY_MAX + Magic.GRAVITY_MIN && lastMove.yDistance > Magic.GRAVITY_ODD + && yDistance < Magic.GRAVITY_ODD && yDistance > -2.0 * Magic.GRAVITY_MAX - Magic.GRAVITY_ODD / 2.0 // 1: Head is obstructed. // TODO: Cover this in a more generic way elsewhere (<= friction envelope + obstructed). - || lastMove.yDistance >= 0.0 && yDistance < GRAVITY_ODD + || lastMove.yDistance >= 0.0 && yDistance < Magic.GRAVITY_ODD && (data.thisMove.headObstructed || lastMove.headObstructed) // 1: Break the block underneath. || lastMove.yDistance < 0.0 && lastMove.to.extraPropertiesValid && lastMove.to.onGround - && yDistance >= -GRAVITY_MAX - GRAVITY_SPAN && yDistance <= GRAVITY_MIN + && yDistance >= -Magic.GRAVITY_MAX - Magic.GRAVITY_SPAN && yDistance <= Magic.GRAVITY_MIN // 1: Slope with slimes (also near ground without velocityJumpPhase, rather lowjump but not always). - || lastMove.yDistance < -GRAVITY_MAX && yDistChange < - GRAVITY_ODD / 2.0 && yDistChange > -GRAVITY_MIN + || lastMove.yDistance < -Magic.GRAVITY_MAX && yDistChange < - Magic.GRAVITY_ODD / 2.0 && yDistChange > -Magic.GRAVITY_MIN // 1: Near ground (slime block). - || lastMove.yDistance == 0.0 && yDistance < -GRAVITY_ODD / 2.5 && yDistance > -GRAVITY_MIN && to.isOnGround(GRAVITY_MIN) + || lastMove.yDistance == 0.0 && yDistance < -Magic.GRAVITY_ODD / 2.5 && yDistance > -Magic.GRAVITY_MIN && to.isOnGround(Magic.GRAVITY_MIN) // 1: Start to fall after touching ground somehow (possibly too slowly). - || (lastMove.touchedGround || lastMove.to.resetCond) && lastMove.yDistance <= GRAVITY_MIN && lastMove.yDistance >= - GRAVITY_MAX - && yDistance < lastMove.yDistance - GRAVITY_SPAN && yDistance < GRAVITY_ODD && yDistance > lastMove.yDistance - GRAVITY_MAX + || (lastMove.touchedGround || lastMove.to.resetCond) && lastMove.yDistance <= Magic.GRAVITY_MIN && lastMove.yDistance >= - Magic.GRAVITY_MAX + && yDistance < lastMove.yDistance - Magic.GRAVITY_SPAN && yDistance < Magic.GRAVITY_ODD && yDistance > lastMove.yDistance - Magic.GRAVITY_MAX ) // 0: With velocity. || data.isVelocityJumpPhase() && ( // 1: Near zero inversion with slimes (rather dirty phase). - lastMove.yDistance > GRAVITY_ODD && lastMove.yDistance < GRAVITY_MAX + GRAVITY_MIN - && yDistance <= -lastMove.yDistance && yDistance > -lastMove.yDistance - GRAVITY_MAX - GRAVITY_ODD + lastMove.yDistance > Magic.GRAVITY_ODD && lastMove.yDistance < Magic.GRAVITY_MAX + Magic.GRAVITY_MIN + && yDistance <= -lastMove.yDistance && yDistance > -lastMove.yDistance - Magic.GRAVITY_MAX - Magic.GRAVITY_ODD // 1: Odd mini-decrease with dirty phase (slime). || lastMove.yDistance < -0.204 && yDistance > -0.26 - && yDistChange > -GRAVITY_MIN && yDistChange < -GRAVITY_ODD / 4.0 + && yDistChange > -Magic.GRAVITY_MIN && yDistChange < -Magic.GRAVITY_ODD / 4.0 // 1: Lot's of decrease near zero TODO: merge later. - || lastMove.yDistance < -GRAVITY_ODD && lastMove.yDistance > -GRAVITY_MIN - && yDistance > -2.0 * GRAVITY_MAX - 2.0 * GRAVITY_MIN && yDistance < -GRAVITY_MAX + || lastMove.yDistance < -Magic.GRAVITY_ODD && lastMove.yDistance > -Magic.GRAVITY_MIN + && yDistance > -2.0 * Magic.GRAVITY_MAX - 2.0 * Magic.GRAVITY_MIN && yDistance < -Magic.GRAVITY_MAX // 1: Odd decrease less near zero. - || yDistChange > -GRAVITY_MIN && yDistChange < -GRAVITY_ODD + || yDistChange > -Magic.GRAVITY_MIN && yDistChange < -Magic.GRAVITY_ODD && lastMove.yDistance < 0.5 && lastMove.yDistance > 0.4 // 1: Small decrease after high edge. // TODO: Consider min <-> span, generic. - || lastMove.yDistance == 0.0 && yDistance > -GRAVITY_MIN && yDistance < -GRAVITY_ODD + || lastMove.yDistance == 0.0 && yDistance > -Magic.GRAVITY_MIN && yDistance < -Magic.GRAVITY_ODD // 1: Too small but decent decrease moving up, marginal violation. || yDistDiffEx > 0.0 && yDistDiffEx < 0.01 - && yDistance > GRAVITY_MAX && yDistance < lastMove.yDistance - GRAVITY_MAX + && yDistance > Magic.GRAVITY_MAX && yDistance < lastMove.yDistance - Magic.GRAVITY_MAX ) // 0: Small distance to set.back. . || data.hasSetBack() && Math.abs(data.getSetBackY() - from.getY()) < 1.0 // TODO: Consider low fall distance as well. && ( // 1: Near ground small decrease. - lastMove.yDistance > GRAVITY_MAX && lastMove.yDistance < 3.0 * GRAVITY_MAX - && yDistChange > - GRAVITY_MIN && yDistChange < -GRAVITY_ODD + lastMove.yDistance > Magic.GRAVITY_MAX && lastMove.yDistance < 3.0 * Magic.GRAVITY_MAX + && yDistChange > - Magic.GRAVITY_MIN && yDistChange < -Magic.GRAVITY_ODD // 1: Bounce without velocity set. TODO: wat? //|| lastMove.yDistance == 0.0 && yDistance > -GRAVITY_MIN && yDistance < GRAVITY_SPAN // 1: Bounce with carpet. @@ -326,29 +220,29 @@ public class Magic { ) // 0: Jump-effect-specific // TODO: Jump effect at reduced lift off envelope -> skip this? - || data.jumpAmplifier > 0 && lastMove.yDistance < GRAVITY_MAX + GRAVITY_MIN / 2.0 && lastMove.yDistance > -2.0 * GRAVITY_MAX - 0.5 * GRAVITY_MIN - && yDistance > -2.0 * GRAVITY_MAX - 2.0 * GRAVITY_MIN && yDistance < GRAVITY_MIN - && yDistChange < -GRAVITY_SPAN + || data.jumpAmplifier > 0 && lastMove.yDistance < Magic.GRAVITY_MAX + Magic.GRAVITY_MIN / 2.0 && lastMove.yDistance > -2.0 * Magic.GRAVITY_MAX - 0.5 * Magic.GRAVITY_MIN + && yDistance > -2.0 * Magic.GRAVITY_MAX - 2.0 * Magic.GRAVITY_MIN && yDistance < Magic.GRAVITY_MIN + && yDistChange < -Magic.GRAVITY_SPAN // 0: Another near 0 yDistance case. // TODO: Inaugurate into some more generic envelope. - || lastMove.yDistance > -GRAVITY_MAX && lastMove.yDistance < GRAVITY_MIN + || lastMove.yDistance > -Magic.GRAVITY_MAX && lastMove.yDistance < Magic.GRAVITY_MIN && !(lastMove.touchedGround || lastMove.to.extraPropertiesValid && lastMove.to.onGroundOrResetCond) - && yDistance < lastMove.yDistance - GRAVITY_MIN / 2.0 && yDistance > lastMove.yDistance - GRAVITY_MAX - 0.5 * GRAVITY_MIN + && yDistance < lastMove.yDistance - Magic.GRAVITY_MIN / 2.0 && yDistance > lastMove.yDistance - Magic.GRAVITY_MAX - 0.5 * Magic.GRAVITY_MIN // 0: Reduced jumping envelope. || data.liftOffEnvelope != LiftOffEnvelope.NORMAL && ( // 1: Wild-card allow half gravity near 0 yDistance. TODO: Check for removal of included cases elsewhere. - lastMove.yDistance > -10.0 * GRAVITY_ODD / 2.0 && lastMove.yDistance < 10.0 * GRAVITY_ODD - && yDistance < lastMove.yDistance - GRAVITY_MIN / 2.0 && yDistance > lastMove.yDistance - GRAVITY_MAX + lastMove.yDistance > -10.0 * Magic.GRAVITY_ODD / 2.0 && lastMove.yDistance < 10.0 * Magic.GRAVITY_ODD + && yDistance < lastMove.yDistance - Magic.GRAVITY_MIN / 2.0 && yDistance > lastMove.yDistance - Magic.GRAVITY_MAX // 1: - || lastMove.yDistance < GRAVITY_MAX + GRAVITY_SPAN && lastMove.yDistance > GRAVITY_ODD - && yDistance > 0.4 * GRAVITY_ODD && yDistance - lastMove.yDistance < -GRAVITY_ODD / 2.0 + || lastMove.yDistance < Magic.GRAVITY_MAX + Magic.GRAVITY_SPAN && lastMove.yDistance > Magic.GRAVITY_ODD + && yDistance > 0.4 * Magic.GRAVITY_ODD && yDistance - lastMove.yDistance < -Magic.GRAVITY_ODD / 2.0 // 1: - || lastMove.yDistance < 0.2 && lastMove.yDistance >= 0.0 && yDistance > -0.2 && yDistance < 2.0 * GRAVITY_MAX + || lastMove.yDistance < 0.2 && lastMove.yDistance >= 0.0 && yDistance > -0.2 && yDistance < 2.0 * Magic.GRAVITY_MAX // 1: - || lastMove.yDistance > 0.4 * GRAVITY_ODD && lastMove.yDistance < GRAVITY_MIN && yDistance == 0.0 + || lastMove.yDistance > 0.4 * Magic.GRAVITY_ODD && lastMove.yDistance < Magic.GRAVITY_MIN && yDistance == 0.0 // 1: Too small decrease, right after lift off. - || data.sfJumpPhase == 1 && lastMove.yDistance > -GRAVITY_ODD && lastMove.yDistance <= GRAVITY_MAX + GRAVITY_SPAN + || data.sfJumpPhase == 1 && lastMove.yDistance > -Magic.GRAVITY_ODD && lastMove.yDistance <= Magic.GRAVITY_MAX + Magic.GRAVITY_SPAN && yDistance - lastMove.yDistance < 0.0114 // 1: Any leaving liquid and keeping distance once. || data.sfJumpPhase == 1 @@ -357,82 +251,6 @@ public class Magic { ; } - /** - * Test for a specific move in-air -> water, then water -> in-air. - * - * @param thisMove - * Not strictly the latest move in MovingData. - * @param lastMove - * Move before thisMove. - * @return - */ - private static boolean splashMove(final MoveData thisMove, final MoveData lastMove) { - // 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) - ; - } - - /** - * Test for a specific move ground/in-air -> water, then water -> in-air. - * - * @param thisMove - * Not strictly the latest move in MovingData. - * @param lastMove - * Move before thisMove. - * @return - */ - private static boolean splashMoveNonStrict(final MoveData thisMove, final MoveData lastMove) { - // Use past move data for two moves. - return !thisMove.touchedGround && thisMove.from.inWater && !thisMove.to.resetCond // Out of water. - && !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 - */ - private static boolean inAir(final MoveData thisMove) { - 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. Needs @@ -454,77 +272,61 @@ public class Magic { // 0: First move into air, moving out of liquid. // (These should probably be oddLiquid cases, might pull pastMove1 to vDistAir later.) (data.liftOffEnvelope == LiftOffEnvelope.LIMIT_NEAR_GROUND || data.liftOffEnvelope == LiftOffEnvelope.LIMIT_LIQUID) - && data.sfJumpPhase == 1 && inAir(thisMove) + && data.sfJumpPhase == 1 && Magic.inAir(thisMove) && ( // 1: Towards ascending rather. - pastMove1.yDistance > lastMove.yDistance - GRAVITY_MAX // Some speed decrease. - && lastMove.yDistance > yDistance + GRAVITY_MAX && lastMove.yDistance > 0.0 // Positive speed. TODO: rather > 1.0 (!). + pastMove1.yDistance > lastMove.yDistance - Magic.GRAVITY_MAX + && lastMove.yDistance > yDistance + Magic.GRAVITY_MAX && lastMove.yDistance > 0.0 // Positive speed. TODO: rather > 1.0 (!). && ( // 2: Odd speed decrease bumping into a block sideways somehow, having moved through water. - yDistDiffEx < 0.0 && splashMove(lastMove, pastMove1) + yDistDiffEx < 0.0 && Magic.splashMove(lastMove, pastMove1) && ( // 3: Odd too high decrease, after middle move being within friction envelope. yDistance > lastMove.yDistance / 5.0 // 3: 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 + || yDistance > -Magic.GRAVITY_MAX + && Math.abs(pastMove1.yDistance - lastMove.yDistance - (lastMove.yDistance - thisMove.yDistance)) < Magic.GRAVITY_MAX ) // 2: 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 + || Magic.inLiquid(pastMove1) && Magic.leavingLiquid(lastMove) && lastMove.yDistance > 4.0 * Magic.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 + && Math.abs(lastMove.yDistance - pastMove1.yDistance) > 4.0 * Magic.GRAVITY_MAX ) // 1: Less 'strict' speed increase, descending rather. || pastMove1.yDistance < 0.0 // Actual speed decrease due to water. - && lastMove.yDistance - GRAVITY_MAX < yDistance && yDistance < 0.7 * lastMove.yDistance + && lastMove.yDistance - Magic.GRAVITY_MAX < yDistance && yDistance < 0.7 * lastMove.yDistance && Math.abs(pastMove1.yDistance + lastMove.yDistance) > 2.5 // (Actually splashMove or aw-ww-wa-aa) - && (splashMove(lastMove, pastMove1) && pastMove1.yDistance > lastMove.yDistance + && (Magic.splashMove(lastMove, pastMove1) && pastMove1.yDistance > lastMove.yDistance // Allow more decrease if moving through more solid water. - || inLiquid(pastMove1) && leavingLiquid(lastMove) && pastMove1.yDistance *.7 > lastMove.yDistance) + || Magic.inLiquid(pastMove1) && Magic.leavingLiquid(lastMove) && pastMove1.yDistance *.7 > lastMove.yDistance) + // 1: Strong decrease after rough keeping speed (hold space bar, with velocity, descending). + || yDistance < - 0.5 // Arbitrary, actually observed was around 2. + && pastMove1.yDistance < yDistance && lastMove.yDistance < yDistance + && Math.abs(pastMove1.yDistance - lastMove.yDistance) < Magic.GRAVITY_ODD + && yDistance < lastMove.yDistance * 0.67 && yDistance > lastMove.yDistance * data.lastFrictionVertical - Magic.GRAVITY_MIN + && (Magic.splashMoveNonStrict(lastMove, pastMove1) || Magic.inLiquid(pastMove1) && Magic.leavingLiquid(lastMove)) ) -// // 0: Odd normal envelope set -// // TODO: (special case with splash move in SurvivalFly.check, might need replacing by new style workaround.) -// || data.liftOffEnvelope == LiftOffEnvelope.NORMAL && data.sfJumpPhase == 1 && inAir(thisMove) -// && DebugUtil.debug("TEST1", true) -// // && data.isVelocityJumpPhase() -// // Velocity very fast into water above. -// && (splashMoveNonStrict(lastMove, pastMove1) || inLiquid(pastMove1) && leavingLiquid(lastMove)) -// // TODO: Store applicable or used friction in MoveData and use enoughFrictionEnvelope? -// && DebugUtil.debug("TEST2", true) -// && yDistance < lastMove.yDistance - Magic.GRAVITY_MAX -// && yDistance > lastMove.yDistance - 2.0 * Magic.GRAVITY_MAX -// && DebugUtil.debug("TEST3", true) -// && (Math.abs(lastMove.yDistance - pastMove1.yDistance) > 4.0 * GRAVITY_MAX -// || pastMove1.yDistance > 3.0 && lastMove.yDistance > 3.0 && Math.abs(lastMove.yDistance - pastMove1.yDistance) < 2.0 * GRAVITY_MAX) + // 0: Odd normal envelope set. + // TODO: Replace special case with splash move in SurvivalFly.check by a new style workaround. + || data.liftOffEnvelope == LiftOffEnvelope.NORMAL && data.sfJumpPhase == 1 && Magic.inAir(thisMove) + // && data.isVelocityJumpPhase() + // Velocity very fast into water above. + && (Magic.splashMoveNonStrict(lastMove, pastMove1) || Magic.inLiquid(pastMove1) && Magic.leavingLiquid(lastMove)) + && yDistance < lastMove.yDistance - Magic.GRAVITY_MAX + && yDistance > lastMove.yDistance - 2.0 * Magic.GRAVITY_MAX + && (Math.abs(lastMove.yDistance - pastMove1.yDistance) > 4.0 * Magic.GRAVITY_MAX + || pastMove1.yDistance > 3.0 && lastMove.yDistance > 3.0 && Math.abs(lastMove.yDistance - pastMove1.yDistance) < 2.0 * Magic.GRAVITY_MAX) ; } - /** - * First move after set-back / teleport. Originally has been found with - * PaperSpigot for MC 1.7.10, however it also does occur on Spigot for MC - * 1.7.10. - * - * @param thisMove - * @param lastMove - * @param data - * @return - */ - static boolean skipPaper(final MoveData thisMove, final MoveData lastMove, final MovingData data) { - // TODO: Confine to from at block level (offset 0)? - final double setBackYDistance = thisMove.to.y - data.getSetBackY(); - return !lastMove.toIsValid && data.sfJumpPhase == 0 && thisMove.mightBeMultipleMoves - && setBackYDistance > 0.0 && setBackYDistance < PAPER_DIST - && thisMove.yDistance > 0.0 && thisMove.yDistance < PAPER_DIST && inAir(thisMove); - } - /** * Several types of odd in-air moves, mostly with gravity near maximum, * friction, medium change. Needs lastMove.toIsValid. @@ -541,49 +343,28 @@ public class Magic { * @param cc * @return true if a workaround applies. */ - static boolean oddJunction(final PlayerLocation from, final PlayerLocation to, + public static boolean oddJunction(final PlayerLocation from, final PlayerLocation to, final double yDistance, final double yDistChange, final double yDistDiffEx, final double maxJumpGain, final boolean resetTo, final MoveData lastMove, final MovingData data, final MovingConfig cc) { // TODO: Cleanup/reduce signature (accept thisMove.yDistance etc.). - if (Magic.oddLiquid(yDistance, yDistDiffEx, maxJumpGain, resetTo, lastMove, data)) { + if (MagicAir.oddLiquid(yDistance, yDistDiffEx, maxJumpGain, resetTo, lastMove, data)) { // Jump after leaving the liquid near ground. return true; } - if (Magic.oddGravity(from, to, yDistance, yDistChange, yDistDiffEx, lastMove, data)) { + if (MagicAir.oddGravity(from, to, yDistance, yDistChange, yDistDiffEx, lastMove, data)) { // Starting to fall / gravity effects. return true; } - if ((yDistDiffEx > 0.0 || yDistance >= 0.0) && Magic.oddSlope(to, yDistance, maxJumpGain, yDistDiffEx, lastMove, data)) { + if ((yDistDiffEx > 0.0 || yDistance >= 0.0) && MagicAir.oddSlope(to, yDistance, maxJumpGain, yDistDiffEx, lastMove, data)) { // Odd decrease after lift-off. return true; } - if (Magic.oddFriction(yDistance, yDistDiffEx, lastMove, data)) { + if (MagicAir.oddFriction(yDistance, yDistDiffEx, lastMove, data)) { // Odd behavior with moving up or (slightly) down, accounting for more than one past move. return true; } return false; } - /** - * Disregarding this move, test if all the way falling after head being - * obstructed. - * - * @param data - * @return - */ - static boolean fallAfterHeadObstructed(final MovingData data, int limit) { - limit = Math.min(limit, data.moveData.size()); - for (int i = 0; i < limit; i++) { - final MoveData move = data.moveData.get(i); - if (!move.toIsValid || move.yDistance >= 0.0) { - return false; - } - else if (move.headObstructed) { - return true; - } - } - return false; - } - } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/magic/MagicLiquid.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/magic/MagicLiquid.java new file mode 100644 index 00000000..f3795b2b --- /dev/null +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/magic/MagicLiquid.java @@ -0,0 +1,150 @@ +package fr.neatmonster.nocheatplus.checks.moving.magic; + +import fr.neatmonster.nocheatplus.checks.moving.MovingData; +import fr.neatmonster.nocheatplus.checks.moving.model.MoveData; +import fr.neatmonster.nocheatplus.utilities.BlockProperties; +import fr.neatmonster.nocheatplus.utilities.PlayerLocation; + +/** + * Magic workarounds for moving in liquid (SurvivalFly.vDistLiquid). + * + * @author asofold + * + */ +public class MagicLiquid { + + /** + * + * @param from + * @param to + * @param baseSpeed + * @param frictDist + * @param thisMove + * @param lastMove + * @param data + * @return The allowed distance for reference, in case the move is allowed. + * If no workaround applies, null is returned. + */ + public static Double liquidWorkarounds(final PlayerLocation from, final PlayerLocation to, final double baseSpeed, final double frictDist, final MoveData lastMove, final MovingData data) { + final MoveData thisMove = data.thisMove; + final double yDistance = thisMove.yDistance; + // Special cases. + // TODO: Re-arrange. + final MoveData pastMove1 = data.moveData.get(1); + if (yDistance >= 0) { + // TODO: liftOffEnvelope: refine conditions (general) , should be near water level. + // TODO: 1.5 high blocks ? + // TODO: Conditions seem warped. + if (yDistance <= 0.5) { + if (lastMove.toIsValid && yDistance < lastMove.yDistance + && lastMove.yDistance - yDistance > Math.max(0.001, yDistance - baseSpeed)) { + // Decrease more than difference to baseSpeed. + return yDistance; + } + if (yDistance <= data.liftOffEnvelope.getMaxJumpGain(data.jumpAmplifier) && !BlockProperties.isLiquid(from.getTypeIdAbove()) + // TODO: What now !? + || !to.isInLiquid() // TODO: impossible !? + || (thisMove.to.onGround || lastMove.toIsValid && lastMove.yDistance - yDistance >= 0.010 || to.isAboveStairs())) { + double vAllowedDistance = baseSpeed + 0.5; + double vDistanceAboveLimit = yDistance - vAllowedDistance; + if (vDistanceAboveLimit <= 0.0) { + return vAllowedDistance; + } + } + } + + 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 yDistance; + } + // Jumping with velocity into water from below, just slightly more decrease than gravity, twice. + if (yDistance > frictDist && yDistance < lastMove.yDistance - Magic.GRAVITY_MAX && data.insideMediumCount <= 1) { + // (Should be able to do without aw-ww-ww confinement.) + // (dirty seems to be set/kept reliably) + return yDistance; + } + if (pastMove1.toIsValid && pastMove1.to.extraPropertiesValid) { + // Cases considering two past moves with moving up. + // Splash move with space space pressed (this move leaving liquid). + if (pastMove1.yDistance > 0.0 && thisMove.yDistance > 0.0 + && pastMove1.yDistance - Magic.GRAVITY_MAX > lastMove.yDistance + && lastMove.yDistance - Magic.GRAVITY_ODD > thisMove.yDistance + && Magic.intoLiquid(lastMove) && Magic.leavingLiquid(thisMove) + ) { + return yDistance; + } + // Velocity use in lastMove, keep air friction roughly. + if (!Magic.resetCond(pastMove1) && lastMove.yDistance - Magic.GRAVITY_MAX > thisMove.yDistance + && Magic.intoLiquid(lastMove) && Magic.leavingLiquid(thisMove) + ) { + return yDistance; + } + } + } + } + // Otherwise, only if last move is available. + else if (lastMove.toIsValid) { + // TODO: Are all these cases really for descending? + // Falling into water, mid-speed (second move after diving in). + if (yDistance > -0.9 && yDistance < lastMove.yDistance + && Math.abs(yDistance - lastMove.yDistance) <= Magic.GRAVITY_MAX + Magic.GRAVITY_MIN + && yDistance - lastMove.yDistance < -Magic.GRAVITY_MIN + //&& !BlockProperties.isLiquid(to.getTypeId(to.getBlockX(), Location.locToBlock(to.getY() + to.getEyeHeight()), to.getBlockZ())) + ) { + return lastMove.yDistance - Magic.GRAVITY_MAX - Magic.GRAVITY_MIN; + } + // Increase speed slightly on second in-medium move (dirty flag may have been reset). + else if (data.insideMediumCount <= 1 + // (No strong decrease:) + && yDistance > lastMove.yDistance - Magic.GRAVITY_MAX + && ( + // Ordinary (some old case). + lastMove.yDistance < 0.8 && yDistance < lastMove.yDistance - Magic.GRAVITY_ODD / 2.0 + // Check with three moves, rather shortly touching water. + || lastMove.yDistance < -0.5 // Arbitrary, actually observed has been < -1.0 + && pastMove1.toIsValid && pastMove1.to.extraPropertiesValid + && Math.abs(pastMove1.yDistance - lastMove.yDistance) < Magic.GRAVITY_MIN + && yDistance <= lastMove.yDistance + && Magic.inLiquid(lastMove) && Magic.intoLiquid(pastMove1) + ) + ) { + return yDistance; + } + // In-water rough near-0-inversion from allowed speed to a negative amount, little more than allowed (magic -0.2 roughly). + else if (lastMove.yDistance >= Magic.GRAVITY_MAX / 10.0 && lastMove.yDistance <= Magic.GRAVITY_MAX + Magic.GRAVITY_MIN / 2.0 + && yDistance < 0.0 && yDistance > -2.0 * Magic.GRAVITY_MAX - Magic.GRAVITY_MIN / 2.0 + && to.isInLiquid() // TODO: Might skip the liquid check, though. + && lastMove.from.inLiquid && lastMove.to.extraPropertiesValid && lastMove.to.inLiquid // TODO: in water only? + ) { + return yDistance; + } + // Lava rather. + else if (data.lastFrictionVertical < 0.65 // (Random, but smaller than water.) + && ( + // Moving downstream. + lastMove.yDistance < 0.0 && yDistance > -0.5 && yDistance < lastMove.yDistance + && lastMove.yDistance - yDistance < Magic.GRAVITY_MIN && BlockProperties.isDownStream(from, to) + // Mix of gravity and base speed [careful: relates to water base speed]. + || lastMove.yDistance < 0.0 && yDistance > -baseSpeed - Magic.GRAVITY_MAX && yDistance < lastMove.yDistance + && lastMove.yDistance - yDistance > Magic.GRAVITY_SPAN + && Math.abs(lastMove.yDistance + baseSpeed) < 0.25 * baseSpeed + // Falling slightly too fast in lava. + || data.insideMediumCount == 1 || data.insideMediumCount == 2 + && lastMove.yDistance < 0.0 && yDistance < lastMove.yDistance + && yDistance - lastMove.yDistance > -Magic.GRAVITY_MIN && yDistance > -0.65 + ) + ) { + return yDistance; + } + } + + // TODO: Also DOWNSTREAM !? + + return null; + } + +}