Search in sources :

Example 11 with PlayerMoveInfo

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

the class FightListener method handleNormalDamage.

/**
 * A player attacked something with DamageCause ENTITY_ATTACK.
 *
 * @param player
 *            The attacking player.
 * @param damaged
 * @param originalDamage
 *            Damage before applying modifiers.
 * @param finalDamage
 *            Damage after applying modifiers.
 * @param tick
 * @param data
 * @return
 */
private boolean handleNormalDamage(final Player player, final boolean attackerIsFake, final Entity damaged, final boolean damagedIsFake, final double originalDamage, final double finalDamage, final int tick, final FightData data, final IPlayerData pData, final IPenaltyList penaltyList) {
    final FightConfig cc = pData.getGenericInstance(FightConfig.class);
    // Illegal enchantments hotfix check.
    if (Items.checkIllegalEnchantmentsAllHands(player, pData)) {
        return true;
    }
    final boolean debug = pData.isDebugActive(checkType);
    boolean cancelled = false;
    final String worldName = player.getWorld().getName();
    final long now = System.currentTimeMillis();
    final boolean worldChanged = !worldName.equals(data.lastWorld);
    final Location loc = player.getLocation(useLoc1);
    // // Bad pitch/yaw, just in case.
    // if (LocUtil.needsDirectionCorrection(useLoc1.getYaw(), useLoc1.getPitch())) {
    // mcAccess.correctDirection(player);
    // player.getLocation(useLoc1);
    // }
    final Location damagedLoc = damaged.getLocation(useLoc2);
    // final double targetDist = CheckUtils.distance(loc, targetLoc); // TODO: Calculate distance as is done in fight.reach !
    final double targetMove;
    final int tickAge;
    // Milliseconds the ticks actually took.
    final long msAge;
    // Blocks per second.
    final double normalizedMove;
    // TODO: Use trace for this ?
    if (data.lastAttackedX == Double.MAX_VALUE || tick < data.lastAttackTick || worldChanged || tick - data.lastAttackTick > 20) {
        // TODO: 20 ?
        tickAge = 0;
        targetMove = 0.0;
        normalizedMove = 0.0;
        msAge = 0;
    } else {
        tickAge = tick - data.lastAttackTick;
        // TODO: Maybe use 3d distance if dy(normalized) is too big.
        targetMove = TrigUtil.distance(data.lastAttackedX, data.lastAttackedZ, damagedLoc.getX(), damagedLoc.getZ());
        msAge = (long) (50f * TickTask.getLag(50L * tickAge, true) * (float) tickAge);
        normalizedMove = msAge == 0 ? targetMove : targetMove * Math.min(20.0, 1000.0 / (double) msAge);
    }
    // TODO: calculate factor for dists: ticks * 50 * lag
    // TODO: dist < width => skip some checks (direction, ..)
    final LocationTrace damagedTrace;
    final Player damagedPlayer;
    if (damaged instanceof Player) {
        damagedPlayer = (Player) damaged;
        // Log.
        if (debug && DataManager.getPlayerData(damagedPlayer).hasPermission(Permissions.ADMINISTRATION_DEBUG, damagedPlayer)) {
            damagedPlayer.sendMessage("Attacked by " + player.getName() + ": inv=" + mcAccess.getHandle().getInvulnerableTicks(damagedPlayer) + " ndt=" + damagedPlayer.getNoDamageTicks());
        }
        // Check for self hit exploits (mind that projectiles are excluded from this.)
        if (selfHit.isEnabled(player, pData) && selfHit.check(player, damagedPlayer, data, cc)) {
            cancelled = true;
        }
        // Get+update the damaged players.
        // TODO: Problem with NPCs: data stays (not a big problem).
        // (This is done even if the event has already been cancelled, to keep track, if the player is on a horse.)
        damagedTrace = DataManager.getPlayerData(damagedPlayer).getGenericInstance(MovingData.class).updateTrace(damagedPlayer, damagedLoc, tick, damagedIsFake ? null : mcAccess.getHandle());
    } else {
        // TODO: This is a temporary workaround.
        damagedPlayer = null;
        // Use a fake trace.
        // TODO: Provide for entities too? E.g. one per player, or a fully fledged bookkeeping thing (EntityData).
        // final MovingConfig mcc = MovingConfig.getConfig(damagedLoc.getWorld().getName());
        // new LocationTrace(mcc.traceSize, mcc.traceMergeDist);
        damagedTrace = null;
    // damagedTrace.addEntry(tick, damagedLoc.getX(), damagedLoc.getY(), damagedLoc.getZ());
    }
    // Log generic properties of this attack.
    if (debug) {
        debug(player, "Attacks " + (damagedPlayer == null ? ("entity " + damaged.getType()) : ("player" + damagedPlayer.getName())) + " damage=" + (finalDamage == originalDamage ? finalDamage : (originalDamage + "/" + finalDamage)));
    }
    // Can't fight dead.
    if (cc.cancelDead) {
        if (damaged.isDead()) {
            cancelled = true;
        }
        // Only allow damaging others if taken damage this tick.
        if (player.isDead() && data.damageTakenByEntityTick != TickTask.getTick()) {
            cancelled = true;
        }
    }
    // LEGACY: 1.9: sweep attack.
    if (BridgeHealth.DAMAGE_SWEEP == null) {
        // TODO: Account for charge/meter thing?
        final int locHashCode = LocUtil.hashCode(loc);
        if (originalDamage == 1.0) {
            // Might be a sweep attack.
            if (tick == data.sweepTick && locHashCode == data.sweepLocationHashCode) {
                // Could further guard by checking equality of loc to last location.
                if (debug) {
                    debug(player, "(Assume sweep attack follow up damage.)");
                }
                return cancelled;
            }
        } else {
            // TODO: More side conditions for a sweep attack.
            data.sweepTick = tick;
            data.sweepLocationHashCode = locHashCode;
        }
    }
    // LEGACY: thorns.
    if (BridgeHealth.DAMAGE_THORNS == null && originalDamage <= 4.0 && tick == data.damageTakenByEntityTick && data.thornsId != Integer.MIN_VALUE && data.thornsId == damaged.getEntityId()) {
        // Don't handle further, but do respect selfhit/canceldead.
        // TODO: Remove soon, at least version-dependent.
        data.thornsId = Integer.MIN_VALUE;
        return cancelled;
    } else {
        data.thornsId = Integer.MIN_VALUE;
    }
    // TODO: Add something on packet level already.
    if (pData.isCheckActive(CheckType.FIGHT_WRONGTURN, player) && wrongTurn.check(player, loc, data, cc)) {
        cancelled = true;
    }
    // Run through the main checks.
    if (!cancelled && speed.isEnabled(player, pData)) {
        if (speed.check(player, now, data, cc, pData)) {
            cancelled = true;
            // Still feed the improbable.
            if (data.speedVL > 50) {
                Improbable.check(player, 2f, now, "fight.speed", pData);
            } else {
                Improbable.feed(player, 2f, now);
            }
        } else if (normalizedMove > 2.0 && Improbable.check(player, 1f, now, "fight.speed", pData)) {
            // Feed improbable in case of ok-moves too.
            // TODO: consider only feeding if attacking with higher average speed (!)
            cancelled = true;
        }
    }
    if (!cancelled && critical.isEnabled(player, pData) && critical.check(player, loc, data, cc, pData, penaltyList)) {
        // TODO: Check config for settings.
        cancelled = true;
    }
    if (!cancelled && noSwing.isEnabled(player, pData) && noSwing.check(player, data, cc)) {
        cancelled = true;
    }
    if (!cancelled && player.isBlocking() && !pData.hasPermission(Permissions.MOVING_SURVIVALFLY_BLOCKING, player)) {
        // TODO: Permission ?
        cancelled = true;
    }
    if (!cancelled) {
        final boolean reachEnabled = reach.isEnabled(player, pData);
        final boolean directionEnabled = direction.isEnabled(player, pData);
        if (reachEnabled || directionEnabled) {
            if (damagedTrace != null) {
                // Checks that use the LocationTrace instance of the attacked entity/player.
                cancelled = locationTraceChecks(player, loc, data, cc, pData, damaged, damagedIsFake, damagedLoc, damagedTrace, tick, now, debug, reachEnabled, directionEnabled);
            } else {
                // Still use the classic methods for non-players. maybe[]
                if (reachEnabled && reach.check(player, loc, damaged, damagedIsFake, damagedLoc, data, cc, pData)) {
                    cancelled = true;
                }
                if (directionEnabled && direction.check(player, loc, damaged, damagedIsFake, damagedLoc, data, cc)) {
                    cancelled = true;
                }
            }
        }
    }
    // TODO: Actual angle needs to be related to the best matching trace element(s) (loop checks).
    if (angle.isEnabled(player, pData)) {
        // Improbable yaw changing: Moving events might be missing up to a ten degrees change.
        if (Combined.checkYawRate(player, loc.getYaw(), now, worldName, pData.isCheckActive(CheckType.COMBINED_YAWRATE, player), pData)) {
            // (Check or just feed).
            // TODO: Work into this somehow attacking the same aim and/or similar aim position (not cancel then).
            cancelled = true;
        }
        // Angle check.
        if (angle.check(player, loc, damaged, worldChanged, data, cc)) {
            if (!cancelled && debug) {
                debug(player, "FIGHT_ANGLE cancel without yawrate cancel.");
            }
            cancelled = true;
        }
    }
    // Set values.
    data.lastWorld = worldName;
    data.lastAttackTick = tick;
    data.lastAttackedX = damagedLoc.getX();
    data.lastAttackedY = damagedLoc.getY();
    data.lastAttackedZ = damagedLoc.getZ();
    // TODO: Evaluate if moving traces can help here.
    if (!cancelled && TrigUtil.distance(loc.getX(), loc.getZ(), damagedLoc.getX(), damagedLoc.getZ()) < 4.5) {
        final MovingData mData = pData.getGenericInstance(MovingData.class);
        // Check if fly checks is an issue at all, re-check "real sprinting".
        final PlayerMoveData lastMove = mData.playerMoves.getFirstPastMove();
        if (lastMove.valid && mData.liftOffEnvelope == LiftOffEnvelope.NORMAL) {
            final double hDist = TrigUtil.xzDistance(loc, lastMove.from);
            if (hDist >= 0.23) {
                // TODO: Might need to check hDist relative to speed / modifiers.
                final MovingConfig mCc = pData.getGenericInstance(MovingConfig.class);
                final PlayerMoveInfo moveInfo = auxMoving.usePlayerMoveInfo();
                moveInfo.set(player, loc, null, mCc.yOnGround);
                if (now <= mData.timeSprinting + mCc.sprintingGrace && MovingUtil.shouldCheckSurvivalFly(player, moveInfo.from, mData, mCc, pData)) {
                    // Judge as "lost sprint" problem.
                    // TODO: What would mData.lostSprintCount > 0  mean here?
                    mData.lostSprintCount = 7;
                    if ((debug || pData.isDebugActive(CheckType.MOVING)) && BuildParameters.debugLevel > 0) {
                        debug(player, "lostsprint: hDist to last from: " + hDist + " | targetdist=" + TrigUtil.distance(loc.getX(), loc.getZ(), damagedLoc.getX(), damagedLoc.getZ()) + " | sprinting=" + player.isSprinting() + " | food=" + player.getFoodLevel() + " | hbuf=" + mData.sfHorizontalBuffer);
                    }
                }
                auxMoving.returnPlayerMoveInfo(moveInfo);
            }
        }
    }
    // (Cancel after sprinting hacks, because of potential fp).
    if (!cancelled && data.attackPenalty.isPenalty(now)) {
        cancelled = true;
        if (debug) {
            debug(player, "~ attack penalty.");
        }
    }
    // Cleanup.
    useLoc1.setWorld(null);
    useLoc2.setWorld(null);
    return cancelled;
}
Also used : Player(org.bukkit.entity.Player) MovingData(fr.neatmonster.nocheatplus.checks.moving.MovingData) PlayerMoveInfo(fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveInfo) PlayerMoveData(fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData) MovingConfig(fr.neatmonster.nocheatplus.checks.moving.MovingConfig) LocationTrace(fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace) Location(org.bukkit.Location)

