Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Border&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Border)
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Border&metric=security_rating)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Border)

**Border** can create and show a border around islands which players cannot pass.
**Border** creates and shows a world border around islands which players cannot pass.

**See the full documentation [here](https://docs.bentobox.world/en/latest/addons/Border/).**

## Like this addon?
[Sponsor tastybento](https://github.com/sponsors/tastybento) to get more addons like this and make this one better!

## Are you a coder?
This is one of the easier addons from a code perspective. Maybe you could make it better! Border is open source and we love Pull Requests. Become a BentoBox co-author today!
This is one of the easier addons from a code perspective. Maybe you could make it better! Border is open source and we love Pull Requests. Become a BentoBox co-author today!
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
<!-- Revision variable removes warning about dynamic version -->
<revision>${build.version}-SNAPSHOT</revision>
<!-- This allows to change between versions and snapshots. -->
<build.version>4.2.1</build.version>
<build.version>4.2.2</build.version>
<build.number>-LOCAL</build.number>
<!-- Sonar Cloud -->
<sonar.projectKey>BentoBoxWorld_Border</sonar.projectKey>
Expand Down
86 changes: 78 additions & 8 deletions src/main/java/world/bentobox/border/listeners/PlayerListener.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package world.bentobox.border.listeners;

import java.util.HashSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
Expand All @@ -11,6 +13,7 @@
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
Expand All @@ -22,9 +25,13 @@
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.event.vehicle.VehicleMoveEvent;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.NumberConversions;
import org.bukkit.util.RayTraceResult;
import org.bukkit.util.Vector;

import org.spigotmc.event.entity.EntityDismountEvent;
import org.spigotmc.event.entity.EntityMountEvent;
import world.bentobox.bentobox.api.events.island.IslandProtectionRangeChangeEvent;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.metadata.MetaDataValue;
Expand All @@ -44,6 +51,7 @@ public class PlayerListener implements Listener {
private final Border addon;
private Set<UUID> inTeleport;
private final BorderShower show;
private Map<Player, BukkitTask> mountedPlayers = new HashMap<>();

public PlayerListener(Border addon) {
this.addon = addon;
Expand All @@ -64,17 +72,19 @@ protected void processEvent(PlayerJoinEvent e) {
// Just for sure, disable world Border
user.getPlayer().setWorldBorder(null);

// Check player perms and return to defaults if players don't have them
if (!e.getPlayer().hasPermission(addon.getPermissionPrefix() + IslandBorderCommand.BORDER_COMMAND_PERM)) {
// Restore barrier on/off to default
user.putMetaData(BorderShower.BORDER_STATE_META_DATA, new MetaDataValue(addon.getSettings().isShowByDefault()));

if (!e.getPlayer().hasPermission(addon.getPermissionPrefix() + BorderTypeCommand.BORDER_TYPE_COMMAND_PERM)) {
// Get the game mode that this player is in
addon.getPlugin().getIWM().getAddon(e.getPlayer().getWorld()).map(gma -> gma.getPermissionPrefix()).filter(
permPrefix -> !e.getPlayer().hasPermission(permPrefix + IslandBorderCommand.BORDER_COMMAND_PERM))
.ifPresent(permPrefix -> {
// Restore barrier on/off to default
user.putMetaData(BorderShower.BORDER_STATE_META_DATA,
new MetaDataValue(addon.getSettings().isShowByDefault()));
if (!e.getPlayer().hasPermission(permPrefix + BorderTypeCommand.BORDER_TYPE_COMMAND_PERM)) {
// Restore default barrier type to player
MetaDataValue metaDataValue = new MetaDataValue(addon.getSettings().getType().getId());
user.putMetaData(PerPlayerBorderProxy.BORDER_BORDERTYPE_META_DATA, metaDataValue);
}
}
});

// Show the border if required one tick after
Bukkit.getScheduler().runTask(addon.getPlugin(), () -> addon.getIslands().getIslandAt(e.getPlayer().getLocation()).ifPresent(i ->
Expand Down Expand Up @@ -151,10 +161,15 @@ public void onPlayerLeaveIsland(PlayerMoveEvent e) {
addon.getIslands().getIslandAt(p.getLocation()).ifPresent(i -> {
Vector unitVector = i.getProtectionCenter().toVector().subtract(p.getLocation().toVector()).normalize()
.multiply(new Vector(1,0,1));
if (unitVector.lengthSquared() <= 0D) {
// Direction is zero, so nothing to do; cannot move.
return;
}
RayTraceResult r = i.getProtectionBoundingBox().rayTrace(p.getLocation().toVector(), unitVector, i.getRange());
if (r != null) {
if (r != null && checkFinite(r.getHitPosition())) {
inTeleport.add(p.getUniqueId());
Location targetPos = r.getHitPosition().toLocation(p.getWorld(), p.getLocation().getYaw(), p.getLocation().getPitch());

if (!e.getPlayer().isFlying() && addon.getSettings().isReturnTeleportBlock()
&& !addon.getIslands().isSafeLocation(targetPos)) {
switch (targetPos.getWorld().getEnvironment()) {
Expand All @@ -174,6 +189,11 @@ public void onPlayerLeaveIsland(PlayerMoveEvent e) {
});
}

public boolean checkFinite(Vector toCheck) {
return NumberConversions.isFinite(toCheck.getX()) && NumberConversions.isFinite(toCheck.getY())
&& NumberConversions.isFinite(toCheck.getZ());
}

/**
* Check if the player is outside the island protection zone that they are supposed to be in.
* @param player - player moving
Expand All @@ -195,6 +215,56 @@ private boolean outsideCheck(Player player, Location from, Location to) {
return addon.getIslands().getIslandAt(to).filter(i -> !i.onIsland(to)).isPresent();
}

/**
* Runs a task while the player is mounting an entity and eject
* if the entity went outside the protection range
* @param event - event
*/
@EventHandler
public void onEntityMount(EntityMountEvent event) {
Entity entity = event.getEntity();
if (!(entity instanceof Player player)) {
return;
}

mountedPlayers.put(player, Bukkit.getScheduler().runTaskTimer(addon.getPlugin(), () -> {
Location loc = player.getLocation();

if (!addon.inGameWorld(loc.getWorld())) {
return;
}
// Eject from mount if outside the protection range
if (addon.getIslands().getProtectedIslandAt(loc).isEmpty()) {
// Force the dismount event for custom entities
if (!event.getMount().eject()) {
var dismountEvent = new EntityDismountEvent(player, event.getMount());
Bukkit.getPluginManager().callEvent(dismountEvent);
}
}
}, 1, 20));
}

/**
* Cancel the running task if the player was mounting an entity
* @param event - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onEntityDismount(EntityDismountEvent event) {
Entity entity = event.getEntity();
if (!(entity instanceof Player player)) {
return;
}

BukkitTask task = mountedPlayers.get(player);
if (task == null) {
return;
}

task.cancel();
mountedPlayers.remove(player);
}


/**
* Refreshes the barrier view when the player moves (more than just moving their head)
* @param e event
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@
import org.powermock.modules.junit4.PowerMockRunner;

import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.events.island.IslandProtectionRangeChangeEvent;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.util.Util;
import world.bentobox.border.Border;
Expand Down Expand Up @@ -82,6 +84,10 @@ public class PlayerListenerTest {
private Island island;
@Mock
private Vehicle vehicle;
@Mock
private IslandWorldManager iwm;
@Mock
private GameModeAddon gma;


/**
Expand Down Expand Up @@ -135,6 +141,15 @@ public void setUp() throws Exception {
// Util
PowerMockito.mockStatic(Util.class, Mockito.RETURNS_MOCKS);

// Plugin
when(addon.getPlugin()).thenReturn(plugin);

// IWM
when(gma.getPermissionPrefix()).thenReturn("bskyblock.");
when(iwm.getAddon(world)).thenReturn(Optional.of(gma));
when(plugin.getIWM()).thenReturn(iwm);


pl = new PlayerListener(addon);

}
Expand Down Expand Up @@ -178,7 +193,7 @@ public void testOnPlayerQuit() {
*/
@Test
public void testOnPlayerRespawn() {
PlayerRespawnEvent event = new PlayerRespawnEvent(player, null, false, false);
PlayerRespawnEvent event = new PlayerRespawnEvent(player, from, false, false, null);
pl.onPlayerRespawn(event);
PowerMockito.verifyStatic(Bukkit.class);
Bukkit.getScheduler();
Expand Down