Package fr.neatmonster.nocheatplus.checks.blockbreak

Source Code of fr.neatmonster.nocheatplus.checks.blockbreak.BlockBreakListener

package fr.neatmonster.nocheatplus.checks.blockbreak;

import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.player.PlayerAnimationEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.inventory.ItemStack;

import fr.neatmonster.nocheatplus.NCPAPIProvider;
import fr.neatmonster.nocheatplus.checks.CheckListener;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.inventory.Items;
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager;
import fr.neatmonster.nocheatplus.permissions.Permissions;
import fr.neatmonster.nocheatplus.stats.Counters;
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
import fr.neatmonster.nocheatplus.utilities.TickTask;

/**
* Central location to listen to events that are relevant for the block break checks.
*
* @see BlockBreakEvent
*/
public class BlockBreakListener extends CheckListener {

    /** The direction check. */
    private final Direction direction = addCheck(new Direction());

    /** The fast break check (per block breaking speed). */
    private final FastBreak fastBreak = addCheck(new FastBreak());
   
    /** The frequency check (number of blocks broken) */
    private final Frequency frequency = addCheck(new Frequency());

    /** The no swing check. */
    private final NoSwing   noSwing   = addCheck(new NoSwing());

    /** The reach check. */
    private final Reach     reach     = addCheck(new Reach());
   
    /** The wrong block check. */
    private final WrongBlock wrongBlock = addCheck(new WrongBlock());
   
    private AlmostBoolean isInstaBreak = AlmostBoolean.NO;
   
