From a491faf6abef01da105efd5cd14418e8ff060d62 Mon Sep 17 00:00:00 2001 From: tastybento Date: Wed, 3 Jan 2024 12:23:35 +0900 Subject: [PATCH 01/14] Version 4.2.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d4e04e9..4ce85e6 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ ${build.version}-SNAPSHOT - 4.2.1 + 4.2.2 -LOCAL BentoBoxWorld_Border From 08df85f38005ed5146dc5b36fc08853cda108847 Mon Sep 17 00:00:00 2001 From: tastybento Date: Wed, 3 Jan 2024 12:24:59 +0900 Subject: [PATCH 02/14] 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. --- .../bentobox/border/listeners/PlayerListener.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/world/bentobox/border/listeners/PlayerListener.java b/src/main/java/world/bentobox/border/listeners/PlayerListener.java index 3568f86..66a9604 100644 --- a/src/main/java/world/bentobox/border/listeners/PlayerListener.java +++ b/src/main/java/world/bentobox/border/listeners/PlayerListener.java @@ -22,6 +22,7 @@ import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.vehicle.VehicleMoveEvent; +import org.bukkit.util.NumberConversions; import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; @@ -151,10 +152,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()) { @@ -174,6 +180,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 From bcae4d987f1e7300fa3aad27381d1524fd255feb Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 4 Feb 2024 16:28:55 -0800 Subject: [PATCH 03/14] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 007a062..e71a362 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![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/).** @@ -12,4 +12,4 @@ [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! \ No newline at end of file +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! From 9ed606e84b12d218ffe3849797e9cf5ca9462517 Mon Sep 17 00:00:00 2001 From: tastybento Date: Wed, 21 Feb 2024 20:57:29 -0800 Subject: [PATCH 04/14] Fix perm issue #120 (#121) --- .../border/listeners/PlayerListener.java | 16 +++++++++------- .../border/listeners/PlayerListenerTest.java | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/main/java/world/bentobox/border/listeners/PlayerListener.java b/src/main/java/world/bentobox/border/listeners/PlayerListener.java index 66a9604..4481b70 100644 --- a/src/main/java/world/bentobox/border/listeners/PlayerListener.java +++ b/src/main/java/world/bentobox/border/listeners/PlayerListener.java @@ -65,17 +65,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 -> diff --git a/src/test/java/world/bentobox/border/listeners/PlayerListenerTest.java b/src/test/java/world/bentobox/border/listeners/PlayerListenerTest.java index 3a62045..632369f 100644 --- a/src/test/java/world/bentobox/border/listeners/PlayerListenerTest.java +++ b/src/test/java/world/bentobox/border/listeners/PlayerListenerTest.java @@ -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; @@ -82,6 +84,10 @@ public class PlayerListenerTest { private Island island; @Mock private Vehicle vehicle; + @Mock + private IslandWorldManager iwm; + @Mock + private GameModeAddon gma; /** @@ -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); } @@ -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(); From b344194ebca980bdcc7abe7f8a089e6b9f2c7ca9 Mon Sep 17 00:00:00 2001 From: evlad Date: Thu, 21 Mar 2024 23:35:11 +0200 Subject: [PATCH 05/14] feat: detect mounted players on entity (#88) --- .../border/listeners/PlayerListener.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/main/java/world/bentobox/border/listeners/PlayerListener.java b/src/main/java/world/bentobox/border/listeners/PlayerListener.java index 4481b70..0e839fa 100644 --- a/src/main/java/world/bentobox/border/listeners/PlayerListener.java +++ b/src/main/java/world/bentobox/border/listeners/PlayerListener.java @@ -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; @@ -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; @@ -22,10 +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; @@ -45,6 +51,7 @@ public class PlayerListener implements Listener { private final Border addon; private Set inTeleport; private final BorderShower show; + private Map mountedPlayers = new HashMap<>(); public PlayerListener(Border addon) { this.addon = addon; @@ -208,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 From a42808a1461f5ff933b5894139c46759dcfb8d67 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 5 May 2024 20:38:29 -0700 Subject: [PATCH 06/14] Version 4.3.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4ce85e6..da70a61 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ ${build.version}-SNAPSHOT - 4.2.2 + 4.3.0 -LOCAL BentoBoxWorld_Border From dda6eb0be3c3a6d275fc024033f5d91a012dda8e Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 5 May 2024 20:58:06 -0700 Subject: [PATCH 07/14] Changes to work with 1.20.6. Has backwards compatibility. (#125) --- pom.xml | 2 +- .../world/bentobox/border/listeners/PlayerListener.java | 6 +++--- .../java/world/bentobox/border/listeners/ShowBarrier.java | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index da70a61..c856070 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ 17 2.0.9 - 1.20.3-R0.1-SNAPSHOT + 1.20.4-R0.1-SNAPSHOT 2.0.0-SNAPSHOT ${build.version}-SNAPSHOT diff --git a/src/main/java/world/bentobox/border/listeners/PlayerListener.java b/src/main/java/world/bentobox/border/listeners/PlayerListener.java index 0e839fa..547027f 100644 --- a/src/main/java/world/bentobox/border/listeners/PlayerListener.java +++ b/src/main/java/world/bentobox/border/listeners/PlayerListener.java @@ -1,7 +1,7 @@ package world.bentobox.border.listeners; -import java.util.HashSet; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -18,6 +18,8 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDismountEvent; +import org.bukkit.event.entity.EntityMountEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; @@ -30,8 +32,6 @@ 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; diff --git a/src/main/java/world/bentobox/border/listeners/ShowBarrier.java b/src/main/java/world/bentobox/border/listeners/ShowBarrier.java index 7cc0150..7267913 100644 --- a/src/main/java/world/bentobox/border/listeners/ShowBarrier.java +++ b/src/main/java/world/bentobox/border/listeners/ShowBarrier.java @@ -34,8 +34,10 @@ public class ShowBarrier implements BorderShower { private final Border addon; - private static final Particle PARTICLE = Particle.REDSTONE; - private static final Particle MAX_PARTICLE = Enums.getIfPresent(Particle.class, "BARRIER_BLOCK").or(Enums.getIfPresent(Particle.class, "BARRIER").or(Particle.BLOCK_CRACK)); + private static final Particle PARTICLE = Enums.getIfPresent(Particle.class, "DUST") + .or(Enums.getIfPresent(Particle.class, "REDSTONE").or(Particle.FLAME)); + private static final Particle MAX_PARTICLE = Enums.getIfPresent(Particle.class, "BARRIER_BLOCK") + .or(Enums.getIfPresent(Particle.class, "BARRIER").or(Particle.FLAME)); private static final Particle.DustOptions PARTICLE_DUST_RED = new Particle.DustOptions(Color.RED, 1.0F); private static final Particle.DustOptions PARTICLE_DUST_BLUE = new Particle.DustOptions(Color.BLUE, 1.0F); private static final int BARRIER_RADIUS = 5; From b96d8190cf76fd17e459d9a4bf1dda1c79ac112d Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 5 May 2024 21:02:19 -0700 Subject: [PATCH 08/14] Fix imports --- .../java/world/bentobox/border/listeners/PlayerListener.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/world/bentobox/border/listeners/PlayerListener.java b/src/main/java/world/bentobox/border/listeners/PlayerListener.java index 677fa3f..547027f 100644 --- a/src/main/java/world/bentobox/border/listeners/PlayerListener.java +++ b/src/main/java/world/bentobox/border/listeners/PlayerListener.java @@ -32,8 +32,6 @@ 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; From ae7ef33139b34c51dddb320757f39c32b5c04ac3 Mon Sep 17 00:00:00 2001 From: Minecraft_15 <147026380+huguyt@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:52:12 +0800 Subject: [PATCH 09/14] Update zh-CN.yml (#127) --- src/main/resources/locales/zh-CN.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/resources/locales/zh-CN.yml b/src/main/resources/locales/zh-CN.yml index ecf0f69..f2601e4 100644 --- a/src/main/resources/locales/zh-CN.yml +++ b/src/main/resources/locales/zh-CN.yml @@ -1,10 +1,9 @@ ---- border: toggle: - description: 打开/关闭边框 - border-on: "&a 启用边框。" - border-off: "&a 边框已禁用。" + description: 启用/禁用边界屏障 + border-on: '&a边界屏障已启用.' + border-off: '&a边界屏障已禁用.' set-type: - description: 更改边框的类型 - changed: "&a 边框类型更改为 &b[type]&a。" - error-unavailable-type: "&c 此类型不可用或不存在。" + description: 更改边界屏障类型 + changed: '&a边界屏障已更改为: &b[type]&a.' + error-unavailable-type: '&c该屏障类型不可用或不存在.' From e00b2c9c3b061dcb5e7070d6c9a80ab42db93095 Mon Sep 17 00:00:00 2001 From: "gitlocalize-app[bot]" <55277160+gitlocalize-app[bot]@users.noreply.github.com> Date: Sat, 8 Jun 2024 10:22:19 -0700 Subject: [PATCH 10/14] Latvian translationa (#128) * Translate lv.yml via GitLocalize * Translate lv.yml via GitLocalize --------- Co-authored-by: mt-gitlocalize Co-authored-by: tastybento --- src/main/resources/locales/lv.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/resources/locales/lv.yml b/src/main/resources/locales/lv.yml index 82caaa9..7718225 100644 --- a/src/main/resources/locales/lv.yml +++ b/src/main/resources/locales/lv.yml @@ -4,3 +4,7 @@ border: description: pārslēdz iespēju redzēt robežu border-on: "&a Robeža ieslēgta." border-off: "&a Robeža izslēgta." + set-type: + description: maina apmales veidu + changed: "&a Apmales veids mainīts uz &b[type]&a." + error-unavailable-type: "&c Šis veids nav pieejams vai neeksistē." From aa8806abc04396e9d32791579a827cc97d3e4684 Mon Sep 17 00:00:00 2001 From: tastybento Date: Thu, 25 Jul 2024 13:07:08 -0700 Subject: [PATCH 11/14] Add explicit bordertype command (#130) * Add explicit bordertype command * Add perm to addon.yml and make it default to off * Remove unused method. --- src/main/java/world/bentobox/border/Border.java | 2 ++ .../border/commands/BorderTypeCommand.java | 7 +++---- .../border/commands/IslandBorderCommand.java | 2 +- .../bentobox/border/listeners/PlayerListener.java | 15 +++++++-------- src/main/resources/addon.yml | 5 ++++- .../border/commands/BorderTypeCommandTest.java | 10 +--------- 6 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/main/java/world/bentobox/border/Border.java b/src/main/java/world/bentobox/border/Border.java index 54b1ba8..78d7d65 100644 --- a/src/main/java/world/bentobox/border/Border.java +++ b/src/main/java/world/bentobox/border/Border.java @@ -14,6 +14,7 @@ import world.bentobox.bentobox.api.configuration.Config; import world.bentobox.bentobox.api.metadata.MetaDataValue; import world.bentobox.bentobox.util.Util; +import world.bentobox.border.commands.BorderTypeCommand; import world.bentobox.border.commands.IslandBorderCommand; import world.bentobox.border.listeners.BorderShower; import world.bentobox.border.listeners.PlayerListener; @@ -52,6 +53,7 @@ public void onEnable() { log("Border hooking into " + gameModeAddon.getDescription().getName()); gameModeAddon.getPlayerCommand().ifPresent(c -> new IslandBorderCommand(this, c, "border")); + gameModeAddon.getPlayerCommand().ifPresent(c -> new BorderTypeCommand(this, c, "bordertype")); } }); diff --git a/src/main/java/world/bentobox/border/commands/BorderTypeCommand.java b/src/main/java/world/bentobox/border/commands/BorderTypeCommand.java index 44dc8d3..e4f183b 100644 --- a/src/main/java/world/bentobox/border/commands/BorderTypeCommand.java +++ b/src/main/java/world/bentobox/border/commands/BorderTypeCommand.java @@ -19,13 +19,12 @@ */ public final class BorderTypeCommand extends CompositeCommand { - public static final String BORDER_TYPE_COMMAND_PERM = "border.type"; private final Border addon; private Island island; private final List availableTypes; - public BorderTypeCommand(Border addon, CompositeCommand parent) { - super(addon, parent, "type"); + public BorderTypeCommand(Border addon, CompositeCommand parent, String commandLabel) { + super(addon, parent, commandLabel); this.addon = addon; this.availableTypes = addon.getAvailableBorderTypesView() .stream() @@ -35,7 +34,7 @@ public BorderTypeCommand(Border addon, CompositeCommand parent) { @Override public void setup() { - this.setPermission(BORDER_TYPE_COMMAND_PERM); + this.setPermission("border." + this.getLabel()); this.setDescription("border.set-type.description"); this.setOnlyPlayer(true); } diff --git a/src/main/java/world/bentobox/border/commands/IslandBorderCommand.java b/src/main/java/world/bentobox/border/commands/IslandBorderCommand.java index 2963909..3a552cc 100644 --- a/src/main/java/world/bentobox/border/commands/IslandBorderCommand.java +++ b/src/main/java/world/bentobox/border/commands/IslandBorderCommand.java @@ -28,7 +28,7 @@ public void setup() { this.setOnlyPlayer(true); setConfigurableRankCommand(); - new BorderTypeCommand(this.getAddon(), this); + new BorderTypeCommand(this.getAddon(), this, "type"); } @Override diff --git a/src/main/java/world/bentobox/border/listeners/PlayerListener.java b/src/main/java/world/bentobox/border/listeners/PlayerListener.java index 547027f..d26a917 100644 --- a/src/main/java/world/bentobox/border/listeners/PlayerListener.java +++ b/src/main/java/world/bentobox/border/listeners/PlayerListener.java @@ -39,7 +39,6 @@ import world.bentobox.bentobox.util.Util; import world.bentobox.border.Border; import world.bentobox.border.PerPlayerBorderProxy; -import world.bentobox.border.commands.BorderTypeCommand; import world.bentobox.border.commands.IslandBorderCommand; /** @@ -75,16 +74,16 @@ protected void processEvent(PlayerJoinEvent e) { // 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)) { + .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 + "border.type") && !e.getPlayer().hasPermission(permPrefix + "border.bordertype")) { // 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 -> @@ -215,7 +214,7 @@ 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 diff --git a/src/main/resources/addon.yml b/src/main/resources/addon.yml index ef18ae2..bedc91a 100644 --- a/src/main/resources/addon.yml +++ b/src/main/resources/addon.yml @@ -14,4 +14,7 @@ permissions: default: op '[gamemode].border.type': description: Player can use border type setting command - default: true \ No newline at end of file + default: true + '[gamemode].bordertype': + description: Player can use bordertype command to change the border type + default: false \ No newline at end of file diff --git a/src/test/java/world/bentobox/border/commands/BorderTypeCommandTest.java b/src/test/java/world/bentobox/border/commands/BorderTypeCommandTest.java index b2bbd3a..f50e1b2 100644 --- a/src/test/java/world/bentobox/border/commands/BorderTypeCommandTest.java +++ b/src/test/java/world/bentobox/border/commands/BorderTypeCommandTest.java @@ -23,7 +23,6 @@ import org.bukkit.World; import org.bukkit.entity.Player; import org.eclipse.jdt.annotation.Nullable; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -139,14 +138,7 @@ public void setUp() throws Exception { when(addon.getSettings()).thenReturn(settings); - ic = new BorderTypeCommand(addon, ac); - } - - /** - * @throws java.lang.Exception - */ - @After - public void tearDown() throws Exception { + ic = new BorderTypeCommand(addon, ac, "type"); } /** From b0abf590b3d0e38260b87f8a1ac38ce3ca73932a Mon Sep 17 00:00:00 2001 From: tastybento Date: Tue, 30 Jul 2024 22:52:03 -0700 Subject: [PATCH 12/14] 131 null to location (#132) * Version 4.3.1 * Add defensive code for null to's #131 --- pom.xml | 2 +- .../java/world/bentobox/border/listeners/PlayerListener.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c856070..a66ebaa 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ ${build.version}-SNAPSHOT - 4.3.0 + 4.3.1 -LOCAL BentoBoxWorld_Border diff --git a/src/main/java/world/bentobox/border/listeners/PlayerListener.java b/src/main/java/world/bentobox/border/listeners/PlayerListener.java index d26a917..8482356 100644 --- a/src/main/java/world/bentobox/border/listeners/PlayerListener.java +++ b/src/main/java/world/bentobox/border/listeners/PlayerListener.java @@ -109,7 +109,7 @@ public void onPlayerTeleport(PlayerTeleportEvent e) { show.clearUser(User.getInstance(player)); - if (!addon.inGameWorld(to.getWorld())) { + if (to == null || !addon.inGameWorld(to.getWorld())) { return; } From 4a917523f4ab0803d74b262511dee75526755aa7 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 1 Sep 2024 08:36:33 -0700 Subject: [PATCH 13/14] If border is off, then don't move player back. --- pom.xml | 2 +- .../bentobox/border/listeners/PlayerListener.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a66ebaa..34f1fc7 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ 2.0.9 1.20.4-R0.1-SNAPSHOT - 2.0.0-SNAPSHOT + 2.5.0-SNAPSHOT ${build.version}-SNAPSHOT diff --git a/src/main/java/world/bentobox/border/listeners/PlayerListener.java b/src/main/java/world/bentobox/border/listeners/PlayerListener.java index 8482356..b62d066 100644 --- a/src/main/java/world/bentobox/border/listeners/PlayerListener.java +++ b/src/main/java/world/bentobox/border/listeners/PlayerListener.java @@ -102,9 +102,20 @@ public void onPlayerRespawn(PlayerRespawnEvent e) { show.showBorder(e.getPlayer(), i))); } + private boolean isOn(Player player) { + // Check if border is off + User user = User.getInstance(player); + return user.getMetaData(BorderShower.BORDER_STATE_META_DATA).map(MetaDataValue::asBoolean) + .orElse(addon.getSettings().isShowByDefault()); + + } + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onPlayerTeleport(PlayerTeleportEvent e) { Player player = e.getPlayer(); + if (!isOn(player)) { + return; + } Location to = e.getTo(); show.clearUser(User.getInstance(player)); @@ -145,6 +156,9 @@ public void onPlayerTeleport(PlayerTeleportEvent e) { @EventHandler(priority = EventPriority.NORMAL) public void onPlayerLeaveIsland(PlayerMoveEvent e) { Player p = e.getPlayer(); + if (!isOn(p)) { + return; + } Location from = e.getFrom(); if (!addon.getSettings().isReturnTeleport() || !outsideCheck(e.getPlayer(), from, e.getTo())) { return; From 4b22a1dc4f9a71946960324490b7b2a94078b220 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 9 Nov 2024 11:32:07 -0800 Subject: [PATCH 14/14] Update to MC 1.21.3 and codemc updates (#134) --- pom.xml | 18 +- .../border/listeners/BlockListener.java | 325 ++++++++++++++++++ 2 files changed, 334 insertions(+), 9 deletions(-) create mode 100644 src/main/java/world/bentobox/border/listeners/BlockListener.java diff --git a/pom.xml b/pom.xml index 34f1fc7..92442e1 100644 --- a/pom.xml +++ b/pom.xml @@ -33,13 +33,9 @@ - - codemc-snapshots - https://repo.codemc.org/repository/maven-snapshots - - codemc-releases - https://repo.codemc.org/repository/maven-releases + bentoboxworld + https://repo.codemc.org/repository/bentoboxworld/ @@ -49,12 +45,12 @@ 17 2.0.9 - 1.20.4-R0.1-SNAPSHOT - 2.5.0-SNAPSHOT + 1.21.3-R0.1-SNAPSHOT + 2.7.1-SNAPSHOT ${build.version}-SNAPSHOT - 4.3.1 + 4.4.0 -LOCAL BentoBoxWorld_Border @@ -109,6 +105,10 @@ spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots + + bentoboxworld + https://repo.codemc.org/repository/bentoboxworld/ + codemc https://repo.codemc.org/repository/maven-snapshots/ diff --git a/src/main/java/world/bentobox/border/listeners/BlockListener.java b/src/main/java/world/bentobox/border/listeners/BlockListener.java new file mode 100644 index 0000000..a7d187d --- /dev/null +++ b/src/main/java/world/bentobox/border/listeners/BlockListener.java @@ -0,0 +1,325 @@ +package world.bentobox.border.listeners; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +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; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDismountEvent; +import org.bukkit.event.entity.EntityMountEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +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 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.util.Util; +import world.bentobox.border.Border; +import world.bentobox.border.PerPlayerBorderProxy; +import world.bentobox.border.commands.IslandBorderCommand; + +/** + * @author tastybento + */ +public class BlockListener implements Listener { + + private static final Vector XZ = new Vector(1,0,1); + private final Border addon; + private Set inTeleport; + private final BorderShower show; + private Map mountedPlayers = new HashMap<>(); + + public BlockListener(Border addon) { + this.addon = addon; + inTeleport = new HashSet<>(); + this.show = addon.getBorderShower(); + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerJoin(PlayerJoinEvent e) { + // Run one-tick after joining because meta data cannot be set otherwise + Bukkit.getScheduler().runTask(addon.getPlugin(), () -> processEvent(e)); + } + + protected void processEvent(PlayerJoinEvent e) { + User user = User.getInstance(e.getPlayer()); + + show.hideBorder(user); + // Just for sure, disable world Border + user.getPlayer().setWorldBorder(null); + + // 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 + "border.type") && !e.getPlayer().hasPermission(permPrefix + "border.bordertype")) { + // 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 -> + show.showBorder(e.getPlayer(), i))); + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerQuit(PlayerQuitEvent e) { + show.clearUser(User.getInstance(e.getPlayer())); + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerRespawn(PlayerRespawnEvent e) { + show.clearUser(User.getInstance(e.getPlayer())); + Bukkit.getScheduler().runTask(addon.getPlugin(), () -> addon.getIslands().getIslandAt(e.getPlayer().getLocation()).ifPresent(i -> + show.showBorder(e.getPlayer(), i))); + } + + private boolean isOn(Player player) { + // Check if border is off + User user = User.getInstance(player); + return user.getMetaData(BorderShower.BORDER_STATE_META_DATA).map(MetaDataValue::asBoolean) + .orElse(addon.getSettings().isShowByDefault()); + + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onPlayerTeleport(PlayerTeleportEvent e) { + Player player = e.getPlayer(); + if (!isOn(player)) { + return; + } + Location to = e.getTo(); + + show.clearUser(User.getInstance(player)); + + if (to == null || !addon.inGameWorld(to.getWorld())) { + return; + } + + TeleportCause cause = e.getCause(); + boolean isBlacklistedCause = cause == TeleportCause.ENDER_PEARL || cause == TeleportCause.CHORUS_FRUIT; + + Bukkit.getScheduler().runTask(addon.getPlugin(), () -> + addon.getIslands().getIslandAt(to).ifPresentOrElse(i -> { + Optional boxedEnderPearlFlag = i.getPlugin().getFlagsManager().getFlag("ALLOW_MOVE_BOX"); + + if (isBlacklistedCause + && (!i.getProtectionBoundingBox().contains(to.toVector()) + || !i.onIsland(player.getLocation()))) { + e.setCancelled(true); + } + + if (boxedEnderPearlFlag.isPresent() + && boxedEnderPearlFlag.get().isSetForWorld(to.getWorld()) + && cause == TeleportCause.ENDER_PEARL) { + e.setCancelled(false); + } + + show.showBorder(player, i); + }, () -> { + if (isBlacklistedCause) { + e.setCancelled(true); + return; + } + }) + ); + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerLeaveIsland(PlayerMoveEvent e) { + Player p = e.getPlayer(); + if (!isOn(p)) { + return; + } + Location from = e.getFrom(); + if (!addon.getSettings().isReturnTeleport() || !outsideCheck(e.getPlayer(), from, e.getTo())) { + return; + } + // Move the player back inside the border + if (addon.getIslands().getProtectedIslandAt(from).isPresent()) { + e.setCancelled(true); + inTeleport.add(p.getUniqueId()); + Util.teleportAsync(p, from).thenRun(() -> inTeleport.remove(p.getUniqueId())); + return; + } + // Backtrack + 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 && 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()) { + case NETHER: + targetPos.getBlock().getRelative(BlockFace.DOWN).setType(Material.NETHERRACK); + break; + case THE_END: + targetPos.getBlock().getRelative(BlockFace.DOWN).setType(Material.END_STONE); + break; + default: + targetPos.getBlock().getRelative(BlockFace.DOWN).setType(Material.STONE); + break; + } + } + Util.teleportAsync(p, targetPos).thenRun(() -> inTeleport.remove(p.getUniqueId())); + } + }); + } + + 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 + * @param from - from location + * @param to - to location + * @return true if outside the island protection zone + */ + private boolean outsideCheck(Player player, Location from, Location to) { + User user = Objects.requireNonNull(User.getInstance(player)); + + if ((from.getWorld() != null && from.getWorld().equals(to.getWorld()) + && from.toVector().multiply(XZ).equals(to.toVector().multiply(XZ))) + || !addon.inGameWorld(player.getWorld()) + || user.getPlayer().getGameMode() == GameMode.SPECTATOR + // || !addon.getIslands().getIslandAt(to).filter(i -> addon.getIslands().locationIsOnIsland(player, i.getProtectionCenter())).isPresent() + || !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(); + } + + /** + * 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 + */ + @EventHandler(priority = EventPriority.NORMAL) + public void onPlayerMove(PlayerMoveEvent e) { + // Remove head movement + if (!e.getFrom().toVector().equals(e.getTo().toVector())) { + addon.getIslands() + .getIslandAt(e.getPlayer().getLocation()) + .ifPresent(i -> show.refreshView(User.getInstance(e.getPlayer()), i)); + } + } + + /** + * Refresh the view when riding in a vehicle + * @param e event + */ + @EventHandler(priority = EventPriority.NORMAL) + 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) + .forEach(p -> addon + .getIslands() + .getIslandAt(p.getLocation()) + .ifPresent(i -> show.refreshView(User.getInstance(p), i))); + } + } + + /** + * Hide and then show the border to react to the change in protection area + * @param e + */ + @EventHandler(priority = EventPriority.NORMAL) + public void onProtectionRangeChange(IslandProtectionRangeChangeEvent e) { + // Hide and show again + e.getIsland().getPlayersOnIsland().forEach(player -> { + show.hideBorder(User.getInstance(player)); + show.showBorder(player, e.getIsland()); + }); + } +}