Package fr.neatmonster.nocheatplus.checks.moving

Source Code of fr.neatmonster.nocheatplus.checks.moving.MovingData

package fr.neatmonster.nocheatplus.checks.moving;

import java.util.HashMap;
import java.util.Map;

import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;

import fr.neatmonster.nocheatplus.checks.access.ACheckData;
import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory;
import fr.neatmonster.nocheatplus.checks.access.ICheckData;
import fr.neatmonster.nocheatplus.config.ConfPaths;
import fr.neatmonster.nocheatplus.config.ConfigFile;
import fr.neatmonster.nocheatplus.config.ConfigManager;
import fr.neatmonster.nocheatplus.utilities.ActionAccumulator;
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
import fr.neatmonster.nocheatplus.utilities.PlayerLocation;

/**
* Player specific data for the moving checks.
*/
public class MovingData extends ACheckData {

    /**
     * Assume the player has to move on ground or so to lift off. TODO: Test, might be better ground.
     */
    private static final MediumLiftOff defaultMediumLiftOff = MediumLiftOff.LIMIT_JUMP;

    //  private static final long IGNORE_SETBACK_Y = BlockProperties.F_SOLID | BlockProperties.F_GROUND | BlockProperties.F_CLIMBABLE | BlockProperties.F_LIQUID;

    /** The factory creating data. */
    public static final CheckDataFactory factory = new CheckDataFactory() {
        @Override
        public final ICheckData getData(final Player player) {
            return MovingData.getData(player);
        }

        @Override
        public ICheckData removeData(final String playerName) {
            return MovingData.removeData(playerName);
        }

        @Override
        public void removeAllData() {
            clear();
        }
    };

    private static Map<String, MovingData> playersMap = new HashMap<String, MovingData>();
    /** The map containing the data per players. */

    /**
     * Gets the data of a specified player.
     *
     * @param player
     *            the player
     * @return the data
     */
    public static MovingData getData(final Player player) {
        // Note that the trace might be null after just calling this.
        MovingData data = playersMap.get(player.getName());
        if (data == null) {
            data = new MovingData(ConfigManager.getConfigFile(player.getWorld().getName()));
            playersMap.put(player.getName(), data);
        }
        return data;
    }

    public static ICheckData removeData(final String playerName) {
        return playersMap.remove(playerName);
    }

    public static void clear() {
        playersMap.clear();
    }

    /**
     * Clear data related to the given world.
     * @param world The world that gets unloaded.
     */
    public static void onWorldUnload(final World world) {
        final String worldName = world.getName();
        for (final MovingData data : playersMap.values()) {
            data.onWorldUnload(worldName);
        }
    }

    public static void onReload() {
        for (final MovingData data : playersMap.values()) {
            data.deleteTrace(); // Safe side.
        }
    }

    /////////////////
    // Not static.
    /////////////////

    // Violation levels -----
    public double         creativeFlyVL            = 0D;
    public double         morePacketsVL            = 0D;
    public double         morePacketsVehicleVL     = 0D;
    public double         noFallVL                 = 0D;
    public double         survivalFlyVL            = 0D;

    // Data shared between the fly checks -----
    public int            bunnyhopDelay;
    public double         jumpAmplifier;
    /** Last time the player was actually sprinting. */
    public long        timeSprinting = 0;

    /** Tick at which walk/fly speeds got changed last time. */
    public int speedTick = 0;
    public float walkSpeed = 0.0f;
    public float flySpeed = 0.0f;

    // Velocity handling.
    // TODO: consider resetting these with clearFlyData and onSetBack.
    /** Vertical velocity modeled as an axis (positive and negative possible) */
    //private final AxisVelocity verVel = new AxisVelocity();
    public int            verticalVelocityCounter;
    public double         verticalFreedom;
    public double         verticalVelocity;
    public int            verticalVelocityUsed = 0;
   
    /** Horizontal velocity modeled as an axis (always positive) */
    private final AxisVelocity horVel = new AxisVelocity();

