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
5 changes: 3 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

<ciManagement>
<system>jenkins</system>
<url>http://ci.codemc.org/job/BentoBoxWorld/job/Border</url>
<url>https://ci.codemc.org/job/BentoBoxWorld/job/Border</url>
</ciManagement>

<issueManagement>
Expand All @@ -51,7 +51,7 @@
<!-- Revision variable removes warning about dynamic version -->
<revision>${build.version}-SNAPSHOT</revision>
<!-- This allows to change between versions and snapshots. -->
<build.version>4.7.0</build.version>
<build.version>4.8.0</build.version>
<build.number>-LOCAL</build.number>
<!-- Sonar Cloud -->
<sonar.projectKey>BentoBoxWorld_Border</sonar.projectKey>
Expand Down Expand Up @@ -224,6 +224,7 @@
<configuration>
<argLine>
${argLine}
-XX:+EnableDynamicAgentLoading
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.math=ALL-UNNAMED
--add-opens java.base/java.io=ALL-UNNAMED
Expand Down
33 changes: 29 additions & 4 deletions src/main/java/world/bentobox/border/Border.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,34 @@
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.BorderColorCommand;
import world.bentobox.border.commands.BorderTypeCommand;
import world.bentobox.border.commands.IslandBorderCommand;
import world.bentobox.border.listeners.BorderShower;
import world.bentobox.border.listeners.PlayerListener;
import world.bentobox.border.listeners.ShowBarrier;
import world.bentobox.border.listeners.ShowWorldBorder;

/**
* Border add-on entry point that wires commands, listeners, and per-player border
* rendering for supported game modes.
* <p>
* Lifecycle:
* <ul>
* <li>{@link #onLoad()} loads and persists configuration.</li>
* <li>{@link #onEnable()} hooks into available game modes, registers commands and listeners,
* and builds the border display implementation.</li>
* </ul>
*/
public class Border extends Addon {

private BorderShower borderShower;

private Settings settings;

private Config<Settings> config = new Config<>(this, Settings.class);
private final Config<Settings> config = new Config<>(this, Settings.class);

private @NonNull List<GameModeAddon> gameModes = new ArrayList<>();
private final @NonNull List<GameModeAddon> gameModes = new ArrayList<>();

private final Set<BorderType> availableBorderTypes = EnumSet.of(BorderType.VANILLA, BorderType.BARRIER);

Expand All @@ -54,6 +66,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"));
gameModeAddon.getPlayerCommand().ifPresent(c -> new BorderColorCommand(this, c, "bordercolor"));
}
});

Expand All @@ -69,12 +82,20 @@ public void onDisable() {
// Nothing to do here
}

/**
* Creates the border shower implementation used for per-player rendering.
*
* @return proxy that delegates to the configured border implementations
*/
private BorderShower createBorder() {
BorderShower customBorder = new ShowBarrier(this);
BorderShower wbapiBorder = new ShowWorldBorder(this);
return new PerPlayerBorderProxy(this, customBorder, wbapiBorder);
}

/**
* @return the active border shower, or {@code null} if the addon is not enabled
*/
public BorderShower getBorderShower() {
return borderShower;
}
Expand All @@ -101,7 +122,7 @@ public Settings getSettings() {
}

/**
* @param world
* @param world to check
* @return true if world is being handled by Border
*/
public boolean inGameWorld(World world) {
Expand Down Expand Up @@ -130,6 +151,10 @@ private void registerPlaceholders()
orElse(new MetaDataValue(getSettings().getType().getId())).asByte()).
orElse(getSettings().getType()).
getCommandLabel());
this.getPlugin().getPlaceholdersManager().registerPlaceholder(this,
"color",
user -> user.getMetaData(PerPlayerBorderProxy.BORDER_COLOR_META_DATA)
.map(MetaDataValue::asString)
.orElse(getSettings().getColor().name().toLowerCase()));
}

}
23 changes: 23 additions & 0 deletions src/main/java/world/bentobox/border/PerPlayerBorderProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,37 @@
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.border.listeners.BorderShower;

