Package cc.co.evenprime.bukkit.nocheat.checks.moving

Source Code of cc.co.evenprime.bukkit.nocheat.checks.moving.MovingCheckListener

package cc.co.evenprime.bukkit.nocheat.checks.moving;

import java.util.LinkedList;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerVelocityEvent;
import org.bukkit.util.Vector;
import cc.co.evenprime.bukkit.nocheat.EventManager;
import cc.co.evenprime.bukkit.nocheat.NoCheat;
import cc.co.evenprime.bukkit.nocheat.NoCheatPlayer;
import cc.co.evenprime.bukkit.nocheat.checks.CheckUtil;
import cc.co.evenprime.bukkit.nocheat.config.ConfigurationCacheStore;
import cc.co.evenprime.bukkit.nocheat.config.Permissions;
import cc.co.evenprime.bukkit.nocheat.data.PreciseLocation;

/**
* Central location to listen to events that are
* relevant for the moving checks
*
*/
public class MovingCheckListener implements Listener, EventManager {

    private final MorePacketsCheck morePacketsCheck;
    private final FlyingCheck      flyingCheck;
    private final RunningCheck     runningCheck;

    private final NoCheat          plugin;

    public MovingCheckListener(NoCheat plugin) {

        flyingCheck = new FlyingCheck(plugin);
        runningCheck = new RunningCheck(plugin);
        morePacketsCheck = new MorePacketsCheck(plugin);

        this.plugin = plugin;
    }

    /**
     * A workaround for players placing blocks below them getting pushed
     * off the block by NoCheat.
     *
     * It essentially moves the "setbackpoint" to the top of the newly
     * placed block, therefore tricking NoCheat into thinking the player
     * was already on top of that block and should be allowed to stay
     * there
     *
     * @param event The BlockPlaceEvent
     */
    @EventHandler(priority = EventPriority.MONITOR)
    public void blockPlace(final BlockPlaceEvent event) {

        // Block wasn't placed, so we don't care
        if(event.isCancelled())
            return;

        final NoCheatPlayer player = plugin.getPlayer(event.getPlayer());
        final MovingConfig config = MovingCheck.getConfig(player);

        // If the player is allowed to fly anyway, the workaround is not needed
        // It's kind of expensive (looking up block types) therefore it makes
        // sense to avoid it
        if(config.allowFlying || !config.runflyCheck || player.hasPermission(Permissions.MOVING_FLYING) || player.hasPermission(Permissions.MOVING_RUNFLY)) {
            return;
        }

        // Get the player-specific stored data that applies here
        final MovingData data = MovingCheck.getData(player);

        final Block block = event.getBlockPlaced();

        if(block == null || !data.runflySetBackPoint.isSet()) {
            return;
        }

        // Keep some results of "expensive calls
        final Location l = player.getPlayer().getLocation();
        final int playerX = l.getBlockX();
        final int playerY = l.getBlockY();
        final int playerZ = l.getBlockZ();
        final int blockY = block.getY();

        // Was the block below the player?
        if(Math.abs(playerX - block.getX()) <= 1 && Math.abs(playerZ - block.getZ()) <= 1 && playerY - blockY >= 0 && playerY - blockY <= 2) {
            // yes
            final int type = CheckUtil.getType(block.getTypeId());
            if(CheckUtil.isSolid(type) || CheckUtil.isLiquid(type)) {
                if(blockY + 1 >= data.runflySetBackPoint.y) {
                    data.runflySetBackPoint.y = (blockY + 1);
                    data.jumpPhase = 0;
                }
            }
        }
    }

    /**
     * If a player gets teleported, it may have two reasons. Either
     * it was NoCheat or another plugin. If it was NoCheat, the target
     * location should match the "data.teleportTo" value.
     *
     * On teleports, reset some movement related data that gets invalid
     *
     * @param event The PlayerTeleportEvent
     */
    @EventHandler(priority = EventPriority.HIGHEST)
    public void teleport(final PlayerTeleportEvent event) {

        NoCheatPlayer player = plugin.getPlayer(event.getPlayer());
        final MovingData data = MovingCheck.getData(player);

        // If it was a teleport initialized by NoCheat, do it anyway
        // even if another plugin said "no"
        if(data.teleportTo.isSet() && data.teleportTo.equals(event.getTo())) {
            event.setCancelled(false);
        } else {
            // Only if it wasn't NoCheat, drop data from morepackets check.
            // If it was NoCheat, we don't want players to exploit the
            // runfly check teleporting to get rid of the "morepackets"
            // data.
            data.clearMorePacketsData();
        }

        // Always drop data from runfly check, as it always loses its validity
        // after teleports. Always!
        data.teleportTo.reset();
        data.clearRunFlyData();

        return;
    }