    // Coordinates.
    /** Last from coordinates. */
    public double         fromX = Double.MAX_VALUE, fromY, fromZ;
    /** Last to coordinates. */
    public double       toX = Double.MAX_VALUE, toY, toZ;
    /** Moving trace (to positions). This is initialized on "playerJoins, i.e. MONITOR, and set to null on playerLeaves."*/
    private LocationTrace trace = null;

    // sf rather
    /** To/from was ground or web or assumed to be etc. */
    public boolean      toWasReset, fromWasReset;
    public MediumLiftOff  mediumLiftOff = defaultMediumLiftOff;

    // Locations shared between all checks.
    private Location    setBack = null;
    private Location    teleported = null;

    // Check specific data -----

    // Data of the creative check.
    public boolean        creativeFlyPreviousRefused;

    // Data of the more packets check.
    /** Packet frequency count. */
    public final ActionFrequency morePacketsFreq;
    /** Burst count. */
    public final ActionFrequency morePacketsBurstFreq;
    private Location      morePacketsSetback = null;

    // Data of the more packets vehicle check.
    public int            morePacketsVehicleBuffer = 50;
    public long           morePacketsVehicleLastTime;
    private Location      morePacketsVehicleSetback = null;
    /** Task id of the morepackets set-back task. */
    public int        morePacketsVehicleTaskId = -1;


    // Data of the no fall check.
    public float          noFallFallDistance = 0;
    /** Last y coordinate from when the player was on ground. */
    public double         noFallMaxY = 0;
    /** Indicate that NoFall should assume the player to be on ground. */
    public boolean noFallAssumeGround = false;
    /** Indicate that NoFall is not to use next damage event for checking on-ground properties. */
    public boolean noFallSkipAirCheck = false;
    // Passable check.
    public double         passableVL;

    // Data of the survival fly check.
    public double     sfHorizontalBuffer = 0.0; // ineffective: SurvivalFly.hBufMax / 2.0;
    /** Event-counter to cover up for sprinting resetting server side only. Set in the FighListener. */
    public int      lostSprintCount = 0;
    public int       sfJumpPhase = 0;
    /** "Dirty" flag, for receiving velocity and similar while in air. */
    public boolean      sfDirty = false;

    /** Indicate low jumping descending phase (likely cheating). */
    public boolean sfLowJump = false;
    public boolean sfNoLowJump = false; // Hacks.

    /**
     * Last valid y distance covered by a move. Integer.MAX_VALUE indicates "not set".
     */
    public double    sfLastYDist = Double.MAX_VALUE;
    public double    sfLastHDist = Double.MAX_VALUE;
    /** Counting while the player is not on ground and not moving. A value <0 means not hovering at all. */
    public int       sfHoverTicks = -1;
    /** First count these down before incrementing sfHoverTicks. Set on join, if configured so. */
    public int       sfHoverLoginTicks = 0;
    public int      sfOnIce = 0;
    public long      sfCobwebTime = 0;
    public double    sfCobwebVL = 0;
    public long      sfVLTime = 0;

    // Accounting info.
    public final ActionAccumulator vDistAcc = new ActionAccumulator(3, 3);


    // HOT FIX
    /** Inconsistency-flag. Set on moving inside of vehicles, reset on exiting properly. Workaround for VehicleLeaveEvent missing. */
    public boolean wasInVehicle = false;
    public MoveConsistency vehicleConsistency = MoveConsistency.INCONSISTENT;

    public MovingData(final ConfigFile config) {
        // TODO: Parameters from cc.
        final int nob = 2 * Math.max(1, Math.min(60, config.getInt(ConfPaths.MOVING_MOREPACKETS_SECONDS)));
        morePacketsFreq = new ActionFrequency(nob, 500);
        morePacketsBurstFreq = new ActionFrequency(12, 5000);
    }

