Search in sources :

Example 11 with PlayerMoveData

use of fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData in project NoCheatPlus by NoCheatPlus.

the class CreativeFly method outpuDebugMove.

private void outpuDebugMove(final Player player, final double hDistance, final double limitH, final double yDistance, final double limitV, final ModelFlying model, final List<String> tags, final MovingData data) {
    final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove();
    StringBuilder builder = new StringBuilder(350);
    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);
    final PlayerMoveData thisMove = data.playerMoves.getCurrentMove();
    if (lastMove.toIsValid) {
        builder.append(" , fdsq: " + StringUtil.fdec3.format(thisMove.distanceSquared / lastMove.distanceSquared));
    }
    if (thisMove.verVelUsed != null) {
        builder.append(" , vVelUsed: " + thisMove.verVelUsed);
    }
    if (data.fireworksBoostDuration > 0 && MovingConfig.ID_JETPACK_ELYTRA.equals(model.getId())) {
        builder.append(" , boost: " + data.fireworksBoostDuration);
    }
    builder.append(" , model: " + model.getId());
    if (!tags.isEmpty()) {
        builder.append(" , tags: ");
        builder.append(StringUtil.join(tags, "+"));
    }
    builder.append(" , jumpphase: " + data.sfJumpPhase);
    thisMove.addExtraProperties(builder, " , ");
    debug(player, builder.toString());
}
Also used : PlayerMoveData(fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData)

Example 12 with PlayerMoveData

use of fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData in project NoCheatPlus by NoCheatPlus.

the class MagicAir method oddElytra.

/**
 * Odd behavior with/after wearing elytra. End rod is not in either hand,
 * elytra is equipped (not checked in here).
 *
 * @param yDistance
 * @param yDistDiffEx
 * @param lastMove
 * @param data
 * @return
 */
@SuppressWarnings("unused")
private static boolean oddElytra(final double yDistance, final double yDistDiffEx, final PlayerMoveData lastMove, final MovingData data) {
    // Organize cases differently here, at the cost of reaching some nesting level, in order to see if it's better to overview.
    final PlayerMoveData thisMove = data.playerMoves.getCurrentMove();
    // Checked below, if needed.
    final PlayerMoveData pastMove1 = data.playerMoves.getSecondPastMove();
    // Both descending moves.
    if (thisMove.yDistance < 0.0 && lastMove.yDistance < 0.0) {
        // Falling too slow.
        if (yDistDiffEx > 0.0) {
            final double yDistChange = thisMove.yDistance - lastMove.yDistance;
            // Increase falling speed somehow.
            if (yDistChange < 0.0) {
                // pastMove1 valid, decreasing speed envelope like above.
                if (pastMove1.toIsValid && pastMove1.yDistance < 0.0) {
                    final double lastYDistChange = lastMove.yDistance - pastMove1.yDistance;
                    // Increase falling speed from past to last.
                    if (lastYDistChange < 0.0) {
                        // TODO: Inaugurate by the one below?
                        if (Math.abs(yDistChange + lastYDistChange) > Magic.GRAVITY_ODD / 2.0) {
                            // TODO: Might further test for a workaround count down or relate to total gain / jump phase.
                            return true;
                        }
                    }
                }
            }
            // Gliding possibly.
            if (Magic.glideVerticalGainEnvelope(thisMove.yDistance, lastMove.yDistance)) {
                // (Further restrictions hardly grip, observed: jump phase > 40, yDistance at -0.214)
                return true;
            }
        }
    }
    return false;
}
Also used : PlayerMoveData(fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData)

Example 13 with PlayerMoveData

use of fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData in project NoCheatPlus by NoCheatPlus.

the class MagicAir method oddFriction.

/**
 * Odd behavior with moving up or (slightly) down, not like the ordinary
 * friction mechanics, accounting for more than one past move. Needs
 * lastMove to be valid.
 *
 * @param yDistance
 * @param lastMove
 * @param data
 * @return
 */
