/* * This file is part of HeavySpleef. * Copyright (c) 2014-2016 Matthias Werning * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.xaniox.heavyspleef.flag.defaults; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import de.xaniox.heavyspleef.core.HeavySpleef; import de.xaniox.heavyspleef.core.MetadatableItemStack; import de.xaniox.heavyspleef.core.SimpleBasicTask; import de.xaniox.heavyspleef.core.Unregister; import de.xaniox.heavyspleef.core.event.PlayerJoinGameEvent; import de.xaniox.heavyspleef.core.event.PlayerLeaveGameEvent; import de.xaniox.heavyspleef.core.event.Subscribe; import de.xaniox.heavyspleef.core.flag.BukkitListener; import de.xaniox.heavyspleef.core.flag.Flag; import de.xaniox.heavyspleef.core.flag.FlagInit; import de.xaniox.heavyspleef.core.flag.Inject; import de.xaniox.heavyspleef.core.game.Game; import de.xaniox.heavyspleef.core.game.GameManager; import de.xaniox.heavyspleef.core.i18n.Messages; import de.xaniox.heavyspleef.core.player.SpleefPlayer; import de.xaniox.heavyspleef.flag.presets.BaseFlag; import de.xaniox.inventoryguilib.GuiInventory; import de.xaniox.inventoryguilib.GuiInventorySlot; import org.bukkit.Material; import org.bukkit.SkullType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.SkullMeta; import org.bukkit.material.MaterialData; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @Flag(name = "tracking", parent = FlagSpectate.class) @BukkitListener public class FlagTrackingSpectate extends BaseFlag { private static final String TRACKER_KEY = "spectate_tracker"; private static final int ITEM_SLOT = 0; private static final int MAX_LINES = 6; private static TrackingTask task; private @Inject Game game; private GuiInventory trackerInventory; private Map<SpleefPlayer, SpleefPlayer> tracking; public FlagTrackingSpectate() { this.tracking = Maps.newHashMap(); } @FlagInit public static void startTrackingTask(HeavySpleef heavySpleef) { task = new TrackingTask(heavySpleef); task.start(); } @Unregister public static void cancelTrackingTask(HeavySpleef heavySpleef) { if (task != null && task.isRunning()) { task.cancel(); } task = null; } @Override public void getDescription(List<String> description) { description.add("Gives spectating players a tracking compass to teleport to ingame players"); } @Subscribe public void onSpectateEnter(FlagSpectate.SpectateEnteredEvent event) { Player bukkitPlayer = event.getPlayer().getBukkitPlayer(); addTrackingCompass(bukkitPlayer); } @Subscribe public void onUpdateSpectateItems(FlagSpectate.UpdateSpectateItemsEvent event) { Player bukkitPlayer = event.getPlayer().getBukkitPlayer(); addTrackingCompass(bukkitPlayer); } private void addTrackingCompass(Player player) { MetadatableItemStack compass = new MetadatableItemStack(Material.COMPASS); ItemMeta meta = compass.getItemMeta(); meta.setDisplayName(getI18N().getString(Messages.Player.TRACKER)); meta.setLore(Lists.newArrayList(getI18N().getString(Messages.Player.TRACKER_LORE))); compass.setItemMeta(meta); compass.setMetadata(TRACKER_KEY, null); Inventory inventory = player.getInventory(); inventory.setItem(ITEM_SLOT, compass); player.updateInventory(); } @Subscribe public void onSpectateLeave(FlagSpectate.SpectateLeaveEvent event) { Player player = event.getPlayer().getBukkitPlayer(); Inventory inventory = player.getInventory(); for (ItemStack stack : inventory.getContents()) { if (stack == null) { continue; } MetadatableItemStack metadatable = new MetadatableItemStack(stack); if (!metadatable.hasItemMeta() || !metadatable.getItemMeta().hasLore() || !metadatable.hasMetadata(TRACKER_KEY)) { continue; } inventory.remove(stack); } player.updateInventory(); tracking.remove(player); } @SuppressWarnings("deprecation") @Subscribe public void onPlayerJoinGame(PlayerJoinGameEvent event) { SpleefPlayer player = event.getPlayer(); GuiInventory trackerInventory = getTrackerInventory(); //Insert the player's head somewhere in the tracker inventory for (int y = 0; y < trackerInventory.getLines(); y++) { for (int x = 0; x < GuiInventory.SLOTS_PER_LINE; x++) { trackerInventory.getSlot(x, y); GuiInventorySlot slot = trackerInventory.getSlot(x, y); if (slot.getItem() != null) { continue; } MaterialData data = new MaterialData(Material.SKULL_ITEM, (byte)SkullType.PLAYER.ordinal()); ItemStack skull = data.toItemStack(1); SkullMeta meta = (SkullMeta) skull.getItemMeta(); meta.setDisplayName(getI18N().getVarString(Messages.Player.TRACKER_SKULL_TITLE) .setVariable("tracking", player.getDisplayName()) .toString()); meta.setOwner(player.getName()); skull.setItemMeta(meta); slot.setItem(skull); slot.setValue(player); break; } } trackerInventory.updateViews(); } @Subscribe public void onPlayerLeaveGame(PlayerLeaveGameEvent event) { SpleefPlayer player = event.getPlayer(); GuiInventory trackerInventory = getTrackerInventory(); GuiInventorySlot slot = trackerInventory.getSlotByValue(player); if (slot == null) { return; } slot.setItem((ItemStack)null); slot.setValue(null); //Shift all other tracked players left for (int y = slot.getY(); y < trackerInventory.getLines(); y++) { for (int x = slot.getX() + 1; x < GuiInventory.SLOTS_PER_LINE; x++) { GuiInventorySlot otherSlot = trackerInventory.getSlot(x, y); int shiftingX = x == 0 ? GuiInventory.SLOTS_PER_LINE - 1 : x; int shiftingY = x == 0 ? y - 1 : y; GuiInventorySlot shiftingSlot = trackerInventory.getSlot(shiftingX, shiftingY); shiftingSlot.setItem(otherSlot.getItem()); shiftingSlot.setValue(otherSlot.getValue()); otherSlot.setItem((ItemStack)null); otherSlot.setValue(null); } } trackerInventory.updateViews(); Iterator<Entry<SpleefPlayer, SpleefPlayer>> iterator = tracking.entrySet().iterator(); while (iterator.hasNext()) { Entry<SpleefPlayer, SpleefPlayer> entry = iterator.next(); if (entry.getValue() != player) { continue; } iterator.remove(); } } @EventHandler(priority = EventPriority.LOW) public void onPlayerInteract(PlayerInteractEvent event) { Action action = event.getAction(); if (action != Action.RIGHT_CLICK_AIR && action != Action.RIGHT_CLICK_BLOCK) { return; } SpleefPlayer player = getHeavySpleef().getSpleefPlayer(event.getPlayer()); FlagSpectate flag = (FlagSpectate) getParent(); if (!flag.isSpectating(player)) { return; } ItemStack clicked = player.getBukkitPlayer().getItemInHand(); if (clicked == null) { return; } MetadatableItemStack metadatable = new MetadatableItemStack(clicked); if (!metadatable.hasItemMeta() || !metadatable.getItemMeta().hasLore() || !metadatable.hasMetadata(TRACKER_KEY)) { return; } //Open inventory getTrackerInventory().open(player.getBukkitPlayer()); //Prevent the player from using the compass as a WorldEdit teleporter for example event.setCancelled(true); } private GuiInventory getTrackerInventory() { int lines = (int) Math.ceil(game.getPlayers().size() / (double)GuiInventory.SLOTS_PER_LINE); if (lines > MAX_LINES) { lines = MAX_LINES; } else if (lines <= 0) { lines = 1; } if (trackerInventory == null) { trackerInventory = new GuiInventory(getHeavySpleef().getPlugin(), lines, getI18N().getString(Messages.Player.TRACKER_INVENTORY_TITLE)) { @Override public void onClick(GuiClickEvent event) { event.setCancelled(true); if (!event.isUpperInventory()) { return; } SpleefPlayer player = getHeavySpleef().getSpleefPlayer(event.getPlayer()); GuiInventorySlot slot = event.getSlot(); SpleefPlayer to = (SpleefPlayer) slot.getValue(); if (to == null) { return; } player.teleport(to.getBukkitPlayer().getLocation()); player.getBukkitPlayer().setCompassTarget(to.getBukkitPlayer().getLocation()); tracking.put(player, to); player.sendMessage(getI18N().getVarString(Messages.Player.TRACKER_NOW_TRACKING) .setVariable("tracking", to.getDisplayName()) .toString()); } }; } else { if (lines != trackerInventory.getLines()) { trackerInventory.setLines(lines); } } return trackerInventory; } private static class TrackingTask extends SimpleBasicTask { private GameManager gameManager; public TrackingTask(HeavySpleef heavySpleef) { super(heavySpleef.getPlugin(), TaskType.SYNC_REPEATING_TASK, 20L, 20L); this.gameManager = heavySpleef.getGameManager(); } @Override public void run() { for (Game game : gameManager.getGames()) { if (!game.isFlagPresent(FlagTrackingSpectate.class)) { continue; } FlagTrackingSpectate flag = game.getFlag(FlagTrackingSpectate.class); Map<SpleefPlayer, SpleefPlayer> trackingMap = flag.tracking; for (Entry<SpleefPlayer, SpleefPlayer> entry : trackingMap.entrySet()) { Player tracker = entry.getKey().getBukkitPlayer(); Player tracking = entry.getValue().getBukkitPlayer(); tracker.setCompassTarget(tracking.getLocation()); } } } } }