    /**
     * Clear the data of the fly checks (not more-packets).
     */
    public void clearFlyData() {
        bunnyhopDelay = 0;
        sfJumpPhase = 0;
        jumpAmplifier = 0;
        setBack = null;
        sfLastYDist = sfLastHDist = Double.MAX_VALUE;
        fromX = toX = Double.MAX_VALUE;
        clearAccounting();
        clearNoFallData();
        removeAllVelocity();
        sfHorizontalBuffer = 0.0;
        lostSprintCount = 0;
        toWasReset = fromWasReset = false; // TODO: true maybe
        sfHoverTicks = sfHoverLoginTicks = -1;
        sfDirty = false;
        sfLowJump = false;
        mediumLiftOff = defaultMediumLiftOff;
        vehicleConsistency = MoveConsistency.INCONSISTENT;
    }

    /**
     * Teleport event: Mildly reset the flying data without losing any important information.
     *
     * @param setBack
     */
    public void onSetBack(final Location setBack) {
        // Reset positions
        resetPositions(teleported);
        // NOTE: Do mind that the reference is used directly for set-backs, should stay consistent, though.

        setSetBack(teleported);
        this.morePacketsSetback = this.morePacketsVehicleSetback = null; // TODO: or set.

        clearAccounting(); // Might be more safe to do this.
        // Keep no-fall data.
        // Fly data: problem is we don't remember the settings for the set back location.
        // Assume the player to start falling from there rather, or be on ground.
        // TODO: Check if to adjust some counters to state before setback?
        // Keep jump amplifier
        // Keep bunny-hop delay (?)
        // keep jump phase.
        sfHorizontalBuffer = 0.0;
        lostSprintCount = 0;
        toWasReset = fromWasReset = false; // TODO: true maybe
        sfHoverTicks = -1; // 0 ?
        sfDirty = false;
        sfLowJump = false;
        mediumLiftOff = defaultMediumLiftOff;
        removeAllVelocity();
        vehicleConsistency = MoveConsistency.INCONSISTENT; // Not entirely sure here.
    }

    /**
     * Move event: Mildly reset some data, prepare setting a new to-Location.
     */
    public void prepareSetBack(final Location loc) {
        clearAccounting();
        sfJumpPhase = 0;
        sfLastYDist = sfLastHDist = Double.MAX_VALUE;
        toWasReset = false;
        fromWasReset = false;
        // Remember where we send the player to.
        setTeleported(loc);
        // TODO: sfHoverTicks ?
    }

    /**
     * Just reset the "last locations" references.
     * @param loc
     */
    public void resetPositions(final Location loc) {
        if (loc == null) {
            resetPositions(Double.MAX_VALUE, 0, 0);
        }
        else {
            resetPositions(loc.getX(), loc.getY(), loc.getZ());
        }
    }

    /**
     * Just reset the "last locations" references.
     * @param loc
     */
    public void resetPositions(PlayerLocation loc) {
        if (loc == null) {
            resetPositions(Double.MAX_VALUE, 0, 0);
        }
        else {
            resetPositions(loc.getX(), loc.getY(), loc.getZ());
        }
    }

    /**
     * Just reset the "last locations" references.
     * @param x
     * @param y
     * @param z
     */
    public void resetPositions(final double x, final double y, final double z) {
        fromX = toX = x;
        fromY = toY = y;
        fromZ = toZ = z;
        sfLastYDist = sfLastHDist = Double.MAX_VALUE;
        sfDirty = false;
        sfLowJump = false;
        mediumLiftOff = defaultMediumLiftOff;
        // TODO: other buffers ?
        // No reset of vehicleConsistency.
    }

    /**
     * Clear accounting data.
     */
    public void clearAccounting() {
        vDistAcc.clear();
    }

    /**
     * Clear the data of the more packets checks.
     */
    public void clearMorePacketsData() {
        morePacketsSetback = null;
        morePacketsVehicleSetback = null;
        // TODO: Also reset other data ?
    }

    /**
     * Clear the data of the new fall check.
     */
    public void clearNoFallData() {
        noFallFallDistance = 0;
        noFallMaxY = 0D;
        noFallSkipAirCheck = false;
    }

