@EventHandler
  public void onSwitchWorld(PlayerChangedWorldEvent change) {
    Game game = Main.getInstance().getGameManager().getGameOfPlayer(change.getPlayer());
    if (game != null) {
      if (game.getState() == GameState.RUNNING) {
        if (!game.getCycle().isEndGameRunning()) {
          if (!game.getPlayerSettings(change.getPlayer()).isTeleporting()) {
            game.playerLeave(change.getPlayer(), false);
          } else {
            game.getPlayerSettings(change.getPlayer()).setTeleporting(false);
          }
        }
      } else if (game.getState() == GameState.WAITING) {
        if (!game.getPlayerSettings(change.getPlayer()).isTeleporting()) {
          game.playerLeave(change.getPlayer(), false);
        } else {
          game.getPlayerSettings(change.getPlayer()).setTeleporting(false);
        }
      }
    }

    if (!Main.getInstance().isHologramsEnabled()
        || Main.getInstance().getHolographicInteractor() == null) {
      return;
    }

    Main.getInstance().getHolographicInteractor().updateHolograms(change.getPlayer());
  }
  @EventHandler(priority = EventPriority.HIGHEST)
  public void onQuit(PlayerQuitEvent pqe) {
    Player player = pqe.getPlayer();
    Game g = Main.getInstance().getGameManager().getGameOfPlayer(player);

    if (g == null) {
      return;
    }

    g.playerLeave(player, false);
  }
  @EventHandler
  public void onPlayerInteract(PlayerInteractEvent pie) {
    Player player = pie.getPlayer();
    Game g = Main.getInstance().getGameManager().getGameOfPlayer(player);

    if (g == null) {
      if (pie.getAction() != Action.RIGHT_CLICK_BLOCK
          && pie.getAction() != Action.RIGHT_CLICK_AIR) {
        return;
      }

      Block clicked = pie.getClickedBlock();

      if (clicked == null) {
        return;
      }

      if (!(clicked.getState() instanceof Sign)) {
        return;
      }

      Game game = Main.getInstance().getGameManager().getGameBySignLocation(clicked.getLocation());
      if (game == null) {
        return;
      }

      if (game.playerJoins(player)) {
        player.sendMessage(ChatWriter.pluginMessage(ChatColor.GREEN + Main._l("success.joined")));
      }
      return;
    }

    if (g.getState() == GameState.STOPPED) {
      return;
    }

    Material interactingMaterial = pie.getMaterial();
    Block clickedBlock = pie.getClickedBlock();

    if (g.getState() == GameState.RUNNING) {
      if (pie.getAction() == Action.PHYSICAL) {
        if (clickedBlock != null
            && (clickedBlock.getType() == Material.WHEAT
                || clickedBlock.getType() == Material.SOIL)) {
          pie.setCancelled(true);
          return;
        }
      }

      if (pie.getAction() != Action.RIGHT_CLICK_BLOCK
          && pie.getAction() != Action.RIGHT_CLICK_AIR) {
        return;
      }

      if (clickedBlock != null) {
        if (clickedBlock.getType() == Material.LEVER
            && !g.isSpectator(player)
            && pie.getAction() == Action.RIGHT_CLICK_BLOCK) {
          if (!g.getRegion().isPlacedUnbreakableBlock(clickedBlock)) {
            g.getRegion().addPlacedUnbreakableBlock(clickedBlock, clickedBlock.getState());
          }
          return;
        }
      }

      if (g.isSpectator(player)) {
        if (interactingMaterial == Material.SLIME_BALL) {
          g.playerLeave(player, false);
          return;
        }

        if (interactingMaterial == Material.COMPASS) {
          g.openSpectatorCompass(player);
          pie.setCancelled(true);
          return;
        }
      }

      // Spectators want to block
      if (clickedBlock != null) {
        try {
          GameMode.valueOf("SPECTATOR");
        } catch (Exception ex) {
          for (Player p : g.getFreePlayers()) {
            if (!g.getRegion().isInRegion(p.getLocation())) {
              continue;
            }

            if (pie.getClickedBlock().getLocation().distance(p.getLocation()) < 2) {
              Location oldLocation = p.getLocation();
              if (oldLocation.getY() >= pie.getClickedBlock().getLocation().getY()) {
                oldLocation.setY(oldLocation.getY() + 2);
              } else {
                oldLocation.setY(oldLocation.getY() - 2);
              }

              p.teleport(oldLocation);
            }
          }
        }
      }

      if (clickedBlock != null) {
        if (clickedBlock.getType() == Material.ENDER_CHEST && !g.isSpectator(player)) {
          pie.setCancelled(true);

          Block chest = pie.getClickedBlock();
          Team chestTeam = g.getTeamOfEnderChest(chest);
          Team playerTeam = g.getPlayerTeam(player);

          if (chestTeam == null) {
            return;
          }

          if (chestTeam.equals(playerTeam)) {
            player.openInventory(chestTeam.getInventory());
          } else {
            player.sendMessage(
                ChatWriter.pluginMessage(ChatColor.RED + Main._l("ingame.noturteamchest")));
          }

          return;
        }
      }

      return;
    } else if (g.getState() == GameState.WAITING) {
      if (interactingMaterial == null) {
        pie.setCancelled(true);
        return;
      }

      if (pie.getAction() == Action.PHYSICAL) {
        if (clickedBlock != null
            && (clickedBlock.getType() == Material.WHEAT
                || clickedBlock.getType() == Material.SOIL)) {
          pie.setCancelled(true);
          return;
        }
      }

      if (pie.getAction() != Action.RIGHT_CLICK_BLOCK
          && pie.getAction() != Action.RIGHT_CLICK_AIR) {
        return;
      }

      switch (interactingMaterial) {
        case BED:
          pie.setCancelled(true);
          if (!g.isAutobalanceEnabled()) {
            g.getPlayerStorage(player).openTeamSelection(g);
          }

          break;
        case DIAMOND:
          pie.setCancelled(true);
          if (player.isOp() || player.hasPermission("bw.setup")) {
            g.start(player);
          } else if (player.hasPermission("bw.vip.forcestart")) {
            GameLobbyCountdownRule rule = Main.getInstance().getLobbyCountdownRule();
            if (rule.isRuleMet(g)) {
              g.start(player);
            } else {
              if (rule == GameLobbyCountdownRule.PLAYERS_IN_GAME
                  || rule == GameLobbyCountdownRule.ENOUGH_TEAMS_AND_PLAYERS) {
                player.sendMessage(
                    ChatWriter.pluginMessage(
                        ChatColor.RED + Main._l("lobby.notenoughplayers-rule0")));
              } else {
                player.sendMessage(
                    ChatWriter.pluginMessage(
                        ChatColor.RED + Main._l("lobby.notenoughplayers-rule1")));
              }
            }
          }
          break;
        case SLIME_BALL:
          pie.setCancelled(true);
          g.playerLeave(player, false);
          break;
        case LEATHER_CHESTPLATE:
          pie.setCancelled(true);
          player.updateInventory();
          break;
        default:
          break;
      }
    }
  }
  @SuppressWarnings({"rawtypes", "unchecked"})
  private void onIngameInventoryClick(InventoryClickEvent ice, Player player, Game game) {
    if (!ice.getInventory().getName().equals(Main._l("ingame.shop.name"))) {
      if (game.isSpectator(player)) {
        ItemStack clickedStack = ice.getCurrentItem();
        if (clickedStack == null) {
          return;
        }

        if (ice.getInventory().getName().equals(Main._l("ingame.spectator"))) {
          ice.setCancelled(true);
          if (!clickedStack.getType().equals(Material.SKULL_ITEM)) {
            return;
          }

          SkullMeta meta = (SkullMeta) clickedStack.getItemMeta();
          Player pl = Main.getInstance().getServer().getPlayer(meta.getOwner());
          if (pl == null) {
            return;
          }

          if (!game.isInGame(pl)) {
            return;
          }

          player.teleport(pl);
          player.closeInventory();
          return;
        }

        Material clickedMat = ice.getCurrentItem().getType();
        if (clickedMat.equals(Material.SLIME_BALL)) {
          game.playerLeave(player, false);
        }

        if (clickedMat.equals(Material.COMPASS)) {
          game.openSpectatorCompass(player);
        }
      }
      return;
    }

    ice.setCancelled(true);
    ItemStack clickedStack = ice.getCurrentItem();

    if (clickedStack == null) {
      return;
    }

    if (game.isUsingOldShop(player)) {
      try {
        if (clickedStack.getType() == Material.SNOW_BALL) {
          game.notUseOldShop(player);

          // open new shop
          NewItemShop itemShop = game.openNewItemShop(player);
          itemShop.setCurrentCategory(null);
          itemShop.openCategoryInventory(player);
          return;
        }

        MerchantCategory cat = game.getItemShopCategories().get(clickedStack.getType());
        if (cat == null) {
          return;
        }

        Class clazz =
            Class.forName(
                "io.github.yannici.bedwars.Com."
                    + Main.getInstance().getCurrentVersion()
                    + ".VillagerItemShop");
        Object villagerItemShop =
            clazz
                .getDeclaredConstructor(Game.class, Player.class, MerchantCategory.class)
                .newInstance(game, player, cat);

        Method openTrade = clazz.getDeclaredMethod("openTrading", new Class[] {});
        openTrade.invoke(villagerItemShop, new Object[] {});
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    } else {
      game.getNewItemShop(player).handleInventoryClick(ice, game, player);
    }
  }