Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;

import org.bukkit.Location;
import org.bukkit.Material;
Expand All @@ -17,7 +19,9 @@
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;

import world.bentobox.bentobox.api.flags.FlagListener;
import world.bentobox.bentobox.lists.Flags;
Expand All @@ -27,13 +31,24 @@
* @author tastybento
*/
public class ExplosionListener extends FlagListener {
/**
* The Sulfur Cube entity type (Minecraft 26.2), resolved at runtime so the code still
* compiles and runs on older API versions. {@code null} when absent.
*/
private static final EntityType SULFUR_CUBE = findFirstMatchingEnum(EntityType.class, "SULFUR_CUBE");

/**
* Contains {@link EntityType}s that generates an explosion.
* A Sulfur Cube with absorbed TNT explodes as itself, not as primed TNT, so it has to be
* included here for the TNT damage flags to apply.
* @since 1.5.0
*/
private static final List<EntityType> TNT_TYPES = List.of(
private static final List<EntityType> TNT_TYPES = Stream.of(
findFirstMatchingEnum(EntityType.class, "PRIMED_TNT", "TNT"),
findFirstMatchingEnum(EntityType.class, "MINECART_TNT", "TNT_MINECART"));
findFirstMatchingEnum(EntityType.class, "MINECART_TNT", "TNT_MINECART"),
SULFUR_CUBE)
.filter(Objects::nonNull)
.toList();

private static <T extends Enum<T>> T findFirstMatchingEnum(Class<T> enumClass, String... values) {
if (enumClass == null || values == null) {
Expand Down Expand Up @@ -87,6 +102,21 @@ public void onTNTPriming(PlayerInteractEvent e) {
}
}

/**
* Protect against priming a Sulfur Cube (with absorbed TNT) unless TNT priming is allowed.
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onSulfurCubePriming(PlayerInteractEntityEvent e) {
if (SULFUR_CUBE == null || e.getRightClicked().getType() != SULFUR_CUBE) {
return;
}
ItemStack item = e.getPlayer().getInventory().getItem(e.getHand());
if (item != null && PRIMING_ITEMS.contains(item.getType())) {
checkIsland(e, e.getPlayer(), e.getRightClicked().getLocation(), Flags.TNT_PRIMING);
}
}

/**
* Prevents TNT explosion from breaking blocks
* @param e - event
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.AfterEach;
Expand Down Expand Up @@ -164,6 +166,26 @@ void testOnExplosionWrongWorld() {
assertFalse(list.isEmpty());
}

@Test
void testOnSulfurCubeExplosion() {
List<Block> list = new ArrayList<>();
list.add(block);
EntityExplodeEvent e = getExplodeEvent(sulfurCube(), location, list);
listener.onExplosion(e);
assertTrue(e.isCancelled());
}

@Test
void testOnSulfurCubeExplosionAllowed() {
when(island.isAllowed(Flags.TNT_DAMAGE)).thenReturn(true);
List<Block> list = new ArrayList<>();
list.add(block);
EntityExplodeEvent e = getExplodeEvent(sulfurCube(), location, list);
listener.onExplosion(e);
assertFalse(e.isCancelled());
assertFalse(list.isEmpty());
}

@Test
void testOnTNTDamageInWorldTNTNotProjectile() {
// Block on fire
Expand Down Expand Up @@ -323,6 +345,23 @@ void testOnEntityExplosion() {
assertTrue(e.isCancelled());
}

@Test
void testOnSulfurCubeEntityExplosion() {
EntityDamageByEntityEvent e = new EntityDamageByEntityEvent(sulfurCube(), mockPlayer,
DamageCause.ENTITY_EXPLOSION, null, 20D);
listener.onExplosion(e);
assertTrue(e.isCancelled());
}

@Test
void testOnSulfurCubeEntityExplosionAllowed() {
when(island.isAllowed(Flags.TNT_DAMAGE)).thenReturn(true);
EntityDamageByEntityEvent e = new EntityDamageByEntityEvent(sulfurCube(), mockPlayer,
DamageCause.ENTITY_EXPLOSION, null, 20D);
listener.onExplosion(e);
assertFalse(e.isCancelled());
}

@Test
void testOnEntityExplosionOutsideIsland() {
Flags.WORLD_TNT_DAMAGE.setDefaultSetting(false);
Expand Down Expand Up @@ -354,4 +393,40 @@ void testOnEntityExplosionWrongWorld() {
assertFalse(e.isCancelled());
}

@Test
void testOnSulfurCubePrimingNotAllowed() {
ItemStack flintAndSteel = new ItemStack(Material.FLINT_AND_STEEL);
when(inv.getItem(EquipmentSlot.HAND)).thenReturn(flintAndSteel);
PlayerInteractEntityEvent e = new PlayerInteractEntityEvent(mockPlayer, sulfurCube(), EquipmentSlot.HAND);
listener.onSulfurCubePriming(e);
assertTrue(e.isCancelled());
}

@Test
void testOnSulfurCubePrimingAllowed() {
ItemStack flintAndSteel = new ItemStack(Material.FLINT_AND_STEEL);
when(island.isAllowed(any(), eq(Flags.TNT_PRIMING))).thenReturn(true);
when(inv.getItem(EquipmentSlot.HAND)).thenReturn(flintAndSteel);
PlayerInteractEntityEvent e = new PlayerInteractEntityEvent(mockPlayer, sulfurCube(), EquipmentSlot.HAND);
listener.onSulfurCubePriming(e);
assertFalse(e.isCancelled());
}

@Test
void testOnSulfurCubePrimingNonPrimingItem() {
ItemStack stone = new ItemStack(Material.STONE);
when(inv.getItem(EquipmentSlot.HAND)).thenReturn(stone);
PlayerInteractEntityEvent e = new PlayerInteractEntityEvent(mockPlayer, sulfurCube(), EquipmentSlot.HAND);
listener.onSulfurCubePriming(e);
assertFalse(e.isCancelled());
}

private Entity sulfurCube() {
Entity sulfurCube = mock(Entity.class);
when(sulfurCube.getType()).thenReturn(EntityType.SULFUR_CUBE);
when(sulfurCube.getWorld()).thenReturn(world);
when(sulfurCube.getLocation()).thenReturn(location);
return sulfurCube;
}

}
Loading