diff --git a/NCPCommons/src/main/java/fr/neatmonster/nocheatplus/utilities/StringUtil.java b/NCPCommons/src/main/java/fr/neatmonster/nocheatplus/utilities/StringUtil.java index f8faa6f6..ddc6ee0c 100644 --- a/NCPCommons/src/main/java/fr/neatmonster/nocheatplus/utilities/StringUtil.java +++ b/NCPCommons/src/main/java/fr/neatmonster/nocheatplus/utilities/StringUtil.java @@ -316,4 +316,16 @@ public class StringUtil { } } + /** + * Format to maximally 3 digits after the comma, always show the sign, + * unless equal. + * + * @param current + * @param previous + * @return + */ + public static String formatDiff(final double current, final double previous) { + return current == previous ? "0" : ((current > previous ? "+" : "-") + fdec3.format(Math.abs(current - previous))); + } + } 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 b3eec3be..372ec047 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 @@ -19,6 +19,7 @@ import fr.neatmonster.nocheatplus.checks.moving.model.LiftOffEnvelope; import fr.neatmonster.nocheatplus.checks.moving.model.ModelFlying; import fr.neatmonster.nocheatplus.checks.moving.model.MoveData; import fr.neatmonster.nocheatplus.checks.moving.util.MovingUtil; +import fr.neatmonster.nocheatplus.compat.Bridge1_9; import fr.neatmonster.nocheatplus.compat.BridgeMisc; import fr.neatmonster.nocheatplus.utilities.PlayerLocation; import fr.neatmonster.nocheatplus.utilities.StringUtil; @@ -328,9 +329,15 @@ public class CreativeFly extends Check { limitV *= data.flySpeed / 0.1; } + // TODO: Hack, move / config / something. + // TODO: Confine more. hdist change relates to ydist change + if (limitV == 0.0 && Bridge1_9.isGlidingWithElytra(from.getPlayer())) { + limitV = hackLytra(yDistance, limitV, thisMove, lastMove, data); + } + if (model.gravity) { // Friction with gravity. - if (model.gravity && lastMove.toIsValid && yDistance > limitV) { // TODO: gravity/friction? + if (yDistance > limitV && model.gravity && lastMove.toIsValid) { // TODO: gravity/friction? // (Disregard gravity.) // TODO: Use last friction (as well)? double frictionDist = lastMove.yDistance * Magic.FRICTION_MEDIUM_AIR; @@ -383,6 +390,50 @@ public class CreativeFly extends Check { return new double[] {limitV, resultV}; } + private double hackLytra(final double yDistance, final double limitV, final MoveData thisMove, final MoveData lastMove, final MovingData data) { + // TODO: Further: jumpphase vs. y-distance to set-back. Problem: velocity + // TODO: Further: record max h and descend speeds and relate to those. + // TODO: Demand total speed to decrease. + if (yDistance > Magic.GLIDE_DESCEND_PHASE_MIN && yDistance < 17.0 * Magic.GRAVITY_MAX + && ( + // Normal envelope. + yDistance - lastMove.yDistance < Magic.GRAVITY_MAX * 1.5 + // Inversion (neg -> pos). + || lastMove.yDistance < -Magic.GRAVITY_SPAN && yDistance < Magic.GRAVITY_MAX + Magic.GRAVITY_ODD && yDistance > Magic.GRAVITY_SPAN + ) + && thisMove.hDistance < lastMove.hDistance + && (lastMove.yDistance > 0.0 || lastMove.hDistance > 0.55) // Demand some speed on the transition. + // Demand total speed to decrease somehow, unless for the very transition. + && (thisMove.distanceSquared / lastMove.distanceSquared < 0.99 + || lastMove.yDistance < 0.0) // Might confine the latter something to be tested. + ) { + if (lastMove.hDistance > 0.52) { + // (Increasing y-distance.) + tags.add("elytra_asc1"); + return yDistance; + } + else if (thisMove.hDistance > Magic.GRAVITY_MIN && yDistance < lastMove.yDistance) { + // (Decreasing y-distance.) + final MoveData pastMove1 = data.moveData.get(1); + if (pastMove1.toIsValid && pastMove1.to.extraPropertiesValid) { + // Demand this being the first one, or decreasing by a decent amount with past two moves. + if ( + // First move rather decreasing. + pastMove1.yDistance < lastMove.yDistance + // Decreasing by a reasonable (?) amount. + || yDistance - pastMove1.yDistance < -0.001 + // && yDistance - lastMove.yDistance < lastMove.yDistance - pastMove1.yDistance - 0.0005 // Probably need remove. + ) { + tags.add("elytra_asc2"); + return yDistance; + } + } + } + + } + return limitV; + } + /** * * @param from @@ -430,8 +481,14 @@ public class CreativeFly extends Check { } private void outpuDebugMove(final Player player, final double hDistance, final double limitH, final double yDistance, final double limitV, final ModelFlying model, final List tags, final MovingData data) { + final MoveData lastMove = data.moveData.getFirst(); StringBuilder builder = new StringBuilder(350); - builder.append("hDist: " + hDistance + " / " + limitH + " , vDist: " + yDistance + " / " + limitV); + final String dHDist = lastMove.toIsValid ? " (" + StringUtil.formatDiff(hDistance, lastMove.hDistance) + ")" : ""; + final String dYDist = lastMove.toIsValid ? " (" + StringUtil.formatDiff(yDistance, lastMove.yDistance)+ ")" : ""; + builder.append("hDist: " + hDistance + dHDist + " / " + limitH + " , vDist: " + yDistance + dYDist + " / " + limitV); + if (lastMove.toIsValid) { + builder.append(" , fdsq: " + StringUtil.fdec3.format(data.thisMove.distanceSquared / lastMove.distanceSquared)); + } if (data.verVelUsed != null) { builder.append(" , vVelUsed: " + data.verVelUsed); } 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 e5617d1e..ccbe7ece 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 @@ -654,11 +654,13 @@ public class SurvivalFly extends Check { } // (Friction is used as is.) } + // TODO: !sfDirty is very coarse, should use friction instead. else if (!sfDirty && from.isOnGround() && player.isSneaking() && reallySneaking.contains(player.getName()) && (!checkPermissions || !player.hasPermission(Permissions.MOVING_SURVIVALFLY_SNEAKING))) { hAllowedDistance = Magic.modSneak * thisMove.walkSpeed * cc.survivalFlySneakingSpeed / 100D; friction = 0.0; // Ensure friction can't be used to speed. // TODO: Attribute modifiers can count in here, e.g. +0.5 (+ 50% doesn't seem to pose a problem, neither speed effect 2). } + // TODO: !sfDirty is very coarse, should use friction instead. else if (!sfDirty && from.isOnGround() && player.isBlocking() && (!checkPermissions || !player.hasPermission(Permissions.MOVING_SURVIVALFLY_BLOCKING))) { hAllowedDistance = Magic.modBlock * thisMove.walkSpeed * cc.survivalFlyBlockingSpeed / 100D; friction = 0.0; // Ensure friction can't be used to speed. @@ -1129,7 +1131,7 @@ public class SurvivalFly extends Check { // y direction change detection. // TODO: Consider using accounting for y-change detection. <- Nope :). - final boolean yDirChange = lastMove.toIsValid && lastMove.yDistance != yDistance && (yDistance <= 0 && lastMove.yDistance >= 0 || yDistance >= 0 && lastMove.yDistance <= 0 ); + final boolean yDirChange = lastMove.toIsValid && lastMove.yDistance != yDistance && (yDistance <= 0.0 && lastMove.yDistance >= 0.0 || yDistance >= 0.0 && lastMove.yDistance <= 0.0 ); if (yDirChange) { // yDirChange uses velocity if needed. vDistanceAboveLimit = yDirChange(from, to, yDistance, vDistanceAboveLimit, lastMove, data); @@ -1147,15 +1149,15 @@ public class SurvivalFly extends Check { } else if (data.verVelUsed == null) { // Only skip if just used. // Here yDistance can be negative and positive. - if (yDistance != 0D) { - data.vDistAcc.add((float) yDistance); - final double accAboveLimit = verticalAccounting(yDistance, data.vDistAcc ,tags, "vacc" + (data.isVelocityJumpPhase() ? "dirty" : "")); - if (accAboveLimit > vDistanceAboveLimit) { - if (data.getOrUseVerticalVelocity(yDistance) == null) { - vDistanceAboveLimit = accAboveLimit; - } + // if (yDistance != 0.0) { + data.vDistAcc.add((float) yDistance); + final double accAboveLimit = verticalAccounting(yDistance, data.vDistAcc ,tags, "vacc" + (data.isVelocityJumpPhase() ? "dirty" : "")); + if (accAboveLimit > vDistanceAboveLimit) { + if (data.getOrUseVerticalVelocity(yDistance) == null) { + vDistanceAboveLimit = accAboveLimit; } } + // } } else { // TODO: Just to exclude source of error, might be redundant. @@ -1475,17 +1477,17 @@ public class SurvivalFly extends Check { || (cc.sfGroundHop || yDistance == 0.0 && !lastMove.touchedGroundWorkaround && !lastMove.from.onGround) && hDistanceBaseRef > 0.0 && hDistance / hDistanceBaseRef < 1.35 ) - // 0: Ground + jump phase conditions. - && ( - // 1: Ordinary/obvious lift-off. - data.sfJumpPhase == 0 && from.isOnGround() - // 1: Touched ground somehow. - || data.sfJumpPhase <= 1 && (thisMove.touchedGroundWorkaround || - lastMove.touchedGround && !lastMove.bunnyHop) - // 1: Double bunny. - || double_bunny) - // 0: Don't allow bunny to run out of liquid. - && !from.isResetCond() && !to.isResetCond() // TODO: !to.isResetCond() should be reviewed. + // 0: Ground + jump phase conditions. + && ( + // 1: Ordinary/obvious lift-off. + data.sfJumpPhase == 0 && from.isOnGround() + // 1: Touched ground somehow. + || data.sfJumpPhase <= 1 && (thisMove.touchedGroundWorkaround || + lastMove.touchedGround && !lastMove.bunnyHop) + // 1: Double bunny. + || double_bunny) + // 0: Don't allow bunny to run out of liquid. + && !from.isResetCond() && !to.isResetCond() // TODO: !to.isResetCond() should be reviewed. ) { // TODO: Jump effect might allow more strictness. // TODO: Expected minimum gain depends on last speed (!). @@ -1832,8 +1834,12 @@ public class SurvivalFly extends Check { final String lostSprint = (data.lostSprintCount > 0 ? (" lostSprint=" + data.lostSprintCount) : ""); final String hVelUsed = hFreedom > 0 ? " hVelUsed=" + StringUtil.fdec3.format(hFreedom) : ""; builder.append("\nonground: " + (data.thisMove.headObstructed ? "(head obstr.) " : "") + (data.thisMove.touchedGroundWorkaround ? "(touched ground) " : "") + (fromOnGround ? "onground -> " : (resetFrom ? "resetcond -> " : "--- -> ")) + (toOnGround ? "onground" : (resetTo ? "resetcond" : "---")) + ", jumpphase: " + data.sfJumpPhase + ", liftoff: " + data.liftOffEnvelope.name() + "(" + data.insideMediumCount + ")"); - final String dHDist = (lastMove.toIsValid && Math.abs(lastMove.hDistance - hDistance) > 0.0005) ? ("(" + (hDistance > lastMove.hDistance ? "+" : "") + StringUtil.fdec3.format(hDistance - lastMove.hDistance) + ")") : ""; - builder.append("\n" + " hDist: " + StringUtil.fdec3.format(hDistance) + dHDist + " / " + StringUtil.fdec3.format(hAllowedDistance) + hBuf + lostSprint + hVelUsed + " , vDist: " + StringUtil.fdec3.format(yDistance) + (!lastMove.toIsValid ? "" : (" (" + (yDistance > lastMove.yDistance ? "+" : "") + StringUtil.fdec3.format(yDistance - lastMove.yDistance) + ")")) + " / " + StringUtil.fdec3.format(vAllowedDistance) + " , sby=" + (data.hasSetBack() ? (data.getSetBackY() + " (" + StringUtil.fdec3.format(to.getY() - data.getSetBackY()) + " / " + data.liftOffEnvelope.getMaxJumpHeight(data.jumpAmplifier) + ")") : "?")); + final String dHDist = lastMove.toIsValid ? " (" + StringUtil.formatDiff(hDistance, lastMove.hDistance) + ")" : ""; + final String dYDist = lastMove.toIsValid ? " (" + StringUtil.formatDiff(yDistance, lastMove.yDistance)+ ")" : ""; + builder.append("\n" + " hDist: " + StringUtil.fdec3.format(hDistance) + dHDist + " / " + StringUtil.fdec3.format(hAllowedDistance) + hBuf + lostSprint + hVelUsed + " , vDist: " + StringUtil.fdec3.format(yDistance) + dYDist + " / " + StringUtil.fdec3.format(vAllowedDistance) + " , sby=" + (data.hasSetBack() ? (data.getSetBackY() + " (" + StringUtil.fdec3.format(to.getY() - data.getSetBackY()) + " / " + data.liftOffEnvelope.getMaxJumpHeight(data.jumpAmplifier) + ")") : "?")); + if (lastMove.toIsValid) { + builder.append(" , fdsq: " + StringUtil.fdec3.format(data.thisMove.distanceSquared / lastMove.distanceSquared)); + } if (data.verVelUsed != null) { builder.append(" , vVelUsed: " + data.verVelUsed + " "); } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/model/ModelFlying.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/model/ModelFlying.java index f7adf3ed..f2ff1953 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/model/ModelFlying.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/model/ModelFlying.java @@ -66,7 +66,7 @@ public class ModelFlying { } public ModelFlying() { - this(null, 100.0, 1.92, 100.0, 128, true, true, false); + this(null, 100.0, 1.92, 100.0, 128, true, true, true); } } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/model/MoveData.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/model/MoveData.java index eaaefd11..539a2c43 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/model/MoveData.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/checks/moving/model/MoveData.java @@ -62,6 +62,9 @@ public class MoveData { */ public double hDistance; + /** Total distance squared. Only valid if toIsValid is set to true. */ + public double distanceSquared; + ////////////////////////////////////////////////////////// // Reset with set, could be lazily set during checking. ////////////////////////////////////////////////////////// @@ -143,6 +146,7 @@ public class MoveData { this.to.setLocation(to); yDistance = this.to.y - this.from.y; hDistance = TrigUtil.distance(this.from.x, this.from.z, this.to.x, this.to.z); + distanceSquared = yDistance * yDistance + hDistance * hDistance; toIsValid = true; } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/DefaultConfig.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/DefaultConfig.java index f519513a..a6a9d3c8 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/DefaultConfig.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/config/DefaultConfig.java @@ -361,6 +361,8 @@ public class DefaultConfig extends ConfigFile { set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "spectator." + ConfPaths.SUB_HORIZONTAL_SPEED, 420); set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "spectator." + ConfPaths.SUB_VERTICAL_ASCEND_SPEED, 100); set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "spectator." + ConfPaths.SUB_VERTICAL_MAXHEIGHT, 128); + set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "spectator." + ConfPaths.SUB_GRAVITY, false); + set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "spectator." + ConfPaths.SUB_GROUND, false); } if (Bridge1_9.hasLevitation()) { set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "levitation." + ConfPaths.SUB_HORIZONTAL_SPEED, 50); @@ -368,14 +370,15 @@ public class DefaultConfig extends ConfigFile { set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "levitation." + ConfPaths.SUB_VERTICAL_MAXHEIGHT, 32); set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "levitation." + ConfPaths.SUB_VERTICAL_GRAVITY, false); set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "levitation." + ConfPaths.SUB_MODIFIERS, false); + set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "levitation." + ConfPaths.SUB_GRAVITY, false); + set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "levitation." + ConfPaths.SUB_GROUND, false); } if (Bridge1_9.hasElytra()) { - set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "elytra." + ConfPaths.SUB_HORIZONTAL_SPEED, 500); + set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "elytra." + ConfPaths.SUB_HORIZONTAL_SPEED, 520); set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "elytra." + ConfPaths.SUB_HORIZONTAL_MODSPRINT, 1.0); set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "elytra." + ConfPaths.SUB_VERTICAL_ASCEND_SPEED, 0); set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "elytra." + ConfPaths.SUB_VERTICAL_MAXHEIGHT, 8); set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "elytra." + ConfPaths.SUB_MODIFIERS, false); - set(ConfPaths.MOVING_CREATIVEFLY_MODEL + "elytra." + ConfPaths.SUB_GROUND, true); } set(ConfPaths.MOVING_CREATIVEFLY_ACTIONS, "log:flyshort:3:5:f cancel vl>100 log:flyshort:0:5:if cancel vl>400 log:flylong:0:5:cif cancel");