@EventHandler(priority = EventPriority.MONITOR)
  public void quitHandler(PlayerQuitEvent event) {
    // update their spam status
    plugin.spamManager.playerQuit(event.getPlayer());

    // set their persistance
    plugin.ph.setOfflineChannel(
        event.getPlayer().getName(), plugin.channelManager.getPlayerChannel(event.getPlayer()));
    plugin.ph.setOfflineVerbosity(
        event.getPlayer().getName(), plugin.chatManager.getVerbosity(event.getPlayer()));

    // remove them from their channel
    plugin.channelManager.removePlayer(event.getPlayer());
    // and remove them from the VoxelChat list
    plugin.chatManager.disableVoxelChat(event.getPlayer());

    // turn off the global join notification
    event.setQuitMessage("");

    // and do our own custom notification
    Player[] players = plugin.getServer().getOnlinePlayers();
    for (int i = 0; i < players.length; i++) {
      if (plugin.chatManager.getVerbosity(players[i]).compareTo(Verbosity.SHOWSOME) >= 0) {
        // they want these messages! show them!
        // TODO: custom join / leave messages
        ColourHandler.sendMessage(
            players[i],
            plugin.permissions.getUser(event.getPlayer()).getPrefix()
                + event.getPlayer().getName()
                + " &ehas left the game!");
      }
    }
  }
  @EventHandler(priority = EventPriority.MONITOR)
  public void joinHandler(PlayerJoinEvent event) {
    // TODO: move to a different plugin!
    // should they be allowed to fly?
    if (plugin.hasPermission(event.getPlayer(), "fly")) {
      event.getPlayer().setAllowFlight(true);
      plugin.log("Allowing flight for " + event.getPlayer().getName());
    }

    // move them into their channel!
    String channel = plugin.ph.getOfflineChannel(event.getPlayer().getName());
    // create the channel if it doesn't exist
    plugin.channelManager.createChannelIfNotExists(channel);
    // and move into it!
    plugin.channelManager.movePlayer(channel, event.getPlayer(), true);

    // get their stored verbosity level
    Verbosity level = plugin.ph.getOfflineVerbosity(event.getPlayer().getName());
    plugin.chatManager.setVerbosity(event.getPlayer(), level);

    // turn off the global join notification
    event.setJoinMessage("");

    // and do our own custom notification
    Player[] players = plugin.getServer().getOnlinePlayers();
    for (int i = 0; i < players.length; i++) {
      if (plugin.chatManager.getVerbosity(players[i]).compareTo(Verbosity.SHOWSOME) >= 0) {
        // they want these messages! show them!
        // TODO: custom join / leave messages
        ColourHandler.sendMessage(
            players[i],
            plugin.permissions.getUser(event.getPlayer()).getPrefix()
                + event.getPlayer().getName()
                + " &ehas joined the game!");
      }
    }

    // and warn them of lockdowns
    if (plugin.spamManager.onLockdown()
        && plugin.chatManager.getVerbosity(event.getPlayer()).compareTo(Verbosity.SHOWSOME) >= 0) {
      PermissionGroup[] groups = plugin.permissions.getGroups();
      String strGroups = new String("");
      for (int i = 0; i < groups.length; i++) {
        if (!groups[i].has("mcnsachat2.ignorelockdown")) {
          strGroups += groups[i].getPrefix() + groups[i].getName() + "&7, ";
        }
      }
      ColourHandler.sendMessage(
          event.getPlayer(),
          "&4ATTENTION!!! &fLockdown mode is activated! The following ranks are temporarily barred from joining the server: "
              + strGroups);
    }

    // now send coloured names to those with voxelchat
    for (int i = 0; i < plugin.chatManager.voxelChat.size(); i++) {
      Player target = plugin.getServer().getPlayerExact(plugin.chatManager.voxelChat.get(i));
      if (target != null) {
        target.sendMessage(
            "\247c\247a\2471\2473\247d\247eq?=$vp="
                + event.getPlayer().getName()
                + ","
                + plugin.permissions.getUser(event.getPlayer()).getPrefix().replace("&", ""));
      }
    }
  }