package in.twizmwaz.cardinal.module.modules.observers;
import com.google.common.base.Optional;
import in.twizmwaz.cardinal.Cardinal;
import in.twizmwaz.cardinal.GameHandler;
import in.twizmwaz.cardinal.chat.ChatConstant;
import in.twizmwaz.cardinal.chat.LocalizedChatMessage;
import in.twizmwaz.cardinal.event.CardinalSpawnEvent;
import in.twizmwaz.cardinal.event.MatchStartEvent;
import in.twizmwaz.cardinal.event.PlayerChangeTeamEvent;
import in.twizmwaz.cardinal.match.Match;
import in.twizmwaz.cardinal.module.Module;
import in.twizmwaz.cardinal.module.ModuleCollection;
import in.twizmwaz.cardinal.module.modules.blitz.Blitz;
import in.twizmwaz.cardinal.module.modules.spawn.SpawnModule;
import in.twizmwaz.cardinal.module.modules.team.TeamModule;
import in.twizmwaz.cardinal.module.modules.titleRespawn.TitleRespawn;
import in.twizmwaz.cardinal.rank.Rank;
import in.twizmwaz.cardinal.util.Items;
import in.twizmwaz.cardinal.util.Players;
import in.twizmwaz.cardinal.util.Teams;
import org.apache.commons.lang.WordUtils;
import org.bukkit.BanList;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Beacon;
import org.bukkit.block.BrewingStand;
import org.bukkit.block.Chest;
import org.bukkit.block.Dispenser;
import org.bukkit.block.Dropper;
import org.bukkit.block.Furnace;
import org.bukkit.block.Hopper;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityCombustByBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.EntityShootBowEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.PotionEffectAddEvent;
import org.bukkit.event.entity.PotionEffectExpireEvent;
import org.bukkit.event.entity.PotionEffectRemoveEvent;
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.hanging.HangingPlaceEvent;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryCreativeEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.player.PlayerAttackEntityEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemBreakEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerPickupExperienceEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.vehicle.VehicleDamageEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.event.vehicle.VehicleExitEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class ObserverModule implements Module {
private final Match match;
private Map<UUID, List<UUID>> viewing = new HashMap<>();
protected ObserverModule(Match match) {
this.match = match;
}
@Override
public void unload() {
HandlerList.unregisterAll(this);
}
@EventHandler
public void onMatchStart(MatchStartEvent event) {
if (Blitz.matchIsBlitz()){
for (Player player : Bukkit.getOnlinePlayers()) {
if (testObserver(player)) {
player.getInventory().setItem(2, null);
}
}
}
}
@EventHandler
public void onCardinalSpawn(CardinalSpawnEvent event) {
if (GameHandler.getGameHandler().getMatch().isRunning() && !event.getTeam().isObserver()) {
Players.resetPlayer(event.getPlayer());
event.getPlayer().setGameMode(GameMode.SURVIVAL);
Players.canInteract(event.getPlayer(), true);
} else {
Players.setObserver(event.getPlayer());
}
}
@EventHandler
public void onBlockChange(BlockPlaceEvent event) {
if (testObserverOrDead(event.getPlayer())) {
event.setCancelled(true);
}
}
@EventHandler
public void onBlockChange(BlockBreakEvent event) {
if (testObserverOrDead(event.getPlayer())) {
event.setCancelled(true);
}
}
@EventHandler
public void onInteraction(PlayerInteractEvent event) {
if (testObserver(event.getPlayer())) {
event.setCancelled(true);
if ((event.getAction().equals(Action.RIGHT_CLICK_AIR) || event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) && (event.getPlayer().getInventory().getItemInMainHand() != null && event.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.WRITTEN_BOOK))){
event.setUseInteractedBlock(Event.Result.DENY);
event.setUseItemInHand(Event.Result.ALLOW);
}
if (event.getClickedBlock() != null && !event.getPlayer().isSneaking() && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
if (event.getClickedBlock().getType().equals(Material.CHEST) || event.getClickedBlock().getType().equals(Material.TRAPPED_CHEST)) {
Inventory chest = Bukkit.createInventory(null, ((Chest) event.getClickedBlock().getState()).getInventory().getSize());
for (int i = 0; i < ((Chest) event.getClickedBlock().getState()).getInventory().getSize(); i++) {
chest.setItem(i, ((Chest) event.getClickedBlock().getState()).getInventory().getItem(i));
}
event.getPlayer().openInventory(chest);
}
if (event.getClickedBlock().getType().equals(Material.FURNACE) || event.getClickedBlock().getType().equals(Material.BURNING_FURNACE)) {
Inventory furnace = Bukkit.createInventory(null, InventoryType.FURNACE);
for (int i = 0; i < ((Furnace) event.getClickedBlock().getState()).getInventory().getSize(); i++) {
furnace.setItem(i, ((Furnace) event.getClickedBlock().getState()).getInventory().getItem(i));
}
event.getPlayer().openInventory(furnace);
}
if (event.getClickedBlock().getType().equals(Material.DISPENSER)) {
Inventory dispenser = Bukkit.createInventory(null, InventoryType.DISPENSER);
for (int i = 0; i < ((Dispenser) event.getClickedBlock().getState()).getInventory().getSize(); i++) {
dispenser.setItem(i, ((Dispenser) event.getClickedBlock().getState()).getInventory().getItem(i));
}
event.getPlayer().openInventory(dispenser);
}
if (event.getClickedBlock().getType().equals(Material.DROPPER)) {
Inventory dropper = Bukkit.createInventory(null, InventoryType.DROPPER);
for (int i = 0; i < ((Dropper) event.getClickedBlock().getState()).getInventory().getSize(); i++) {
dropper.setItem(i, ((Dropper) event.getClickedBlock().getState()).getInventory().getItem(i));
}
event.getPlayer().openInventory(dropper);
}
if (event.getClickedBlock().getType().equals(Material.HOPPER)) {
Inventory hopper = Bukkit.createInventory(null, InventoryType.HOPPER);
for (int i = 0; i < ((Hopper) event.getClickedBlock().getState()).getInventory().getSize(); i++) {
hopper.setItem(i, ((Hopper) event.getClickedBlock().getState()).getInventory().getItem(i));
}
event.getPlayer().openInventory(hopper);
}
if (event.getClickedBlock().getType().equals(Material.BREWING_STAND)) {
Inventory brewingStand = Bukkit.createInventory(null, InventoryType.BREWING);
for (int i = 0; i < ((BrewingStand) event.getClickedBlock().getState()).getInventory().getSize(); i++) {
brewingStand.setItem(i, ((BrewingStand) event.getClickedBlock().getState()).getInventory().getItem(i));
}
event.getPlayer().openInventory(brewingStand);
}
if (event.getClickedBlock().getType().equals(Material.BEACON)) {
Inventory beacon = Bukkit.createInventory(null, InventoryType.BEACON);
for (int i = 0; i < ((Beacon) event.getClickedBlock().getState()).getInventory().getSize(); i++) {
beacon.setItem(i, ((Beacon) event.getClickedBlock().getState()).getInventory().getItem(i));
}
event.getPlayer().openInventory(beacon);
}
}
}
}
@EventHandler(ignoreCancelled = true)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if (testObserver(event.getPlayer())) {
if (event.getRightClicked() instanceof Player && !event.getPlayer().isSneaking()){
if (event.getHand().equals(EquipmentSlot.HAND)) openInventory(event.getPlayer(), (Player) event.getRightClicked(), false);
} else if (event.getRightClicked() instanceof ItemFrame) {
event.setCancelled(true);
}
}
}
@EventHandler
public void onInventoryClose(InventoryCloseEvent event) {
for (UUID uuid : viewing.keySet()) {
if (viewing.get(uuid).contains(event.getPlayer().getUniqueId())) {
List<UUID> viewingList = viewing.get(uuid);
viewingList.remove(event.getPlayer().getUniqueId());
viewing.put(uuid, viewingList);
}
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onViewingInventoryClick(CraftItemEvent event) {
updateNextTick(event.getActor());
}
@EventHandler(priority = EventPriority.MONITOR)
public void onViewingInventoryMoveItem(InventoryClickEvent event) {
updateNextTick(event.getActor());
}
@EventHandler(priority = EventPriority.MONITOR)
public void onViewingInventoryClick(InventoryCreativeEvent event) {
updateNextTick(event.getActor());
}
@EventHandler(priority = EventPriority.MONITOR)
public void onViewingInventoryMoveItem(InventoryDragEvent event) {
updateNextTick(event.getActor());
}
@EventHandler
public void onViewingPlayerPickupItem(PlayerPickupItemEvent event) {
refreshView(event.getPlayer().getUniqueId());
}
@EventHandler
public void onViewingPlayerDropItem(PlayerDropItemEvent event) {
refreshView(event.getPlayer().getUniqueId());
}
@EventHandler
public void onViewingFoodLevelChange(FoodLevelChangeEvent event) {
refreshView(event.getEntity().getUniqueId());
}
@EventHandler
public void onViewingEntityDamage(EntityDamageEvent event) {
if (event.getEntity() instanceof Player) {
refreshView(event.getEntity().getUniqueId());
}
}
@EventHandler
public void onViewingEntityRegainHealth(EntityRegainHealthEvent event) {
if (event.getEntity() instanceof Player) {
refreshView(event.getEntity().getUniqueId());
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onViewingEntityAddEffect(PotionEffectAddEvent event) {
if (event.getEntity() instanceof Player) {
updateNextTick((Player)event.getEntity());
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onViewingEntityRemoveEffect(PotionEffectRemoveEvent event) {
if (event.getEntity() instanceof Player) {
updateNextTick((Player)event.getEntity());
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onViewingEntityExpireEffect(PotionEffectExpireEvent event) {
if (event.getEntity() instanceof Player) {
updateNextTick((Player)event.getEntity());
}
}
private void updateNextTick(final Player player) {
Bukkit.getScheduler().scheduleSyncDelayedTask(Cardinal.getInstance(), new Runnable() {
@Override
public void run() {
refreshView(player.getUniqueId());
}
});
}
@EventHandler(priority = EventPriority.HIGH)
public void onViewingPlayerRespawn(PlayerRespawnEvent event) {
refreshView(event.getPlayer().getUniqueId());
}
@EventHandler
public void onEntityShootBow(EntityShootBowEvent event) {
if (event.getEntity() instanceof Player) {
refreshView(event.getEntity().getUniqueId());
}
}
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
refreshView(event.getPlayer().getUniqueId());
}
@EventHandler
public void onPlayerItemConsume(PlayerItemConsumeEvent event) {
refreshView(event.getPlayer().getUniqueId());
}
@EventHandler
public void onPlayerItemBreak(PlayerItemBreakEvent event) {
refreshView(event.getPlayer().getUniqueId());
}
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
refreshView(event.getPlayer().getUniqueId());
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
closeInventories(event.getPlayer().getUniqueId());
}
@EventHandler (priority = EventPriority.MONITOR)
public void onPlayerChangeTeamEvent(PlayerChangeTeamEvent event) {
if (event.getNewTeam().isPresent() && event.getNewTeam().get().isObserver()){
closeInventories(event.getPlayer().getUniqueId());
}
}
public void openInventory(Player viewer, Player view, boolean message){
if (testObserver(viewer) && !testObserver(view)) {
viewer.openInventory(getFakeInventory(view, viewer.getLocale()));
if (!viewing.containsKey(view.getUniqueId())) {
viewing.put(view.getUniqueId(), new ArrayList<UUID>());
}
viewing.get(view.getUniqueId()).add(viewer.getUniqueId());
} else if (message){
viewer.sendMessage(ChatColor.RED + new LocalizedChatMessage(ChatConstant.ERROR_INVENTORY_NOT_VIEWABLE).getMessage(viewer.getLocale()));
}
}
public void closeInventories (UUID uuid) {
if (viewing.containsKey(uuid)) {
for (int i = 0; i < viewing.get(uuid).size(); i++) {
if (Bukkit.getPlayer(viewing.get(uuid).get(0)) != null) {
Bukkit.getPlayer(viewing.get(uuid).get(0)).closeInventory();
}
}
}
}
public void refreshView(final UUID view) {
if (Bukkit.getPlayer(view) != null && viewing.containsKey(view)) {
List<UUID> viewers = viewing.get(view);
for (int i = 0; i < viewers.size(); i++) {
Player player = Bukkit.getPlayer(viewers.get(i));
if (player != null && player.getOpenInventory().getTitle().contains(Bukkit.getPlayer(view).getName())) {
Inventory fake = getFakeInventory(Bukkit.getPlayer(view), player.getLocale());
for (int i2 = 0; i2 < 45; i2 ++) {
try {
player.getOpenInventory().setItem(i2, fake.getItem(i2));
} catch (NullPointerException e) {
}
}
if (!player.getOpenInventory().getTitle().equals(Bukkit.getPlayer(view).getDisplayName())){
player.openInventory(fake);
viewing.get(view).add(viewers.get(i));
}
}
}
}
}
public Inventory getFakeInventory(Player player, String locale) {
Inventory inventory = Bukkit.createInventory(null, 45, player.getDisplayName().length() > 32 ? Teams.getTeamColorByPlayer(player) + player.getName() : player.getDisplayName());
inventory.setItem(0, player.getInventory().getHelmet());
inventory.setItem(1, player.getInventory().getChestplate());
inventory.setItem(2, player.getInventory().getLeggings());
inventory.setItem(3, player.getInventory().getBoots());
inventory.setItem(4, player.getInventory().getItemInOffHand());
ItemStack potion;
if (player.getActivePotionEffects().size() > 0){
ArrayList<String> effects = new ArrayList<>();
for (PotionEffect effect : player.getActivePotionEffects()) {
String effectName = WordUtils.capitalizeFully(effect.getType().getName().toLowerCase().replaceAll("_", " "));
effects.add(ChatColor.YELLOW + effectName + " " + (effect.getAmplifier() + 1));
}
potion = Items.createItem(Material.POTION, 1, (short) 0, ChatColor.AQUA + "" + ChatColor.ITALIC + new LocalizedChatMessage(ChatConstant.UI_POTION_EFFECTS).getMessage(locale), effects);
} else {
potion = Items.createItem(Material.GLASS_BOTTLE, 1, (short) 0, ChatColor.AQUA + "" + ChatColor.ITALIC + new LocalizedChatMessage(ChatConstant.UI_POTION_EFFECTS).getMessage(locale), new ArrayList<>(Collections.singletonList(ChatColor.YELLOW + new LocalizedChatMessage(ChatConstant.UI_NO_POTION_EFFECTS).getMessage(locale))));
}
inventory.setItem(6, potion);
ItemStack food = Items.createItem(Material.COOKED_BEEF, player.getFoodLevel(), (short) 0, ChatColor.AQUA + "" + ChatColor.ITALIC + new LocalizedChatMessage(ChatConstant.UI_HUNGER_LEVEL).getMessage(locale));
inventory.setItem(7, food);
ItemStack health = Items.createItem(Material.REDSTONE, (int) Math.ceil(player.getHealth()), (short) 0, ChatColor.AQUA + "" + ChatColor.ITALIC + new LocalizedChatMessage(ChatConstant.UI_HEALTH_LEVEL).getMessage(locale));
inventory.setItem(8, health);
for (int i = 36; i <= 44; i++) {
inventory.setItem(i, player.getInventory().getItem(i - 36));
}
for (int i = 9; i <= 35; i++) {
inventory.setItem(i, player.getInventory().getItem(i));
}
return inventory;
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (event.getWhoClicked() instanceof Player && (testDead((Player) event.getWhoClicked()) || (testObserver((Player) event.getWhoClicked()) && !event.getInventory().getType().equals(InventoryType.PLAYER)))) {
event.setCancelled(true);
}
}
@EventHandler
public void onPlayerPickupExperience(PlayerPickupExperienceEvent event) {
if (testObserverOrDead(event.getPlayer())) {
event.setCancelled(true);
}
}
@EventHandler
public void onPlayerDropItem(PlayerDropItemEvent event) {
if (testObserverOrDead(event.getPlayer())) {
event.getItemDrop().remove();
}
}
@EventHandler
public void onEntityAttack(EntityDamageByEntityEvent event) {
if (event.getDamager() instanceof Player) {
if (testObserverOrDead((Player) event.getDamager())) {
event.setCancelled(true);
}
}
}
@EventHandler
public void onEntityAttack(PlayerAttackEntityEvent event) {
if (testObserverOrDead(event.getPlayer())) {
event.setCancelled(true);
}
}
@EventHandler
public void onVehicleDamage(VehicleDamageEvent event) {
if (event.getAttacker() instanceof Player && testObserverOrDead((Player) event.getAttacker())) {
event.setCancelled(true);
}
}
@EventHandler
public void onVehicleEnter(VehicleEnterEvent event) {
if (event.getEntered() instanceof Player && testObserverOrDead((Player) event.getEntered())) {
event.setCancelled(true);
}
}
@EventHandler
public void onVehicleExit(VehicleExitEvent event) {
if (event.getExited() instanceof Player && testObserverOrDead((Player) event.getExited())) {
event.setCancelled(true);
}
}
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
if (testObserver(event.getPlayer())) {
if (event.getTo().getY() <= -64) {
TeamModule teamModule = Teams.getTeamById("observers").get();
ModuleCollection<SpawnModule> modules = new ModuleCollection<>();
for (SpawnModule spawnModule : match.getModules().getModules(SpawnModule.class)) {
if (spawnModule.getTeam() == teamModule) modules.add(spawnModule);
}
event.setTo(modules.getRandom().getLocation());
}
}
}
@EventHandler
public void onPlayerTeleport(PlayerTeleportEvent event) {
if (testObserver(event.getPlayer())) {
if (event.getTo().getY() <= -64) {
TeamModule teamModule = Teams.getTeamById("observers").get();
ModuleCollection<SpawnModule> modules = new ModuleCollection<>();
for (SpawnModule spawnModule : match.getModules().getModules(SpawnModule.class)) {
if (spawnModule.getTeam() == teamModule) modules.add(spawnModule);
}
event.setTo(modules.getRandom().getLocation());
}
}
}
@EventHandler
public void onEntityDamage(EntityDamageEvent event) {
if (event.getEntity() instanceof Player) {
if (testObserverOrDead((Player) event.getEntity())) {
event.setCancelled(true);
}
}
}
@EventHandler
public void onPlayerConnect(PlayerLoginEvent event) {
if (Bukkit.getBanList(BanList.Type.NAME).isBanned(event.getPlayer().getName())) {
event.disallow(PlayerLoginEvent.Result.KICK_BANNED, Bukkit.getBanList(BanList.Type.NAME).getBanEntry(event.getPlayer().getName()).getReason());
} else if (Rank.whitelistBypass(event.getPlayer().getUniqueId())) {
event.allow();
}
}
@EventHandler
public void onHangingPlace(HangingPlaceEvent event) {
if (testObserverOrDead(event.getPlayer())) {
event.setCancelled(true);
}
}
@EventHandler
public void onHangingBreak(HangingBreakByEntityEvent event) {
if (event.getRemover() instanceof Player) {
if (testObserverOrDead((Player) event.getRemover())) {
event.setCancelled(true);
}
}
}
@EventHandler
public void PlayerInteractAtEntityEvent(PlayerInteractAtEntityEvent event) {
if (testObserverOrDead(event.getPlayer())) {
event.setCancelled(true);
}
}
@EventHandler
public void onEntityCombustEvent(EntityCombustByBlockEvent event) {
if (event.getEntity() instanceof Player && testObserver((Player)event.getEntity())){
event.getEntity().setFireTicks(0);
}
}
public static boolean testObserverOrDead(Player player) {
return testObserver(player) || testDead(player);
}
public static boolean testObserver(Player player) {
Optional<TeamModule> team = Teams.getTeamByPlayer(player);
return (team.isPresent() && team.get().isObserver() || !GameHandler.getGameHandler().getMatch().isRunning());
}
public static boolean testDead(Player player) {
return GameHandler.getGameHandler().getMatch().isRunning() && GameHandler.getGameHandler().getMatch().getModules().getModule(TitleRespawn.class).isDeadUUID(player.getUniqueId());
}
}