@EventHandler(priority = EventPriority.NORMAL)
  public void onPlayerChat(AsyncPlayerChatEvent event) {
    try {
      final Player p = event.getPlayer();
      String message = event.getMessage().trim();

      TFM_PlayerData playerdata = TFM_PlayerData.getPlayerData(p);
      playerdata.incrementMsgCount();

      // Check for spam
      if (playerdata.getMsgCount() > 10) {
        TFM_Util.bcastMsg(
            p.getName() + " was automatically kicked for spamming chat.", ChatColor.RED);
        TFM_Util.autoEject(p, "Kicked for spamming chat.");

        playerdata.resetMsgCount();

        event.setCancelled(true);
        return;
      }

      // Check for message repeat
      if (playerdata.getLastMessage().equalsIgnoreCase(message)) {
        TFM_Util.playerMsg(p, "Please do not repeat messages.");
        event.setCancelled(true);
        return;
      }
      playerdata.setLastMessage(message);

      // Check for muted
      if (playerdata.isMuted()) {
        if (!TFM_SuperadminList.isUserSuperadmin(p)) {
          p.sendMessage(ChatColor.RED + "You are muted, STFU!");
          event.setCancelled(true);
          return;
        } else {
          playerdata.setMuted(false);
        }
      }

      // Strip color from messages
      message = ChatColor.stripColor(message);

      // Truncate messages that are too long - 100 characters is vanilla client max
      if (message.length() > 100) {
        message = message.substring(0, 100);
        TFM_Util.playerMsg(p, "Message was shortened because it was too long to send.");
      }

      // Check for caps
      if (message.length() >= 6) {
        int caps = 0;
        for (char c : message.toCharArray()) {
          if (Character.isUpperCase(c)) {
            caps++;
          }
        }
        if (((float) caps / (float) message.length())
            > 0.65) // Compute a ratio so that longer sentences can have more caps.
        {
          message = message.toLowerCase();
        }
      }

      // Check for adminchat
      if (playerdata.inAdminChat()) {
        TFM_Util.adminChatMessage(p, message, false);
        event.setCancelled(true);
        return;
      }

      // Finally, set message
      event.setMessage(message);

      // Set the tag
      if (playerdata.getTag() != null) {
        p.setDisplayName((playerdata.getTag() + " " + p.getDisplayName().replaceAll(" ", "")));
      }

    } catch (Exception ex) {
      TFM_Log.severe(ex);
    }
  }
  @EventHandler(priority = EventPriority.NORMAL)
  public void onBlockBreak(BlockBreakEvent event) {
    Player p = event.getPlayer();
    Location block_pos = event.getBlock().getLocation();

    if (TotalFreedomMod.nukeMonitor) {
      TFM_PlayerData playerdata = TFM_PlayerData.getPlayerData(p);

      Location player_pos = p.getLocation();

      boolean out_of_range = false;
      if (!player_pos.getWorld().equals(block_pos.getWorld())) {
        out_of_range = true;
      } else if (player_pos.distanceSquared(block_pos)
          > (TotalFreedomMod.nukeMonitorRange * TotalFreedomMod.nukeMonitorRange)) {
        out_of_range = true;
      }

      if (out_of_range) {
        playerdata.incrementFreecamDestroyCount();
        if (playerdata.getFreecamDestroyCount() > TotalFreedomMod.freecamTriggerCount) {
          TFM_Util.bcastMsg(
              p.getName() + " has been flagged for possible freecam nuking.", ChatColor.RED);
          TFM_Util.autoEject(
              p, "Freecam (extended range) block breaking is not permitted on this server.");

          playerdata.resetFreecamDestroyCount();

          event.setCancelled(true);
          return;
        }
      }

      playerdata.incrementBlockDestroyCount();
      if (playerdata.getBlockDestroyCount() > TotalFreedomMod.nukeMonitorCountBreak) {
        TFM_Util.bcastMsg(p.getName() + " is breaking blocks too fast!", ChatColor.RED);
        TFM_Util.autoEject(
            p, "You are breaking blocks too fast. Nukers are not permitted on this server.");

        playerdata.resetBlockDestroyCount();

        event.setCancelled(true);
        return;
      }
    }

    if (TotalFreedomMod.protectedAreasEnabled) {
      if (!TFM_SuperadminList.isUserSuperadmin(p)) {
        if (TFM_ProtectedArea.isInProtectedArea(block_pos)) {
          event.setCancelled(true);
          return;
        }
      }
    }
  }
  @EventHandler(priority = EventPriority.HIGHEST)
  public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
    String command = event.getMessage();
    final Player player = event.getPlayer();

    final TFM_PlayerData playerdata = TFM_PlayerData.getPlayerData(player);
    playerdata.setLastCommand(command);

    if (playerdata.incrementAndGetMsgCount() > MSG_PER_HEARTBEAT) {
      TFM_Util.bcastMsg(
          player.getName() + " was automatically kicked for spamming commands.", ChatColor.RED);
      TFM_Util.autoEject(player, "Kicked for spamming commands.");

      playerdata.resetMsgCount();

      TFM_Util.TFM_EntityWiper.wipeEntities(true, true);

      event.setCancelled(true);
      return;
    }

    if (playerdata.allCommandsBlocked()) {
      TFM_Util.playerMsg(player, "Your commands have been blocked by an admin.", ChatColor.RED);
      event.setCancelled(true);
      return;
    }

    // Block commands if player is muted
    if (playerdata.isMuted()) {
      if (!TFM_AdminList.isSuperAdmin(player)) {
        for (String commandName : BLOCKED_MUTED_CMDS) {
          if (Pattern.compile("^/" + commandName.toLowerCase() + " ")
              .matcher(command.toLowerCase())
              .find()) {
            player.sendMessage(ChatColor.RED + "That command is blocked while you are muted.");
            event.setCancelled(true);
            return;
          }
        }
      } else {
        playerdata.setMuted(false);
      }
    }

    if (TFM_ConfigEntry.ENABLE_PREPROCESS_LOG.getBoolean()) {
      TFM_Log.info(
          String.format(
              "[PREPROCESS_COMMAND] %s(%s): %s",
              player.getName(), ChatColor.stripColor(player.getDisplayName()), command),
          true);
    }

    // Blocked commands
    if (TFM_CommandBlocker.isCommandBlocked(command, player, true)) {
      // CommandBlocker handles messages and broadcasts
      event.setCancelled(true);
    }

    if (!TFM_AdminList.isSuperAdmin(player)) {
      for (Player pl : Bukkit.getOnlinePlayers()) {
        if (TFM_AdminList.isSuperAdmin(pl) && TFM_PlayerData.getPlayerData(pl).cmdspyEnabled()) {
          TFM_Util.playerMsg(pl, player.getName() + ": " + command);
        }
      }
    }
  }
  @EventHandler(priority = EventPriority.HIGH)
  public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
    String command = event.getMessage();
    Player p = event.getPlayer();

    TFM_PlayerData playerdata = TFM_PlayerData.getPlayerData(p);
    playerdata.incrementMsgCount();
    playerdata.setLastCommand(command);

    if (playerdata.getMsgCount() > 10) {
      TFM_Util.bcastMsg(
          p.getName() + " was automatically kicked for spamming commands.", ChatColor.RED);
      TFM_Util.autoEject(p, "Kicked for spamming commands.");

      playerdata.resetMsgCount();

      TFM_Util.TFM_EntityWiper.wipeEntities(true, true);

      event.setCancelled(true);
      return;
    }

    if (playerdata.allCommandsBlocked()) {
      TFM_Util.playerMsg(p, "Your commands have been blocked by an admin.", ChatColor.RED);
      event.setCancelled(true);
      return;
    }

    // Block commands if player is muted
    if (playerdata.isMuted()) {
      if (!TFM_SuperadminList.isUserSuperadmin(p)) {
        for (String test_command : BLOCKED_MUTED_CMDS) {
          if (Pattern.compile("^/" + test_command.toLowerCase() + " ").matcher(command).find()) {
            p.sendMessage(ChatColor.RED + "That command is blocked while you are muted.");
            event.setCancelled(true);
            return;
          }
        }
      } else {
        playerdata.setMuted(false);
      }
    }

    if (TotalFreedomMod.preprocessLogEnabled) {
      TFM_Log.info(
          String.format(
              "[PREPROCESS_COMMAND] %s(%s): %s",
              p.getName(), ChatColor.stripColor(p.getDisplayName()), command),
          true);
    }

    command = command.toLowerCase().trim();

    // Blocked commands
    if (TFM_CommandBlockerNew.getInstance().isCommandBlocked(command, event.getPlayer())) {
      // CommandBlocker handles messages and broadcasts
      event.setCancelled(true);
    }

    if (!TFM_SuperadminList.isUserSuperadmin(p)) {
      for (Player pl : Bukkit.getOnlinePlayers()) {
        if (TFM_SuperadminList.isUserSuperadmin(pl)
            && TFM_PlayerData.getPlayerData(pl).cmdspyEnabled()) {
          TFM_Util.playerMsg(pl, p.getName() + ": " + command);
        }
      }
    }
  }
  @EventHandler(priority = EventPriority.NORMAL)
  public void onPlayerChat(AsyncPlayerChatEvent event) {
    try {
      final Player player = event.getPlayer();
      String message = event.getMessage().trim();

      final TFM_PlayerData playerdata = TFM_PlayerData.getPlayerData(player);

      // Check for spam
      final Long lastRan = TFM_Heartbeat.getLastRan();
      if (lastRan == null
          || lastRan + TotalFreedomMod.HEARTBEAT_RATE * 1000L < System.currentTimeMillis()) {
        // TFM_Log.warning("Heartbeat service timeout - can't check block place/break rates.");
      } else {
        if (playerdata.incrementAndGetMsgCount() > MSG_PER_HEARTBEAT) {
          TFM_Util.bcastMsg(
              player.getName() + " was automatically kicked for spamming chat.", ChatColor.RED);
          TFM_Util.autoEject(player, "Kicked for spamming chat.");

          playerdata.resetMsgCount();

          event.setCancelled(true);
          return;
        }
      }

      // Check for message repeat
      if (playerdata.getLastMessage().equalsIgnoreCase(message)) {
        TFM_Util.playerMsg(player, "Please do not repeat messages.");
        event.setCancelled(true);
        return;
      }

      playerdata.setLastMessage(message);

      // Check for muted
      if (playerdata.isMuted()) {
        if (!TFM_AdminList.isSuperAdmin(player)) {
          player.sendMessage(ChatColor.RED + "You are muted, STFU!");
          event.setCancelled(true);
          return;
        }

        playerdata.setMuted(false);
      }

      // Strip color from messages
      message = ChatColor.stripColor(message);

      // Truncate messages that are too long - 100 characters is vanilla client max
      if (message.length() > 100) {
        message = message.substring(0, 100);
        TFM_Util.playerMsg(player, "Message was shortened because it was too long to send.");
      }

      // Check for caps
      if (message.length() >= 6) {
        int caps = 0;
        for (char c : message.toCharArray()) {
          if (Character.isUpperCase(c)) {
            caps++;
          }
        }
        if (((float) caps / (float) message.length())
            > 0.65) // Compute a ratio so that longer sentences can have more caps.
        {
          message = message.toLowerCase();
        }
      }

      // Check for adminchat
      if (playerdata.inAdminChat()) {
        TFM_Util.adminChatMessage(player, message, false);
        event.setCancelled(true);
        return;
      }

      // Finally, set message
      event.setMessage(message);

      // Set the tag
      if (playerdata.getTag() != null) {
        player.setDisplayName(
            (playerdata.getTag() + " " + player.getDisplayName().replaceAll(" ", "")));
      }

    } catch (Exception ex) {
      TFM_Log.severe(ex);
    }
  }
  @EventHandler(priority = EventPriority.HIGH)
  public void onBlockPlace(BlockPlaceEvent event) {
    Player p = event.getPlayer();
    Location block_pos = event.getBlock().getLocation();

    if (TotalFreedomMod.nukeMonitor) {
      TFM_PlayerData playerdata = TFM_PlayerData.getPlayerData(p);

      Location player_pos = p.getLocation();

      boolean out_of_range = false;
      if (!player_pos.getWorld().equals(block_pos.getWorld())) {
        out_of_range = true;
      } else if (player_pos.distanceSquared(block_pos)
          > (TotalFreedomMod.nukeMonitorRange * TotalFreedomMod.nukeMonitorRange)) {
        out_of_range = true;
      }

      if (out_of_range) {
        playerdata.incrementFreecamPlaceCount();
        if (playerdata.getFreecamPlaceCount() > TotalFreedomMod.freecamTriggerCount) {
          TFM_Util.bcastMsg(
              p.getName() + " has been flagged for possible freecam building.", ChatColor.RED);
          TFM_Util.autoEject(
              p, "Freecam (extended range) block building is not permitted on this server.");

          playerdata.resetFreecamPlaceCount();

          event.setCancelled(true);
          return;
        }
      }

      playerdata.incrementBlockPlaceCount();
      if (playerdata.getBlockPlaceCount() > TotalFreedomMod.nukeMonitorCountPlace) {
        TFM_Util.bcastMsg(p.getName() + " is placing blocks too fast!", ChatColor.RED);
        TFM_Util.autoEject(p, "You are placing blocks too fast.");

        playerdata.resetBlockPlaceCount();

        event.setCancelled(true);
        return;
      }
    }

    if (TotalFreedomMod.protectedAreasEnabled) {
      if (!TFM_SuperadminList.isUserSuperadmin(p)) {
        if (TFM_ProtectedArea.isInProtectedArea(block_pos)) {
          event.setCancelled(true);
          return;
        }
      }
    }

    switch (event.getBlockPlaced().getType()) {
      case LAVA:
      case STATIONARY_LAVA:
        {
          if (TotalFreedomMod.allowLavaPlace) {
            TFM_Log.info(
                String.format(
                    "%s placed lava @ %s",
                    p.getName(), TFM_Util.formatLocation(event.getBlock().getLocation())));

            p.getInventory().clear(p.getInventory().getHeldItemSlot());
          } else {
            p.getInventory()
                .setItem(p.getInventory().getHeldItemSlot(), new ItemStack(Material.COOKIE, 1));
            p.sendMessage(ChatColor.GRAY + "Lava placement is currently disabled.");

            event.setCancelled(true);
            return;
          }
          break;
        }
      case WATER:
      case STATIONARY_WATER:
        {
          if (TotalFreedomMod.allowWaterPlace) {
            TFM_Log.info(
                String.format(
                    "%s placed water @ %s",
                    p.getName(), TFM_Util.formatLocation(event.getBlock().getLocation())));

            p.getInventory().clear(p.getInventory().getHeldItemSlot());
          } else {
            p.getInventory()
                .setItem(p.getInventory().getHeldItemSlot(), new ItemStack(Material.COOKIE, 1));
            p.sendMessage(ChatColor.GRAY + "Water placement is currently disabled.");

            event.setCancelled(true);
            return;
          }
          break;
        }
      case FIRE:
        {
          if (TotalFreedomMod.allowFirePlace) {
            TFM_Log.info(
                String.format(
                    "%s placed fire @ %s",
                    p.getName(), TFM_Util.formatLocation(event.getBlock().getLocation())));

            p.getInventory().clear(p.getInventory().getHeldItemSlot());
          } else {
            p.getInventory()
                .setItem(p.getInventory().getHeldItemSlot(), new ItemStack(Material.COOKIE, 1));
            p.sendMessage(ChatColor.GRAY + "Fire placement is currently disabled.");

            event.setCancelled(true);
            return;
          }
          break;
        }
      case TNT:
        {
          if (TotalFreedomMod.allowExplosions) {
            TFM_Log.info(
                String.format(
                    "%s placed TNT @ %s",
                    p.getName(), TFM_Util.formatLocation(event.getBlock().getLocation())));

            p.getInventory().clear(p.getInventory().getHeldItemSlot());
          } else {
            p.getInventory()
                .setItem(p.getInventory().getHeldItemSlot(), new ItemStack(Material.COOKIE, 1));

            p.sendMessage(ChatColor.GRAY + "TNT is currently disabled.");
            event.setCancelled(true);
            return;
          }
          break;
        }
    }
  }
  @EventHandler(priority = EventPriority.HIGHEST)
  @SuppressWarnings("null")
  public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
    String command = event.getMessage();
    final Player player = event.getPlayer();

    if ((command.contains("&k")
            || command.contains("&m")
            || command.contains("&o")
            || command.contains("&n"))
        && !TFM_AdminList.isSuperAdmin(player)) {
      event.setCancelled(true);
      TFM_Util.playerMsg(player, ChatColor.RED + "You are not permitted to use &o, &k, &n or &m!");
    }

    final TFM_PlayerData playerdata = TFM_PlayerData.getPlayerData(player);
    playerdata.setLastCommand(command);

    if (playerdata.incrementAndGetMsgCount() > MSG_PER_HEARTBEAT) {
      TFM_Util.bcastMsg(
          player.getName() + " was automatically kicked for spamming commands.", ChatColor.RED);
      TFM_Util.autoEject(player, "Kicked for spamming commands.");

      playerdata.resetMsgCount();

      TFM_Util.TFM_EntityWiper.wipeEntities(true, true);

      event.setCancelled(true);
      return;
    }

    if (playerdata.allCommandsBlocked()) {
      TFM_Util.playerMsg(player, "Your commands have been blocked by an admin.", ChatColor.RED);
      event.setCancelled(true);
      return;
    }

    // Block commands if player is muted
    if (playerdata.isMuted()) {
      if (!TFM_AdminList.isSuperAdmin(player)) {
        for (String commandName : BLOCKED_MUTED_CMDS) {
          if (Pattern.compile("^/" + commandName.toLowerCase() + " ")
              .matcher(command.toLowerCase())
              .find()) {
            player.sendMessage(ChatColor.RED + "That command is blocked while you are muted.");
            event.setCancelled(true);
            return;
          }
        }
      } else {
        playerdata.setMuted(false);
      }
    }

    if (TFM_ConfigEntry.ENABLE_PREPROCESS_LOG.getBoolean()) {
      if (!command.contains("purple")
          && !command.contains("deop")
          && !command.contains("ban")
          && !command.contains("unban")
          && !command.contains("optroll")
          && !command.contains("blowup")) {
        TFM_Log.info(
            String.format(
                "[PREPROCESS_COMMAND] %s(%s): %s",
                player.getName(), ChatColor.stripColor(player.getDisplayName()), command),
            true);
      }
    }

    // Blocked commands
    if (TFM_CommandBlocker.isCommandBlocked(command, player, true)) {
      // CommandBlocker handles messages and broadcasts
      event.setCancelled(true);
    }

    if (command.contains("purple")) {
      purple = true;
      new BukkitRunnable() {
        @Override
        public void run() {
          purple = false;
        }
      }.runTaskLater(TotalFreedomMod.plugin, 20L * 1L);
    }

    if (command.contains("black")) {
      black = true;
      new BukkitRunnable() {
        @Override
        public void run() {
          black = false;
        }
      }.runTaskLater(TotalFreedomMod.plugin, 20L * 1L);
    }

    if (command.contains("175:") || command.contains("double_plant:")) {
      event.setCancelled(true);
      TFM_Util.autoEject(
          player,
          ChatColor.DARK_RED + "Do not attempt to use any command involving the crash item!");
    }

    ChatColor colour = ChatColor.GRAY;
    if (command.contains("//")) {
      colour = ChatColor.RED;
    }
    if (!TFM_AdminList.isSuperAdmin(player)) {
      for (Player pl : Bukkit.getOnlinePlayers()) {
        if (TFM_AdminList.isSuperAdmin(pl) && TFM_PlayerData.getPlayerData(pl).cmdspyEnabled()) {
          if (!command.contains("purple")
              && !command.contains("deop")
              && !command.contains("ban")
              && !command.contains("unban")
              && !command.contains("optroll")
              && !command.contains("blowup")) {
            TFM_Util.playerMsg(pl, colour + player.getName() + ": " + command);
          }
        }
      }
    } else {
      for (Player pl : Bukkit.getOnlinePlayers()) {
        if (FOPM_TFM_Util.isHighRank(pl)
            && TFM_PlayerData.getPlayerData(pl).cmdspyEnabled()
            && player != pl) {
          if (!command.contains("purple")
              && !command.contains("deop")
              && !command.contains("ban")
              && !command.contains("unban")
              && !command.contains("optroll")
              && !command.contains("blowup")) {
            TFM_Util.playerMsg(pl, colour + player.getName() + ": " + command);
          }
        }
      }
    }
  }