    /**
     * Set the set-back location, this will also adjust the y-coordinate for some block types (at least air).
     * @param loc
     */
    public void setSetBack(final PlayerLocation loc) {
        if (setBack == null) {
            setBack = loc.getLocation();
        }
        else{
            LocUtil.set(setBack, loc);
        }
        // TODO: Consider adjusting the set-back-y here. Problem: Need to take into account for bounding box (collect max-ground-height needed).
    }

    /**
     * Convenience method.
     * @param loc
     */
    public void setSetBack(final Location loc) {
        if (setBack == null) {
            setBack = LocUtil.clone(loc);
        }
        else{
            LocUtil.set(setBack, loc);
        }
    }

    /**
     * Get the set-back location with yaw and pitch set form ref.
     * @param ref
     * @return
     */
    public Location getSetBack(final Location ref) {
        return LocUtil.clone(setBack, ref);
    }

    /**
     * Get the set-back location with yaw and pitch set from ref.
     * @param ref
     * @return
     */
    public Location getSetBack(final PlayerLocation ref) {
        return LocUtil.clone(setBack, ref);
    }

    public boolean hasSetBack() {
        return setBack != null;
    }

    public boolean hasSetBackWorldChanged(final Location loc) {
        if (setBack == null) {
            return true;
        }
        else {
            return setBack.getWorld().equals(loc.getWorld());
        }
    }


    public double getSetBackX() {
        return setBack.getX();
    }

    public double getSetBackY() {
        return setBack.getY();
    }

    public double getSetBackZ() {
        return setBack.getZ();
    }

    public void setSetBackY(final double y) {
        setBack.setY(y);
    }

    /**
     * Return a copy of the teleported-to Location.
     * @return
     */
    public final Location getTeleported() {
        // TODO: here a reference might do.
        return teleported == null ? teleported : LocUtil.clone(teleported);
    }

    /**
     * Set teleport-to location to recognize NCP set-backs. This copies the coordinates and world.
     * @param loc
     */
    public final void setTeleported(final Location loc) {
        teleported = LocUtil.clone(loc); // Always overwrite.
    }

    public boolean hasMorePacketsSetBack() {
        return morePacketsSetback != null;
    }

    public final void setMorePacketsSetBack(final PlayerLocation loc) {
        if (morePacketsSetback == null) {
            morePacketsSetback = loc.getLocation();
        }
        else {
            LocUtil.set(morePacketsSetback, loc);
        }
    }

    public final void setMorePacketsSetBack(final Location loc) {
        if (morePacketsSetback == null) {
            morePacketsSetback = LocUtil.clone(loc);
        }
        else {
            LocUtil.set(morePacketsSetback, loc);
        }
    }

    public Location getMorePacketsSetBack() {
        return LocUtil.clone(morePacketsSetback);
    }

    public boolean hasMorePacketsVehicleSetBack() {
        return morePacketsVehicleSetback != null;
    }

    public final void setMorePacketsVehicleSetBack(final PlayerLocation loc) {
        if (morePacketsVehicleSetback == null) {
            morePacketsVehicleSetback = loc.getLocation();
        }
        else {
            LocUtil.set(morePacketsVehicleSetback, loc);
        }
    }

    public final void setMorePacketsVehicleSetBack(final Location loc) {
        if (morePacketsVehicleSetback == null) {
            morePacketsVehicleSetback = LocUtil.clone(loc);
        }
        else {
            LocUtil.set(morePacketsVehicleSetback, loc);
        }
    }

    public final Location getMorePacketsVehicleSetBack() {
        return LocUtil.clone(morePacketsVehicleSetback);
    }

    public final void resetTeleported() {
        teleported = null;
    }

    /**
     * Set set-back location to null.
     */
    public final void resetSetBack() {
        setBack = null;
    }

    /**
     * Just set the last "to-coordinates", no world check.
     * @param to
     */
    public final void setTo(final Location to) {
        toX = to.getX();
        toY = to.getY();
        toZ = to.getZ();
    }

