From 625bfa631b1ebcb478cae7767400a55d8845c580 Mon Sep 17 00:00:00 2001 From: tastybento Date: Mon, 16 Sep 2024 21:04:44 -0700 Subject: [PATCH 1/3] Change how creeper damage flag works. #2507 --- .../world/bentobox/bentobox/Settings.java | 22 +++++++++- .../flags/protection/ExplosionListener.java | 1 + .../flags/worldsettings/CreeperListener.java | 23 ++-------- .../bentobox/managers/IslandsManager.java | 3 +- .../worldsettings/CreeperListenerTest.java | 44 +++++++++++++++++++ .../bentobox/managers/IslandsManagerTest.java | 41 ++++++++++++++--- 6 files changed, 106 insertions(+), 28 deletions(-) create mode 100644 src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListenerTest.java diff --git a/src/main/java/world/bentobox/bentobox/Settings.java b/src/main/java/world/bentobox/bentobox/Settings.java index c149907b2..992aa0333 100644 --- a/src/main/java/world/bentobox/bentobox/Settings.java +++ b/src/main/java/world/bentobox/bentobox/Settings.java @@ -141,7 +141,6 @@ public class Settings implements ConfigObject { private Set fakePlayers = new HashSet<>(); /* PANELS */ - @ConfigComment("Toggle whether panels should be closed or not when the player clicks anywhere outside of the inventory view.") @ConfigEntry(path = "panel.close-on-click-outside") private boolean closePanelOnClickOutside = true; @@ -189,6 +188,13 @@ public class Settings implements ConfigObject { /* * Island */ + @ConfigComment("Override island distance mismatch checking. BentoBox normally refuses to run if") + @ConfigComment("the island distance in the gamemode config is different to the one stored in the database") + @ConfigComment("for safety. This overrides that check. You should never need this, and if you do not understand it") + @ConfigComment("keep it as false") + @ConfigEntry(path = "island.override-safety-check") + private boolean overrideSafetyCheck = false; + // Number of islands @ConfigComment("The default number of concurrent islands a player may have.") @ConfigComment("This may be overridden by individual game mode config settings.") @@ -1034,4 +1040,18 @@ public class Settings implements ConfigObject { this.hideUsedBlueprints = hideUsedBlueprints; } + /** + * @return the overrideSafetyCheck + */ + public boolean isOverrideSafetyCheck() { + return overrideSafetyCheck; + } + + /** + * @param overrideSafetyCheck the overrideSafetyCheck to set + */ + public void setOverrideSafetyCheck(boolean overrideSafetyCheck) { + this.overrideSafetyCheck = overrideSafetyCheck; + } + } diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/ExplosionListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/ExplosionListener.java index d000eea7f..ca332a19f 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/ExplosionListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/ExplosionListener.java @@ -20,6 +20,7 @@ import org.bukkit.event.player.PlayerInteractEvent; import com.google.common.base.Enums; import com.google.common.base.Optional; +import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.flags.FlagListener; import world.bentobox.bentobox.lists.Flags; diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListener.java index 7adf0d6d6..def31f71d 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListener.java @@ -13,6 +13,7 @@ import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; +import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.flags.FlagListener; import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.user.User; @@ -40,7 +41,8 @@ public class CreeperListener extends FlagListener { if (!Flags.CREEPER_DAMAGE.isSetForWorld(e.getLocation().getWorld())) { // If any were removed, then prevent damage too e.blockList().clear(); - e.setCancelled(true); + // Still allow player and mob damage + e.setCancelled(false); return; } // Check for griefing @@ -55,25 +57,6 @@ public class CreeperListener extends FlagListener { } } - - /** - * Prevent entities being damaged by explosion - * @param e - event - * @since 1.10.0 - */ - @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) - public void onExplosion(final EntityDamageByEntityEvent e) { - if (!e.getCause().equals(EntityDamageEvent.DamageCause.ENTITY_EXPLOSION) || !getIWM().inWorld(e.getEntity().getLocation()) - || !e.getDamager().getType().equals(EntityType.CREEPER)) { - return; - } - // If creeper damage is not allowed in world cancel the damage - if (!Flags.CREEPER_DAMAGE.isSetForWorld(e.getEntity().getWorld())) { - e.setCancelled(true); - } - } - - /** * Prevent creepers from igniting if they are not allowed to grief * @param e - event diff --git a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java index 7e594c111..e532d6a03 100644 --- a/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java +++ b/src/main/java/world/bentobox/bentobox/managers/IslandsManager.java @@ -1267,7 +1267,8 @@ public class IslandsManager { // These will be deleted later deletedIslands.add(island.getUniqueId()); } // Check island distance and if incorrect stop BentoBox - else if (island.getWorld() != null && plugin.getIWM().inWorld(island.getWorld()) + else if (!plugin.getSettings().isOverrideSafetyCheck() && island.getWorld() != null + && plugin.getIWM().inWorld(island.getWorld()) && island.getRange() != plugin.getIWM().getIslandDistance(island.getWorld())) { throw new IOException("Island distance mismatch!\n" + "World '" + island.getWorld().getName() + "' distance " + plugin.getIWM().getIslandDistance(island.getWorld()) + " != island range " diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListenerTest.java new file mode 100644 index 000000000..37b47d398 --- /dev/null +++ b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListenerTest.java @@ -0,0 +1,44 @@ +package world.bentobox.bentobox.listeners.flags.worldsettings; + +import static org.junit.Assert.*; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * + */ +public class CreeperListenerTest { + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}. + */ + @Test + public void testOnExplosion() { + fail("Not yet implemented"); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onPlayerInteractEntity(org.bukkit.event.player.PlayerInteractEntityEvent)}. + */ + @Test + public void testOnPlayerInteractEntity() { + fail("Not yet implemented"); + } + +} diff --git a/src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java b/src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java index fa84ccec0..fc2967a0d 100644 --- a/src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java +++ b/src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java @@ -153,6 +153,8 @@ public class IslandsManagerTest extends AbstractCommonSetup { // Class under test IslandsManager im; + private Settings settings; + @SuppressWarnings("unchecked") @BeforeClass public static void beforeClass() throws IllegalAccessException, InvocationTargetException, IntrospectionException { @@ -187,12 +189,12 @@ public class IslandsManagerTest extends AbstractCommonSetup { when(world.getEnvironment()).thenReturn(World.Environment.NORMAL); when(iwm.inWorld(any(World.class))).thenReturn(true); when(iwm.inWorld(any(Location.class))).thenReturn(true); + when(iwm.getIslandDistance(any())).thenReturn(25); when(plugin.getIWM()).thenReturn(iwm); // Settings - Settings s = mock(Settings.class); - when(plugin.getSettings()).thenReturn(s); - when(s.getDatabaseType()).thenReturn(DatabaseType.JSON); + settings = new Settings(); + when(plugin.getSettings()).thenReturn(settings); // World when(world.getEnvironment()).thenReturn(World.Environment.NORMAL); @@ -827,14 +829,41 @@ public class IslandsManagerTest extends AbstractCommonSetup { /** * Test method for * {@link world.bentobox.bentobox.managers.IslandsManager#load()}. + * @throws IOException + * @throws IntrospectionException + * @throws NoSuchMethodException + * @throws ClassNotFoundException + * @throws InvocationTargetException + * @throws IllegalAccessException + * @throws InstantiationException */ @Test - public void testLoad() { - // - // im.load(); + public void testLoad() throws IOException, InstantiationException, IllegalAccessException, + InvocationTargetException, ClassNotFoundException, NoSuchMethodException, IntrospectionException { + when(island.getRange()).thenReturn(100); + when(h.loadObjects()).thenReturn(List.of(island)); + try { + im.load(); + } catch (IOException e) { + assertEquals("Island distance mismatch!\n" + "World 'world' distance 25 != island range 100!\n" + + "Island ID in database is null.\n" + + "Island distance in config.yml cannot be changed mid-game! Fix config.yml or clean database.", + e.getMessage()); + } } + @Test + public void testLoadNoDistanceCheck() throws IOException, InstantiationException, IllegalAccessException, + InvocationTargetException, ClassNotFoundException, NoSuchMethodException, IntrospectionException { + settings.setOverrideSafetyCheck(true); + when(island.getUniqueId()).thenReturn(UUID.randomUUID().toString()); + when(island.getRange()).thenReturn(100); + when(h.loadObjects()).thenReturn(List.of(island)); + im.load(); + // No exception should be thrown + } + /** * Test method for * {@link world.bentobox.bentobox.managers.IslandsManager#locationIsOnIsland(org.bukkit.entity.Player, org.bukkit.Location)}. From 5a4cbcce250ab70cef325035a6791758007d94cf Mon Sep 17 00:00:00 2001 From: tastybento Date: Mon, 16 Sep 2024 21:23:45 -0700 Subject: [PATCH 2/3] Add some tests --- .../flags/worldsettings/CreeperListener.java | 5 +- .../worldsettings/CreeperListenerTest.java | 102 +++++++++++++++++- 2 files changed, 98 insertions(+), 9 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListener.java index def31f71d..6ea941017 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListener.java @@ -8,12 +8,9 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; -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 world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.flags.FlagListener; import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.user.User; @@ -43,8 +40,8 @@ public class CreeperListener extends FlagListener { e.blockList().clear(); // Still allow player and mob damage e.setCancelled(false); - return; } + // Check for griefing Creeper creeper = (Creeper)e.getEntity(); if (!Flags.CREEPER_GRIEFING.isSetForWorld(e.getLocation().getWorld()) diff --git a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListenerTest.java index 37b47d398..2733fe692 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListenerTest.java @@ -1,21 +1,50 @@ package world.bentobox.bentobox.listeners.flags.worldsettings; -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import java.util.ArrayList; +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.entity.Creeper; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.EntityExplodeEvent; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.listeners.flags.AbstractCommonSetup; +import world.bentobox.bentobox.lists.Flags; +import world.bentobox.bentobox.util.Util; /** * */ -public class CreeperListenerTest { +@RunWith(PowerMockRunner.class) +@PrepareForTest({ Bukkit.class, BentoBox.class, Flags.class, Util.class }) +public class CreeperListenerTest extends AbstractCommonSetup { + + private CreeperListener cl; /** * @throws java.lang.Exception */ @Before public void setUp() throws Exception { + super.setUp(); + + cl = new CreeperListener(); } /** @@ -23,14 +52,77 @@ public class CreeperListenerTest { */ @After public void tearDown() throws Exception { + User.clearUsers(); + Mockito.framework().clearInlineMocks(); } /** * Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}. */ @Test - public void testOnExplosion() { - fail("Not yet implemented"); + public void testOnExplosionNotCreeper() { + List list = new ArrayList<>(); + Entity entity = mock(Entity.class); + when(entity.getType()).thenReturn(EntityType.TNT); + when(iwm.inWorld(location)).thenReturn(true); + EntityExplodeEvent event = new EntityExplodeEvent(entity, location, list, 0); + cl.onExplosion(event); + assertFalse(event.isCancelled()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}. + */ + @Test + public void testOnExplosionNotInWorld() { + List list = new ArrayList<>(); + Entity entity = mock(Entity.class); + when(entity.getLocation()).thenReturn(location); + when(entity.getType()).thenReturn(EntityType.CREEPER); + when(iwm.inWorld(location)).thenReturn(false); + EntityExplodeEvent event = new EntityExplodeEvent(entity, location, list, 0); + cl.onExplosion(event); + assertFalse(event.isCancelled()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}. + */ + @Test + public void testOnExplosionCreeperInWorldDamageOK() { + List list = new ArrayList<>(); + list.add(mock(Block.class)); + list.add(mock(Block.class)); + list.add(mock(Block.class)); + Creeper entity = mock(Creeper.class); + when(entity.getLocation()).thenReturn(location); + when(entity.getType()).thenReturn(EntityType.CREEPER); + when(iwm.inWorld(location)).thenReturn(true); + EntityExplodeEvent event = new EntityExplodeEvent(entity, location, list, 0); + cl.onExplosion(event); + assertFalse(event.isCancelled()); + assertFalse(event.blockList().isEmpty()); // No clearing of block list + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}. + */ + @Test + public void testOnExplosionCreeperInWorldDamageNOK() { + Flags.CREEPER_DAMAGE.setSetting(world, false); + List list = new ArrayList<>(); + list.add(mock(Block.class)); + list.add(mock(Block.class)); + list.add(mock(Block.class)); + Creeper entity = mock(Creeper.class); + when(location.getWorld()).thenReturn(world); + when(entity.getLocation()).thenReturn(location); + when(entity.getType()).thenReturn(EntityType.CREEPER); + when(iwm.inWorld(location)).thenReturn(true); + EntityExplodeEvent event = new EntityExplodeEvent(entity, location, list, 0); + cl.onExplosion(event); + assertFalse(event.isCancelled()); + assertTrue(event.blockList().isEmpty()); // No clearing of block list } /** @@ -38,7 +130,7 @@ public class CreeperListenerTest { */ @Test public void testOnPlayerInteractEntity() { - fail("Not yet implemented"); + //TODO } } From 4876064a46925c58097171d8d040d25572d69d23 Mon Sep 17 00:00:00 2001 From: tastybento Date: Mon, 16 Sep 2024 21:26:25 -0700 Subject: [PATCH 3/3] Remove unused import --- .../bentobox/listeners/flags/protection/ExplosionListener.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/ExplosionListener.java b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/ExplosionListener.java index ca332a19f..d000eea7f 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/flags/protection/ExplosionListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/flags/protection/ExplosionListener.java @@ -20,7 +20,6 @@ import org.bukkit.event.player.PlayerInteractEvent; import com.google.common.base.Enums; import com.google.common.base.Optional; -import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.flags.FlagListener; import world.bentobox.bentobox.lists.Flags;