Skip to content

Commit e90755d

Browse files
authored
Merge pull request #2508 from BentoBoxWorld/2507_Allow_creepers_to_hurt_but_not_destroy_blocks
Change how creeper damage flag works. #2507
2 parents 060e700 + 4876064 commit e90755d

File tree

5 files changed

+197
-31
lines changed

5 files changed

+197
-31
lines changed

src/main/java/world/bentobox/bentobox/Settings.java

+21-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,6 @@ public class Settings implements ConfigObject {
141141
private Set<String> fakePlayers = new HashSet<>();
142142

143143
/* PANELS */
144-
145144
@ConfigComment("Toggle whether panels should be closed or not when the player clicks anywhere outside of the inventory view.")
146145
@ConfigEntry(path = "panel.close-on-click-outside")
147146
private boolean closePanelOnClickOutside = true;
@@ -189,6 +188,13 @@ public class Settings implements ConfigObject {
189188
/*
190189
* Island
191190
*/
191+
@ConfigComment("Override island distance mismatch checking. BentoBox normally refuses to run if")
192+
@ConfigComment("the island distance in the gamemode config is different to the one stored in the database")
193+
@ConfigComment("for safety. This overrides that check. You should never need this, and if you do not understand it")
194+
@ConfigComment("keep it as false")
195+
@ConfigEntry(path = "island.override-safety-check")
196+
private boolean overrideSafetyCheck = false;
197+
192198
// Number of islands
193199
@ConfigComment("The default number of concurrent islands a player may have.")
194200
@ConfigComment("This may be overridden by individual game mode config settings.")
@@ -1034,4 +1040,18 @@ public void setHideUsedBlueprints(boolean hideUsedBlueprints) {
10341040
this.hideUsedBlueprints = hideUsedBlueprints;
10351041
}
10361042

1043+
/**
1044+
* @return the overrideSafetyCheck
1045+
*/
1046+
public boolean isOverrideSafetyCheck() {
1047+
return overrideSafetyCheck;
1048+
}
1049+
1050+
/**
1051+
* @param overrideSafetyCheck the overrideSafetyCheck to set
1052+
*/
1053+
public void setOverrideSafetyCheck(boolean overrideSafetyCheck) {
1054+
this.overrideSafetyCheck = overrideSafetyCheck;
1055+
}
1056+
10371057
}

src/main/java/world/bentobox/bentobox/listeners/flags/worldsettings/CreeperListener.java

+3-23
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
import org.bukkit.entity.Player;
99
import org.bukkit.event.EventHandler;
1010
import org.bukkit.event.EventPriority;
11-
import org.bukkit.event.entity.EntityDamageByEntityEvent;
12-
import org.bukkit.event.entity.EntityDamageEvent;
1311
import org.bukkit.event.entity.EntityExplodeEvent;
1412
import org.bukkit.event.player.PlayerInteractEntityEvent;
1513

@@ -40,9 +38,10 @@ public void onExplosion(final EntityExplodeEvent e) {
4038
if (!Flags.CREEPER_DAMAGE.isSetForWorld(e.getLocation().getWorld())) {
4139
// If any were removed, then prevent damage too
4240
e.blockList().clear();
43-
e.setCancelled(true);
44-
return;
41+
// Still allow player and mob damage
42+
e.setCancelled(false);
4543
}
44+
4645
// Check for griefing
4746
Creeper creeper = (Creeper)e.getEntity();
4847
if (!Flags.CREEPER_GRIEFING.isSetForWorld(e.getLocation().getWorld())
@@ -55,25 +54,6 @@ public void onExplosion(final EntityExplodeEvent e) {
5554
}
5655
}
5756

58-
59-
/**
60-
* Prevent entities being damaged by explosion
61-
* @param e - event
62-
* @since 1.10.0
63-
*/
64-
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
65-
public void onExplosion(final EntityDamageByEntityEvent e) {
66-
if (!e.getCause().equals(EntityDamageEvent.DamageCause.ENTITY_EXPLOSION) || !getIWM().inWorld(e.getEntity().getLocation())
67-
|| !e.getDamager().getType().equals(EntityType.CREEPER)) {
68-
return;
69-
}
70-
// If creeper damage is not allowed in world cancel the damage
71-
if (!Flags.CREEPER_DAMAGE.isSetForWorld(e.getEntity().getWorld())) {
72-
e.setCancelled(true);
73-
}
74-
}
75-
76-
7757
/**
7858
* Prevent creepers from igniting if they are not allowed to grief
7959
* @param e - event

src/main/java/world/bentobox/bentobox/managers/IslandsManager.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1267,7 +1267,8 @@ public void load() throws IOException {
12671267
// These will be deleted later
12681268
deletedIslands.add(island.getUniqueId());
12691269
} // Check island distance and if incorrect stop BentoBox
1270-
else if (island.getWorld() != null && plugin.getIWM().inWorld(island.getWorld())
1270+
else if (!plugin.getSettings().isOverrideSafetyCheck() && island.getWorld() != null
1271+
&& plugin.getIWM().inWorld(island.getWorld())
12711272
&& island.getRange() != plugin.getIWM().getIslandDistance(island.getWorld())) {
12721273
throw new IOException("Island distance mismatch!\n" + "World '" + island.getWorld().getName()
12731274
+ "' distance " + plugin.getIWM().getIslandDistance(island.getWorld()) + " != island range "
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package world.bentobox.bentobox.listeners.flags.worldsettings;
2+
3+
import static org.junit.Assert.assertFalse;
4+
import static org.junit.Assert.assertTrue;
5+
import static org.mockito.Mockito.mock;
6+
import static org.mockito.Mockito.when;
7+
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
11+
import org.bukkit.Bukkit;
12+
import org.bukkit.block.Block;
13+
import org.bukkit.entity.Creeper;
14+
import org.bukkit.entity.Entity;
15+
import org.bukkit.entity.EntityType;
16+
import org.bukkit.event.entity.EntityExplodeEvent;
17+
import org.junit.After;
18+
import org.junit.Before;
19+
import org.junit.Test;
20+
import org.junit.runner.RunWith;
21+
import org.mockito.Mockito;
22+
import org.powermock.core.classloader.annotations.PrepareForTest;
23+
import org.powermock.modules.junit4.PowerMockRunner;
24+
25+
import world.bentobox.bentobox.BentoBox;
26+
import world.bentobox.bentobox.api.user.User;
27+
import world.bentobox.bentobox.listeners.flags.AbstractCommonSetup;
28+
import world.bentobox.bentobox.lists.Flags;
29+
import world.bentobox.bentobox.util.Util;
30+
31+
/**
32+
*
33+
*/
34+
@RunWith(PowerMockRunner.class)
35+
@PrepareForTest({ Bukkit.class, BentoBox.class, Flags.class, Util.class })
36+
public class CreeperListenerTest extends AbstractCommonSetup {
37+
38+
private CreeperListener cl;
39+
40+
/**
41+
* @throws java.lang.Exception
42+
*/
43+
@Before
44+
public void setUp() throws Exception {
45+
super.setUp();
46+
47+
cl = new CreeperListener();
48+
}
49+
50+
/**
51+
* @throws java.lang.Exception
52+
*/
53+
@After
54+
public void tearDown() throws Exception {
55+
User.clearUsers();
56+
Mockito.framework().clearInlineMocks();
57+
}
58+
59+
/**
60+
* Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}.
61+
*/
62+
@Test
63+
public void testOnExplosionNotCreeper() {
64+
List<Block> list = new ArrayList<>();
65+
Entity entity = mock(Entity.class);
66+
when(entity.getType()).thenReturn(EntityType.TNT);
67+
when(iwm.inWorld(location)).thenReturn(true);
68+
EntityExplodeEvent event = new EntityExplodeEvent(entity, location, list, 0);
69+
cl.onExplosion(event);
70+
assertFalse(event.isCancelled());
71+
}
72+
73+
/**
74+
* Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}.
75+
*/
76+
@Test
77+
public void testOnExplosionNotInWorld() {
78+
List<Block> list = new ArrayList<>();
79+
Entity entity = mock(Entity.class);
80+
when(entity.getLocation()).thenReturn(location);
81+
when(entity.getType()).thenReturn(EntityType.CREEPER);
82+
when(iwm.inWorld(location)).thenReturn(false);
83+
EntityExplodeEvent event = new EntityExplodeEvent(entity, location, list, 0);
84+
cl.onExplosion(event);
85+
assertFalse(event.isCancelled());
86+
}
87+
88+
/**
89+
* Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}.
90+
*/
91+
@Test
92+
public void testOnExplosionCreeperInWorldDamageOK() {
93+
List<Block> list = new ArrayList<>();
94+
list.add(mock(Block.class));
95+
list.add(mock(Block.class));
96+
list.add(mock(Block.class));
97+
Creeper entity = mock(Creeper.class);
98+
when(entity.getLocation()).thenReturn(location);
99+
when(entity.getType()).thenReturn(EntityType.CREEPER);
100+
when(iwm.inWorld(location)).thenReturn(true);
101+
EntityExplodeEvent event = new EntityExplodeEvent(entity, location, list, 0);
102+
cl.onExplosion(event);
103+
assertFalse(event.isCancelled());
104+
assertFalse(event.blockList().isEmpty()); // No clearing of block list
105+
}
106+
107+
/**
108+
* Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}.
109+
*/
110+
@Test
111+
public void testOnExplosionCreeperInWorldDamageNOK() {
112+
Flags.CREEPER_DAMAGE.setSetting(world, false);
113+
List<Block> list = new ArrayList<>();
114+
list.add(mock(Block.class));
115+
list.add(mock(Block.class));
116+
list.add(mock(Block.class));
117+
Creeper entity = mock(Creeper.class);
118+
when(location.getWorld()).thenReturn(world);
119+
when(entity.getLocation()).thenReturn(location);
120+
when(entity.getType()).thenReturn(EntityType.CREEPER);
121+
when(iwm.inWorld(location)).thenReturn(true);
122+
EntityExplodeEvent event = new EntityExplodeEvent(entity, location, list, 0);
123+
cl.onExplosion(event);
124+
assertFalse(event.isCancelled());
125+
assertTrue(event.blockList().isEmpty()); // No clearing of block list
126+
}
127+
128+
/**
129+
* Test method for {@link world.bentobox.bentobox.listeners.flags.worldsettings.CreeperListener#onPlayerInteractEntity(org.bukkit.event.player.PlayerInteractEntityEvent)}.
130+
*/
131+
@Test
132+
public void testOnPlayerInteractEntity() {
133+
//TODO
134+
}
135+
136+
}

src/test/java/world/bentobox/bentobox/managers/IslandsManagerTest.java

+35-6
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ public class IslandsManagerTest extends AbstractCommonSetup {
153153
// Class under test
154154
IslandsManager im;
155155

156+
private Settings settings;
157+
156158
@SuppressWarnings("unchecked")
157159
@BeforeClass
158160
public static void beforeClass() throws IllegalAccessException, InvocationTargetException, IntrospectionException {
@@ -187,12 +189,12 @@ public void setUp() throws Exception {
187189
when(world.getEnvironment()).thenReturn(World.Environment.NORMAL);
188190
when(iwm.inWorld(any(World.class))).thenReturn(true);
189191
when(iwm.inWorld(any(Location.class))).thenReturn(true);
192+
when(iwm.getIslandDistance(any())).thenReturn(25);
190193
when(plugin.getIWM()).thenReturn(iwm);
191194

192195
// Settings
193-
Settings s = mock(Settings.class);
194-
when(plugin.getSettings()).thenReturn(s);
195-
when(s.getDatabaseType()).thenReturn(DatabaseType.JSON);
196+
settings = new Settings();
197+
when(plugin.getSettings()).thenReturn(settings);
196198

197199
// World
198200
when(world.getEnvironment()).thenReturn(World.Environment.NORMAL);
@@ -827,12 +829,39 @@ public void testIsAtSpawn() {
827829
/**
828830
* Test method for
829831
* {@link world.bentobox.bentobox.managers.IslandsManager#load()}.
832+
* @throws IOException
833+
* @throws IntrospectionException
834+
* @throws NoSuchMethodException
835+
* @throws ClassNotFoundException
836+
* @throws InvocationTargetException
837+
* @throws IllegalAccessException
838+
* @throws InstantiationException
830839
*/
831840
@Test
832-
public void testLoad() {
833-
//
834-
// im.load();
841+
public void testLoad() throws IOException, InstantiationException, IllegalAccessException,
842+
InvocationTargetException, ClassNotFoundException, NoSuchMethodException, IntrospectionException {
843+
when(island.getRange()).thenReturn(100);
844+
when(h.loadObjects()).thenReturn(List.of(island));
845+
try {
846+
im.load();
847+
} catch (IOException e) {
848+
assertEquals("Island distance mismatch!\n" + "World 'world' distance 25 != island range 100!\n"
849+
+ "Island ID in database is null.\n"
850+
+ "Island distance in config.yml cannot be changed mid-game! Fix config.yml or clean database.",
851+
e.getMessage());
852+
}
853+
854+
}
835855

856+
@Test
857+
public void testLoadNoDistanceCheck() throws IOException, InstantiationException, IllegalAccessException,
858+
InvocationTargetException, ClassNotFoundException, NoSuchMethodException, IntrospectionException {
859+
settings.setOverrideSafetyCheck(true);
860+
when(island.getUniqueId()).thenReturn(UUID.randomUUID().toString());
861+
when(island.getRange()).thenReturn(100);
862+
when(h.loadObjects()).thenReturn(List.of(island));
863+
im.load();
864+
// No exception should be thrown
836865
}
837866

838867
/**

0 commit comments

Comments
 (0)