/**
* Delegates border rendering to either the custom or vanilla implementation
* based on the per-player border type metadata.
* <p>
* Selection rules:
* <ul>
* <li>If the player has no border type metadata, the add-on default is used.</li>
* <li>If the metadata id is unknown or not enabled, the add-on default is used.</li>
* <li>Otherwise, the stored border type is honored.</li>
* </ul>
*/
public final class PerPlayerBorderProxy implements BorderShower {

/**
* Metadata key for a player's preferred border type id.
*/
public static final String BORDER_BORDERTYPE_META_DATA = "Border_bordertype";
/**
* Metadata key for a player's preferred border color id.
*/
public static final String BORDER_COLOR_META_DATA = "Border_color";

private final Border addon;
private final BorderShower customBorder;
private final BorderShower vanillaBorder;

/**
* @param addon owning add-on providing settings and available types
* @param customBorder custom border renderer (barrier-based)
* @param vanillaBorder vanilla world border renderer
*/
public PerPlayerBorderProxy(Border addon, BorderShower customBorder, BorderShower vanillaBorder) {
this.addon = addon;
this.customBorder = customBorder;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package world.bentobox.border.commands;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import world.bentobox.bentobox.api.commands.CompositeCommand;
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;
import world.bentobox.border.PerPlayerBorderProxy;
import world.bentobox.border.Settings.BorderColor;

/**
* Command to allow players with the appropriate permission to set their own border color.
* Permission required: [gamemode].border.color.[color] e.g. bskyblock.border.color.red
*/
public final class BorderColorCommand extends CompositeCommand {

private static final List<String> COLOR_NAMES = Arrays.stream(BorderColor.values())
.map(c -> c.name().toLowerCase())
.toList();

private final Border addon;
private Island island;

public BorderColorCommand(Border addon, CompositeCommand parent, String commandLabel) {
super(addon, parent, commandLabel);
this.addon = addon;
}

@Override
public void setup() {
this.setPermission("border.color");
this.setDescription("border.set-color.description");
this.setOnlyPlayer(true);
}

@Override
public boolean canExecute(User user, String label, List<String> args) {
if (!this.getWorld().equals(Util.getWorld(user.getWorld()))) {
user.sendMessage("general.errors.wrong-world");
return false;
}
island = getIslands().getIsland(getWorld(), user);
return island != null;
}

@Override
public boolean execute(User user, String label, List<String> args) {
if (args.size() != 1) {
this.showHelp(this, user);
return false;
}

String colorArg = args.getFirst().toLowerCase();

if (!COLOR_NAMES.contains(colorArg)) {
user.sendMessage("border.set-color.error-invalid-color");
return false;
}

String permPrefix = getPlugin().getIWM().getPermissionPrefix(getWorld());
String colorPerm = permPrefix + "border.color." + colorArg;
if (!user.hasPermission(colorPerm)) {
user.sendMessage("general.errors.no-permission", "[permission]", colorPerm);
return false;
}

BorderColor color = BorderColor.valueOf(colorArg.toUpperCase());
addon.getBorderShower().hideBorder(user);
user.putMetaData(PerPlayerBorderProxy.BORDER_COLOR_META_DATA, new MetaDataValue(color.name()));
addon.getBorderShower().showBorder(user.getPlayer(), island);
user.sendMessage("border.set-color.changed", "[color]", colorArg);
return true;
}

@Override
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
String permPrefix = getPlugin().getIWM().getPermissionPrefix(getWorld());
return Optional.of(COLOR_NAMES.stream()
.filter(c -> user.hasPermission(permPrefix + "border.color." + c))
.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ public boolean execute(User user, String label, List<String> args) {
return false;
}

if (availableTypes.stream().anyMatch(args.get(0)::equalsIgnoreCase)) {
changeBorderTypeTo(user, args.get(0));
if (availableTypes.stream().anyMatch(args.getFirst()::equalsIgnoreCase)) {
changeBorderTypeTo(user, args.getFirst());
return true;
}

Expand All @@ -88,7 +88,7 @@ private void toggleBorderType(User user)

if (index + 1 >= borderTypes.size())
{
this.changeBorderTypeTo(user, borderTypes.get(0).getCommandLabel());
this.changeBorderTypeTo(user, borderTypes.getFirst().getCommandLabel());
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
public class IslandBorderCommand extends CompositeCommand {

public static final String BORDER_COMMAND_PERM = "border.toggle";
private Border addon;
private final Border addon;
private Island island;

public IslandBorderCommand(Border addon, CompositeCommand parent, String label) {
Expand All @@ -29,6 +29,7 @@ public void setup() {
setConfigurableRankCommand();

new BorderTypeCommand(this.getAddon(), this, "type");
new BorderColorCommand(this.getAddon(), this, "color");
}

@Override
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/world/bentobox/border/listeners/BorderShower.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,26 @@
*
*/
public interface BorderShower {
public static final String BORDER_STATE_META_DATA = "Border_state";
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);
void showBorder(Player player, Island island);

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

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

Expand All @@ -45,15 +45,15 @@ public default void clearUser(User user) {
* @param user user
* @param island island
*/
public default void refreshView(User user, Island island){
default void refreshView(User user, Island island){
// Do nothing
}

/**
* Teleports an entity, typically a player back within the island space they are in
* @param entity entity
*/
public default void teleportEntity(Border addon, Entity entity) {
default void teleportEntity(Border addon, Entity entity) {
addon.getIslands().getIslandAt(entity.getLocation()).ifPresent(i -> {
Vector unitVector = i.getCenter().toVector().subtract(entity.getLocation().toVector()).normalize()
.multiply(new Vector(1, 0, 1));
Expand Down
Loading