    /**
     * Just for security, if a player switches between worlds, reset the
     * runfly and morepackets checks data, because it is definitely invalid
     * now
     *
     * @param event The PlayerChangedWorldEvent
     */
    @EventHandler(priority = EventPriority.MONITOR)
    public void worldChange(final PlayerChangedWorldEvent event) {
        // Maybe this helps with people teleporting through multiverse portals having problems?
        final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer()));
        data.teleportTo.reset();
        data.clearRunFlyData();
        data.clearMorePacketsData();
    }

    /**
     * When a player uses a portal, all information related to the
     * moving checks becomes invalid.
     *
     * @param event
     */
    @EventHandler(priority = EventPriority.MONITOR)
    public void portal(final PlayerPortalEvent event) {
        final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer()));
        data.clearMorePacketsData();
        data.clearRunFlyData();
    }

    /**
     * When a player respawns, all information related to the
     * moving checks becomes invalid.
     *
     * @param event
     */
    @EventHandler(priority = EventPriority.MONITOR)
    public void respawn(final PlayerRespawnEvent event) {
        final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer()));
        data.clearMorePacketsData();
        data.clearRunFlyData();
    }

    /**
     * When a player moves, he will be checked for various
     * suspicious behaviour.
     *
     * @param event The PlayerMoveEvent
     */
    @EventHandler(priority = EventPriority.LOWEST)
    public void move(final PlayerMoveEvent event) {

        // Don't care for vehicles
        if(event.isCancelled() || event.getPlayer().isInsideVehicle())
            return;

        // Don't care for movements that are very high distance or to another
        // world (such that it is very likely the event data was modified by
        // another plugin before we got it)
        if(!event.getFrom().getWorld().equals(event.getTo().getWorld()) || event.getFrom().distanceSquared(event.getTo()) > 400) {
            return;
        }

        final NoCheatPlayer player = plugin.getPlayer(event.getPlayer());

        final MovingConfig cc = MovingCheck.getConfig(player);
        final MovingData data = MovingCheck.getData(player);

        // Advance various counters and values that change per movement
        // tick. They are needed to decide on how fast a player may
        // move.
        tickVelocities(data);

        // Remember locations
        data.from.set(event.getFrom());
        final Location to = event.getTo();
        data.to.set(to);

        PreciseLocation newTo = null;

        /** RUNFLY CHECK SECTION **/
        // If the player isn't handled by runfly checks
        if(!cc.runflyCheck || player.hasPermission(Permissions.MOVING_RUNFLY)) {
            // Just because he is allowed now, doesn't mean he will always
            // be. So forget data about the player related to moving
            data.clearRunFlyData();
        } else if(cc.allowFlying || (player.isCreative() && cc.identifyCreativeMode) || player.hasPermission(Permissions.MOVING_FLYING)) {
            // Only do the limited flying check
            newTo = flyingCheck.check(player, data, cc);
        } else {
            // Go for the full treatment
            newTo = runningCheck.check(player, data, cc);
        }

        /** MOREPACKETS CHECK SECTION **/
        if(!cc.morePacketsCheck || player.hasPermission(Permissions.MOVING_MOREPACKETS)) {
            data.clearMorePacketsData();
        } else if(newTo == null) {
            newTo = morePacketsCheck.check(player, data, cc);
        }

        // Did one of the check(s) decide we need a new "to"-location?
        if(newTo != null) {
            // Compose a new location based on coordinates of "newTo" and
            // viewing direction of "event.getTo()" to allow the player to
            // look somewhere else despite getting pulled back by NoCheat
            event.setTo(new Location(player.getPlayer().getWorld(), newTo.x, newTo.y, newTo.z, to.getYaw(), to.getPitch()));

            // remember where we send the player to
            data.teleportTo.set(newTo);
        }
    }

    /**
     * Just try to estimate velocities over time
     * Not very precise, but works good enough most
     * of the time.
     *
     * @param data
     */
    private void tickVelocities(MovingData data) {

        /******** DO GENERAL DATA MODIFICATIONS ONCE FOR EACH EVENT *****/
        if(data.horizVelocityCounter > 0) {
            data.horizVelocityCounter--;
        } else if(data.horizFreedom > 0.001) {
            data.horizFreedom *= 0.90;
        }

        if(data.vertVelocity <= 0.1) {
            data.vertVelocityCounter--;
        }
        if(data.vertVelocityCounter > 0) {
            data.vertFreedom += data.vertVelocity;
            data.vertVelocity *= 0.90;
        } else if(data.vertFreedom > 0.001) {
            // Counter has run out, now reduce the vert freedom over time
            data.vertFreedom *= 0.93;
        }
    }

    /**
     * Player got a velocity packet. The server can't keep track
     * of actual velocity values (by design), so we have to try
     * and do that ourselves. Very rough estimates.
     *
     * @param event The PlayerVelocityEvent
     */
    @EventHandler(priority = EventPriority.MONITOR)
    public void velocity(final PlayerVelocityEvent event) {
        if(event.isCancelled())
            return;

        final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer()));

        final Vector v = event.getVelocity();

        double newVal = v.getY();
        if(newVal >= 0.0D) {
            data.vertVelocity += newVal;
            data.vertFreedom += data.vertVelocity;
        }

        data.vertVelocityCounter = 50;

        newVal = Math.sqrt(Math.pow(v.getX(), 2) + Math.pow(v.getZ(), 2));
        if(newVal > 0.0D) {
            data.horizFreedom += newVal;
            data.horizVelocityCounter = 30;
        }
    }

    public List<String> getActiveChecks(ConfigurationCacheStore cc) {
        LinkedList<String> s = new LinkedList<String>();

        MovingConfig m = MovingCheck.getConfig(cc);

        if(m.runflyCheck) {

            if(!m.allowFlying) {
                s.add("moving.runfly");
                if(m.sneakingCheck)
                    s.add("moving.sneaking");
                if(m.nofallCheck)
                    s.add("moving.nofall");
            } else
                s.add("moving.flying");

        }
        if(m.morePacketsCheck)
            s.add("moving.morepackets");

        return s;
    }
}
TOP

Related Classes of cc.co.evenprime.bukkit.nocheat.checks.moving.MovingCheckListener

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.