Added offline redstone world flag

Removed constructor from LockAndBanListener. Due to loading order, some
manager objects are null. Flags load very early so must assume
everything is null.
This commit is contained in:
tastybento 2018-07-06 10:05:00 -07:00
parent a60bcc8a22
commit 4963ea573c
6 changed files with 198 additions and 33 deletions

View File

@ -447,6 +447,13 @@ protection:
description: "Toggle access"
name: Music
hint: "No jukebox use"
OFFLINE_REDSTONE:
description: |
&aWhen disabled, redstone
&awill not operate on islands
&awhere all members are offline.
&aMay help reduce lag.
name: "Offline Redstone"
PISTON_PUSH:
description: |
&aAllow pistons to push

View File

@ -239,12 +239,6 @@ public class Settings implements DataObject, WorldSettings {
@ConfigEntry(path = "world.end.dragon-spawn")
private boolean dragonSpawn = false;
@ConfigComment("Disable redstone operation on islands unless a team member is online.")
@ConfigComment("This may reduce lag but it can cause problems with visitors needing to use a redstone system.")
@ConfigComment("Default is false, because it is an experimental feature that can break a lot of redstone systems.")
@ConfigEntry(path = "world.disable-offline-redstone")
private boolean disableOfflineRedstone = false;
@ConfigComment("Removing mobs - this kills all monsters in the vicinity. Benefit is that it helps")
@ConfigComment("players return to their island if the island has been overrun by monsters.")
@ConfigComment("This setting is toggled in world flags and set by the settings GUI.")
@ -503,18 +497,6 @@ public class Settings implements DataObject, WorldSettings {
public void setMuteDeathMessages(boolean muteDeathMessages) {
this.muteDeathMessages = muteDeathMessages;
}
/**
* @return the disableOfflineRedstone
*/
public boolean isDisableOfflineRedstone() {
return disableOfflineRedstone;
}
/**
* @param disableOfflineRedstone the disableOfflineRedstone to set
*/
public void setDisableOfflineRedstone(boolean disableOfflineRedstone) {
this.disableOfflineRedstone = disableOfflineRedstone;
}
/**
* @return the chestItems
*/

View File

@ -17,30 +17,22 @@ import org.bukkit.util.Vector;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.api.user.User;
import us.tastybento.bskyblock.lists.Flags;
import us.tastybento.bskyblock.managers.IslandsManager;
/**
* Listener for the lock flag
* Also handles ban protection
*
*
* @author tastybento
*
*/
public class LockAndBanListener implements Listener {
private IslandsManager im;
private enum CheckResult {
BANNED,
LOCKED,
OPEN
}
/**
* Enforces island bans and locks
*/
public LockAndBanListener() {
this.im = BSkyBlock.getInstance().getIslands();
}
// Teleport check
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
@ -79,12 +71,12 @@ public class LockAndBanListener implements Listener {
e.getVehicle().getPassengers().stream().filter(en -> en instanceof Player).map(en -> (Player)en).forEach(p -> {
if (!checkAndNotify(p, e.getTo()).equals(CheckResult.OPEN)) {
p.leaveVehicle();
p.teleport(e.getFrom());
p.teleport(e.getFrom());
e.getFrom().getWorld().playSound(e.getFrom(), Sound.BLOCK_ANVIL_HIT, 1F, 1F);
eject(p);
}
});
}
}
// Login check
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
@ -103,7 +95,7 @@ public class LockAndBanListener implements Listener {
private CheckResult check(Player player, Location loc) {
// See if the island is locked to non-members or player is banned
return im.getProtectedIslandAt(loc)
return BSkyBlock.getInstance().getIslands().getProtectedIslandAt(loc)
.map(is -> {
if (is.isBanned(player.getUniqueId())) {
return CheckResult.BANNED;
@ -143,9 +135,9 @@ public class LockAndBanListener implements Listener {
private void eject(Player player) {
player.setGameMode(GameMode.SPECTATOR);
// Teleport player to their home
if (im.hasIsland(player.getWorld(), player.getUniqueId())) {
im.homeTeleport(player.getWorld(), player);
} // else, TODO: teleport somewhere else?
if (BSkyBlock.getInstance().getIslands().hasIsland(player.getWorld(), player.getUniqueId())) {
BSkyBlock.getInstance().getIslands().homeTeleport(player.getWorld(), player);
} // else, TODO: teleport somewhere else?
}
}

View File

@ -0,0 +1,29 @@
package us.tastybento.bskyblock.listeners.flags;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockRedstoneEvent;
import us.tastybento.bskyblock.api.flags.AbstractFlagListener;
import us.tastybento.bskyblock.lists.Flags;
public class OfflineRedstoneListener extends AbstractFlagListener {
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void onBlockRedstone(BlockRedstoneEvent e) {
// If offline redstone is allowed then return
if (!Flags.OFFLINE_REDSTONE.isSetForWorld(e.getBlock().getWorld())) {
// Check if island exists and members are online
getIslands().getProtectedIslandAt(e.getBlock().getLocation()).ifPresent(i -> {
for (UUID uuid : i.getMemberSet()) {
if (Bukkit.getPlayer(uuid) != null) {
return;
}
}
e.setNewCurrent(0);
});
}
}
}

View File

@ -28,6 +28,7 @@ import us.tastybento.bskyblock.listeners.flags.IslandRespawnListener;
import us.tastybento.bskyblock.listeners.flags.ItemDropPickUpListener;
import us.tastybento.bskyblock.listeners.flags.LeashListener;
import us.tastybento.bskyblock.listeners.flags.LockAndBanListener;
import us.tastybento.bskyblock.listeners.flags.OfflineRedstoneListener;
import us.tastybento.bskyblock.listeners.flags.PVPListener;
import us.tastybento.bskyblock.listeners.flags.PhysicalInteractionListener;
import us.tastybento.bskyblock.listeners.flags.PistonPushListener;
@ -173,6 +174,8 @@ public class Flags {
.listener(new RemoveMobsListener()).allowedByDefault(true).onClick(new WorldToggleClickListener("REMOVE_MOBS")).build();
public static final Flag ISLAND_RESPAWN = new FlagBuilder().id("ISLAND_RESPAWN").icon(Material.TORCH).type(Type.WORLD_SETTING)
.listener(new IslandRespawnListener()).allowedByDefault(true).onClick(new WorldToggleClickListener("ISLAND_RESPAWN")).build();
public static final Flag OFFLINE_REDSTONE = new FlagBuilder().id("OFFLINE_REDSTONE").icon(Material.REDSTONE_COMPARATOR).type(Type.WORLD_SETTING)
.listener(new OfflineRedstoneListener()).allowedByDefault(true).onClick(new WorldToggleClickListener("OFFLINE_REDSTONE")).build();
/**
* @return List of all the flags in this class

View File

@ -0,0 +1,152 @@
package us.tastybento.bskyblock.listeners.flags;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockRedstoneEvent;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.api.configuration.WorldSettings;
import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.lists.Flags;
import us.tastybento.bskyblock.managers.IslandWorldManager;
import us.tastybento.bskyblock.managers.IslandsManager;
import us.tastybento.bskyblock.util.Util;
@RunWith(PowerMockRunner.class)
@PrepareForTest({BSkyBlock.class, Util.class, Bukkit.class })
public class OfflineRedstoneListenerTest {
private World world;
private UUID uuid;
private Island island;
private IslandsManager im;
private Location inside;
private Block block;
@Before
public void setUp() throws Exception {
// Set up plugin
BSkyBlock plugin = mock(BSkyBlock.class);
Whitebox.setInternalState(BSkyBlock.class, "instance", plugin);
// World
world = mock(World.class);
// Owner
uuid = UUID.randomUUID();
// Island initialization
island = mock(Island.class);
when(island.getOwner()).thenReturn(uuid);
// Add members
Builder<UUID> set = new ImmutableSet.Builder<>();
set.add(UUID.randomUUID());
set.add(UUID.randomUUID());
set.add(UUID.randomUUID());
set.add(UUID.randomUUID());
when(island.getMemberSet()).thenReturn(set.build());
im = mock(IslandsManager.class);
when(plugin.getIslands()).thenReturn(im);
when(im.getIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(island);
inside = mock(Location.class);
Optional<Island> opIsland = Optional.ofNullable(island);
when(im.getProtectedIslandAt(Mockito.eq(inside))).thenReturn(opIsland);
// Blocks
block = mock(Block.class);
when(block.getWorld()).thenReturn(world);
when(block.getLocation()).thenReturn(inside);
PowerMockito.mockStatic(Util.class);
when(Util.getWorld(Mockito.any())).thenReturn(world);
// World Settings
IslandWorldManager iwm = mock(IslandWorldManager.class);
when(plugin.getIWM()).thenReturn(iwm);
WorldSettings ws = mock(WorldSettings.class);
when(iwm.getWorldSettings(Mockito.any())).thenReturn(ws);
Map<String, Boolean> worldFlags = new HashMap<>();
when(ws.getWorldFlags()).thenReturn(worldFlags);
PowerMockito.mockStatic(Bukkit.class);
}
@Test
public void testOnBlockRedstoneDoNothing() {
// Make an event to give some current to block
BlockRedstoneEvent e = new BlockRedstoneEvent(block, 0, 10);
OfflineRedstoneListener orl = new OfflineRedstoneListener();
Flags.OFFLINE_REDSTONE.setSetting(world, true);
orl.onBlockRedstone(e);
// Current remains 10
assertEquals(10, e.getNewCurrent());
}
@Test
public void testOnBlockRedstoneMembersOnline() {
// Make an event to give some current to block
BlockRedstoneEvent e = new BlockRedstoneEvent(block, 0, 10);
OfflineRedstoneListener orl = new OfflineRedstoneListener();
// Offline redstone not allowed
Flags.OFFLINE_REDSTONE.setSetting(world, false);
// Members are online
when(Bukkit.getPlayer(Mockito.any(UUID.class))).thenReturn(mock(Player.class));
orl.onBlockRedstone(e);
// Current remains 10
assertEquals(10, e.getNewCurrent());
}
@Test
public void testOnBlockRedstoneMembersOffline() {
// Make an event to give some current to block
BlockRedstoneEvent e = new BlockRedstoneEvent(block, 0, 10);
OfflineRedstoneListener orl = new OfflineRedstoneListener();
// Offline redstone not allowed
Flags.OFFLINE_REDSTONE.setSetting(world, false);
// Members are online
when(Bukkit.getPlayer(Mockito.any(UUID.class))).thenReturn(null);
orl.onBlockRedstone(e);
// Current will be 0
assertEquals(0, e.getNewCurrent());
}
@Test
public void testOnBlockRedstoneNonIsland() {
// Make an event to give some current to block
BlockRedstoneEvent e = new BlockRedstoneEvent(block, 0, 10);
OfflineRedstoneListener orl = new OfflineRedstoneListener();
Flags.OFFLINE_REDSTONE.setSetting(world, false);
when(im.getProtectedIslandAt(Mockito.eq(inside))).thenReturn(Optional.empty());
orl.onBlockRedstone(e);
// Current remains 10
assertEquals(10, e.getNewCurrent());
}
}