Skip to content

Commit 87ee921

Browse files
Release 4.2.2 (#124)
* 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]>
1 parent 84e322a commit 87ee921

4 files changed

Lines changed: 97 additions & 12 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Border&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Border)
55
[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=BentoBoxWorld_Border&metric=security_rating)](https://sonarcloud.io/dashboard?id=BentoBoxWorld_Border)
66

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

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

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

1414
## Are you a coder?
15-
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!
15+
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!

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
<!-- Revision variable removes warning about dynamic version -->
5555
<revision>${build.version}-SNAPSHOT</revision>
5656
<!-- This allows to change between versions and snapshots. -->
57-
<build.version>4.2.1</build.version>
57+
<build.version>4.2.2</build.version>
5858
<build.number>-LOCAL</build.number>
5959
<!-- Sonar Cloud -->
6060
<sonar.projectKey>BentoBoxWorld_Border</sonar.projectKey>

src/main/java/world/bentobox/border/listeners/PlayerListener.java

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package world.bentobox.border.listeners;
22

33
import java.util.HashSet;
4+
import java.util.HashMap;
5+
import java.util.Map;
46
import java.util.Objects;
57
import java.util.Optional;
68
import java.util.Set;
@@ -11,6 +13,7 @@
1113
import org.bukkit.Location;
1214
import org.bukkit.Material;
1315
import org.bukkit.block.BlockFace;
16+
import org.bukkit.entity.Entity;
1417
import org.bukkit.entity.Player;
1518
import org.bukkit.event.EventHandler;
1619
import org.bukkit.event.EventPriority;
@@ -22,9 +25,13 @@
2225
import org.bukkit.event.player.PlayerTeleportEvent;
2326
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
2427
import org.bukkit.event.vehicle.VehicleMoveEvent;
28+
import org.bukkit.scheduler.BukkitTask;
29+
import org.bukkit.util.NumberConversions;
2530
import org.bukkit.util.RayTraceResult;
2631
import org.bukkit.util.Vector;
2732

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

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

67-
// Check player perms and return to defaults if players don't have them
68-
if (!e.getPlayer().hasPermission(addon.getPermissionPrefix() + IslandBorderCommand.BORDER_COMMAND_PERM)) {
69-
// Restore barrier on/off to default
70-
user.putMetaData(BorderShower.BORDER_STATE_META_DATA, new MetaDataValue(addon.getSettings().isShowByDefault()));
71-
72-
if (!e.getPlayer().hasPermission(addon.getPermissionPrefix() + BorderTypeCommand.BORDER_TYPE_COMMAND_PERM)) {
75+
// Get the game mode that this player is in
76+
addon.getPlugin().getIWM().getAddon(e.getPlayer().getWorld()).map(gma -> gma.getPermissionPrefix()).filter(
77+
permPrefix -> !e.getPlayer().hasPermission(permPrefix + IslandBorderCommand.BORDER_COMMAND_PERM))
78+
.ifPresent(permPrefix -> {
79+
// Restore barrier on/off to default
80+
user.putMetaData(BorderShower.BORDER_STATE_META_DATA,
81+
new MetaDataValue(addon.getSettings().isShowByDefault()));
82+
if (!e.getPlayer().hasPermission(permPrefix + BorderTypeCommand.BORDER_TYPE_COMMAND_PERM)) {
7383
// Restore default barrier type to player
7484
MetaDataValue metaDataValue = new MetaDataValue(addon.getSettings().getType().getId());
7585
user.putMetaData(PerPlayerBorderProxy.BORDER_BORDERTYPE_META_DATA, metaDataValue);
7686
}
77-
}
87+
});
7888

7989
// Show the border if required one tick after
8090
Bukkit.getScheduler().runTask(addon.getPlugin(), () -> addon.getIslands().getIslandAt(e.getPlayer().getLocation()).ifPresent(i ->
@@ -151,10 +161,15 @@ public void onPlayerLeaveIsland(PlayerMoveEvent e) {
151161
addon.getIslands().getIslandAt(p.getLocation()).ifPresent(i -> {
152162
Vector unitVector = i.getProtectionCenter().toVector().subtract(p.getLocation().toVector()).normalize()
153163
.multiply(new Vector(1,0,1));
164+
if (unitVector.lengthSquared() <= 0D) {
165+
// Direction is zero, so nothing to do; cannot move.
166+
return;
167+
}
154168
RayTraceResult r = i.getProtectionBoundingBox().rayTrace(p.getLocation().toVector(), unitVector, i.getRange());
155-
if (r != null) {
169+
if (r != null && checkFinite(r.getHitPosition())) {
156170
inTeleport.add(p.getUniqueId());
157171
Location targetPos = r.getHitPosition().toLocation(p.getWorld(), p.getLocation().getYaw(), p.getLocation().getPitch());
172+
158173
if (!e.getPlayer().isFlying() && addon.getSettings().isReturnTeleportBlock()
159174
&& !addon.getIslands().isSafeLocation(targetPos)) {
160175
switch (targetPos.getWorld().getEnvironment()) {
@@ -174,6 +189,11 @@ public void onPlayerLeaveIsland(PlayerMoveEvent e) {
174189
});
175190
}
176191

192+
public boolean checkFinite(Vector toCheck) {
193+
return NumberConversions.isFinite(toCheck.getX()) && NumberConversions.isFinite(toCheck.getY())
194+
&& NumberConversions.isFinite(toCheck.getZ());
195+
}
196+
177197
/**
178198
* Check if the player is outside the island protection zone that they are supposed to be in.
179199
* @param player - player moving
@@ -195,6 +215,56 @@ private boolean outsideCheck(Player player, Location from, Location to) {
195215
return addon.getIslands().getIslandAt(to).filter(i -> !i.onIsland(to)).isPresent();
196216
}
197217

218+
/**
219+
* Runs a task while the player is mounting an entity and eject
220+
* if the entity went outside the protection range
221+
* @param event - event
222+
*/
223+
@EventHandler
224+
public void onEntityMount(EntityMountEvent event) {
225+
Entity entity = event.getEntity();
226+
if (!(entity instanceof Player player)) {
227+
return;
228+
}
229+
230+
mountedPlayers.put(player, Bukkit.getScheduler().runTaskTimer(addon.getPlugin(), () -> {
231+
Location loc = player.getLocation();
232+
233+
if (!addon.inGameWorld(loc.getWorld())) {
234+
return;
235+
}
236+
// Eject from mount if outside the protection range
237+
if (addon.getIslands().getProtectedIslandAt(loc).isEmpty()) {
238+
// Force the dismount event for custom entities
239+
if (!event.getMount().eject()) {
240+
var dismountEvent = new EntityDismountEvent(player, event.getMount());
241+
Bukkit.getPluginManager().callEvent(dismountEvent);
242+
}
243+
}
244+
}, 1, 20));
245+
}
246+
247+
/**
248+
* Cancel the running task if the player was mounting an entity
249+
* @param event - event
250+
*/
251+
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
252+
public void onEntityDismount(EntityDismountEvent event) {
253+
Entity entity = event.getEntity();
254+
if (!(entity instanceof Player player)) {
255+
return;
256+
}
257+
258+
BukkitTask task = mountedPlayers.get(player);
259+
if (task == null) {
260+
return;
261+
}
262+
263+
task.cancel();
264+
mountedPlayers.remove(player);
265+
}
266+
267+
198268
/**
199269
* Refreshes the barrier view when the player moves (more than just moving their head)
200270
* @param e event

src/test/java/world/bentobox/border/listeners/PlayerListenerTest.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@
4040
import org.powermock.modules.junit4.PowerMockRunner;
4141

4242
import world.bentobox.bentobox.BentoBox;
43+
import world.bentobox.bentobox.api.addons.GameModeAddon;
4344
import world.bentobox.bentobox.api.events.island.IslandProtectionRangeChangeEvent;
4445
import world.bentobox.bentobox.api.user.User;
4546
import world.bentobox.bentobox.database.objects.Island;
47+
import world.bentobox.bentobox.managers.IslandWorldManager;
4648
import world.bentobox.bentobox.managers.IslandsManager;
4749
import world.bentobox.bentobox.util.Util;
4850
import world.bentobox.border.Border;
@@ -82,6 +84,10 @@ public class PlayerListenerTest {
8284
private Island island;
8385
@Mock
8486
private Vehicle vehicle;
87+
@Mock
88+
private IslandWorldManager iwm;
89+
@Mock
90+
private GameModeAddon gma;
8591

8692

8793
/**
@@ -135,6 +141,15 @@ public void setUp() throws Exception {
135141
// Util
136142
PowerMockito.mockStatic(Util.class, Mockito.RETURNS_MOCKS);
137143

144+
// Plugin
145+
when(addon.getPlugin()).thenReturn(plugin);
146+
147+
// IWM
148+
when(gma.getPermissionPrefix()).thenReturn("bskyblock.");
149+
when(iwm.getAddon(world)).thenReturn(Optional.of(gma));
150+
when(plugin.getIWM()).thenReturn(iwm);
151+
152+
138153
pl = new PlayerListener(addon);
139154

140155
}
@@ -178,7 +193,7 @@ public void testOnPlayerQuit() {
178193
*/
179194
@Test
180195
public void testOnPlayerRespawn() {
181-
PlayerRespawnEvent event = new PlayerRespawnEvent(player, null, false, false);
196+
PlayerRespawnEvent event = new PlayerRespawnEvent(player, from, false, false, null);
182197
pl.onPlayerRespawn(event);
183198
PowerMockito.verifyStatic(Bukkit.class);
184199
Bukkit.getScheduler();

0 commit comments

Comments
 (0)