Extracted standard nether/end spawns protection into its own listener

It was previously handled in the NetherPortals listener
This commit is contained in:
Florian CUNY 2019-02-16 11:09:34 +01:00
parent 5d7a7a0363
commit a364128c5e
4 changed files with 143 additions and 391 deletions

View File

@ -26,6 +26,7 @@ import world.bentobox.bentobox.listeners.JoinLeaveListener;
import world.bentobox.bentobox.listeners.NetherPortals;
import world.bentobox.bentobox.listeners.PanelListenerManager;
import world.bentobox.bentobox.listeners.NetherTreesListener;
import world.bentobox.bentobox.listeners.StandardSpawnProtectionListener;
import world.bentobox.bentobox.managers.AddonsManager;
import world.bentobox.bentobox.managers.CommandsManager;
import world.bentobox.bentobox.managers.FlagsManager;
@ -204,6 +205,8 @@ public class BentoBox extends JavaPlugin {
manager.registerEvents(new JoinLeaveListener(this), this);
// Panel listener manager
manager.registerEvents(new PanelListenerManager(), this);
// Standard Nether/End spawns protection
manager.registerEvents(new StandardSpawnProtectionListener(this), this);
// Nether portals
manager.registerEvents(new NetherPortals(this), this);
// Nether trees conversion

View File

@ -30,77 +30,13 @@ import world.bentobox.bentobox.util.Util;
import world.bentobox.bentobox.util.teleport.SafeSpotTeleport;
public class NetherPortals implements Listener {
private static final String SPAWN_PROTECTED = "protection.spawn-protected";
private final BentoBox plugin;
public NetherPortals(@NonNull BentoBox plugin) {
this.plugin = plugin;
}
/**
* Function to check proximity to nether or end spawn location.
* Used when playing with the standard nether or end.
*
* @param location - the location
* @return true if in the spawn area, false if not
*/
private boolean atSpawn(Location location) {
Vector p = location.toVector().multiply(new Vector(1, 0, 1));
Vector spawn = location.getWorld().getSpawnLocation().toVector().multiply(new Vector(1, 0, 1));
int radiusSquared = plugin.getIWM().getNetherSpawnRadius(location.getWorld()) * plugin.getIWM().getNetherSpawnRadius(location.getWorld());
return (spawn.distanceSquared(p) < radiusSquared);
}
/**
* If the player is not in the standard nether or standard end or op, do nothing.
* Used to protect the standard spawn for nether or end
* @param player - the player
* @return true if nothing needs to be done
*/
private boolean noAction(Player player) {
if (player.isOp()
|| player.getWorld().getEnvironment().equals(Environment.NORMAL)
|| !plugin.getIWM().inWorld(player.getLocation())) {
return true;
}
// Player is in an island world and in a nether or end
return (player.getWorld().getEnvironment().equals(Environment.NETHER) && plugin.getIWM().isNetherIslands(player.getWorld()))
|| (player.getWorld().getEnvironment().equals(Environment.THE_END) && plugin.getIWM().isEndIslands(player.getWorld()));
}
/**
* Prevents blocks from being broken
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent e) {
if (noAction(e.getPlayer())) {
return;
}
if (atSpawn(e.getBlock().getLocation())) {
User user = User.getInstance(e.getPlayer());
user.sendMessage(SPAWN_PROTECTED, TextVariables.DESCRIPTION, user.getTranslation(Flags.BREAK_BLOCKS.getHintReference()));
e.setCancelled(true);
}
}
/**
* Protects standard nether or end spawn from bucket abuse
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBucketEmpty(PlayerBucketEmptyEvent e) {
if (noAction(e.getPlayer())) {
return;
}
if (atSpawn(e.getBlockClicked().getLocation())) {
User user = User.getInstance(e.getPlayer());
user.sendMessage(SPAWN_PROTECTED, TextVariables.DESCRIPTION, user.getTranslation(Flags.BUCKET.getHintReference()));
e.setCancelled(true);
}
}
/**
* Handle end portals
* @param e - event
@ -148,28 +84,6 @@ public class NetherPortals implements Listener {
}
}
/**
* Prevent standard nether or end spawns from being blown up
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public boolean onExplosion(EntityExplodeEvent e) {
if (!plugin.getIWM().inWorld(e.getLocation())
|| plugin.getIWM().isIslandNether(e.getLocation().getWorld())
|| plugin.getIWM().isIslandEnd(e.getLocation().getWorld())) {
// Not used in island worlds
return false;
}
// Find out what is exploding
Entity expl = e.getEntity();
if (expl == null) {
return false;
}
e.blockList().removeIf(b -> atSpawn(b.getLocation()));
return true;
}
/**
* When returning from the standard nether, teleport to the player's island
* @param e
@ -241,21 +155,4 @@ public class NetherPortals implements Listener {
.build();
return true;
}
/**
* Prevents placing of blocks at standard nether or end spawns
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onPlayerBlockPlace(BlockPlaceEvent e) {
if (noAction(e.getPlayer())) {
return;
}
if (atSpawn(e.getBlock().getLocation())) {
User user = User.getInstance(e.getPlayer());
user.sendMessage(SPAWN_PROTECTED, TextVariables.DESCRIPTION, user.getTranslation(Flags.PLACE_BLOCKS.getHintReference()));
e.setCancelled(true);
}
}
}

View File

@ -0,0 +1,139 @@
package world.bentobox.bentobox.listeners;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.player.PlayerBucketEmptyEvent;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.lists.Flags;
/**
* Handles protection of the standard Nether and/or End spawns.
*
* @author tastybento
*/
public class StandardSpawnProtectionListener implements Listener {
private static final String SPAWN_PROTECTED = "protection.spawn-protected";
private final BentoBox plugin;
public StandardSpawnProtectionListener(@NonNull BentoBox plugin) {
this.plugin = plugin;
}
/**
* Prevents placing blocks at standard nether or end spawns.
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent e) {
if (noAction(e.getPlayer())) {
return;
}
if (atSpawn(e.getBlock().getLocation())) {
User user = User.getInstance(e.getPlayer());
user.sendMessage(SPAWN_PROTECTED, TextVariables.DESCRIPTION, user.getTranslation(Flags.PLACE_BLOCKS.getHintReference()));
e.setCancelled(true);
}
}
/**
* Prevents blocks from being broken.
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent e) {
if (noAction(e.getPlayer())) {
return;
}
if (atSpawn(e.getBlock().getLocation())) {
User user = User.getInstance(e.getPlayer());
user.sendMessage(SPAWN_PROTECTED, TextVariables.DESCRIPTION, user.getTranslation(Flags.BREAK_BLOCKS.getHintReference()));
e.setCancelled(true);
}
}
/**
* Prevent standard nether or end spawns from being blown up.
*
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public boolean onExplosion(EntityExplodeEvent e) {
if (!plugin.getIWM().inWorld(e.getLocation())
|| plugin.getIWM().isIslandNether(e.getLocation().getWorld())
|| plugin.getIWM().isIslandEnd(e.getLocation().getWorld())) {
// Not used in island worlds
return false;
}
// Find out what is exploding
Entity expl = e.getEntity();
if (expl == null) {
return false;
}
e.blockList().removeIf(b -> atSpawn(b.getLocation()));
return true;
}
/**
* Protects standard nether or end spawn from bucket abuse.
* @param e - event
*/
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBucketEmpty(PlayerBucketEmptyEvent e) {
if (noAction(e.getPlayer())) {
return;
}
if (atSpawn(e.getBlockClicked().getLocation())) {
User user = User.getInstance(e.getPlayer());
user.sendMessage(SPAWN_PROTECTED, TextVariables.DESCRIPTION, user.getTranslation(Flags.BUCKET.getHintReference()));
e.setCancelled(true);
}
}
/**
* Check proximity to nether or end spawn location.
* Used when playing with the standard nether or end.
*
* @param location - the location
* @return true if in the spawn area, false if not
*/
private boolean atSpawn(@NonNull Location location) {
Vector p = location.toVector().multiply(new Vector(1, 0, 1));
Vector spawn = location.getWorld().getSpawnLocation().toVector().multiply(new Vector(1, 0, 1));
int radiusSquared = plugin.getIWM().getNetherSpawnRadius(location.getWorld()) * plugin.getIWM().getNetherSpawnRadius(location.getWorld());
return (spawn.distanceSquared(p) < radiusSquared);
}
/**
* If the player is not in the standard nether or standard end or op, do nothing.
* Used to protect the standard spawn for nether or end.
*
* @param player - the player
* @return true if nothing needs to be done
*/
private boolean noAction(@NonNull Player player) {
if (player.isOp()
|| player.getWorld().getEnvironment().equals(World.Environment.NORMAL)
|| !plugin.getIWM().inWorld(player.getLocation())) {
return true;
}
// Player is in an island world and in a nether or end
return (player.getWorld().getEnvironment().equals(World.Environment.NETHER) && plugin.getIWM().isNetherIslands(player.getWorld()))
|| (player.getWorld().getEnvironment().equals(World.Environment.THE_END) && plugin.getIWM().isEndIslands(player.getWorld()));
}
}

View File

@ -153,107 +153,6 @@ public class NetherPortalsTest {
when(iwm.inWorld(any(Location.class))).thenReturn(false);
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.NetherPortals#onBlockBreak(org.bukkit.event.block.BlockBreakEvent)}.
*/
@Test
public void testOnBlockBreakNoAction() {
NetherPortals np = new NetherPortals(plugin);
Block block = mock(Block.class);
Player player = mock(Player.class);
// Ops can do anything
when(player.isOp()).thenReturn(true);
BlockBreakEvent e = new BlockBreakEvent(block, player);
np.onBlockBreak(e);
assertFalse(e.isCancelled());
// not op, but not in right world
when(player.isOp()).thenReturn(false);
World w = mock(World.class);
when(w.getEnvironment()).thenReturn(Environment.NORMAL);
when(player.getWorld()).thenReturn(w);
np.onBlockBreak(e);
assertFalse(e.isCancelled());
// not op, island world
when(player.getWorld()).thenReturn(world);
np.onBlockBreak(e);
assertFalse(e.isCancelled());
// Nether, but not standard nether
when(player.getWorld()).thenReturn(nether);
when(iwm.isNetherIslands(Mockito.any())).thenReturn(true);
np.onBlockBreak(e);
assertFalse(e.isCancelled());
// End, but not standard end
when(player.getWorld()).thenReturn(nether);
when(iwm.isEndIslands(Mockito.any())).thenReturn(true);
np.onBlockBreak(e);
assertFalse(e.isCancelled());
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.NetherPortals#onBlockBreak(org.bukkit.event.block.BlockBreakEvent)}.
*/
@Test
public void testOnBlockBreakActionAwayFromSpawn() {
NetherPortals np = new NetherPortals(plugin);
Block block = mock(Block.class);
Location far = mock(Location.class);
when(far.toVector()).thenReturn(new Vector(10000, 56, 2000));
when(far.getWorld()).thenReturn(nether);
when(block.getLocation()).thenReturn(far);
Player player = mock(Player.class);
// Standard nether
when(player.getWorld()).thenReturn(nether);
when(iwm.isNetherIslands(world)).thenReturn(false);
BlockBreakEvent e = new BlockBreakEvent(block, player);
np.onBlockBreak(e);
assertFalse(e.isCancelled());
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.NetherPortals#onBlockBreak(org.bukkit.event.block.BlockBreakEvent)}.
*/
@Test
public void testOnBlockBreakActionAtSpawn() {
NetherPortals np = new NetherPortals(plugin);
Block block = mock(Block.class);
Location near = mock(Location.class);
when(near.toVector()).thenReturn(new Vector(0, 56, 0));
when(near.getWorld()).thenReturn(nether);
when(block.getLocation()).thenReturn(near);
Player player = mock(Player.class);
// Standard nether
when(player.getWorld()).thenReturn(nether);
when(iwm.isNetherIslands(world)).thenReturn(false);
BlockBreakEvent e = new BlockBreakEvent(block, player);
np.onBlockBreak(e);
Mockito.verify(block).getLocation();
assertTrue(e.isCancelled());
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.NetherPortals#onBucketEmpty(org.bukkit.event.player.PlayerBucketEmptyEvent)}.
*/
@Test
public void testOnBucketEmpty() {
NetherPortals np = new NetherPortals(plugin);
Block block = mock(Block.class);
Location near = mock(Location.class);
when(near.toVector()).thenReturn(new Vector(0, 56, 0));
when(near.getWorld()).thenReturn(nether);
when(block.getLocation()).thenReturn(near);
Player player = mock(Player.class);
// Standard nether
when(player.getWorld()).thenReturn(nether);
when(iwm.isNetherIslands(world)).thenReturn(false);
PlayerBucketEmptyEvent e = new PlayerBucketEmptyEvent(player, block, null, null, null);
np.onBucketEmpty(e);
Mockito.verify(block).getLocation();
assertTrue(e.isCancelled());
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.NetherPortals#onEndIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}.
*/
@ -365,170 +264,6 @@ public class NetherPortalsTest {
assertTrue(e.isCancelled());
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.NetherPortals#onExplosion(org.bukkit.event.entity.EntityExplodeEvent)}.
*/
@Test
public void testOnExplosionNotInWorld() {
NetherPortals np = new NetherPortals(plugin);
// Null entity
Entity en = null;
// Entity, Location, list of Blocks, yield
Block block = mock(Block.class);
Location blockLoc = mock(Location.class);
when(blockLoc.toVector()).thenReturn(new Vector(10000,0,10000));
when(block.getLocation()).thenReturn(blockLoc);
when(blockLoc.getWorld()).thenReturn(nether);
// One block will be blown up by the wither
List<Block> affectedBlocks = new ArrayList<>();
affectedBlocks.add(block);
Location from = mock(Location.class);
when(from.getWorld()).thenReturn(mock(World.class));
// Not in world
wrongWorld();
EntityExplodeEvent e = new EntityExplodeEvent(en, from, affectedBlocks, 0);
assertFalse(np.onExplosion(e));
}
@Test
public void testOnExplosionInWorldNotNetherOrEnd() {
NetherPortals np = new NetherPortals(plugin);
// Null entity
Entity en = null;
// Entity, Location, list of Blocks, yield
Block block = mock(Block.class);
Location blockLoc = mock(Location.class);
when(blockLoc.toVector()).thenReturn(new Vector(10000,0,10000));
when(block.getLocation()).thenReturn(blockLoc);
when(blockLoc.getWorld()).thenReturn(nether);
// One block will be blown up by the wither
List<Block> affectedBlocks = new ArrayList<>();
affectedBlocks.add(block);
Location from = mock(Location.class);
when(from.getWorld()).thenReturn(mock(World.class));
EntityExplodeEvent e = new EntityExplodeEvent(en, from, affectedBlocks, 0);
assertFalse(np.onExplosion(e));
}
@Test
public void testOnExplosionIslands() {
NetherPortals np = new NetherPortals(plugin);
// Null entity
Entity en = null;
// Entity, Location, list of Blocks, yield
Block block = mock(Block.class);
Location blockLoc = mock(Location.class);
when(blockLoc.toVector()).thenReturn(new Vector(10000,0,10000));
when(block.getLocation()).thenReturn(blockLoc);
when(blockLoc.getWorld()).thenReturn(nether);
// One block will be blown up by the wither
List<Block> affectedBlocks = new ArrayList<>();
affectedBlocks.add(block);
Location from = mock(Location.class);
// In world, in nether, nether islands
when(from.getWorld()).thenReturn(nether);
when(iwm.isNetherIslands(world)).thenReturn(true);
EntityExplodeEvent e = new EntityExplodeEvent(en, from, affectedBlocks, 0);
assertFalse(np.onExplosion(e));
// In world, in end, end islands
when(from.getWorld()).thenReturn(end);
when(iwm.isNetherIslands(world)).thenReturn(false);
when(iwm.isEndIslands(world)).thenReturn(true);
assertFalse(np.onExplosion(e));
}
@Test
public void testOnExplosionNullEntity() {
NetherPortals np = new NetherPortals(plugin);
// Entity, Location, list of Blocks, yield
Block block = mock(Block.class);
Location blockLoc = mock(Location.class);
when(blockLoc.toVector()).thenReturn(new Vector(10000,0,10000));
when(block.getLocation()).thenReturn(blockLoc);
when(blockLoc.getWorld()).thenReturn(nether);
// One block will be blown up by the wither
List<Block> affectedBlocks = new ArrayList<>();
affectedBlocks.add(block);
Location from = mock(Location.class);
// In world, in nether, nether islands
when(from.getWorld()).thenReturn(nether);
when(iwm.isNetherIslands(world)).thenReturn(false);
EntityExplodeEvent e = new EntityExplodeEvent(null, from, affectedBlocks, 0);
assertFalse(np.onExplosion(e));
}
@Test
public void testOnExplosionAwayFromSpawn() {
NetherPortals np = new NetherPortals(plugin);
// Null entity
Entity en = mock(Entity.class);
// Entity, Location, list of Blocks, yield
Block block = mock(Block.class);
Location blockLoc = mock(Location.class);
when(blockLoc.toVector()).thenReturn(new Vector(10000,0,10000));
when(block.getLocation()).thenReturn(blockLoc);
when(blockLoc.getWorld()).thenReturn(nether);
// One block will be blown up by the wither
List<Block> affectedBlocks = new ArrayList<>();
affectedBlocks.add(block);
Location from = mock(Location.class);
// In world, in nether, standard nether, null entity
when(from.getWorld()).thenReturn(nether);
when(iwm.isNetherIslands(world)).thenReturn(false);
EntityExplodeEvent e = new EntityExplodeEvent(en, from, affectedBlocks, 0);
// Real entity, away from spawn
assertTrue(np.onExplosion(e));
// Block should still exist because it is away from spawn
assertFalse(e.blockList().isEmpty());
}
@Test
public void testOnExplosion() {
NetherPortals np = new NetherPortals(plugin);
// Null entity
Entity en = null;
// Entity, Location, list of Blocks, yield
Block block = mock(Block.class);
Location blockLoc = mock(Location.class);
when(blockLoc.toVector()).thenReturn(new Vector(10000,0,10000));
when(block.getLocation()).thenReturn(blockLoc);
when(blockLoc.getWorld()).thenReturn(nether);
// One block will be blown up by the wither
List<Block> affectedBlocks = new ArrayList<>();
affectedBlocks.add(block);
Location from = mock(Location.class);
when(from.getWorld()).thenReturn(mock(World.class));
// In world, in nether, standard nether, null entity
when(from.getWorld()).thenReturn(nether);
when(iwm.isNetherIslands(world)).thenReturn(false);
// Real entity, next to spawn
en = mock(Entity.class);
when(blockLoc.toVector()).thenReturn(new Vector(0,0,0));
EntityExplodeEvent e = new EntityExplodeEvent(en, from, affectedBlocks, 0);
// Block exists before
assertFalse(e.blockList().isEmpty());
assertTrue(np.onExplosion(e));
// Block removed
assertTrue(e.blockList().isEmpty());
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.NetherPortals#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}.
*/
@ -703,26 +438,4 @@ public class NetherPortalsTest {
Mockito.verify(from).toVector();
Mockito.verify(im, Mockito.never()).getIslandLocation(Mockito.any(), Mockito.any());
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.NetherPortals#onPlayerBlockPlace(org.bukkit.event.block.BlockPlaceEvent)}.
*/
@Test
public void testOnPlayerBlockPlace() {
NetherPortals np = new NetherPortals(plugin);
Block block = mock(Block.class);
Location near = mock(Location.class);
when(near.toVector()).thenReturn(new Vector(0, 56, 0));
when(near.getWorld()).thenReturn(nether);
when(block.getLocation()).thenReturn(near);
Player player = mock(Player.class);
// Standard nether
when(player.getWorld()).thenReturn(nether);
when(iwm.isNetherIslands(world)).thenReturn(false);
when(iwm.isNetherGenerate(world)).thenReturn(true);
BlockPlaceEvent e = new BlockPlaceEvent(block, null, block, null, player, false, null);
np.onPlayerBlockPlace(e);
Mockito.verify(block).getLocation();
assertTrue(e.isCancelled());
}
}