    /**
     * Add horizontal velocity (distance). <br>
     * @param vel Assumes positive values always.
     */
    public void addHorizontalVelocity(final Velocity vel) {
        horVel.add(vel);
    }
   
    /**
     * Add vertical velocity (distance). <br>
     * @param vel
     */
    public void addVerticalVelocity(final Velocity vel) {
        horVel.add(vel);
    }

    /**
     * Remove all vertical and horizontal velocity.
     */
    public void removeAllVelocity() {
        horVel.clear();
//        verVel.clear();
    }

    /**
     * Remove all velocity entries that are invalid. Checks both active and queued.
     * <br>(This does not catch invalidation by speed / direction changing.)
     * @param tick All velocity added before this tick gets removed.
     */
    public void removeInvalidVelocity(final int tick) {
        horVel.removeInvalid(tick);
//        verVel.removeInvalid(tick);
    }

    /**
     * Clear only active horizontal velocity.
     */
    public void clearActiveHorVel() {
        horVel.clearActive();
    }
   
    /**
     * Clear only active horizontal velocity.
     */
    public void clearActiveVerVel() {
        horVel.clearActive();
    }

    public boolean hasActiveHorVel() {
        return horVel.hasActive();
    }

    public boolean hasQueuedHorVel() {
        return horVel.hasQueued();
    }
   
//    public boolean hasActiveVerVel() {
//        return verVel.hasActive();
//    }

//    public boolean hasQueuedVerVel() {
//        return verVel.hasQueued();
//    }

    /**
     * Called for moving events, increase age of velocity, decrease amounts, check which entries are invalid. Both horizontal and vertical.
     */
    public void velocityTick() {
        // Horizontal velocity (intermediate concept).
        horVel.tick();
       
        // Vertical velocity (new concept).
//        verVel.tick();
        if (verticalVelocity <= 0.09D) {
            verticalVelocityUsed ++;
            verticalVelocityCounter--;
        }
        else if (verticalVelocityCounter > 0) {
            verticalVelocityUsed ++;
            verticalFreedom += verticalVelocity;
            verticalVelocity = Math.max(0.0, verticalVelocity -0.09);
            // TODO: Consider using up counter ? / better use velocity entries / even better use x,y,z entries right away .
        } else if (verticalFreedom > 0.001D) {
            if (verticalVelocityUsed == 1 && verticalVelocity > 1.0) {
                // Workarounds.
                verticalVelocityUsed = 0;
                verticalVelocity = 0;
                verticalFreedom = 0;
            }
            else{
                // Counter has run out, now reduce the vertical freedom over time.
                verticalVelocityUsed ++;
                verticalFreedom *= 0.93D;
            }
        }
    }

    /**
     * Get effective amount of all used velocity. Non-destructive.
     * @return
     */
    public double getHorizontalFreedom() {
        return horVel.getFreedom();
    }

    /**
     * Use all queued velocity until at least amount is matched.
     * Amount is the horizontal distance that is to be covered by velocity (active has already been checked).
     * <br>
     * If the modeling changes (max instead of sum or similar), then this will be affected.
     * @param amount The amount used.
     * @return
     */
    public double useHorizontalVelocity(final double amount) {
        return horVel.use(amount);
    }

    /**
     * Debugging.
     * @param builder
     */
    public void addHorizontalVelocity(final StringBuilder builder) {
        if (horVel.hasActive()) {
            builder.append("\n" + " horizontal velocity (active):");
            horVel.addActive(builder);
        }
        if (horVel.hasQueued()) {
            builder.append("\n" + " horizontal velocity (queued):");
            horVel.AddQueued(builder);
        }
    }

    /**
     * Test if the location is the same, ignoring pitch and yaw.
     * @param loc
     * @return
     */
    public boolean isSetBack(final Location loc) {
        if (loc == null || setBack == null) {
            return false;
        }
        if (!loc.getWorld().getName().equals(setBack.getWorld().getName())) {
            return false;
        }
        return loc.getX() == setBack.getX() && loc.getY() == setBack.getY() && loc.getZ() == setBack.getZ();
    }

