package tc.oc.pgm.antigrief; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; import com.google.common.collect.Lists; import net.md_5.bungee.api.chat.TranslatableComponent; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerAttackEntityEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import tc.oc.commons.bukkit.channels.AdminChannel; import tc.oc.commons.bukkit.chat.ComponentRenderers; import tc.oc.commons.bukkit.chat.ListComponent; import tc.oc.commons.bukkit.chat.NameStyle; import tc.oc.commons.bukkit.event.ObserverKitApplyEvent; import tc.oc.commons.core.inject.Proxied; import tc.oc.commons.core.plugin.PluginFacet; import tc.oc.pgm.PGMTranslations; import tc.oc.pgm.match.MatchManager; import tc.oc.pgm.match.MatchPlayer; import tc.oc.pgm.match.ParticipantState; import tc.oc.pgm.tnt.TNTMatchModule; import tc.oc.pgm.tracker.EntityResolver; public class DefuseListener implements PluginFacet, Listener { public static final Material DEFUSE_ITEM = Material.SHEARS; public static final int DEFUSE_SLOT = 4; private final MatchManager mm; private final EntityResolver entityResolver; private final AdminChannel adminChannel; @Inject DefuseListener(MatchManager mm, @Proxied EntityResolver entityResolver, AdminChannel adminChannel) { this.mm = mm; this.entityResolver = entityResolver; this.adminChannel = adminChannel; } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void rightClickDefuse(final PlayerInteractEntityEvent event) { ItemStack hand = event.getPlayer().getItemInHand(); if(hand == null || hand.getType() != DEFUSE_ITEM) return; this.participantDefuse(event.getPlayer(), event.getRightClicked()); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void leftClickDefuse(final PlayerAttackEntityEvent event) { this.participantDefuse(event.getPlayer(), event.getLeftClicked()); } private void participantDefuse(Player player, Entity entity) { if(!AntiGrief.Defuse.enabled()) return; // check tnt if(!(entity instanceof TNTPrimed)) return; TNTMatchModule tntmm = mm.getMatch(player.getWorld()).getMatchModule(TNTMatchModule.class); if(tntmm != null && !tntmm.getProperties().friendlyDefuse) return; MatchPlayer clicker = this.mm.getPlayer(player); if(clicker == null || !clicker.canInteract()) return; // check water Block block = entity.getLocation().getBlock(); if(block != null && (block.getType() == Material.WATER || block.getType() == Material.STATIONARY_WATER)) { clicker.sendMessage(ChatColor.RED + PGMTranslations.t("defuse.water", clicker)); return; } // check owner MatchPlayer owner = this.mm.getPlayer(entityResolver.getOwner(entity)); if(owner == null || (owner != clicker && owner.getParty() == clicker.getParty())) { // cannot defuse own TNT // defuse TNT entity.remove(); if(owner != null) { this.notifyDefuse(clicker, entity, ChatColor.RED + PGMTranslations.t("defuse.player", clicker, owner.getDisplayName(clicker) + ChatColor.RED)); adminChannel.broadcast(clicker.getDisplayName() + ChatColor.WHITE + " defused " + owner.getDisplayName() + ChatColor.WHITE + "'s " + ChatColor.DARK_RED + "TNT"); } else { this.notifyDefuse(clicker, entity, ChatColor.RED + PGMTranslations.t("defuse.world", clicker)); } } } private void notifyDefuse(MatchPlayer clicker, Entity entity, String message) { clicker.sendMessage(message); for(Player viewer : Bukkit.getOnlinePlayers()) { viewer.playSound(entity.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 1, 1); } } @EventHandler(priority = EventPriority.HIGHEST) public void checkDefuse(final PlayerInteractEvent event) { if(!AntiGrief.Defuse.enabled()) return; ItemStack hand = event.getPlayer().getItemInHand(); if(hand == null || hand.getType() != DEFUSE_ITEM) return; MatchPlayer clicker = this.mm.getPlayer(event.getPlayer()); if(clicker != null && clicker.isObserving() && clicker.getBukkit().hasPermission("pgm.defuse")) { if(event.getAction() == Action.RIGHT_CLICK_AIR) { this.obsTntDefuse(clicker.getBukkit(), event.getPlayer().getLocation()); } else if(event.getAction() == Action.RIGHT_CLICK_BLOCK) { this.obsTntDefuse(clicker.getBukkit(), event.getClickedBlock().getLocation()); } } } private void obsTntDefuse(Player player, Location loc) { List<ParticipantState> owners = this.removeTnt(loc, 5.0); if(owners != null && !owners.isEmpty()) { ComponentRenderers.send( player, new TranslatableComponent( "defuse.player", new ListComponent( Lists.transform(owners, owner -> owner.getStyledName(NameStyle.COLOR)) ) ) ); } } // Original code borrowed from WorldEdit private List<ParticipantState> removeTnt(Location origin, double radius) { if(radius <= 0) return null; List<ParticipantState> owners = new ArrayList<>(); double radiusSq = radius * radius; for(Entity ent : origin.getWorld().getEntities()) { if(origin.distanceSquared(ent.getLocation()) > radiusSq) continue; if(ent instanceof TNTPrimed) { ParticipantState player = entityResolver.getOwner(ent); if(player != null) { owners.add(player); } ent.remove(); } } List<ParticipantState> uniqueOwners = new ArrayList<>(); for(ParticipantState player : owners) { if(!uniqueOwners.contains(player)) { uniqueOwners.add(player); } } return uniqueOwners; } @EventHandler public void giveKit(final ObserverKitApplyEvent event) { final MatchPlayer player = mm.getPlayer(event.getPlayer()); if(player == null) return; if(!player.isObservingType()) return; if(!player.getBukkit().hasPermission("pgm.defuse")) return; ItemStack shears = new ItemStack(DEFUSE_ITEM); // TODO: Update information if locale changes ItemMeta meta = shears.getItemMeta(); meta.addItemFlags(ItemFlag.values()); meta.setDisplayName(PGMTranslations.t("defuse.displayName", player)); meta.setLore(Lists.newArrayList(ChatColor.GRAY + PGMTranslations.t("defuse.tooltip", player))); shears.setItemMeta(meta); event.getPlayer().getInventory().setItem(DEFUSE_SLOT, shears); } }