private static boolean oddFriction(final double yDistance, final double yDistDiffEx, final PlayerMoveData lastMove, final MovingData data) {
    // Use past move data for two moves.
    final PlayerMoveData pastMove1 = data.playerMoves.getSecondPastMove();
    if (!lastMove.to.extraPropertiesValid || !pastMove1.toIsValid || !pastMove1.to.extraPropertiesValid) {
        return false;
    }
    final PlayerMoveData thisMove = data.playerMoves.getCurrentMove();
    return // (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 && Magic.inAir(thisMove) && (// 1: Towards ascending rather.
    pastMove1.yDistance > lastMove.yDistance - Magic.GRAVITY_MAX && lastMove.yDistance > yDistance + Magic.GRAVITY_MAX && // Positive speed. TODO: rather > 1.0 (!).
    lastMove.yDistance > 0.0 && (// 2: Odd speed decrease bumping into a block sideways somehow, having moved through water.
    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 > -Magic.GRAVITY_MAX && Math.abs(pastMove1.yDistance - lastMove.yDistance - (lastMove.yDistance - thisMove.yDistance)) < Magic.GRAVITY_MAX) || // TODO: Might explicitly demand (lava) friction decrease from pastMove1 to lastMove.
    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 * Magic.GRAVITY_MAX) || // 1: Less 'strict' speed increase, descending rather.
    pastMove1.yDistance < 0.0 && // Actual speed decrease due to water.
    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)
    (Magic.splashMove(lastMove, pastMove1) && pastMove1.yDistance > lastMove.yDistance || // Allow more decrease if moving through more solid water.
    Magic.inLiquid(pastMove1) && Magic.leavingLiquid(lastMove) && pastMove1.yDistance * .7 > lastMove.yDistance) || // 1: Strong decrease after rough keeping speed (hold space bar, with velocity, descending).
    // Arbitrary, actually observed was around 2.
    yDistance < -0.5 && 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))) || // 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) && // 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);
}
Also used : PlayerMoveData(fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData)

Example 14 with PlayerMoveData

use of fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData in project NoCheatPlus by NoCheatPlus.

the class SurvivalFly method check.

/**
 * @param player
 * @param from
 * @param to
 * @param multiMoveCount
 *            =: Ordinary, 1/2: first/second of a split move.
 * @param data
 * @param cc
 * @param tick
 * @param now
 * @param useBlockChangeTracker
 * @return
 */