    /**
     * Called when a player leaves the server.
     */
    public void onPlayerLeave() {
        removeAllVelocity();
        deleteTrace();
    }

    /**
     * Clean up data related to worlds with the given name (not case-sensitive).
     * @param worldName
     */
    public void onWorldUnload(final String worldName) {
        // TODO: Unlink world references.
        if (teleported != null && worldName.equalsIgnoreCase(teleported.getWorld().getName())) {
            resetTeleported();
        }
        if (setBack != null && worldName.equalsIgnoreCase(setBack.getWorld().getName())) {
            clearFlyData();
        }
        if (morePacketsSetback != null && worldName.equalsIgnoreCase(morePacketsSetback.getWorld().getName()) || morePacketsVehicleSetback != null && worldName.equalsIgnoreCase(morePacketsVehicleSetback.getWorld().getName())) {
            clearMorePacketsData();
            clearNoFallData(); // just in case.
        }
    }

    public void adjustWalkSpeed(final float walkSpeed, final int tick, final int speedGrace) {
        if (walkSpeed > this.walkSpeed) {
            this.walkSpeed = walkSpeed;
            this.speedTick = tick;
        } else if (walkSpeed < this.walkSpeed) {
            if (tick - this.speedTick > speedGrace) {
                this.walkSpeed = walkSpeed;
                this.speedTick = tick;
            }
        } else {
            this.speedTick = tick;
        }
    }

    public void adjustFlySpeed(final float flySpeed, final int tick, final int speedGrace) {
        if (flySpeed > this.flySpeed) {
            this.flySpeed = flySpeed;
            this.speedTick = tick;
        } else if (flySpeed < this.flySpeed) {
            if (tick - this.speedTick > speedGrace) {
                this.flySpeed = flySpeed;
                this.speedTick = tick;
            }
        } else {
            this.speedTick = tick;
        }
    }

    /**
     * This tests for a LocationTrace instance being set at all, not for locations having been added.
     * @return
     */
    public boolean hasTrace() {
        return trace != null;
    }

    /**
     * Convenience: Access method to simplify coding, being aware of some plugins using Player implementations as NPCs, leading to traces not being present.
     * @return
     */
    public LocationTrace getTrace(final Player player) {
        if (trace == null) {
            final MovingConfig cc = MovingConfig.getConfig(player);
            trace = new LocationTrace(cc.traceSize, cc.traceMergeDist);
        }
        return trace;
    }

    /**
     * Convenience
     * @param player
     * @param loc
     */
    public void resetTrace(final Player player, final Location loc, final long time) {
        final MovingConfig cc = MovingConfig.getConfig(player);
        resetTrace(loc, time, cc.traceSize, cc.traceMergeDist);
    }

    /**
     * Convenience method to add a location to the trace, creates the trace if necessary.
     * @param player
     * @param loc
     * @param time
     * @return Updated LocationTrace instance, for convenient use, without sticking too much to MovingData.
     */
    public LocationTrace updateTrace(final Player player, final Location loc, final long time) {
        final LocationTrace trace = getTrace(player);
        trace.addEntry(time, loc.getX(), loc.getY(), loc.getZ());
        return trace;
    }

    /**
     * Convenience: Create or just reset the trace, add the current location.
     * @param loc
     * @param size
     * @param mergeDist
     * @param traceMergeDist
     */
    public void resetTrace(final Location loc, final long time, final int size, double mergeDist) {
        if (trace == null || trace.getMaxSize() != size || trace.getMergeDist() != mergeDist) {
            trace = new LocationTrace(size, mergeDist);
        } else {
            trace.reset();
        }
        trace.addEntry(time, loc.getX(), loc.getY(), loc.getZ());
    }

    public void deleteTrace() {
        trace = null;
    }

}
TOP

Related Classes of fr.neatmonster.nocheatplus.checks.moving.MovingData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.