diff --git a/src/main/java/world/bentobox/bentobox/api/events/flags/InvincibleVistorFlagDamageRemovalEvent.java b/src/main/java/world/bentobox/bentobox/api/events/flags/InvincibleVistorFlagDamageRemovalEvent.java new file mode 100644 index 000000000..080f94e05 --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/api/events/flags/InvincibleVistorFlagDamageRemovalEvent.java @@ -0,0 +1,50 @@ +package world.bentobox.bentobox.api.events.flags; + +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; + +import world.bentobox.bentobox.api.events.BentoBoxEvent; + +/** + * This event is fired just before damage is prevented to visitors on an island, if that protection is provided. + * @author tastybento + * + */ +public class InvincibleVistorFlagDamageRemovalEvent extends BentoBoxEvent implements Cancellable { + private final Player player; + private final DamageCause cause; + private boolean cancel; + + /** + * This event is fired just before damage is prevented to visitors on an island, if that protection is provided. + * @param player player being protected + * @param cause damage cause + */ + public InvincibleVistorFlagDamageRemovalEvent(Player player, DamageCause cause) { + this.player = player; + this.cause = cause; + } + @Override + public boolean isCancelled() { + return cancel; + } + @Override + public void setCancelled(boolean cancel) { + this.cancel = cancel; + } + + /** + * @return the player + */ + public Player getPlayer() { + return player; + } + /** + * @return the cause + */ + public DamageCause getCause() { + return cause; + } +} + diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/InvincibleVisitorsListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/InvincibleVisitorsListener.java index 00e5e7b5e..35cdef4f0 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/InvincibleVisitorsListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/InvincibleVisitorsListener.java @@ -4,6 +4,7 @@ import java.util.Comparator; import java.util.Objects; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.World; @@ -18,6 +19,7 @@ import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.addons.GameModeAddon; +import world.bentobox.bentobox.api.events.flags.InvincibleVistorFlagDamageRemovalEvent; import world.bentobox.bentobox.api.flags.FlagListener; import world.bentobox.bentobox.api.panels.Panel; import world.bentobox.bentobox.api.panels.PanelItem; @@ -130,13 +132,21 @@ public void onVisitorGetDamage(EntityDamageEvent e) { World world = e.getEntity().getWorld(); if (!(e.getEntity() instanceof Player p) || !getIWM().inWorld(world) - || e.getEntity().hasMetadata("NPC") + || p.hasMetadata("NPC") || !getIWM().getIvSettings(world).contains(e.getCause().name()) - || getIslands().userIsOnIsland(world, User.getInstance(e.getEntity())) + || getIslands().userIsOnIsland(world, User.getInstance(p)) || PVPAllowed(p.getLocation()) ) { return; } + // Fire event + InvincibleVistorFlagDamageRemovalEvent event = new InvincibleVistorFlagDamageRemovalEvent(p, e.getCause()); + Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { + // Give others a chance to ignore the protection + return; + } + // Player is a visitor and should be protected from damage e.setCancelled(true); // Handle the void - teleport player back to island in a safe spot @@ -169,12 +179,12 @@ public void onVisitorTargeting(EntityTargetLivingEntityEvent e) World world = e.getEntity().getWorld(); if (!(e.getTarget() instanceof Player p) || - !this.getIWM().inWorld(world) || - e.getTarget().hasMetadata("NPC") || - this.getIslands().userIsOnIsland(world, User.getInstance(e.getTarget())) || - this.PVPAllowed(p.getLocation()) || - e.getReason() == EntityTargetEvent.TargetReason.TARGET_DIED || - !this.getIWM().getIvSettings(world).contains(DamageCause.ENTITY_ATTACK.name())) + !this.getIWM().inWorld(world) || + e.getTarget().hasMetadata("NPC") || + this.getIslands().userIsOnIsland(world, User.getInstance(e.getTarget())) || + this.PVPAllowed(p.getLocation()) || + e.getReason() == EntityTargetEvent.TargetReason.TARGET_DIED || + !this.getIWM().getIvSettings(world).contains(DamageCause.ENTITY_ATTACK.name())) { return; } @@ -182,5 +192,6 @@ public void onVisitorTargeting(EntityTargetLivingEntityEvent e) // Cancel targeting event. e.setCancelled(true); } + } diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/InvincibleVisitorsListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/InvincibleVisitorsListenerTest.java index 3dff93414..deaf38675 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/InvincibleVisitorsListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/InvincibleVisitorsListenerTest.java @@ -36,6 +36,7 @@ import org.bukkit.inventory.ItemFactory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.plugin.PluginManager; import org.bukkit.util.Vector; import org.eclipse.jdt.annotation.Nullable; import org.junit.After; @@ -51,6 +52,7 @@ import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.addons.GameModeAddon; +import world.bentobox.bentobox.api.events.flags.InvincibleVistorFlagDamageRemovalEvent; import world.bentobox.bentobox.api.flags.Flag; import world.bentobox.bentobox.api.panels.Panel; import world.bentobox.bentobox.api.panels.PanelItem; @@ -84,6 +86,8 @@ public class InvincibleVisitorsListenerTest { private Location location; @Mock private World world; + @Mock + private PluginManager pim; /** */ @@ -169,6 +173,7 @@ public void setUp() throws Exception { ItemMeta imeta = mock(ItemMeta.class); when(itemF.getItemMeta(any())).thenReturn(imeta); when(Bukkit.getItemFactory()).thenReturn(itemF); + when(Bukkit.getPluginManager()).thenReturn(pim); Inventory top = mock(Inventory.class); when(top.getSize()).thenReturn(9); @@ -279,6 +284,7 @@ public void testOnVisitorGetDamageNotVoid() { listener.onVisitorGetDamage(e); assertTrue(e.isCancelled()); verify(player, never()).setGameMode(eq(GameMode.SPECTATOR)); + verify(pim).callEvent(any(InvincibleVistorFlagDamageRemovalEvent.class)); } @Test @@ -297,6 +303,7 @@ public void testOnVisitorGetDamageVoidIslandHere() { // Player should be teleported to this island listener.onVisitorGetDamage(e); assertTrue(e.isCancelled()); + verify(pim).callEvent(any(InvincibleVistorFlagDamageRemovalEvent.class)); } @Test @@ -307,6 +314,7 @@ public void testOnVisitorGetDamageVoidNoIslandHerePlayerHasNoIsland() { // Player should die listener.onVisitorGetDamage(e); assertFalse(e.isCancelled()); + verify(pim).callEvent(any(InvincibleVistorFlagDamageRemovalEvent.class)); } @Test @@ -320,5 +328,6 @@ public void testOnVisitorGetDamageVoidPlayerHasIsland() { listener.onVisitorGetDamage(e); assertTrue(e.isCancelled()); verify(im).homeTeleportAsync(any(), eq(player)); + verify(pim).callEvent(any(InvincibleVistorFlagDamageRemovalEvent.class)); } }