Search in sources :

Example 1 with LocationTrace

use of fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace in project NoCheatPlus by NoCheatPlus.

the class TestLocationTrace method testEmptyIterator.

@Test
public void testEmptyIterator() {
    // Expected to fail.
    int size = 80;
    LocationTrace trace = new LocationTrace(size, size, pool);
    try {
        trace.oldestIterator();
        fail("Expect an exception on trying to get an empty iterator (oldest).");
    } catch (IllegalArgumentException ex) {
    }
    try {
        trace.latestIterator();
        fail("Expect an exception on trying to get an empty iterator (latest).");
    } catch (IllegalArgumentException ex) {
    }
    try {
        trace.maxAgeIterator(0);
        fail("Expect an exception on trying to get an empty iterator (maxAge).");
    } catch (IllegalArgumentException ex) {
    }
}
Also used : LocationTrace(fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace) Test(org.junit.Test)

Example 2 with LocationTrace

use of fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace in project NoCheatPlus by NoCheatPlus.

the class TestLocationTrace method testSize.

@Test
public void testSize() {
    int size = 80;
    LocationTrace trace = new LocationTrace(size, size, pool);
    // Empty
    if (!trace.isEmpty()) {
        fail("Trace must be empty on start.");
    }
    if (trace.size() != 0) {
        fail("Size must be 0 at start.");
    }
    // Adding up to size elements.
    for (int i = 0; i < size; i++) {
        trace.addEntry(i, i, i, i, 0, 0);
        if (trace.size() != i + 1) {
            fail("Wrong size, expect " + (i + 1) + ", got instead: " + trace.size());
        }
    }
    // Adding a lot of elements.
    for (int i = 0; i < 1000; i++) {
        trace.addEntry(i + size, i, i, i, 0, 0);
        if (trace.size() != size) {
            fail("Wrong size, expect " + size + ", got instead: " + trace.size());
        }
    }
}
Also used : LocationTrace(fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace) Test(org.junit.Test)

Example 3 with LocationTrace

use of fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace in project NoCheatPlus by NoCheatPlus.

the class TestLocationTrace method testIteratorSizeAndOrder.

@Test
public void testIteratorSizeAndOrder() {
    int size = 80;
    LocationTrace trace = new LocationTrace(size, size, pool);
    // Adding up to size elements.
    for (int i = 0; i < size; i++) {
        trace.addEntry(i, i, i, i, 0, 0);
    }
    // Test size with one time filled up.
    testIteratorSizeAndOrder(trace, 80);
    // Add size / 2 elements, to test cross-boundary iteration.
    for (int i = 0; i < size / 2; i++) {
        trace.addEntry(i + size, i, i, i, 0, 0);
    }
    // Test size again.
    testIteratorSizeAndOrder(trace, 80);
}
Also used : LocationTrace(fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace) Test(org.junit.Test)

Example 4 with LocationTrace

use of fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace 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 5 with LocationTrace

use of fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace in project NoCheatPlus by NoCheatPlus.

the class TestLocationTrace method testMergeZeroDist.

@Test
public void testMergeZeroDist() {
    int size = 80;
    LocationTrace trace = new LocationTrace(size, size, pool);
    for (int i = 0; i < 1000; i++) {
        trace.addEntry(i + size, 0, 0, 0, 0, 0);
        if (trace.size() != 1) {
            fail("Wrong size, expect 1, got instead: " + trace.size());
        }
    }
}
Also used : LocationTrace(fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace) Test(org.junit.Test)

Aggregations

LocationTrace (fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace)7 Test (org.junit.Test)6 ITraceEntry (fr.neatmonster.nocheatplus.checks.moving.location.tracking.LocationTrace.ITraceEntry)2 MovingConfig (fr.neatmonster.nocheatplus.checks.moving.MovingConfig)1 MovingData (fr.neatmonster.nocheatplus.checks.moving.MovingData)1 PlayerMoveData (fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData)1 PlayerMoveInfo (fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveInfo)1 Location (org.bukkit.Location)1 Player (org.bukkit.entity.Player)1