public Location check(final Player player, final PlayerLocation from, final PlayerLocation to, final int multiMoveCount, final MovingData data, final MovingConfig cc, final IPlayerData pData, final int tick, final long now, final boolean useBlockChangeTracker) {
    tags.clear();
    final boolean debug = pData.isDebugActive(type);
    if (debug) {
        justUsedWorkarounds.clear();
        data.ws.setJustUsedIds(justUsedWorkarounds);
    }
    final PlayerMoveData thisMove = data.playerMoves.getCurrentMove();
    final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove();
    final boolean isSamePos = from.isSamePos(to);
    // Calculate some distances.
    final double xDistance, yDistance, zDistance, hDistance;
    final boolean hasHdist;
    if (isSamePos) {
        // TODO: Could run a completely different check here (roughly none :p).
        xDistance = yDistance = zDistance = hDistance = 0.0;
        hasHdist = false;
    } else {
        xDistance = to.getX() - from.getX();
        yDistance = thisMove.yDistance;
        zDistance = to.getZ() - from.getZ();
        if (xDistance == 0.0 && zDistance == 0.0) {
            hDistance = 0.0;
            hasHdist = false;
        } else {
            hasHdist = true;
            hDistance = thisMove.hDistance;
        }
    }
    // Recover from data removal (somewhat random insertion point).
    if (data.liftOffEnvelope == LiftOffEnvelope.UNKNOWN) {
        data.adjustMediumProperties(from);
    }
    // Set some flags.
    final boolean fromOnGround = thisMove.from.onGround;
    // TODO: Work in the past ground stuff differently (thisMove, touchedGround?, from/to ...)
    final boolean toOnGround = thisMove.to.onGround || useBlockChangeTracker && toOnGroundPastStates(from, to, thisMove, tick, data, cc);
    final boolean resetTo = toOnGround || to.isResetCond();
    // Determine if the player is actually sprinting.
    final boolean sprinting;
    if (data.lostSprintCount > 0) {
        // NOTE: This could extend the "sprinting grace" period, theoretically, until on ground.
        if (resetTo && (fromOnGround || from.isResetCond()) || hDistance <= Magic.WALK_SPEED) {
            // Invalidate.
            data.lostSprintCount = 0;
            tags.add("invalidate_lostsprint");
            if (now <= data.timeSprinting + cc.sprintingGrace) {
                sprinting = true;
            } else {
                sprinting = false;
            }
        } else {
            tags.add("lostsprint");
            sprinting = true;
            if (data.lostSprintCount < 3 && toOnGround || to.isResetCond()) {
                data.lostSprintCount = 0;
            } else {
                data.lostSprintCount--;
            }
        }
    } else if (now <= data.timeSprinting + cc.sprintingGrace) {
        // Within grace period for hunger level being too low for sprinting on server side (latency).
        if (now != data.timeSprinting) {
            tags.add("sprintgrace");
        }
        sprinting = true;
    } else {
        sprinting = false;
    }
    // Use the player-specific walk speed.
    // TODO: Might get from listener.
    // TODO: Use in lostground?
    thisMove.walkSpeed = Magic.WALK_SPEED * ((double) data.walkSpeed / Magic.DEFAULT_WALKSPEED);
    setNextFriction(thisMove, data, cc);
    // ///////////////////////////////
    // Mixed checks (lost ground).
    // ///////////////////////////////
    final boolean resetFrom;
    if (fromOnGround || from.isResetCond()) {
        resetFrom = true;
    } else // TODO: Extra workarounds for toOnGround (step-up is a case with to on ground)?
    if (isSamePos) {
        // TODO: This isn't correct, needs redesign.
        if (useBlockChangeTracker && from.isOnGroundOpportune(cc.yOnGround, 0L, blockChangeTracker, data.blockChangeRef, tick)) {
            // TODO: Quick addition. Reconsider entry points etc.
            resetFrom = true;
            tags.add("pastground_from");
        } else if (lastMove.toIsValid) {
            // Note that to is not on ground either.
            resetFrom = LostGround.lostGroundStill(player, from, to, hDistance, yDistance, sprinting, lastMove, data, cc, tags);
        } else {
            resetFrom = false;
        }
    } else {
        // "Lost ground" workaround.
        // TODO: More refined conditions possible ?
        // TODO: Consider if (!resetTo) ?
        // Check lost-ground workarounds.
        resetFrom = LostGround.lostGround(player, from, to, hDistance, yDistance, sprinting, lastMove, data, cc, useBlockChangeTracker ? blockChangeTracker : null, tags);
    // Note: if not setting resetFrom, other places have to check assumeGround...
    }
    if (thisMove.touchedGround) {
        if (!thisMove.from.onGround && !thisMove.to.onGround) {
            // Lost ground workaround has just been applied, check resetting of the dirty flag.
            // TODO: Always/never reset with any ground touched?
            data.resetVelocityJumpPhase(tags);
        } else if (multiMoveCount == 0 && thisMove.from.onGround && !lastMove.touchedGround && TrigUtil.isSamePosAndLook(thisMove.from, lastMove.to)) {
            // Ground somehow appeared out of thin air (block place).
            data.setSetBack(from);
            if (debug) {
                debug(player, "Adjust set back on move: from is now on ground.");
            }
        }
    }
    // Renew the "dirty"-flag (in-air phase affected by velocity).
    if (data.isVelocityJumpPhase() || data.resetVelocityJumpPhase(tags)) {
        // (Reset is done after checks run.)
        tags.add("dirty");
    }
    // Check if head is obstructed.
    // if (!resetFrom || !resetTo) {
    thisMove.headObstructed = (yDistance > 0.0 ? from.isHeadObstructed(yDistance) : from.isHeadObstructed());
    // TODO: Consider setting on ground_height always?
    if ((from.getBlockFlags() & BlockProperties.F_ALLOW_LOWJUMP) != 0) {
        // TODO: Specialize - test for foot region?
        data.sfNoLowJump = true;
    }
    // ////////////////////
    // Horizontal move.
    // ////////////////////
    // TODO: Account for lift-off medium / if in air [i.e. account for medium + friction]?
    // Alter some data / flags.
    // TODO: Design to do the changing at the bottom? [if change: check limits in bunnyHop(...)]
    data.bunnyhopDelay--;
    // Set flag for swimming with the flowing direction of liquid.
    thisMove.downStream = hDistance > thisMove.walkSpeed * Magic.modSwim && thisMove.from.inLiquid && from.isDownStream(xDistance, zDistance);
    // TODO: Re-model ice stuff and other (e.g. general thing: ground-modifier + reset conditions).
    if (thisMove.from.onIce || thisMove.to.onIce) {
        // TODO: 1. Test if this can simply be removed. 2. Ensure data.sfOnIce resets with a violation.
        data.sfOnIce = 20;
    } else if (data.sfOnIce > 0) {
        // TODO: Here some friction might apply, could become a general thing with bunny and other.
        // TODO: Other reset conditions.
        data.sfOnIce--;
    }
    /*
         * TODO: if (Bridge1_9.isGlidingWithElytra(player)) { // Force stop
         * gliding?
         */
    // TODO: Remove these local variables ?
    double hAllowedDistance = 0.0, hDistanceAboveLimit = 0.0, hFreedom = 0.0;
    if (hasHdist) {
        // Check allowed vs. taken horizontal distance.
        // Get the allowed distance.
        hAllowedDistance = setAllowedhDist(player, sprinting, thisMove, data, cc, pData, false);
        // Judge if horizontal speed is above limit.
        hDistanceAboveLimit = hDistance - hAllowedDistance;
        // Velocity, buffers and after failure checks.
        if (hDistanceAboveLimit > 0) {
            // TODO: Move more of the workarounds (buffer, bunny, ...) into this method.
            final double[] res = hDistAfterFailure(player, from, to, hAllowedDistance, hDistanceAboveLimit, sprinting, thisMove, lastMove, data, cc, pData, false);
            hAllowedDistance = res[0];
            hDistanceAboveLimit = res[1];
            hFreedom = res[2];
        } else {
            data.clearActiveHorVel();
            hFreedom = 0.0;
            if (resetFrom && data.bunnyhopDelay <= 6) {
                data.bunnyhopDelay = 0;
            }
        }
        // hacc (if enabled, always update)
        final double fcmhv = Math.max(1.0, Math.min(10.0, thisMove.hDistance / thisMove.hAllowedDistanceBase));
        data.combinedMediumHCount++;
        data.combinedMediumHValue += fcmhv;
        // TODO: Balance, where to check / use (...).
        if (data.combinedMediumHCount > 30) {
            // TODO: Early trigger (> 0,1,2,5?), for way too high values. [in that case don't reset]
            final double fcmh = data.combinedMediumHValue / (double) data.combinedMediumHCount;
            final double limitFCMH;
            // TODO: with buffer use, might want to skip.
            if (data.liftOffEnvelope == LiftOffEnvelope.NORMAL) {
                limitFCMH = 1.34;
            } else if (data.liftOffEnvelope == LiftOffEnvelope.LIMIT_LIQUID || data.liftOffEnvelope == LiftOffEnvelope.LIMIT_NEAR_GROUND) {
                // limitFCMH = 1.05; // Seems to work on 1.10
                // 1.8.8 in-water moves with jumping near/on surface. 1.2 is max factor for one move (!).
                limitFCMH = 1.1;
            // TODO: Version+context dependent setting and/or confine by in-water moves, whatever.
            } else {
                limitFCMH = 1.0;
            }
            // TODO: Fly-NoFly + bunny-water transitions pose issues.
            if (fcmh > limitFCMH && !data.isVelocityJumpPhase()) {
                hDistanceAboveLimit = hDistance * (fcmh - limitFCMH);
                tags.add("hacc");
                // Reset for now.
                data.combinedMediumHCount = 0;
                data.combinedMediumHValue = 0.0;
            } else {
                // TODO: Other cases (1.0, between, ...)?
                data.combinedMediumHCount = 1;
                data.combinedMediumHValue = fcmhv;
            }
        }
        // TODO: Complete re-modeling.
        if (hDistanceAboveLimit <= 0D && hDistance > 0.1D && yDistance == 0D && !toOnGround && !fromOnGround && lastMove.toIsValid && lastMove.yDistance == 0D && BlockProperties.isLiquid(to.getTypeId()) && BlockProperties.isLiquid(from.getTypeId()) && !from.isHeadObstructed() && // TODO: Might decrease margin here.
        !to.isHeadObstructed()) {
            // TODO: Relative hdistance.
            // TODO: Might check actual bounds (collidesBlock). Might implement + use BlockProperties.getCorrectedBounds or getSomeHeight.
            hDistanceAboveLimit = Math.max(hDistanceAboveLimit, hDistance);
            tags.add("waterwalk");
        }
        // Prevent players from sprinting if they're moving backwards (allow buffers to cover up !?).
        if (sprinting && data.lostSprintCount == 0 && !cc.assumeSprint && hDistance > thisMove.walkSpeed && !data.hasActiveHorVel()) {
            // TODO: speed effects ?
            if (TrigUtil.isMovingBackwards(xDistance, zDistance, from.getYaw()) && !pData.hasPermission(Permissions.MOVING_SURVIVALFLY_SPRINTING, player)) {
                // (Might have to account for speeding permissions.)
                // TODO: hDistance is too harsh?
                hDistanceAboveLimit = Math.max(hDistanceAboveLimit, hDistance);
                // Might add it anyway.
                tags.add("sprintback");
            }
        }
    } else {
        /*
             * TODO: Consider to log and/or remember when this was last time
             * cleared [add time distance to tags/log on violations].
             */
        data.clearActiveHorVel();
        thisMove.hAllowedDistanceBase = 0.0;
        thisMove.hAllowedDistance = 0.0;
    // TODO: Other properties should be set as well?
    }
    // ////////////////////////
    // Vertical move.
    // ////////////////////////
    // Calculate the vertical speed limit based on the current jump phase.
    double vAllowedDistance = 0, vDistanceAboveLimit = 0;
    // Distinguish certain media.
    if (yDistance >= 0.0 && yDistance <= cc.sfStepHeight && toOnGround && fromOnGround) {
        // Wild-card allow step height from ground to ground.
        // TODO: Which of (fromOnGround || data.noFallAssumeGround || lastMove.toIsValid && lastMove.yDistance < 0.0)?
        vAllowedDistance = cc.sfStepHeight;
    } else if (from.isInWeb()) {
        // TODO: Further confine conditions.
        final double[] res = vDistWeb(player, thisMove, toOnGround, hDistanceAboveLimit, now, data, cc);
        vAllowedDistance = res[0];
        vDistanceAboveLimit = res[1];
        if (res[0] == Double.MIN_VALUE && res[1] == Double.MIN_VALUE) {
            // Silent set back.
            if (debug) {
                tags.add("silentsbcobweb");
                outputDebug(player, to, data, cc, hDistance, hAllowedDistance, hFreedom, yDistance, vAllowedDistance, fromOnGround, resetFrom, toOnGround, resetTo, thisMove);
                data.ws.setJustUsedIds(null);
            }
            // (OK)
            return data.getSetBack(to);
        }
    } else if (from.isOnClimbable()) {
        // Ladder types.
        vDistanceAboveLimit = vDistClimbable(player, from, to, fromOnGround, toOnGround, thisMove, lastMove, yDistance, data);
    } else if (thisMove.from.inLiquid) {
        // && (Math.abs(yDistance) > 0.2 || to.isInLiquid())) {
        // Swimming...
        final double[] res = vDistLiquid(from, to, toOnGround, yDistance, lastMove, data);
        vAllowedDistance = res[0];
        vDistanceAboveLimit = res[1];
        if (vDistanceAboveLimit <= 0.0 && yDistance > 0.0 && Math.abs(yDistance) > Magic.swimBaseSpeedV()) {
            data.setFrictionJumpPhase();
        }
    } else {
        final double[] res = vDistAir(now, player, from, fromOnGround, resetFrom, to, toOnGround, resetTo, hDistanceAboveLimit, yDistance, multiMoveCount, lastMove, data, cc, pData);
        vAllowedDistance = res[0];
        vDistanceAboveLimit = res[1];
    }
    // Post-check recovery.
    if (useBlockChangeTracker && vDistanceAboveLimit > 0.0) // Skip for now: && Math.abs(yDistance) <= 1.55
    {
        // TODO: Better place for checking for moved blocks [redesign for intermediate result objects?].
        // Vertical push/pull.
        double[] blockMoveResult = getVerticalBlockMoveResult(yDistance, from, to, tick, data);
        if (blockMoveResult != null) {
            vAllowedDistance = blockMoveResult[0];
            vDistanceAboveLimit = blockMoveResult[1];
        }
    }
    // Push/pull sideways.
    // TODO: Slightly itchy: regard x and z separately (Better in another spot).
    // TODO: on ground -> on ground improvements.
    // Debug output.
    final int tagsLength;
    if (debug) {
        outputDebug(player, to, data, cc, hDistance, hAllowedDistance, hFreedom, yDistance, vAllowedDistance, fromOnGround, resetFrom, toOnGround, resetTo, thisMove);
        tagsLength = tags.size();
        data.ws.setJustUsedIds(null);
    } else {
        // JIT vs. IDE.
        tagsLength = 0;
    }
    // /////////////////////
    // Handle violations.
    // /////////////////////
    final boolean inAir = Magic.inAir(thisMove);
    final double result = (Math.max(hDistanceAboveLimit, 0D) + Math.max(vDistanceAboveLimit, 0D)) * 100D;
    if (result > 0D) {
        final Location vLoc = handleViolation(now, result, player, from, to, data, cc);
        if (inAir) {
            data.sfVLInAir = true;
        }
        if (vLoc != null) {
            return vLoc;
        }
    } else {
        // TODO: Switch to move count instead of time (!).
        if (data.getPlayerMoveCount() - data.sfVLTime > cc.survivalFlyVLFreezeCount && (!cc.survivalFlyVLFreezeInAir || !inAir || // Favor bunny-hopping slightly: clean descend.
        !data.sfVLInAir && data.liftOffEnvelope == LiftOffEnvelope.NORMAL && lastMove.toIsValid && lastMove.yDistance < -Magic.GRAVITY_MIN && thisMove.yDistance - lastMove.yDistance < -Magic.GRAVITY_MIN)) {
            // Relax VL.
            data.survivalFlyVL *= 0.95;
            // Finally check horizontal buffer regain.
            if (hDistanceAboveLimit < 0.0 && result <= 0.0 && !isSamePos && data.sfHorizontalBuffer < cc.hBufMax) {
                // TODO: max min other conditions ?
                hBufRegain(hDistance, Math.min(0.2, Math.abs(hDistanceAboveLimit)), data, cc);
            }
        }
    }
    // ////////////////////////////////////////////////////////////////////////////////////////////
    // Set data for normal move or violation without cancel (cancel would have returned above).
    // ////////////////////////////////////////////////////////////////////////////////////////////
    // Check LiftOffEnvelope.
    // TODO: Web before liquid? Climbable?
    // TODO: isNextToGround(0.15, 0.4) allows a little much (yMargin), but reduces false positives.
    // TODO: nextToGround: Shortcut with block-flags ?
    final LiftOffEnvelope oldLiftOffEnvelope = data.liftOffEnvelope;
    if (to.isInLiquid()) {
        if (fromOnGround && !toOnGround && data.liftOffEnvelope == LiftOffEnvelope.NORMAL && data.sfJumpPhase <= 0 && !thisMove.from.inLiquid) {
        // KEEP
        } else if (to.isNextToGround(0.15, 0.4)) {
            // Consent with ground.
            data.liftOffEnvelope = LiftOffEnvelope.LIMIT_NEAR_GROUND;
        } else {
            // TODO: Distinguish strong limit from normal.
            data.liftOffEnvelope = LiftOffEnvelope.LIMIT_LIQUID;
        }
    } else if (thisMove.to.inWeb) {
        // TODO: Test.
        data.liftOffEnvelope = LiftOffEnvelope.NO_JUMP;
    } else if (resetTo) {
        // TODO: This might allow jumping on vines etc., but should do for the moment.
        data.liftOffEnvelope = LiftOffEnvelope.NORMAL;
    } else if (thisMove.from.inLiquid) {
        if (!resetTo && data.liftOffEnvelope == LiftOffEnvelope.NORMAL && data.sfJumpPhase <= 0) {
        // KEEP
        } else if (to.isNextToGround(0.15, 0.4)) {
            // TODO: Problematic: y-distance slope can be low jump.
            data.liftOffEnvelope = LiftOffEnvelope.LIMIT_NEAR_GROUND;
        } else {
            // TODO: Distinguish strong limit.
            data.liftOffEnvelope = LiftOffEnvelope.LIMIT_LIQUID;
        }
    } else if (thisMove.from.inWeb) {
        // TODO: Test.
        data.liftOffEnvelope = LiftOffEnvelope.NO_JUMP;
    } else if (resetFrom || thisMove.touchedGround) {
        // TODO: Where exactly to put noFallAssumeGround ?
        data.liftOffEnvelope = LiftOffEnvelope.NORMAL;
    } else {
    // Keep medium.
    // TODO: Is above stairs ?
    }
    // Count how long one is moving inside of a medium.
    if (oldLiftOffEnvelope != data.liftOffEnvelope) {
        data.insideMediumCount = 0;
        data.combinedMediumHCount = 0;
        data.combinedMediumHValue = 0.0;
    } else if (!resetFrom || !resetTo) {
        data.insideMediumCount = 0;
    } else {
        data.insideMediumCount++;
    }
    // Apply reset conditions.
    if (resetTo) {
        // The player has moved onto ground.
        if (toOnGround) {
            // Reset bunny-hop-delay.
            if (data.bunnyhopDelay > 0 && yDistance > 0.0 && to.getY() > data.getSetBackY() + 0.12 && !from.isResetCond() && !to.isResetCond()) {
                data.bunnyhopDelay = 0;
                tags.add("resetbunny");
            }
        }
        // Reset data.
        data.setSetBack(to);
        data.sfJumpPhase = 0;
        data.clearAccounting();
        data.sfNoLowJump = false;
        if (data.sfLowJump && resetFrom) {
            // Prevent reset if coming from air (purpose of the flag).
            data.sfLowJump = false;
        }
        if (hFreedom <= 0.0 && thisMove.verVelUsed == null) {
            data.resetVelocityJumpPhase(tags);
        }
    } else if (resetFrom) {
        // The player moved from ground.
        data.setSetBack(from);
        // This event is already in air.
        data.sfJumpPhase = 1;
        data.clearAccounting();
        data.sfLowJump = false;
    // not resetting nolowjump (?)...
    // Don't reset velocity phase unless moving into resetcond.
    // if (hFreedom <= 0.0 && data.verVelUsed == null && (!data.noFallAssumeGround || fromOnGround)) {
    // data.resetVelocityJumpPhase(tags);
    // }
    } else {
        data.sfJumpPhase++;
        // TODO: Void-to-void: Rather handle unified somewhere else (!).
        if (to.getY() < 0.0 && cc.sfSetBackPolicyVoid) {
            data.setSetBack(to);
        }
    }
    if (inAir) {
        // Adjust in-air counters.
        if (yDistance == 0.0) {
            data.sfZeroVdistRepeat++;
        } else {
            data.sfZeroVdistRepeat = 0;
        }
    } else {
        data.sfZeroVdistRepeat = 0;
        data.ws.resetConditions(WRPT.G_RESET_NOTINAIR);
        data.sfVLInAir = false;
    }
    // Horizontal velocity invalidation.
    if (hDistance <= (cc.velocityStrictInvalidation ? thisMove.hAllowedDistanceBase : thisMove.hAllowedDistanceBase / 2.0)) {
        // TODO: Should there be other side conditions?
        // Invalidate used horizontal velocity.
        // debug(player, "*** INVALIDATE ON SPEED");
        data.clearActiveHorVel();
    }
    // TODO: Pull down tick / timing data (perhaps add an API object for millis + source + tick + sequence count (+ source of sequence count).
    if (debug) {
        // TODO: Only update, if velocity is queued at all.
        data.getVerticalVelocityTracker().updateBlockedState(tick, // Assume blocked with being in web/water, despite not entirely correct.
        thisMove.headObstructed || thisMove.from.resetCond, // (Similar here.)
        thisMove.touchedGround || thisMove.to.resetCond);
        // TODO: TEST: Check unused velocity here too. (Should have more efficient process, pre-conditions for checking.)
        UnusedVelocity.checkUnusedVelocity(player, type, data, cc);
    }
    // Adjust data.
    data.lastFrictionHorizontal = data.nextFrictionHorizontal;
    data.lastFrictionVertical = data.nextFrictionVertical;
    // Log tags added after violation handling.
    if (debug && tags.size() > tagsLength) {
        logPostViolationTags(player);
    }
    return null;
}
Also used : LiftOffEnvelope(fr.neatmonster.nocheatplus.checks.moving.model.LiftOffEnvelope) PlayerMoveData(fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData) PlayerLocation(fr.neatmonster.nocheatplus.utilities.location.PlayerLocation) Location(org.bukkit.Location)