    private final Counters counters = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Counters.class);
    private final int idCancelDIllegalItem = counters.registerKey("illegalitem");
   
    public BlockBreakListener(){
      super(CheckType.BLOCKBREAK);
    }

    /**
     * We listen to BlockBreak events for obvious reasons.
     *
     * @param event
     *            the event
     */
    @EventHandler(ignoreCancelled = false, priority = EventPriority.LOWEST)
    public void onBlockBreak(final BlockBreakEvent event) {
       
        final Player player = event.getPlayer();
       
        // Illegal enchantments hotfix check.
        if (Items.checkIllegalEnchantments(player, player.getItemInHand())) {
          event.setCancelled(true);
          counters.addPrimaryThread(idCancelDIllegalItem, 1);
        }
       
      // Cancelled events only leads to resetting insta break.
      if (event.isCancelled()) {
        isInstaBreak = AlmostBoolean.NO;
        return;
      }
     
      // TODO: maybe invalidate instaBreak on some occasions.
     

        final Block block = event.getBlock();

        boolean cancelled = false;

        // Do the actual checks, if still needed. It's a good idea to make computationally cheap checks first, because
        // it may save us from doing the computationally expensive checks.
       
        final BlockBreakConfig cc = BlockBreakConfig.getConfig(player);
        final BlockBreakData data = BlockBreakData.getData(player);
        final long now = System.currentTimeMillis();
       
        final GameMode gameMode = player.getGameMode();
       
        // Has the player broken a block that was not damaged before?
        if (wrongBlock.isEnabled(player) && wrongBlock.check(player, block, cc, data, isInstaBreak)) {
          cancelled = true;
        }

        // Has the player broken more blocks per second than allowed?
        if (!cancelled && frequency.isEnabled(player) && frequency.check(player, cc, data)) {
          cancelled = true;
        }
         
        // Has the player broken blocks faster than possible?
        if (!cancelled && gameMode != GameMode.CREATIVE && fastBreak.isEnabled(player) && fastBreak.check(player, block, isInstaBreak, cc, data)) {
          cancelled = true;
        }

        // Did the arm of the player move before breaking this block?
        if (!cancelled && noSwing.isEnabled(player) && noSwing.check(player, data)) {
          cancelled = true;
        }

        // Is the block really in reach distance?
        if (!cancelled && reach.isEnabled(player) && reach.check(player, block, data)) {
          cancelled = true;
        }

        // Did the player look at the block at all?
        if (!cancelled && direction.isEnabled(player) && direction.check(player, block, data)) {
          cancelled = true;
        }
       
        // Destroying liquid blocks.
        if (!cancelled && BlockProperties.isLiquid(block.getType()) && !player.hasPermission(Permissions.BLOCKBREAK_BREAK_LIQUID) && !NCPExemptionManager.isExempted(player, CheckType.BLOCKBREAK_BREAK)){
            cancelled = true;
        }

        // On cancel...
        if (cancelled) {
          event.setCancelled(cancelled);
          // Reset damage position:
          // TODO: Review this (!), check if set at all !?
        data.clickedX = block.getX();
        data.clickedY = block.getY();
        data.clickedZ = block.getZ();
        }
        else{
          // Invalidate last damage position:
//          data.clickedX = Integer.MAX_VALUE;
        }
       
        if (isInstaBreak.decideOptimistically()) {
          data.wasInstaBreak = now;
        }
        else {
          data.wasInstaBreak = 0;
        }
       
        // Adjust data.
        data.fastBreakBreakTime = now;
//        data.fastBreakfirstDamage = now;
        isInstaBreak = AlmostBoolean.NO;
    }

    /**
     * We listen to PlayerAnimation events because it is (currently) equivalent to "player swings arm" and we want to
     * check if they did that between block breaks.
     *
     * @param event
     *            the event
     */
    @EventHandler(
            priority = EventPriority.MONITOR)
    public void onPlayerAnimation(final PlayerAnimationEvent event) {
        // Just set a flag to true when the arm was swung.
//      System.out.println("Animation");
        BlockBreakData.getData(event.getPlayer()).noSwingArmSwung = true;
    }

    /**
     * We listen to BlockInteract events to be (at least in many cases) able to distinguish between block break events
     * that were triggered by players actually digging and events that were artificially created by plugins.
     *
     * @param event
     *            the event
     */
    @EventHandler(
            ignoreCancelled = false, priority = EventPriority.LOWEST)
    public void onPlayerInteract(final PlayerInteractEvent event) {
//      System.out.println("Interact("+event.isCancelled()+"): " + event.getClickedBlock());
      // The following is to set the "first damage time" for a block.
     
      // Return if it is not left clicking a block.
      // (Allows right click to be ignored.)
      isInstaBreak = AlmostBoolean.NO;
        if (event.getAction() != Action.LEFT_CLICK_BLOCK) {
          return;
        }
        checkBlockDamage(event.getPlayer(), event.getClickedBlock(), event);
    }
   
    @EventHandler(ignoreCancelled = false, priority = EventPriority.LOWEST)
    public void onBlockDamageLowest(final BlockDamageEvent event) {
      if (event.getInstaBreak()) {
        // Indicate that this might have been set by CB/MC.
        isInstaBreak = AlmostBoolean.MAYBE;
      }
    }
   
    @EventHandler(ignoreCancelled = false, priority = EventPriority.MONITOR)
    public void onBlockDamage(final BlockDamageEvent event) {
      if (!event.isCancelled() && event.getInstaBreak()) {
        // Keep MAYBE.
        if (isInstaBreak != AlmostBoolean.MAYBE) {
          isInstaBreak = AlmostBoolean.YES;
        }
      }
      else {
        isInstaBreak = AlmostBoolean.NO;
      }
      checkBlockDamage(event.getPlayer(), event.getBlock(), event);
    }
   
    private void checkBlockDamage(final Player player, final Block block, final Cancellable event){
      final long now = System.currentTimeMillis();
        final BlockBreakData data = BlockBreakData.getData(player);
       
//        if (event.isCancelled()){
//          // Reset the time, to avoid certain kinds of cheating. => WHICH ?
//          data.fastBreakfirstDamage = now;
//          data.clickedX = Integer.MAX_VALUE; // Should be enough to reset that one.
//          return;
//        }
     
        // Do not care about null blocks.
        if (block == null) {
          return;
        }
       
        final int tick = TickTask.getTick();
        // Skip if already set to the same block without breaking within one tick difference.
        final ItemStack stack = player.getItemInHand();
        final Material tool = stack == null ? null: stack.getType();
        if (data.toolChanged(tool)) {
          // Update.
        } else if (tick < data.clickedTick || now < data.fastBreakfirstDamage || now < data.fastBreakBreakTime) {
          // Time/tick ran backwards: Update.
          // Tick running backwards should not happen in the main thread unless for reload. A plugin could reset it (not intended).
        } else if (data.fastBreakBreakTime < data.fastBreakfirstDamage && data.clickedX == block.getX() &&  data.clickedZ == block.getZ() &&  data.clickedY == block.getY()){
          // Preserve first damage time.
          if (tick - data.clickedTick <= 1 ) {
            return;
          }
        }
        // (Always set, the interact event only fires once: the first time.)
        // Only record first damage:
        data.setClickedBlock(block, tick, now, tool);
    }
   
    @EventHandler(ignoreCancelled = false, priority = EventPriority.MONITOR)
    public void onItemHeld(final PlayerItemHeldEvent event) {
      // Reset clicked block.
      // TODO: Not for 1.5.2 and before?
      final Player player = event.getPlayer();
      final BlockBreakData data = BlockBreakData.getData(player);
      if (data.toolChanged(player.getInventory().getItem(event.getNewSlot()))) {
        data.resetClickedBlock();
      }
    }
   
}
TOP

Related Classes of fr.neatmonster.nocheatplus.checks.blockbreak.BlockBreakListener

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.