bentobox/src/main/java/world/bentobox/bentobox/listeners/flags/protection/TNTListener.java

156 lines
5.9 KiB
Java

package world.bentobox.bentobox.listeners.flags.protection;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import world.bentobox.bentobox.api.flags.FlagListener;
import world.bentobox.bentobox.lists.Flags;
/**
* Protects islands from visitors blowing things up
* @author tastybento
*/
public class TNTListener extends FlagListener {
/**
* Contains {@link EntityType}s that generates an explosion.
* @since 1.5.0
*/
private static final List<EntityType> TNT_TYPES = List.of(EntityType.PRIMED_TNT, EntityType.MINECART_TNT);
/**
* Contains {@link Material}s that can be used to prime a TNT.
* @since 1.5.0
*/
private static final List<Material> PRIMING_ITEMS = List.of(Material.FLINT_AND_STEEL, Material.FIRE_CHARGE);
/**
* Protect TNT from being set light by a fire arrow
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onTNTDamage(EntityChangeBlockEvent e) {
// Check world
if (!e.getBlock().getType().equals(Material.TNT) || !getIWM().inWorld(e.getBlock().getLocation())) {
return;
}
// Stop TNT from being damaged if it is being caused by a visitor with a flaming arrow
if (e.getEntity() instanceof Projectile projectile) {
// Find out who fired it
if (projectile.getShooter() instanceof Player shooter && projectile.getFireTicks() > 0
&& !checkIsland(e, shooter, e.getBlock().getLocation(), Flags.TNT_PRIMING)) {
// Remove the arrow
projectile.remove();
e.setCancelled(true);
}
}
}
/**
* Protect against priming of TNT unless TNT priming is allowed
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onTNTPriming(PlayerInteractEvent e) {
if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK)
&& e.getClickedBlock() != null
&& e.getClickedBlock().getType().equals(Material.TNT)
&& PRIMING_ITEMS.contains(e.getMaterial())) {
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.TNT_PRIMING);
}
}
/**
* Prevents TNT explosion from breaking blocks
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onExplosion(final EntityExplodeEvent e) {
// Check world and types
if (!getIWM().inWorld(e.getLocation()) || !TNT_TYPES.contains(e.getEntityType())) {
return;
}
if (protect(e.getLocation())) {
// This is protected as a whole, so just cancel the event
e.setCancelled(true);
} else {
// Remove any blocks from the explosion list if required
e.blockList().removeIf(b -> protect(b.getLocation()));
}
}
protected boolean protect(Location location) {
return getIslands().getProtectedIslandAt(location).map(i -> !i.isAllowed(Flags.TNT_DAMAGE))
.orElseGet(() -> !Flags.WORLD_TNT_DAMAGE.isSetForWorld(location.getWorld()));
}
/**
* Prevents TNT explosion from damaging entities.
* @param e event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onExplosion(final EntityDamageByEntityEvent e) {
// Check if this in world, an explosion, and TNT exploding
if (getIWM().inWorld(e.getEntity().getLocation())
&& e.getCause().equals(EntityDamageEvent.DamageCause.ENTITY_EXPLOSION)
&& TNT_TYPES.contains(e.getDamager().getType())) {
// Check if it is disallowed, then cancel it.
e.setCancelled(protect(e.getEntity().getLocation()));
}
}
protected boolean protectBlockExplode(Location location) {
return getIslands().getProtectedIslandAt(location).map(i -> !i.isAllowed(Flags.BLOCK_EXPLODE_DAMAGE))
.orElseGet(() -> !Flags.WORLD_BLOCK_EXPLODE_DAMAGE.isSetForWorld(location.getWorld()));
}
/**
* Prevents block explosion from breaking blocks
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onExplosion(final BlockExplodeEvent e) {
// Check world
if (!getIWM().inWorld(e.getBlock().getLocation())) {
return;
}
if (protectBlockExplode(e.getBlock().getLocation())) {
// This is protected as a whole, so just cancel the event
e.setCancelled(true);
} else {
// Remove any blocks from the explosion list if required
e.blockList().removeIf(b -> protectBlockExplode(b.getLocation()));
}
}
/**
* Prevents block explosion from damaging entities.
* @param e event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onExplosion(final EntityDamageEvent e) {
// Check if this in world and a block explosion
if (getIWM().inWorld(e.getEntity().getLocation())
&& e.getCause().equals(EntityDamageEvent.DamageCause.BLOCK_EXPLOSION)) {
// Check if it is disallowed, then cancel it.
e.setCancelled(protectBlockExplode(e.getEntity().getLocation()));
}
}
}