Example 15 with PlayerMoveData

use of fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData in project NoCheatPlus by NoCheatPlus.

the class SurvivalFly method setAllowedhDist.

/**
 * Set hAllowedDistanceBase and hAllowedDistance in thisMove. Not exact,
 * check permissions as far as necessary, if flag is set to check them.
 *
 * @param player
 * @param sprinting
 * @param thisMove
 * @param data
 * @param cc
 * @param checkPermissions
 *            If to check permissions, allowing to speed up a little bit.
 *            Only set to true after having failed with it set to false.
 * @return Allowed distance.
 */
private double setAllowedhDist(final Player player, final boolean sprinting, final PlayerMoveData thisMove, final MovingData data, final MovingConfig cc, final IPlayerData pData, final boolean checkPermissions) {
    // TODO: Optimize for double checking?
    final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove();
    double hAllowedDistance = 0D;
    final boolean sfDirty = data.isVelocityJumpPhase();
    // Friction to use with this move.
    double friction = data.lastFrictionHorizontal;
    // TODO: sfDirty: Better friction/envelope-based.
    boolean useBaseModifiers = false;
    if (thisMove.from.inWeb) {
        data.sfOnIce = 0;
        // TODO: if (from.isOnIce()) <- makes it even slower !
        // Does include sprinting by now (would need other accounting methods).
        hAllowedDistance = Magic.modWeb * thisMove.walkSpeed * cc.survivalFlyWalkingSpeed / 100D;
        // Ensure friction can't be used to speed.
        friction = 0.0;
    } else if (thisMove.from.inLiquid && thisMove.to.inLiquid) {
        // Check all liquids (lava might demand even slower speed though).
        // TODO: Test how to go with only checking from (less dolphins).
        // TODO: Sneaking and blocking applies to when in water !
        hAllowedDistance = Magic.modSwim * thisMove.walkSpeed * cc.survivalFlySwimmingSpeed / 100D;
        if (thisMove.from.inWater || !thisMove.from.inLava) {
            // (We don't really have other liquids, though.)
            final int level = BridgeEnchant.getDepthStriderLevel(player);
            if (level > 0) {
                // The hard way.
                hAllowedDistance *= Magic.modDepthStrider[level];
                // Modifiers: Most speed seems to be reached on ground, but couldn't nail down.
                useBaseModifiers = true;
            }
        }
    // (Friction is used as is.)
    } else // TODO: !sfDirty is very coarse, should use friction instead.
    if (!sfDirty && thisMove.from.onGround && player.isSneaking() && reallySneaking.contains(player.getName()) && (!checkPermissions || !pData.hasPermission(Permissions.MOVING_SURVIVALFLY_SNEAKING, player))) {
        hAllowedDistance = Magic.modSneak * thisMove.walkSpeed * cc.survivalFlySneakingSpeed / 100D;
        // Ensure friction can't be used to speed.
        friction = 0.0;
    // TODO: Attribute modifiers can count in here, e.g. +0.5 (+ 50% doesn't seem to pose a problem, neither speed effect 2).
    } else // TODO: !sfDirty is very coarse, should use friction instead.
    if (!sfDirty && thisMove.from.onGround && player.isBlocking() && (!checkPermissions || !pData.hasPermission(Permissions.MOVING_SURVIVALFLY_BLOCKING, player))) {
        hAllowedDistance = Magic.modBlock * thisMove.walkSpeed * cc.survivalFlyBlockingSpeed / 100D;
        // Ensure friction can't be used to speed.
        friction = 0.0;
    } else {
        useBaseModifiers = true;
        if (sprinting) {
            hAllowedDistance = thisMove.walkSpeed * cc.survivalFlySprintingSpeed / 100D;
        } else {
            hAllowedDistance = thisMove.walkSpeed * cc.survivalFlyWalkingSpeed / 100D;
        }
        // Ensure friction can't be used to speed.
        // TODO: Model bunny hop as a one time peak + friction. Allow medium based friction.
        friction = 0.0;
    }
    // Apply modifiers (sprinting, attributes, ...).
    if (useBaseModifiers) {
        if (sprinting) {
            hAllowedDistance *= data.multSprinting;
        }
        // Note: Attributes count in slowness potions, thus leaving out isn't possible.
        final double attrMod = attributeAccess.getHandle().getSpeedAttributeMultiplier(player);
        if (attrMod == Double.MAX_VALUE) {
            // TODO: Slowness potion.
            // Count in speed potions.
            final double speedAmplifier = mcAccess.getHandle().getFasterMovementAmplifier(player);
            if (!Double.isInfinite(speedAmplifier)) {
                hAllowedDistance *= 1.0D + 0.2D * (speedAmplifier + 1);
            }
        } else {
            hAllowedDistance *= attrMod;
            // Hack for allow sprint-jumping with slowness.
            if (sprinting && hAllowedDistance < 0.29 && cc.sfSlownessSprintHack && (// TODO: Test/balance thresholds (walkSpeed, attrMod).
            player.hasPotionEffect(PotionEffectType.SLOW) || data.walkSpeed < Magic.DEFAULT_WALKSPEED || attrMod < 1.0)) {
                // TODO: Should restrict further by yDistance, ground and other (jumping only).
                // TODO: Restrict to not in water (depth strider)?
                hAllowedDistance = slownessSprintHack(player, hAllowedDistance);
            }
        }
    }
    // Assume: If in liquids this would be placed right here.
    if (thisMove.downStream) {
        hAllowedDistance *= Magic.modDownStream;
    }
    // If the player is on ice, give them a higher maximum speed.
    if (data.sfOnIce > 0) {
        hAllowedDistance *= Magic.modIce;
    }
    // Speeding bypass permission (can be combined with other bypasses).
    if (checkPermissions && pData.hasPermission(Permissions.MOVING_SURVIVALFLY_SPEEDING, player)) {
        hAllowedDistance *= cc.survivalFlySpeedingSpeed / 100D;
    }
    // Base speed is set.
    thisMove.hAllowedDistanceBase = hAllowedDistance;
    // Friction mechanics (next move).
    if (thisMove.hDistance <= hAllowedDistance) {
        // Move is within lift-off/burst envelope, allow next time.
        // TODO: This probably is the wrong place (+ bunny, + buffer)?
        data.nextFrictionHorizontal = 1.0;
    }
    // Friction or not (this move).
    if (lastMove.toIsValid && friction > 0.0) {
        // Consider friction.
        // TODO: Invalidation mechanics.
        // TODO: Friction model for high speeds?
        hAllowedDistance = Math.max(hAllowedDistance, lastMove.hDistance * friction);
    }
    // if (hAllowedDistance < thisMove.hDistance) {
    // // After failure recovery.
    // if (lastMove.toIsValid) {
    // final double hDistDiff = thisMove.hDistance - lastMove.hDistance;
    // // Elytra.
    // if (hDistDiff < Magic.GLIDE_HORIZONTAL_GAIN_MAX
    // && Magic.inAir(thisMove) && Bridge1_9.isWearingElytra(player)) {
    // // (Abrupt hdist stops aren't covered yet anyway.)
    // hAllowedDistance = thisMove.hDistance;
    // data.nextFrictionHorizontal = Magic.FRICTION_MEDIUM_AIR;
    // }
    // }
    // }
    thisMove.hAllowedDistance = hAllowedDistance;
    return thisMove.hAllowedDistance;
}
Also used : PlayerMoveData(fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData)