Example 12 with PlayerMoveInfo

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

the class Critical method check.

/**
 * Checks a player.
 *
 * @param player
 *            the player
 * @return true, if successful
 */
public boolean check(final Player player, final Location loc, final FightData data, final FightConfig cc, final IPlayerData pData, final IPenaltyList penaltyList) {
    boolean cancel = false;
    final double mcFallDistance = (double) player.getFallDistance();
    // not in liquid, not in vehicle, and without blindness effect).
    if (mcFallDistance > 0.0 && !player.isInsideVehicle() && !player.hasPotionEffect(PotionEffectType.BLINDNESS)) {
        if (pData.isDebugActive(type)) {
            debug(player, "y=" + loc.getY() + " mcfalldist=" + mcFallDistance);
        }
        // Might be a violation.
        final MovingConfig mcc = pData.getGenericInstance(MovingConfig.class);
        final MovingData dataM = pData.getGenericInstance(MovingData.class);
        // TODO: Skip near the highest jump height (needs check if head collided with something solid, which also detects low jump).
        if (!dataM.isVelocityJumpPhase() && (dataM.sfLowJump && !dataM.sfNoLowJump && dataM.liftOffEnvelope == LiftOffEnvelope.NORMAL || mcFallDistance < cc.criticalFallDistance && !BlockProperties.isResetCond(player, loc, mcc.yOnGround))) {
            // TODO: Use past move tracking to check for SurvivalFly and the like?
            final PlayerMoveInfo moveInfo = auxMoving.usePlayerMoveInfo();
            moveInfo.set(player, loc, null, mcc.yOnGround);
            if (MovingUtil.shouldCheckSurvivalFly(player, moveInfo.from, dataM, mcc, pData)) {
                data.criticalVL += 1.0;
                // Execute whatever actions are associated with this check and
                // the violation level and find out if we should cancel the event.
                final ViolationData vd = new ViolationData(this, player, data.criticalVL, 1.0, cc.criticalActions);
                if (vd.needsParameters()) {
                    final List<String> tags = new ArrayList<String>();
                    if (dataM.sfLowJump) {
                        tags.add("lowjump");
                    }
                    vd.setParameter(ParameterName.TAGS, StringUtil.join(tags, "+"));
                }
                cancel = executeActions(vd).willCancel();
            // TODO: Introduce penalty instead of cancel.
            }
            auxMoving.returnPlayerMoveInfo(moveInfo);
        }
    }
    return cancel;
}
Also used : MovingData(fr.neatmonster.nocheatplus.checks.moving.MovingData) ArrayList(java.util.ArrayList) MovingConfig(fr.neatmonster.nocheatplus.checks.moving.MovingConfig) ViolationData(fr.neatmonster.nocheatplus.checks.ViolationData) PlayerMoveInfo(fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveInfo)

Aggregations

PlayerMoveInfo (fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveInfo)12 Location (org.bukkit.Location)7 IPlayerData (fr.neatmonster.nocheatplus.players.IPlayerData)6 PlayerLocation (fr.neatmonster.nocheatplus.utilities.location.PlayerLocation)6 Player (org.bukkit.entity.Player)6 PlayerMoveData (fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData)3 EventHandler (org.bukkit.event.EventHandler)3 MovingConfig (fr.neatmonster.nocheatplus.checks.moving.MovingConfig)2 MovingData (fr.neatmonster.nocheatplus.checks.moving.MovingData)2 ArrayList (java.util.ArrayList)2 ViolationData (fr.neatmonster.nocheatplus.checks.ViolationData)1 CombinedData (fr.neatmonster.nocheatplus.checks.combined.CombinedData)1 LocationTrace (fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace)1 VehicleMoveInfo (fr.neatmonster.nocheatplus.checks.moving.model.VehicleMoveInfo)1