Skip to content

Commit

Permalink
Added option to use WorldBorderAPI
Browse files Browse the repository at this point in the history
  • Loading branch information
tastybento committed Feb 21, 2021
1 parent 68cd4a7 commit 1ad4d9a
Show file tree
Hide file tree
Showing 9 changed files with 332 additions and 184 deletions.
15 changes: 14 additions & 1 deletion src/main/java/world/bentobox/border/Border.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import java.util.ArrayList;
import java.util.List;

import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import org.eclipse.jdt.annotation.NonNull;

import world.bentobox.bentobox.api.addons.Addon;
Expand All @@ -16,7 +18,7 @@

public final class Border extends Addon {

private final PlayerBorder playerBorder = new PlayerBorder(this);
private PlayerBorder playerBorder;

private Settings settings;

Expand All @@ -37,6 +39,7 @@ public void onLoad() {
@Override
public void onEnable() {
gameModes.clear();
playerBorder = new PlayerBorder(this);
// Register commands
getPlugin().getAddonsManager().getGameModeAddons().forEach(gameModeAddon -> {

Expand Down Expand Up @@ -83,6 +86,16 @@ private void loadSettings() {
}
// Save new version
this.config.saveConfigObject(settings);

// Check for WorldBorderAPI
if (getSettings().isUseWbapi()) {
Plugin plugin = Bukkit.getPluginManager().getPlugin("WorldBorderAPI");
if (plugin == null || !plugin.isEnabled()) {
getLogger().warning("WorldBorderAPI not found. Download from https://github.com/yannicklamprecht/WorldBorderAPI/releases");
this.setState(State.DISABLED);
return;
}
}
}

public Settings getSettings() {
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/world/bentobox/border/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,15 @@ public class Settings implements ConfigObject {
@ConfigEntry(path = "disabled-gamemodes")
private Set<String> disabledGameModes = new HashSet<>();

@ConfigComment("")
@ConfigComment("Use vanilla world border. Requires WorldBorderAPI plugin.")
@ConfigComment("Download from https://github.com/yannicklamprecht/WorldBorderAPI/releases")
@ConfigEntry(path = "use-wbapi")
private boolean useWbapi = false;

@ConfigComment("")
@ConfigComment("Use barrier blocks. If false, the border is indicated by particles only.")
@ConfigComment("Only applicable if vanilla world border is not used")
@ConfigEntry(path = "use-barrier-blocks")
private boolean useBarrierBlocks = true;

Expand Down Expand Up @@ -91,4 +98,18 @@ public boolean isShowMaxBorder() {
public void setShowMaxBorder(boolean showMaxBorder) {
this.showMaxBorder = showMaxBorder;
}

/**
* @return the useWbapi
*/
public boolean isUseWbapi() {
return useWbapi;
}

/**
* @param useWbapi the useWbapi to set
*/
public void setUseWbapi(boolean useWbapi) {
this.useWbapi = useWbapi;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import world.bentobox.bentobox.api.metadata.MetaDataValue;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.border.Border;
import world.bentobox.border.listeners.PlayerBorder;
import world.bentobox.border.listeners.BorderShower;

public class IslandBorderCommand extends CompositeCommand {

Expand All @@ -32,14 +32,14 @@ public boolean canExecute(User user, String label, List<String> args) {

@Override
public boolean execute(User user, String label, List<String> args) {
boolean on = user.getMetaData(PlayerBorder.BORDER_STATE_META_DATA).map(md -> md.asBoolean()).orElse(addon.getSettings().isShowByDefault());
boolean on = user.getMetaData(BorderShower.BORDER_STATE_META_DATA).map(md -> md.asBoolean()).orElse(addon.getSettings().isShowByDefault());
if (on) {
user.sendMessage("border.toggle.border-off");
user.putMetaData(PlayerBorder.BORDER_STATE_META_DATA, new MetaDataValue(false));
addon.getPlayerBorder().hideBarrier(user);
user.putMetaData(BorderShower.BORDER_STATE_META_DATA, new MetaDataValue(false));
addon.getPlayerBorder().getBorder().hideBorder(user);
} else {
user.sendMessage("border.toggle.border-on");
user.putMetaData(PlayerBorder.BORDER_STATE_META_DATA, new MetaDataValue(true));
user.putMetaData(BorderShower.BORDER_STATE_META_DATA, new MetaDataValue(true));
}
return true;
}
Expand Down
36 changes: 36 additions & 0 deletions src/main/java/world/bentobox/border/listeners/BorderShower.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package world.bentobox.border.listeners;

import org.bukkit.entity.Player;

import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;

/**
* A border shower class
* @author tastybento
*
*/
public interface BorderShower {
public static final String BORDER_STATE_META_DATA = "Border_state";

/**
* Show the barrier to the player on an island
* @param player - player to show
* @param island - island
*/
public void showBorder(Player player, Island island);

/**
* Hide the barrier
* @param user - user
*/
public void hideBorder(User user);

/**
* Removes any cache
* @param user - user
*/
default public void clearUser(User user) {};


}
178 changes: 13 additions & 165 deletions src/main/java/world/bentobox/border/listeners/PlayerBorder.java
Original file line number Diff line number Diff line change
@@ -1,30 +1,14 @@
package world.bentobox.border.listeners;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.event.vehicle.VehicleMoveEvent;
import org.bukkit.util.Vector;

import world.bentobox.bentobox.api.events.island.IslandProtectionRangeChangeEvent;
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;

/**
Expand All @@ -34,30 +18,31 @@
*/
public class PlayerBorder implements Listener {

public static final String BORDER_STATE_META_DATA = "Border_state";
private static final BlockData BLOCK = Material.BARRIER.createBlockData();
private final Border addon;
private static final Particle PARTICLE = Particle.REDSTONE;
private static final Particle MAX_PARTICLE = Particle.BARRIER;
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;
private final Map<UUID, Set<BarrierBlock>> barrierBlocks = new HashMap<>();

private final BorderShower barrier;

/**
* @param addon
*/
public PlayerBorder(Border addon) {
super();
this.addon = addon;
this.barrier = addon.getSettings().isUseWbapi() ? new ShowWorldBorder(addon) : new ShowBarrier(addon);
}

/**
* @return the barrier
*/
public BorderShower getBorder() {
return barrier;
}


@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 -> showBarrier(e.getPlayer(), i));
addon.getIslands().getIslandAt(e.getPlayer().getLocation()).ifPresent(i -> barrier.showBorder(e.getPlayer(), i));
}
}

Expand All @@ -66,153 +51,16 @@ public void onVehicleMove(VehicleMoveEvent e) {
// Remove head movement
if (!e.getFrom().toVector().equals(e.getTo().toVector())) {
e.getVehicle().getPassengers().stream().filter(en -> en instanceof Player).map(en -> (Player)en).forEach(p ->
addon.getIslands().getIslandAt(p.getLocation()).ifPresent(i -> showBarrier(p, i)));
addon.getIslands().getIslandAt(p.getLocation()).ifPresent(i -> barrier.showBorder(p, i)));
}
}

@EventHandler(priority = EventPriority.NORMAL)
public void onProtectionRangeChange(IslandProtectionRangeChangeEvent e) {
// Cleans up barrier blocks that were on old range
e.getIsland().getPlayersOnIsland().forEach(player -> hideBarrier(User.getInstance(player)));
e.getIsland().getPlayersOnIsland().forEach(player -> barrier.hideBorder(User.getInstance(player)));
}

/**
* Show the barrier to the player on an island
* @param player - player to show
* @param island - island
*/
public void showBarrier(Player player, Island island) {

if (addon.getSettings().getDisabledGameModes().contains(island.getGameMode()))
return;

if (!User.getInstance(player).getMetaData(BORDER_STATE_META_DATA).map(MetaDataValue::asBoolean).orElse(addon.getSettings().isShowByDefault())) {
return;
}

// Get the locations to show
Location loc = player.getLocation();
showWalls(player, loc,
island.getMinProtectedX(),
island.getMaxProtectedX(),
island.getMinProtectedZ(),
island.getMaxProtectedZ(), false);
// If the max border needs to be shown, show it as well
if (addon.getSettings().isShowMaxBorder()) {
showWalls(player, loc,
island.getMinX(),
island.getMaxX(),
island.getMinZ(),
island.getMaxZ(), true);
}

}

private void showWalls(Player player, Location loc, int xMin, int xMax, int zMin, int zMax, boolean max) {
if (loc.getBlockX() - xMin < BARRIER_RADIUS) {
// Close to min x
for (int z = Math.max(loc.getBlockZ() - BARRIER_RADIUS, zMin); z < loc.getBlockZ() + BARRIER_RADIUS && z < zMax; z++) {
for (int y = -BARRIER_RADIUS; y < BARRIER_RADIUS; y++) {
showPlayer(player, xMin-1, loc.getBlockY() + y, z, max);
}
}
}
if (loc.getBlockZ() - zMin < BARRIER_RADIUS) {
// Close to min z
for (int x = Math.max(loc.getBlockX() - BARRIER_RADIUS, xMin); x < loc.getBlockX() + BARRIER_RADIUS && x < xMax; x++) {
for (int y = -BARRIER_RADIUS; y < BARRIER_RADIUS; y++) {
showPlayer(player, x, loc.getBlockY() + y, zMin-1, max);
}
}
}
if (xMax - loc.getBlockX() < BARRIER_RADIUS) {
// Close to max x
for (int z = Math.max(loc.getBlockZ() - BARRIER_RADIUS, zMin); z < loc.getBlockZ() + BARRIER_RADIUS && z < zMax; z++) {
for (int y = -BARRIER_RADIUS; y < BARRIER_RADIUS; y++) {
showPlayer(player, xMax, loc.getBlockY() + y, z, max); // not xMax+1, that's outside the region
}
}
}
if (zMax - loc.getBlockZ() < BARRIER_RADIUS) {
// Close to max z
for (int x = Math.max(loc.getBlockX() - BARRIER_RADIUS, xMin); x < loc.getBlockX() + BARRIER_RADIUS && x < xMax; x++) {
for (int y = -BARRIER_RADIUS; y < BARRIER_RADIUS; y++) {
showPlayer(player, x, loc.getBlockY() + y, zMax, max); // not zMax+1, that's outside the region
}
}
}

}

private void showPlayer(Player player, int i, int j, int k, boolean max) {
// Get if on or in border
if (addon.getSettings().isUseBarrierBlocks()
&& player.getLocation().getBlockX() == i
&& player.getLocation().getBlockZ() == k) {
teleportPlayer(player);
return;
}
Location l = new Location(player.getWorld(), i, j, k);
Util.getChunkAtAsync(l).thenAccept(c -> {
if (j < 0 || j > player.getWorld().getMaxHeight()) {
User.getInstance(player).spawnParticle(max ? MAX_PARTICLE : PARTICLE, PARTICLE_DUST_RED, i + 0.5D, j + 0.0D, k + 0.5D);
} else {
User.getInstance(player).spawnParticle(max ? MAX_PARTICLE : PARTICLE, PARTICLE_DUST_BLUE, i + 0.5D, j + 0.0D, k + 0.5D);
}
if (addon.getSettings().isUseBarrierBlocks() && (l.getBlock().isEmpty() || l.getBlock().isLiquid())) {
player.sendBlockChange(l, BLOCK);
barrierBlocks.computeIfAbsent(player.getUniqueId(), u -> new HashSet<>()).add(new BarrierBlock(l, l.getBlock().getBlockData()));
}
});
}

private void teleportPlayer(Player p) {
addon.getIslands().getIslandAt(p.getLocation()).ifPresent(i -> {
Vector unitVector = i.getCenter().toVector().subtract(p.getLocation().toVector()).normalize()
.multiply(new Vector(1,0,1));
p.setVelocity(new Vector (0,0,0));
// 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);
});
}

/**
* Hide the barrier
* @param user - user
*/
public void hideBarrier(User user) {
if (barrierBlocks.containsKey(user.getUniqueId())) {
barrierBlocks.get(user.getUniqueId()).stream()
.filter(v -> v.l.getWorld().equals(user.getWorld()))
.forEach(v -> {
user.getPlayer().sendBlockChange(v.l, v.oldBlockData);
});
// Clean up
clearUser(user);
}
}

/**
* Removes any cached barrier blocks
* @param user - user
*/
public void clearUser(User user) {
barrierBlocks.remove(user.getUniqueId());
}

private class BarrierBlock {
Location l;
BlockData oldBlockData;
public BarrierBlock(Location l, BlockData oldBlockData) {
super();
this.l = l;
this.oldBlockData = oldBlockData;
}

}

}

0 comments on commit 1ad4d9a

Please sign in to comment.