Aggregations

PlayerMoveData (fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData)25 Location (org.bukkit.Location)11 PlayerLocation (fr.neatmonster.nocheatplus.utilities.location.PlayerLocation)9 IPlayerData (fr.neatmonster.nocheatplus.players.IPlayerData)5 MovingData (fr.neatmonster.nocheatplus.checks.moving.MovingData)3 PlayerMoveInfo (fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveInfo)3 SimpleEntry (fr.neatmonster.nocheatplus.checks.moving.velocity.SimpleEntry)3 Player (org.bukkit.entity.Player)3 ViolationData (fr.neatmonster.nocheatplus.checks.ViolationData)2 MovingConfig (fr.neatmonster.nocheatplus.checks.moving.MovingConfig)2 AccountEntry (fr.neatmonster.nocheatplus.checks.moving.velocity.AccountEntry)2 RichBoundsLocation (fr.neatmonster.nocheatplus.utilities.location.RichBoundsLocation)2 ActionList (fr.neatmonster.nocheatplus.actions.ActionList)1 Check (fr.neatmonster.nocheatplus.checks.Check)1 CombinedData (fr.neatmonster.nocheatplus.checks.combined.CombinedData)1 LocationTrace (fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace)1 LiftOffEnvelope (fr.neatmonster.nocheatplus.checks.moving.model.LiftOffEnvelope)1 LocationData (fr.neatmonster.nocheatplus.checks.moving.model.LocationData)1 ModelFlying (fr.neatmonster.nocheatplus.checks.moving.model.ModelFlying)1 CountableLocation (fr.neatmonster.nocheatplus.checks.net.model.CountableLocation)1