diff --git a/pom.xml b/pom.xml index 04c7c0c..1b7e25d 100644 --- a/pom.xml +++ b/pom.xml @@ -46,12 +46,12 @@ 5.10.2 5.11.0 - 1.21.10-R0.1-SNAPSHOT + 1.21.11-R0.1-SNAPSHOT 3.10.0 ${build.version}-SNAPSHOT - 4.6.0 + 4.7.0 -LOCAL BentoBoxWorld_Border @@ -210,6 +210,11 @@ 3.14.1 ${java.version} + true + + -J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED + -J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED + diff --git a/src/main/java/world/bentobox/border/Border.java b/src/main/java/world/bentobox/border/Border.java index 78d7d65..7c0e7d5 100644 --- a/src/main/java/world/bentobox/border/Border.java +++ b/src/main/java/world/bentobox/border/Border.java @@ -19,7 +19,7 @@ import world.bentobox.border.listeners.BorderShower; import world.bentobox.border.listeners.PlayerListener; import world.bentobox.border.listeners.ShowBarrier; -import world.bentobox.border.listeners.ShowVirtualWorldBorder; +import world.bentobox.border.listeners.ShowWorldBorder; public class Border extends Addon { @@ -71,7 +71,7 @@ public void onDisable() { private BorderShower createBorder() { BorderShower customBorder = new ShowBarrier(this); - BorderShower wbapiBorder = new ShowVirtualWorldBorder(this); + BorderShower wbapiBorder = new ShowWorldBorder(this); return new PerPlayerBorderProxy(this, customBorder, wbapiBorder); } @@ -131,4 +131,5 @@ private void registerPlaceholders() orElse(getSettings().getType()). getCommandLabel()); } + } diff --git a/src/main/java/world/bentobox/border/PerPlayerBorderProxy.java b/src/main/java/world/bentobox/border/PerPlayerBorderProxy.java index f5b2901..b53bfee 100644 --- a/src/main/java/world/bentobox/border/PerPlayerBorderProxy.java +++ b/src/main/java/world/bentobox/border/PerPlayerBorderProxy.java @@ -1,13 +1,15 @@ package world.bentobox.border; +import java.util.Optional; + +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; + import world.bentobox.bentobox.api.metadata.MetaDataValue; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.border.listeners.BorderShower; -import java.util.Optional; - public final class PerPlayerBorderProxy implements BorderShower { public static final String BORDER_BORDERTYPE_META_DATA = "Border_bordertype"; @@ -76,11 +78,11 @@ private BorderType getDefaultBorderType() { } @Override - public void teleportPlayer(Player player) { + public void teleportEntity(Border addon, Entity player) { if (getBorderType(User.getInstance(player)) == BorderType.BARRIER) { - customBorder.teleportPlayer(player); + customBorder.teleportEntity(addon, player); } else { - vanillaBorder.teleportPlayer(player); + vanillaBorder.teleportEntity(addon, player); } } diff --git a/src/main/java/world/bentobox/border/Settings.java b/src/main/java/world/bentobox/border/Settings.java index 5fd7ed8..c53a802 100644 --- a/src/main/java/world/bentobox/border/Settings.java +++ b/src/main/java/world/bentobox/border/Settings.java @@ -22,13 +22,28 @@ public class Settings implements ConfigObject { private Set disabledGameModes = new HashSet<>(); @ConfigComment("") - @ConfigComment("Border type. Options are VANILLA, which uses the vanillia-style board or BARRIER,") + @ConfigComment("Border type. Options are VANILLA, which uses the vanilla-style boarder or BARRIER,") @ConfigComment("which uses particles and barrier blocks. If players have permission to use the barrier type") @ConfigComment("they may override this option. If they do not have permission or lose the permission") @ConfigComment("then this setting will be used.") @ConfigEntry(path = "type") private BorderType type = BorderType.VANILLA; + public enum BorderColor { + RED, GREEN, BLUE + } + @ConfigComment("") + @ConfigComment("Vanilla border color. Only applies if the border type is VANILLA.") + @ConfigComment("Selection is RED, GREEN, BLUE.") + @ConfigEntry(path = "color") + private BorderColor color = BorderColor.BLUE; + + @ConfigComment("") + @ConfigComment("Bounce items back inside the border if they are thrown by a player.") + @ConfigComment("Without this, items can be thrown outside the border.") + @ConfigEntry(path = "bounce-back") + private boolean bounceBack = true; + @ConfigComment("") @ConfigComment("Teleport players back inside the border if they somehow get outside.") @ConfigComment("This will teleport players back inside if they toggle the border with a command.") @@ -192,4 +207,32 @@ public boolean isReturnTeleportBlock() { public void setReturnTeleportBlock(boolean returnTeleportBlock) { this.returnTeleportBlock = returnTeleportBlock; } + + /** + * @return the bounceBack + */ + public boolean isBounceBack() { + return bounceBack; + } + + /** + * @param bounceBack the bounceBack to set + */ + public void setBounceBack(boolean bounceBack) { + this.bounceBack = bounceBack; + } + + /** + * @return the color + */ + public BorderColor getColor() { + return color; + } + + /* * + * @param color the color to set + */ + public void setColor(BorderColor color) { + this.color = color; + } } diff --git a/src/main/java/world/bentobox/border/listeners/BorderShower.java b/src/main/java/world/bentobox/border/listeners/BorderShower.java index e42d5da..6c25d47 100644 --- a/src/main/java/world/bentobox/border/listeners/BorderShower.java +++ b/src/main/java/world/bentobox/border/listeners/BorderShower.java @@ -1,9 +1,15 @@ package world.bentobox.border.listeners; +import org.bukkit.Location; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.util.Vector; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.bentobox.util.Util; +import world.bentobox.border.Border; /** * A border shower class @@ -44,9 +50,19 @@ public default void refreshView(User user, Island island){ } /** - * Teleports player back within the island space they are in - * @param player player + * Teleports an entity, typically a player back within the island space they are in + * @param entity entity */ - public void teleportPlayer(Player player); + public default void teleportEntity(Border addon, Entity entity) { + addon.getIslands().getIslandAt(entity.getLocation()).ifPresent(i -> { + Vector unitVector = i.getCenter().toVector().subtract(entity.getLocation().toVector()).normalize() + .multiply(new Vector(1, 0, 1)); + // Get distance from border + Location to = entity.getLocation().toVector().add(unitVector).toLocation(entity.getWorld()); + to.setPitch(entity.getLocation().getPitch()); + to.setYaw(entity.getLocation().getYaw()); + Util.teleportAsync(entity, to, TeleportCause.PLUGIN); + }); + } } diff --git a/src/main/java/world/bentobox/border/listeners/PlayerListener.java b/src/main/java/world/bentobox/border/listeners/PlayerListener.java index ebcc91f..8b4f3d1 100644 --- a/src/main/java/world/bentobox/border/listeners/PlayerListener.java +++ b/src/main/java/world/bentobox/border/listeners/PlayerListener.java @@ -14,6 +14,7 @@ import org.bukkit.Material; import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; +import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -22,6 +23,8 @@ import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.event.entity.EntityDismountEvent; import org.bukkit.event.entity.EntityMountEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; @@ -29,16 +32,17 @@ import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.vehicle.VehicleMoveEvent; +import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitTask; import org.bukkit.util.NumberConversions; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; -import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.events.island.IslandProtectionRangeChangeEvent; import world.bentobox.bentobox.api.flags.Flag; import world.bentobox.bentobox.api.metadata.MetaDataValue; import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.util.Util; import world.bentobox.border.Border; import world.bentobox.border.BorderType; @@ -111,7 +115,7 @@ public void onPlayerDamage(EntityDamageEvent e) { } Material type = p.getLocation().getBlock().getRelative(BlockFace.DOWN).getType(); if (type == Material.AIR) { - ((BorderShower) show).teleportPlayer(p); + ((BorderShower) show).teleportEntity(addon, p); e.setCancelled(true); } } @@ -204,8 +208,13 @@ public void onPlayerLeaveIsland(PlayerMoveEvent e) { Util.teleportAsync(p, from).thenRun(() -> inTeleport.remove(p.getUniqueId())); return; } - // Backtrack - addon.getIslands().getIslandAt(p.getLocation()).ifPresent(i -> { + // Backtrack - try to find island at current location, or fall back to the player's own island + Optional optionalIsland = addon.getIslands().getIslandAt(p.getLocation()); + if (optionalIsland.isEmpty()) { + optionalIsland = Optional + .ofNullable(addon.getIslands().getIsland(p.getWorld(), User.getInstance(p))); + } + optionalIsland.ifPresent(i -> { Vector unitVector = i.getProtectionCenter().toVector().subtract(p.getLocation().toVector()).normalize() .multiply(new Vector(1,0,1)); if (unitVector.lengthSquared() <= 0D) { @@ -259,7 +268,10 @@ private boolean outsideCheck(Player player, Location from, Location to) { || !user.getMetaData(BorderShower.BORDER_STATE_META_DATA).map(MetaDataValue::asBoolean).orElse(addon.getSettings().isShowByDefault())) { return false; } - return addon.getIslands().getIslandAt(to).filter(i -> !i.onIsland(to)).isPresent(); + Optional islandAt = addon.getIslands().getIslandAt(to); + // Player is outside if they are on an island but not within its protection zone, + // or if they are not on any island at all (e.g., pushed out by piston) + return islandAt.isEmpty() || islandAt.filter(i -> !i.onIsland(to)).isPresent(); } /** @@ -338,8 +350,8 @@ public void onVehicleMove(VehicleMoveEvent e) { // Remove head movement if (!e.getFrom().toVector().equals(e.getTo().toVector())) { e.getVehicle().getPassengers().stream().filter(Player.class::isInstance).map(Player.class::cast) - .filter(this::isOn).forEach(p -> addon.getIslands().getIslandAt(p.getLocation()) - .ifPresent(i -> show.refreshView(User.getInstance(p), i))); + .filter(this::isOn).forEach(p -> addon.getIslands().getIslandAt(p.getLocation()) + .ifPresent(i -> show.refreshView(User.getInstance(p), i))); } } @@ -357,4 +369,61 @@ public void onProtectionRangeChange(IslandProtectionRangeChangeEvent e) { } }); } + + /** + * Bounces items back to inside the barrier if thrown by a player + * @param event event + */ + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onItemDrop(PlayerDropItemEvent event) { + if (addon.getSettings().isBounceBack() + && addon.inGameWorld(event.getPlayer().getWorld()) + && isOn(event.getPlayer()) + ) { + // Get this island + addon.getIslands().getIslandAt(event.getPlayer().getLocation()).ifPresent(is -> trackItem(event.getItemDrop(), is)); + } + } + + /** + * Bounces items back to inside the barrier if dropped when a player dies + * @param event event + */ + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onPlayerDeath(PlayerDeathEvent event) { + if (addon.getSettings().isBounceBack() + && addon.inGameWorld(event.getPlayer().getWorld()) + && isOn(event.getPlayer())) { + // Get this island + addon.getIslands().getIslandAt(event.getPlayer().getLocation()).ifPresent(is -> { + event.getDrops().forEach(item -> trackItem(event.getPlayer().getWorld().dropItemNaturally(event.getPlayer().getLocation(), item), is)); + event.getDrops().clear(); // We handled them + }); + } + } + + private void trackItem(Item item, Island island) { + new BukkitRunnable() { + int ticksActive = 0; + + @Override + public void run() { + // Stop tracking if the item is picked up, despawned, or 20 seconds have passed + if (!item.isValid() || ticksActive > 400) { + this.cancel(); + return; + } + + Location loc = item.getLocation(); + // Check if the item is going outside the border + if (!island.onIsland(loc)) { + // Reverse the direction + item.setVelocity(item.getVelocity().multiply(-0.5)); + this.cancel(); + } + ticksActive++; + } + }.runTaskTimer(addon.getPlugin(), 1L, 2L); // Check every 2 ticks (0.1 seconds) + } + } diff --git a/src/main/java/world/bentobox/border/listeners/ShowBarrier.java b/src/main/java/world/bentobox/border/listeners/ShowBarrier.java index f235c4d..05673fb 100644 --- a/src/main/java/world/bentobox/border/listeners/ShowBarrier.java +++ b/src/main/java/world/bentobox/border/listeners/ShowBarrier.java @@ -12,13 +12,13 @@ import org.bukkit.Material; import org.bukkit.Particle; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.util.Vector; import com.google.common.base.Enums; -import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.metadata.MetaDataValue; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; @@ -136,7 +136,7 @@ private void showPlayer(Player player, int i, int j, int k, boolean max) { if (addon.getSettings().isUseBarrierBlocks() && player.getLocation().getBlockX() == i && player.getLocation().getBlockZ() == k) { - teleportPlayer(player); + teleportEntity(player); } Location l = new Location(player.getWorld(), i, j, k); @@ -157,17 +157,17 @@ private void showPlayer(Player player, int i, int j, int k, boolean max) { /** * Teleport player back within the island space they are in - * @param p player + * @param entity player or entity */ - public void teleportPlayer(Player p) { - addon.getIslands().getIslandAt(p.getLocation()).ifPresent(i -> { - Vector unitVector = i.getCenter().toVector().subtract(p.getLocation().toVector()).normalize() + public void teleportEntity(Entity entity) { + addon.getIslands().getIslandAt(entity.getLocation()).ifPresent(i -> { + Vector unitVector = i.getCenter().toVector().subtract(entity.getLocation().toVector()).normalize() .multiply(new Vector(1, 0, 1)); // Get distance from border - Location to = p.getLocation().toVector().add(unitVector).toLocation(p.getWorld()); - to.setPitch(p.getLocation().getPitch()); - to.setYaw(p.getLocation().getYaw()); - Util.teleportAsync(p, to, TeleportCause.PLUGIN); + Location to = entity.getLocation().toVector().add(unitVector).toLocation(entity.getWorld()); + to.setPitch(entity.getLocation().getPitch()); + to.setYaw(entity.getLocation().getYaw()); + Util.teleportAsync(entity, to, TeleportCause.PLUGIN); }); } diff --git a/src/main/java/world/bentobox/border/listeners/ShowVirtualWorldBorder.java b/src/main/java/world/bentobox/border/listeners/ShowWorldBorder.java similarity index 67% rename from src/main/java/world/bentobox/border/listeners/ShowVirtualWorldBorder.java rename to src/main/java/world/bentobox/border/listeners/ShowWorldBorder.java index 45f9359..4ac93e9 100644 --- a/src/main/java/world/bentobox/border/listeners/ShowVirtualWorldBorder.java +++ b/src/main/java/world/bentobox/border/listeners/ShowWorldBorder.java @@ -6,6 +6,7 @@ import org.bukkit.Location; import org.bukkit.World.Environment; import org.bukkit.WorldBorder; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.util.Vector; @@ -21,11 +22,12 @@ * @author tastybento * */ -public class ShowVirtualWorldBorder implements BorderShower { +public class ShowWorldBorder implements BorderShower { + private static final long MAX_TICKS = 107374182; private final Border addon; - public ShowVirtualWorldBorder(Border addon) { + public ShowWorldBorder(Border addon) { this.addon = addon; } @@ -45,6 +47,16 @@ public void showBorder(Player player, Island island) { double size = Math.min(island.getRange() * 2D, (island.getProtectionRange() + addon.getSettings().getBarrierOffset()) * 2D); wb.setSize(size); wb.setWarningDistance(0); + switch(addon.getSettings().getColor()) { + case RED: + wb.changeSize(wb.getSize() - 0.1, MAX_TICKS); + break; + case GREEN: + wb.changeSize(wb.getSize() + 0.1, MAX_TICKS); + break; + case BLUE: + break; + } player.setWorldBorder(wb); } @@ -55,17 +67,17 @@ public void hideBorder(User user) { /** * Teleport player back within the island space they are in - * @param p player + * @param entity player */ - public void teleportPlayer(Player p) { - addon.getIslands().getIslandAt(p.getLocation()).ifPresent(i -> { - Vector unitVector = i.getCenter().toVector().subtract(p.getLocation().toVector()).normalize() + public void teleportEntity(Entity entity) { + addon.getIslands().getIslandAt(entity.getLocation()).ifPresent(i -> { + Vector unitVector = i.getCenter().toVector().subtract(entity.getLocation().toVector()).normalize() .multiply(new Vector(1, 0, 1)); // Get distance from border - Location to = p.getLocation().toVector().add(unitVector).toLocation(p.getWorld()); - to.setPitch(p.getLocation().getPitch()); - to.setYaw(p.getLocation().getYaw()); - Util.teleportAsync(p, to, TeleportCause.PLUGIN); + Location to = entity.getLocation().toVector().add(unitVector).toLocation(entity.getWorld()); + to.setPitch(entity.getLocation().getPitch()); + to.setYaw(entity.getLocation().getYaw()); + Util.teleportAsync(entity, to, TeleportCause.PLUGIN); }); } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b19ac3b..7e4a657 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,4 +1,4 @@ -# Border addon configuration file {$version} +# Border addon configuration file # See the documentation at https://docs.bentobox.world/en/latest/addons/Border/ # # This list stores GameModes in which Border addon should not work. @@ -13,6 +13,10 @@ disabled-gamemodes: [] # then this setting will be used. type: VANILLA # +# Bounce items back inside the border if they are thrown by a player. +# Without this, items can be thrown outside the border. +bounce-back: true +# # Teleport players back inside the border if they somehow get outside. # This will teleport players back inside if they toggle the border with a command. return-teleport: true diff --git a/src/test/java/world/bentobox/border/listeners/PlayerListenerTest.java b/src/test/java/world/bentobox/border/listeners/PlayerListenerTest.java index 794c024..e505e1f 100644 --- a/src/test/java/world/bentobox/border/listeners/PlayerListenerTest.java +++ b/src/test/java/world/bentobox/border/listeners/PlayerListenerTest.java @@ -72,6 +72,8 @@ public class PlayerListenerTest extends CommonTestSetup { private Vehicle vehicle; @Mock private GameModeAddon gma; + + private MockedStatic mockedUser; /** @@ -81,7 +83,7 @@ public class PlayerListenerTest extends CommonTestSetup { @BeforeEach public void setUp() throws Exception { super.setUp(); - MockedStatic mockedUser = Mockito.mockStatic(User.class, Mockito.RETURNS_MOCKS); + mockedUser = Mockito.mockStatic(User.class, Mockito.RETURNS_MOCKS); mockedUser.when(() -> User.getInstance(any(Player.class))).thenReturn(user); // Border Shower @@ -142,6 +144,7 @@ public void setUp() throws Exception { @Override @AfterEach public void tearDown() throws Exception { + mockedUser.closeOnDemand(); super.tearDown(); } @@ -314,6 +317,27 @@ public void testOnPlayerLeaveIslandReturnTeleportWaaayOutsideIsland() { mockedUtil.verify(() -> Util.teleportAsync(any(), any()), times(2)); } + /** + * Test method for {@link world.bentobox.border.listeners.PlayerListener#onPlayerLeaveIsland(org.bukkit.event.player.PlayerMoveEvent)}. + * Tests the scenario where a player is pushed completely outside any island (e.g., by a piston) + * and getIslandAt returns empty. The plugin should fall back to the player's own island. + */ + @Test + public void testOnPlayerLeaveIslandTeleportsWhenCompletelyOutsideIsland() { + // Player is completely outside any island - getIslandAt returns empty + when(im.getIslandAt(any())).thenReturn(Optional.empty()); + when(im.getProtectedIslandAt(any())).thenReturn(Optional.empty()); + // But the player has their own island + when(im.getIsland(any(), any(User.class))).thenReturn(island); + when(island.onIsland(any())).thenReturn(false); + settings.setReturnTeleport(true); + PlayerMoveEvent event = new PlayerMoveEvent(player, from, to); + pl.onPlayerLeaveIsland(event); + assertFalse(event.isCancelled()); + // Verify teleportAsync was called to teleport the player back + mockedUtil.verify(() -> Util.teleportAsync(any(), any()), times(2)); + } + /** * Test method for {@link world.bentobox.border.listeners.PlayerListener#onPlayerMove(org.bukkit.event.player.PlayerMoveEvent)}. */ diff --git a/src/test/java/world/bentobox/border/listeners/ShowBarrierTest.java b/src/test/java/world/bentobox/border/listeners/ShowBarrierTest.java index 392c851..814284e 100644 --- a/src/test/java/world/bentobox/border/listeners/ShowBarrierTest.java +++ b/src/test/java/world/bentobox/border/listeners/ShowBarrierTest.java @@ -47,6 +47,8 @@ public class ShowBarrierTest extends CommonTestSetup { @Mock private @NonNull Location center; + private MockedStatic mockedUser; + /** * @throws java.lang.Exception */ @@ -77,7 +79,7 @@ public void setUp() throws Exception { when(im.getIslandAt(any(Location.class))).thenReturn(Optional.of(island)); // User - MockedStatic mockedUser = Mockito.mockStatic(User.class, Mockito.RETURNS_MOCKS); + mockedUser = Mockito.mockStatic(User.class, Mockito.RETURNS_MOCKS); mockedUser.when(() -> User.getInstance(any(Player.class))).thenReturn(user); when(user.getMetaData(anyString())).thenReturn(Optional.empty()); when(user.getPlayer()).thenReturn(player); @@ -98,6 +100,9 @@ public void setUp() throws Exception { @Override @AfterEach public void tearDown() throws Exception { + if (mockedUser != null) { + mockedUser.close(); + } super.tearDown(); } diff --git a/src/test/java/world/bentobox/border/listeners/ShowVirtualWorldBorderTest.java b/src/test/java/world/bentobox/border/listeners/ShowVirtualWorldBorderTest.java index c8872e7..57b5d63 100644 --- a/src/test/java/world/bentobox/border/listeners/ShowVirtualWorldBorderTest.java +++ b/src/test/java/world/bentobox/border/listeners/ShowVirtualWorldBorderTest.java @@ -2,10 +2,12 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.bukkit.Bukkit; +import org.bukkit.World.Environment; import org.bukkit.WorldBorder; import org.bukkit.entity.Player; import org.bukkit.util.Vector; @@ -30,7 +32,7 @@ public class ShowVirtualWorldBorderTest extends CommonTestSetup { @Mock private Border addon; private Settings settings; - private ShowVirtualWorldBorder svwb; + private ShowWorldBorder svwb; @Mock private @NonNull User user; @Mock @@ -64,7 +66,7 @@ public void setUp() throws Exception { // Bukkit mockedBukkit.when(() -> Bukkit.createWorldBorder()).thenReturn(wb); - svwb = new ShowVirtualWorldBorder(addon); + svwb = new ShowWorldBorder(addon); } @Override @@ -74,7 +76,7 @@ public void tearDown() throws Exception { } /** - * Test method for {@link world.bentobox.border.listeners.ShowVirtualWorldBorder#ShowVirtualWorldBorder(world.bentobox.border.Border)}. + * Test method for {@link world.bentobox.border.listeners.ShowWorldBorder#ShowVirtualWorldBorder(world.bentobox.border.Border)}. */ @Test public void testShowVirtualWorldBorder() { @@ -82,7 +84,7 @@ public void testShowVirtualWorldBorder() { } /** - * Test method for {@link world.bentobox.border.listeners.ShowVirtualWorldBorder#showBorder(org.bukkit.entity.Player, world.bentobox.bentobox.database.objects.Island)}. + * Test method for {@link world.bentobox.border.listeners.ShowWorldBorder#showBorder(org.bukkit.entity.Player, world.bentobox.bentobox.database.objects.Island)}. */ @Test public void testShowBorder() { @@ -92,7 +94,7 @@ public void testShowBorder() { } /** - * Test method for {@link world.bentobox.border.listeners.ShowVirtualWorldBorder#showBorder(org.bukkit.entity.Player, world.bentobox.bentobox.database.objects.Island)}. + * Test method for {@link world.bentobox.border.listeners.ShowWorldBorder#showBorder(org.bukkit.entity.Player, world.bentobox.bentobox.database.objects.Island)}. */ @Test public void testShowBorderWithOffset() { @@ -103,7 +105,7 @@ public void testShowBorderWithOffset() { } /** - * Test method for {@link world.bentobox.border.listeners.ShowVirtualWorldBorder#showBorder(org.bukkit.entity.Player, world.bentobox.bentobox.database.objects.Island)}. + * Test method for {@link world.bentobox.border.listeners.ShowWorldBorder#showBorder(org.bukkit.entity.Player, world.bentobox.bentobox.database.objects.Island)}. */ @Test public void testShowBorderWithLargeOffset() { @@ -114,7 +116,7 @@ public void testShowBorderWithLargeOffset() { } /** - * Test method for {@link world.bentobox.border.listeners.ShowVirtualWorldBorder#hideBorder(world.bentobox.bentobox.api.user.User)}. + * Test method for {@link world.bentobox.border.listeners.ShowWorldBorder#hideBorder(world.bentobox.bentobox.api.user.User)}. */ @Test public void testHideBorder() { @@ -123,4 +125,39 @@ public void testHideBorder() { verify(mockPlayer).setWorldBorder(null); } + /** + * Test method for {@link world.bentobox.border.listeners.ShowWorldBorder#showBorder(org.bukkit.entity.Player, world.bentobox.bentobox.database.objects.Island)}. + * Tests that border is shown when player is in an island nether world. + */ + @Test + public void testShowBorderInIslandNetherWorld() { + // Setup: Player is in a nether environment that IS an island nether world + when(world.getEnvironment()).thenReturn(Environment.NETHER); + when(iwm.isIslandNether(world)).thenReturn(true); + when(addon.getPlugin()).thenReturn(plugin); + + svwb.showBorder(mockPlayer, island); + + // Verify that the border was set (border should show in island nether worlds) + verify(mockPlayer).setWorldBorder(wb); + verify(wb).setSize(200.0D); + } + + /** + * Test method for {@link world.bentobox.border.listeners.ShowWorldBorder#showBorder(org.bukkit.entity.Player, world.bentobox.bentobox.database.objects.Island)}. + * Tests that border is NOT shown when player is in a non-island nether world. + */ + @Test + public void testShowBorderInNonIslandNetherWorld() { + // Setup: Player is in a nether environment that is NOT an island nether world + when(world.getEnvironment()).thenReturn(Environment.NETHER); + when(iwm.isIslandNether(world)).thenReturn(false); + when(addon.getPlugin()).thenReturn(plugin); + + svwb.showBorder(mockPlayer, island); + + // Verify that the border was NOT set (border should not show in non-island nether worlds) + verify(mockPlayer, never()).setWorldBorder(any()); + } + }