Skip to content

Commit

Permalink
Release 4.2.2 (#124)
Browse files Browse the repository at this point in the history
* Version 4.2.2

* Added protection against console error spam if island size is zero.

If the protection range is 0 then the caluclations to teleport players
back into the border will result in infinite values and other
strangeness so this prevents that. This is an edge case and only really
happens when the island size has been set wrongly.

* Update README.md

* Fix perm issue #120 (#121)

* feat: detect mounted players on entity (#88)

---------

Co-authored-by: evlad <[email protected]>
  • Loading branch information
tastybento and emmanuelvlad authored Apr 20, 2024
1 parent 84e322a commit 87ee921
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 12 deletions.
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

0 comments on commit 87ee921

Please sign in to comment.