1
0
mirror of https://github.com/BentoBoxWorld/Warps.git synced 2024-11-25 12:06:24 +01:00

Merge branch 'develop' of https://github.com/BentoBoxWorld/Warps.git into develop

This commit is contained in:
tastybento 2024-07-02 09:36:17 -07:00
commit fe83d097ca
18 changed files with 447 additions and 101 deletions

View File

@ -17,6 +17,7 @@ import world.bentobox.bentobox.api.flags.clicklisteners.CycleClick;
import world.bentobox.bentobox.managers.RanksManager; import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util; import world.bentobox.bentobox.util.Util;
import world.bentobox.level.Level; import world.bentobox.level.Level;
import world.bentobox.warps.commands.ToggleWarpCommand;
import world.bentobox.warps.commands.WarpCommand; import world.bentobox.warps.commands.WarpCommand;
import world.bentobox.warps.commands.WarpsCommand; import world.bentobox.warps.commands.WarpsCommand;
import world.bentobox.warps.config.Settings; import world.bentobox.warps.config.Settings;
@ -100,6 +101,7 @@ public class Warp extends Addon {
// Load the master warp and warps command // Load the master warp and warps command
new WarpCommand(this); new WarpCommand(this);
new WarpsCommand(this); new WarpsCommand(this);
new ToggleWarpCommand(this);
} }
} }
@ -140,6 +142,7 @@ public class Warp extends Addon {
new WarpCommand(this, gameModeAddon.getPlayerCommand().get()); new WarpCommand(this, gameModeAddon.getPlayerCommand().get());
new WarpsCommand(this, gameModeAddon.getPlayerCommand().get()); new WarpsCommand(this, gameModeAddon.getPlayerCommand().get());
new ToggleWarpCommand(this, gameModeAddon.getPlayerCommand().get());
this.hooked = true; this.hooked = true;
} }
}); });
@ -288,7 +291,7 @@ public class Warp extends Addon {
} }
return switch (requestLabel) { return switch (requestLabel) {
case "getSortedWarps" -> getWarpSignsManager().getSortedWarps(world); case "getSortedWarps" -> getWarpSignsManager().getSortedWarps(world);
case "getWarp" -> uuid == null ? null : getWarpSignsManager().getWarp(world, uuid); case "getWarp" -> uuid == null ? null : getWarpSignsManager().getWarpLocation(world, uuid);
case "getWarpMap" -> getWarpSignsManager().getWarpMap(world); case "getWarpMap" -> getWarpSignsManager().getWarpMap(world);
case "hasWarp" -> uuid == null ? null : getWarpSignsManager().hasWarp(world, uuid); case "hasWarp" -> uuid == null ? null : getWarpSignsManager().hasWarp(world, uuid);
case "listWarps" -> getWarpSignsManager().listWarps(world); case "listWarps" -> getWarpSignsManager().listWarps(world);

View File

@ -0,0 +1,61 @@
package world.bentobox.warps.commands;
import org.bukkit.Bukkit;
import org.bukkit.World;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.warps.Warp;
import world.bentobox.warps.event.WarpToggleEvent;
import world.bentobox.warps.objects.PlayerWarp;
import java.util.List;
import java.util.UUID;
public class ToggleWarpCommand extends CompositeCommand {
private final Warp addon;
public ToggleWarpCommand(Warp addon, CompositeCommand bsbIslandCmd) {
super(bsbIslandCmd, addon.getSettings().getToggleWarpCommand());
this.addon = addon;
}
public ToggleWarpCommand(Warp addon) {
super(addon.getSettings().getToggleWarpCommand());
this.addon = addon;
}
@Override
public void setup() {
this.setPermission(this.getParent() == null ? Warp.WELCOME_WARP_SIGNS + ".togglewarp" : "island.warp.toggle");
this.setOnlyPlayer(true);
this.setDescription("togglewarp.help.description");
}
@Override
public boolean execute(User user, String s, List<String> list) {
UUID userUUID = user.getUniqueId();
World userWorld = user.getWorld();
// Check if the user has a warp
boolean hasWarp = addon.getWarpSignsManager().hasWarp(userWorld, userUUID);
if (hasWarp) {
// If the user has a warp, toggle its visibility
PlayerWarp warp = addon.getWarpSignsManager().getPlayerWarp(userWorld, userUUID);
// Check extreme case if PlayerWarp is null
if (warp == null) {
user.sendMessage("togglewarp.error.generic");
return false;
}
warp.toggle();
Bukkit.getPluginManager().callEvent(new WarpToggleEvent(userUUID, warp));
String message = warp.isEnabled() ? "togglewarp.enabled" : "togglewarp.disabled";
user.sendMessage(message);
} else {
user.sendMessage("togglewarp.error.no-warp");
}
return false;
}
}

View File

@ -50,12 +50,12 @@ public class WarpCommand extends DelayedTeleportCommand {
user.sendMessage("warps.warpTip", "[text]", addon.getSettings().getWelcomeLine()); user.sendMessage("warps.warpTip", "[text]", addon.getSettings().getWelcomeLine());
return false; return false;
} else { } else {
// Attemp to find warp with exact player's name // Attempt to find warp with exact player's name
UUID foundWarp = warpList.stream().filter(u -> getPlayers().getName(u).equalsIgnoreCase(args.get(0))).findFirst().orElse(null); UUID foundWarp = warpList.stream().filter(u -> getPlayers().getName(u).equalsIgnoreCase(args.get(0))).findFirst().orElse(null);
if (foundWarp == null) { if (foundWarp == null) {
// Atempt to find warp which starts with the given name // Attempt to find warp which starts with the given name
UUID foundAlernativeWarp = warpList.stream().filter(u -> getPlayers().getName(u).toLowerCase().startsWith(args.get(0).toLowerCase())).findFirst().orElse(null); UUID foundAlernativeWarp = warpList.stream().filter(u -> getPlayers().getName(u).toLowerCase().startsWith(args.get(0).toLowerCase())).findFirst().orElse(null);
if (foundAlernativeWarp == null) { if (foundAlernativeWarp == null) {

View File

@ -61,6 +61,8 @@ public class Settings implements ConfigObject
String warpCommand = "warp"; String warpCommand = "warp";
@ConfigEntry(path = "warps-command") @ConfigEntry(path = "warps-command")
String warpsCommand = "warps"; String warpsCommand = "warps";
@ConfigEntry(path = "togglewarp-command")
String toggleWarpCommand = "togglewarp";
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Section: Constructor // Section: Constructor
@ -205,6 +207,21 @@ public class Settings implements ConfigObject
this.warpsCommand = warpsCommand; this.warpsCommand = warpsCommand;
} }
/**
* @return the toggleWarpCommand
*/
public String getToggleWarpCommand() {
return toggleWarpCommand;
}
/**
* @param toggleWarpCommand the toggleWarpCommand to set
*/
public void setToggleWarpCommand(String toggleWarpCommand) {
this.toggleWarpCommand = toggleWarpCommand;
}
/** /**
* @return the removeExistingWarpsWhenFlagChanges * @return the removeExistingWarpsWhenFlagChanges
*/ */

View File

@ -15,7 +15,7 @@ import world.bentobox.warps.Warp;
* @author Poslovitch * @author Poslovitch
* *
*/ */
public class WarpCreateEvent extends Event{ public class WarpCreateEvent extends Event {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private final Location warpLoc; private final Location warpLoc;

View File

@ -0,0 +1,72 @@
package world.bentobox.warps.event;
import org.bukkit.Location;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import world.bentobox.warps.objects.PlayerWarp;
import java.util.UUID;
/**
* This event is fired when a warp is toggled
* A Listener to this event can use it only to get information. e.g: broadcast something
*
* @since 1.16.0
* @author TreemanKing
*/
public class WarpToggleEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private final UUID user;
private final PlayerWarp playerWarp;
public WarpToggleEvent(UUID user, PlayerWarp playerWarp) {
this.playerWarp = playerWarp;
this.user = user;
}
/**
* Gets the user who has toggled the warp
*
* @return the UUID of the player who toggled the warp
*/
public UUID getUser() {
return user;
}
/**
* Gets the state of the warp
*
* @return true if the warp is enabled, false otherwise
*/
public boolean isEnabled() {
return playerWarp.isEnabled();
}
/**
* Gets the PlayerWarp object
*
* @return the PlayerWarp object
*/
public PlayerWarp getPlayerWarp() {
return playerWarp;
}
/**
* Gets the location of the toggled warp
*
* @return the location of the warp
*/
public Location getLocation() {
return playerWarp.getLocation();
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View File

@ -28,6 +28,7 @@ import world.bentobox.bentobox.api.events.team.TeamLeaveEvent;
import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util; import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.objects.PlayerWarp;
import world.bentobox.warps.Warp; import world.bentobox.warps.Warp;
import world.bentobox.warps.event.WarpRemoveEvent; import world.bentobox.warps.event.WarpRemoveEvent;
@ -60,12 +61,12 @@ public class WarpSignsListener implements Listener {
@Override @Override
public void run() { public void run() {
boolean changed = false; boolean changed = false;
Iterator<Map.Entry<UUID, Location>> iterator = Iterator<Map.Entry<UUID, PlayerWarp>> iterator =
addon.getWarpSignsManager().getWarpMap(event.getWorld()).entrySet().iterator(); addon.getWarpSignsManager().getWarpMap(event.getWorld()).entrySet().iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
Map.Entry<UUID, Location> entry = iterator.next(); Map.Entry<UUID, PlayerWarp> entry = iterator.next();
UUID uuid = entry.getKey(); UUID uuid = entry.getKey();
Location location = entry.getValue(); Location location = entry.getValue().getLocation();
if (event.getChunk().getX() == location.getBlockX() >> 4 if (event.getChunk().getX() == location.getBlockX() >> 4
&& event.getChunk().getZ() == location.getBlockZ() >> 4 && event.getChunk().getZ() == location.getBlockZ() >> 4
&& !Tag.SIGNS.isTagged(location.getBlock().getType())) { && !Tag.SIGNS.isTagged(location.getBlock().getType())) {
@ -126,16 +127,16 @@ public class WarpSignsListener implements Listener {
private boolean isPlayersSign(Player player, Block b, boolean inWorld) { private boolean isPlayersSign(Player player, Block b, boolean inWorld) {
// Welcome sign detected - check to see if it is this player's sign // Welcome sign detected - check to see if it is this player's sign
Map<UUID, Location> list = addon.getWarpSignsManager().getWarpMap(b.getWorld()); Map<UUID, PlayerWarp> list = addon.getWarpSignsManager().getWarpMap(b.getWorld());
String reqPerm = inWorld ? addon.getPermPrefix(b.getWorld()) + "mod.removesign" : Warp.WELCOME_WARP_SIGNS + ".mod.removesign"; String reqPerm = inWorld ? addon.getPermPrefix(b.getWorld()) + "mod.removesign" : Warp.WELCOME_WARP_SIGNS + ".mod.removesign";
return ((list.containsKey(player.getUniqueId()) && list.get(player.getUniqueId()).equals(b.getLocation())) return ((list.containsKey(player.getUniqueId()) && list.get(player.getUniqueId()).getLocation().equals(b.getLocation()))
|| player.isOp() || player.hasPermission(reqPerm)); || player.isOp() || player.hasPermission(reqPerm));
} }
private boolean isWarpSign(Block b) { private boolean isWarpSign(Block b) {
Sign s = (Sign) b.getState(); Sign s = (Sign) b.getState();
return s.getLine(0).equalsIgnoreCase(ChatColor.GREEN + addon.getSettings().getWelcomeLine()) return s.getLine(0).equalsIgnoreCase(ChatColor.GREEN + addon.getSettings().getWelcomeLine())
&& addon.getWarpSignsManager().getWarpMap(b.getWorld()).containsValue(s.getLocation()); && addon.getWarpSignsManager().getWarpMap(b.getWorld()).values().stream().anyMatch(playerWarp -> playerWarp.getLocation().equals(s.getLocation()));
} }
/** /**
@ -158,19 +159,24 @@ public class WarpSignsListener implements Listener {
if (noPerms(user, b.getWorld(), inWorld)) { if (noPerms(user, b.getWorld(), inWorld)) {
return; return;
} }
// TODO: These checks are useless if the sign is placed outside a BSB world.
// This will mean level and rank requirements are nil in the case of allow-in-other-worlds: true.
// I'm not sure if there is a better way around this without adding new API checking for primary
// or last island accessed with relevant permissions.
// ignored.
if (inWorld && noLevelOrIsland(user, b.getWorld())) { if (inWorld && noLevelOrIsland(user, b.getWorld())) {
e.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine()); e.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine());
return; return;
} }
if(!hasCorrectIslandRank(b, user)) { if (inWorld && !hasCorrectIslandRank(b, user)) {
e.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine()); e.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine());
user.sendMessage("warps.error.not-correct-rank"); user.sendMessage("warps.error.not-correct-rank");
return; return;
} }
// Check if the player already has a sign // Check if the player already has a sign
final Location oldSignLoc = addon.getWarpSignsManager().getWarp(b.getWorld(), user.getUniqueId()); final Location oldSignLoc = addon.getWarpSignsManager().getWarpLocation(b.getWorld(), user.getUniqueId());
if (oldSignLoc != null) { if (oldSignLoc != null) {
// A sign already exists. Check if it still there and if // A sign already exists. Check if it still there and if
// so, // so,
@ -216,15 +222,15 @@ public class WarpSignsListener implements Listener {
final Island island = e.getIsland(); final Island island = e.getIsland();
final Map<UUID, Location> islandWarps = addon final Map<UUID, PlayerWarp> islandWarps = addon
.getWarpSignsManager() .getWarpSignsManager()
.getWarpMap(island.getWorld()) .getWarpMap(island.getWorld())
.entrySet() .entrySet()
.stream() .stream()
.filter(x -> island.inIslandSpace(x.getValue())) .filter(x -> island.inIslandSpace(x.getValue().getLocation()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
for(Map.Entry<UUID, Location> entry : islandWarps.entrySet()) { for(Map.Entry<UUID, PlayerWarp> entry : islandWarps.entrySet()) {
if(island.getRank(entry.getKey()) >= e.getSetTo()) continue; if(island.getRank(entry.getKey()) >= e.getSetTo()) continue;
//The user has a lower rank than the new set value. //The user has a lower rank than the new set value.

View File

@ -37,7 +37,9 @@ import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.lists.Flags; import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.util.Util; import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.objects.PlayerWarp;
import world.bentobox.warps.Warp; import world.bentobox.warps.Warp;
import world.bentobox.warps.event.WarpCreateEvent;
import world.bentobox.warps.event.WarpInitiateEvent; import world.bentobox.warps.event.WarpInitiateEvent;
import world.bentobox.warps.objects.WarpsData; import world.bentobox.warps.objects.WarpsData;
import world.bentobox.warps.panels.Utils; import world.bentobox.warps.panels.Utils;
@ -54,7 +56,7 @@ public class WarpSignsManager {
private static final String WARPS = "warps"; private static final String WARPS = "warps";
private final BentoBox plugin; private final BentoBox plugin;
// Map of all warps stored as player, warp sign Location // Map of all warps stored as player, warp sign Location
private Map<World, Map<UUID, Location>> worldsWarpList; private Map<World, Map<UUID, PlayerWarp>> worldsWarpList;
// Database handler for level data // Database handler for level data
private final Database<WarpsData> handler; private final Database<WarpsData> handler;
@ -67,7 +69,7 @@ public class WarpSignsManager {
* @return map of warps * @return map of warps
*/ */
@NonNull @NonNull
public Map<UUID, Location> getWarpMap(@Nullable World world) { public Map<UUID, PlayerWarp> getWarpMap(@Nullable World world) {
return worldsWarpList.computeIfAbsent(Util.getWorld(world), k -> new HashMap<>()); return worldsWarpList.computeIfAbsent(Util.getWorld(world), k -> new HashMap<>());
} }
@ -99,13 +101,15 @@ public class WarpSignsManager {
return false; return false;
} }
// Check for warps placed in a location where there was a warp before // Check for warps placed in a location where there was a warp before
if (getWarpMap(loc.getWorld()).containsValue(loc)) { for (PlayerWarp playerWarp : getWarpMap(loc.getWorld()).values()) {
// remove the warp at this location, then place it if (playerWarp.getLocation().equals(loc)) {
this.removeWarp(loc); this.removeWarp(loc);
break;
} }
getWarpMap(loc.getWorld()).put(playerUUID, loc); }
getWarpMap(loc.getWorld()).put(playerUUID, new PlayerWarp(loc, true));
saveWarpList(); saveWarpList();
Bukkit.getPluginManager().callEvent(new WarpInitiateEvent(addon, loc, playerUUID)); Bukkit.getPluginManager().callEvent(new WarpCreateEvent(addon, loc, playerUUID));
return true; return true;
} }
@ -118,7 +122,13 @@ public class WarpSignsManager {
* @return Location of warp or null * @return Location of warp or null
*/ */
@Nullable @Nullable
public Location getWarp(World world, UUID playerUUID) { public Location getWarpLocation(World world, UUID playerUUID) {
PlayerWarp playerWarp = getWarpMap(world).get(playerUUID);
return playerWarp != null ? playerWarp.getLocation() : null;
}
@Nullable
public PlayerWarp getPlayerWarp(World world, UUID playerUUID) {
return getWarpMap(world).get(playerUUID); return getWarpMap(world).get(playerUUID);
} }
@ -129,7 +139,7 @@ public class WarpSignsManager {
*/ */
@NonNull @NonNull
public String getWarpOwner(Location location) { public String getWarpOwner(Location location) {
return getWarpMap(location.getWorld()).entrySet().stream().filter(en -> en.getValue().equals(location)) return getWarpMap(location.getWorld()).entrySet().stream().filter(en -> en.getValue().getLocation().equals(location))
.findFirst().map(en -> plugin.getPlayers().getName(en.getKey())).orElse(""); .findFirst().map(en -> plugin.getPlayers().getName(en.getKey())).orElse("");
} }
@ -139,7 +149,7 @@ public class WarpSignsManager {
* @return Optional UUID of warp owner or empty if there is none * @return Optional UUID of warp owner or empty if there is none
*/ */
public Optional<UUID> getWarpOwnerUUID(Location location) { public Optional<UUID> getWarpOwnerUUID(Location location) {
return getWarpMap(location.getWorld()).entrySet().stream().filter(en -> en.getValue().equals(location)) return getWarpMap(location.getWorld()).entrySet().stream().filter(en -> en.getValue().getLocation().equals(location))
.findFirst().map(Map.Entry::getKey); .findFirst().map(Map.Entry::getKey);
} }
@ -159,6 +169,10 @@ public class WarpSignsManager {
// Bigger value of time means a more recent login // Bigger value of time means a more recent login
TreeMap<Long, UUID> map = new TreeMap<>(); TreeMap<Long, UUID> map = new TreeMap<>();
getWarpMap(world).forEach((uuid, value) -> { getWarpMap(world).forEach((uuid, value) -> {
// If the warp is not enabled, skip this iteration
if (!value.isEnabled()) {
return;
}
// If never played, will be zero // If never played, will be zero
long lastPlayed = addon.getServer().getOfflinePlayer(uuid).getLastPlayed(); long lastPlayed = addon.getServer().getOfflinePlayer(uuid).getLastPlayed();
// This aims to avoid the chance that players logged off at exactly the same time // This aims to avoid the chance that players logged off at exactly the same time
@ -187,7 +201,11 @@ public class WarpSignsManager {
public Set<UUID> listWarps(@NonNull World world) { public Set<UUID> listWarps(@NonNull World world) {
// Remove any null locations // Remove any null locations
getWarpMap(world).values().removeIf(Objects::isNull); getWarpMap(world).values().removeIf(Objects::isNull);
return getWarpMap(world).entrySet().stream().filter(e -> Util.sameWorld(world, Objects.requireNonNull(e.getValue().getWorld()))).map(Map.Entry::getKey).collect(Collectors.toSet()); // Remove any warps that have not been toggled on
Map<UUID, PlayerWarp> enabledWarps = getWarpMap(world).entrySet().stream()
.filter(entry -> entry.getValue().isEnabled())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return enabledWarps.keySet();
} }
/** /**
@ -200,7 +218,8 @@ public class WarpSignsManager {
warpsData = handler.loadObject(WARPS); warpsData = handler.loadObject(WARPS);
// Load into map // Load into map
if (warpsData != null) { if (warpsData != null) {
warpsData.getWarpSigns().forEach((location,uuid) -> { warpsData.getWarpSigns().forEach((pw, uuid) -> {
Location location = pw.getLocation();
if (location != null && location.getWorld() != null) { if (location != null && location.getWorld() != null) {
if (location.getWorld().isChunkLoaded(location.getBlockX() >> 4, location.getBlockZ() >> 4) if (location.getWorld().isChunkLoaded(location.getBlockX() >> 4, location.getBlockZ() >> 4)
&& !location.getBlock().getType().name().contains("SIGN")) { && !location.getBlock().getType().name().contains("SIGN")) {
@ -208,7 +227,7 @@ public class WarpSignsManager {
} }
// Add to map // Add to map
getWarpMap(location.getWorld()).put(uuid, location); getWarpMap(location.getWorld()).put(uuid, new PlayerWarp(location, true));
} }
}); });
} else { } else {
@ -239,10 +258,10 @@ public class WarpSignsManager {
*/ */
public void removeWarp(Location loc) { public void removeWarp(Location loc) {
popSign(loc); popSign(loc);
Iterator<Entry<UUID, Location>> it = getWarpMap(loc.getWorld()).entrySet().iterator(); Iterator<Entry<UUID, PlayerWarp>> it = getWarpMap(loc.getWorld()).entrySet().iterator();
while (it.hasNext()) { while (it.hasNext()) {
Entry<UUID, Location> en = it.next(); Entry<UUID, PlayerWarp> en = it.next();
if (en.getValue().equals(loc)) { if (en.getValue().getLocation().equals(loc)) {
// Inform player // Inform player
Optional.ofNullable(addon.getServer().getPlayer(en.getKey())) Optional.ofNullable(addon.getServer().getPlayer(en.getKey()))
.map(User::getInstance) .map(User::getInstance)
@ -262,7 +281,7 @@ public class WarpSignsManager {
*/ */
public void removeWarp(World world, UUID uuid) { public void removeWarp(World world, UUID uuid) {
if (getWarpMap(world).containsKey(uuid)) { if (getWarpMap(world).containsKey(uuid)) {
popSign(getWarpMap(world).get(uuid)); popSign(getWarpMap(world).get(uuid).getLocation());
getWarpMap(world).remove(uuid); getWarpMap(world).remove(uuid);
} }
@ -298,7 +317,7 @@ public class WarpSignsManager {
@NonNull @NonNull
public SignCacheItem getSignInfo(@NonNull World world, @NonNull UUID uuid) { public SignCacheItem getSignInfo(@NonNull World world, @NonNull UUID uuid) {
//get the sign info //get the sign info
Location signLocation = getWarp(world, uuid); Location signLocation = getWarpLocation(world, uuid);
if (signLocation == null || !signLocation.getBlock().getType().name().contains("SIGN")) { if (signLocation == null || !signLocation.getBlock().getType().name().contains("SIGN")) {
return new SignCacheItem(); return new SignCacheItem();
} }
@ -350,6 +369,11 @@ public class WarpSignsManager {
float yaw = Util.blockFaceToFloat(directionFacing); float yaw = Util.blockFaceToFloat(directionFacing);
final Location actualWarp = new Location(inFront.getWorld(), inFront.getBlockX() + 0.5D, inFront.getBlockY(), final Location actualWarp = new Location(inFront.getWorld(), inFront.getBlockX() + 0.5D, inFront.getBlockY(),
inFront.getBlockZ() + 0.5D, yaw, 30F); inFront.getBlockZ() + 0.5D, yaw, 30F);
WarpInitiateEvent e = new WarpInitiateEvent(addon, actualWarp, user.getUniqueId());
Bukkit.getPluginManager().callEvent(e);
if (e.isCancelled()) {
return;
}
//BentoBox prevents people from teleporting to an island when //BentoBox prevents people from teleporting to an island when
//the user is banned from the island for example. //the user is banned from the island for example.
//By checking if the teleport succeeded before sending the messages, //By checking if the teleport succeeded before sending the messages,
@ -387,7 +411,7 @@ public class WarpSignsManager {
* @param owner - owner of the warp * @param owner - owner of the warp
*/ */
public void warpPlayer(@NonNull World world, @NonNull User user, @NonNull UUID owner) { public void warpPlayer(@NonNull World world, @NonNull User user, @NonNull UUID owner) {
final Location warpSpot = getWarp(world, owner); final Location warpSpot = getWarpLocation(world, owner);
// Check if the warp spot is safe // Check if the warp spot is safe
if (warpSpot == null) { if (warpSpot == null) {
user.sendMessage("warps.error.does-not-exist"); user.sendMessage("warps.error.does-not-exist");

View File

@ -0,0 +1,32 @@
package world.bentobox.warps.objects;
import com.google.gson.annotations.Expose;
import org.bukkit.Location;
import java.io.Serializable;
public class PlayerWarp implements Serializable {
@Expose
private final Location location;
@Expose
private boolean isEnabled;
public PlayerWarp(Location location, boolean isEnabled) {
this.location = location;
this.isEnabled = isEnabled;
}
public Location getLocation() {
return location;
}
public boolean isEnabled() {
return isEnabled;
}
public void toggle() {
isEnabled = !isEnabled;
}
}

View File

@ -17,9 +17,13 @@ public class WarpsData implements DataObject {
@Expose @Expose
private String uniqueId = "warps"; private String uniqueId = "warps";
@Expose
@Deprecated @Expose
private Map<Location, UUID> warpSigns = new HashMap<>(); private Map<Location, UUID> warpSigns = new HashMap<>();
@Expose
private Map<PlayerWarp, UUID> newWarpSigns = new HashMap<>();
public WarpsData() { public WarpsData() {
// Required by YAML database // Required by YAML database
} }
@ -34,24 +38,40 @@ public class WarpsData implements DataObject {
this.uniqueId = uniqueId; this.uniqueId = uniqueId;
} }
public Map<Location, UUID> getWarpSigns() { public Map<PlayerWarp, UUID> getWarpSigns() {
if (warpSigns == null) convertOldWarpSigns();
if (newWarpSigns == null)
return new HashMap<>(); return new HashMap<>();
return warpSigns; return newWarpSigns;
}
public void setWarpSigns(Map<Location, UUID> warpSigns) {
this.warpSigns = warpSigns;
} }
/** /**
* Puts all the data from the map into this objects ready for saving * Method for converting old warp signs to new warp signs
*/
public void convertOldWarpSigns() {
if (warpSigns == null) {
return;
}
for (Map.Entry<Location, UUID> entry : warpSigns.entrySet()) {
PlayerWarp playerWarp = new PlayerWarp(entry.getKey(), true);
newWarpSigns.put(playerWarp, entry.getValue());
}
warpSigns = null;
}
public void setWarpSigns(Map<PlayerWarp, UUID> warpSigns) {
this.newWarpSigns = warpSigns;
}
/**
* Puts all the data from the map into these objects ready for saving
* @param worldsWarpList 2D map of warp locations by world vs UUID * @param worldsWarpList 2D map of warp locations by world vs UUID
* @return this class filled with data * @return this class filled with data
*/ */
public WarpsData save(Map<World, Map<UUID, Location>> worldsWarpList) { public WarpsData save(Map<World, Map<UUID, PlayerWarp>> worldsWarpList) {
getWarpSigns().clear(); getWarpSigns().clear();
worldsWarpList.values().forEach(world -> world.forEach((uuid,location) -> warpSigns.put(location, uuid))); worldsWarpList.values().forEach(world -> world.forEach((uuid,playerWarp) -> newWarpSigns.put(playerWarp, uuid)));
return this; return this;
} }

View File

@ -52,7 +52,7 @@ public class Utils
List<String> permissions = user.getEffectivePermissions().stream(). List<String> permissions = user.getEffectivePermissions().stream().
map(PermissionAttachmentInfo::getPermission). map(PermissionAttachmentInfo::getPermission).
filter(permission -> permission.startsWith(permPrefix)). filter(permission -> permission.startsWith(permPrefix)).
collect(Collectors.toList()); toList();
for (String permission : permissions) for (String permission : permissions)
{ {

View File

@ -18,3 +18,6 @@ permissions:
'[gamemode].island.addwarp': '[gamemode].island.addwarp':
description: Player can create a welcome warp sign description: Player can create a welcome warp sign
default: true default: true
'[gamemode].island.togglewarp':
description: Player can toggle a warp sign
default: true

View File

@ -33,3 +33,4 @@ allow-in-other-worlds: false
# Warp and warps commands. You can change them if they clash with other addons or plugins. # Warp and warps commands. You can change them if they clash with other addons or plugins.
warp-command: warp warp-command: warp
warps-command: warps warps-command: warps
togglewarp-command: togglewarp

View File

@ -60,6 +60,16 @@ warps:
# Prefix for messages that are send from server. # Prefix for messages that are send from server.
prefix: "&l&6 [BentoBox]: &r" prefix: "&l&6 [BentoBox]: &r"
togglewarp:
help:
description: "toggle the warp sign"
enabled: "&a Your warp is now visible!"
disabled: "&c Your warp is now hidden!"
error:
no-permission: "&c You do not have permission to do that!"
generic: "&c An error occurred while toggling your warp."
no-warp: "&c You do not have a warp to toggle!"
protection: protection:
flags: flags:
PLACE_WARP: PLACE_WARP:

View File

@ -4,25 +4,50 @@ warp:
description: te téléporte au Warp d'un autre joueur description: te téléporte au Warp d'un autre joueur
parameters: "<pseudo>" parameters: "<pseudo>"
warps: warps:
deactivate: "&cAncien panneau de Warp désactivé !" deactivate: "&c Ancienne pancarte de warp désactivée !"
error: error:
does-not-exist: "&cCe Warp n'existe plus !" does-not-exist: "&c Oh ! Cette téléportation n'existe plus !"
no-permission: "&cVous n'avez pas la permission pour faire cela !" no-permission: "&c Vous n'avez pas le droit de faire cela !"
no-remove: "&cVous ne pouvez pas supprimer ce panneau !" no-remove: "&c Vous ne pouvez pas enlever cette pancarte !"
no-warps-yet: "&cIl n'y a encore aucun Warp sur ce serveur." no-warps-yet: "&c Il n'y a pas encore de téléportation disponible"
not-enough-level: "&cVotre niveau d'île n'est pas assez élevé pour faire cela not-enough-level: "&c Le niveau de votre île n'est pas assez élevé !"
!" not-on-island: "&c Vous devez être sur votre île pour faire cela !"
not-on-island: "&cVous devez être sur votre île pour faire cela !" not-safe: "&c Cette téléportation n'est pas sûre !"
not-safe: "&cCe Warp n'est pas sûr!" your-level-is: "&c Le niveau de votre île n'est que [level] et doit être supérieur
your-level-is: "&cVotre île est seulement niveau [level] et doit être niveau [required]." à [required]. Exécutez la commande level."
not-correct-rank: "&c Vous n'avez pas le grade adéquat pour poser une chaîne !"
help: help:
description: Ouvre le menu des Warps description: Ouvre le menu des Warps
next: "&6Page suivante" player-warped: "&2 [name] s'est rendu à votre pancarte de téléportation [gamemode]
player-warped: "& 2 [pseudo] s'est téléporté à votre panneau Warp !" !"
previous: "&6Page précédente" sign-removed: "&c Panneau de téléportation enlevé !"
random: "&4 Warp aléatoire " success: "&a Succès !"
sign-removed: "&cPanneau de Warp supprimé !" warpTip: "&6 Placer une pancarte de téléportation avec [text] sur le dessus"
success: "&aSuccès !" warpToPlayersSign: "&6 Téléportation a la pancarte de [player]"
title: Panneau Warp gui:
warpTip: "&6Placez un panneau et écrivez [text] sur la première ligne." titles:
warpToPlayersSign: "&6 Téléportation vers le panneau de [pseudo]" warp-title: "&0&l Pancarte de téléportation"
buttons:
previous:
name: "&f&l Page précédente"
description: "&7 Aller à la page [numéro]."
next:
name: "&f&l Page suivante"
description: "&7 Passer à la page [numéro]."
warp:
name: "&f&l [name]"
description: "[sign_text]"
random:
name: "&f&l Téléportation aléatoire"
description: "&7 Hmm, où vais-je apparaître ?"
tips:
click-to-previous: "&e Cliquez sur &7 pour afficher la page précédente."
click-to-next: "&e Cliquez sur &7 pour afficher la page suivante."
click-to-warp: "&e Cliquez sur &7 pour te téléporter."
conversations:
prefix: "&l&6 [BentoBox]: &r"
protection:
flags:
PLACE_WARP:
name: Place téléportation
description: Autoriser le placement d'un panneau téléportation

View File

@ -1,27 +1,60 @@
--- # ##########################################################################################
# This is a YML file. Be careful when editing. Check your edits in a YAML checker like #
# the one at http://yaml-online-parser.appspot.com #
# ##########################################################################################
warp: warp:
help: help:
description: 传送到该玩家的传送木牌处 description: 传送至对应玩家的坐标告示牌
parameters: "<player name>" parameters: <player name>
warps: warps:
help: deactivate: '&c检测到不活跃的坐标告示牌!'
description: 打开传送面板
title: 传送木牌
deactivate: "&c 旧传送牌已停用!"
error: error:
does-not-exist: "&c 哦不!那个传送点已经没了!" does-not-exist: '&c啊哦! 那个传送点已经不存在了!'
no-permission: "&c 你无权那样做!" no-permission: '&c你没有权限做这件事!'
no-remove: "&c 你拿不掉那个牌子的!" no-remove: '&c你不能移除该告示牌!'
no-warps-yet: "&c 暂无可用传送点" no-warps-yet: '&c尚无可用传送点.'
not-enough-level: "&c 你的岛等级不够高!" not-enough-level: '&c你空岛的等级还不够高!'
not-on-island: "&c 你得在自己的岛屿上操作!" not-on-island: '&c你必须在自己的空岛上做这件事!'
not-safe: "&c 目标传送点不安全!" not-safe: '&c该传送点不安全!'
your-level-is: "&c 你的岛现在 [level] 级,需要 [required] 级。 试试岛屿等级命令吧。" your-level-is: '&c你空岛的等级只有[level], 但必须高于[required]. 使用/is level查看等级.'
next: "&6 次页" not-correct-rank: '&c你在团队中的地位不足以让你设立传送点!'
player-warped: "&2 [name] 传送到了你的传送牌!" help:
previous: "&6 前页" description: 打开传送点面板
random: "&4 随机传送" player-warped: '&2 [name]传送到了你[gamemode]的坐标告示牌!'
sign-removed: "&c 拆掉传送牌了!" sign-removed: '&c坐标告示牌已移除!'
success: "&a 成了!" success: '&a成功!'
warpTip: "&6 放个牌子第一行写 [text]" warpTip: '&6放置一个顶部为[text]的坐标告示牌'
warpToPlayersSign: "&6 正传送到 [player] 的牌子" warpToPlayersSign: '&6正在传送至[player]的坐标告示牌'
gui:
titles:
# The title of warp panel
warp-title: '&0&l坐标告示牌'
buttons:
# Button that is used in multi-page GUIs which allows to return to previous page.
previous:
name: '&f&l上一页'
description: '&7跳转到第[number]页' # Button that is used in multi-page GUIs which allows to go to next page.
next:
name: '&f&l下一页'
description: '&7跳转到第[number]页' # Button for a warp
warp:
name: '&f&l [name]'
description: '[sign_text]' # Button for a random warp
random:
name: '&f&l随机传送'
description: '&7嗯...我会出现在哪里?'
tips:
click-to-previous: '&e点击&7 查看上一页.'
click-to-next: '&e点击&7 查看下一页.'
click-to-warp: '&e点击&7 进行传送.'
conversations:
# Prefix for messages that are send from server.
prefix: '&l&6 [BentoBox]: &r'
protection:
flags:
PLACE_WARP:
name: 放置传送点
description: 允许放置坐标告示牌

View File

@ -8,7 +8,9 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -40,6 +42,7 @@ import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
@ -60,9 +63,11 @@ import world.bentobox.bentobox.managers.PlaceholdersManager;
import world.bentobox.bentobox.managers.PlayersManager; import world.bentobox.bentobox.managers.PlayersManager;
import world.bentobox.bentobox.util.Util; import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.config.Settings; import world.bentobox.warps.config.Settings;
import world.bentobox.warps.event.WarpCreateEvent;
import world.bentobox.warps.event.WarpInitiateEvent; import world.bentobox.warps.event.WarpInitiateEvent;
import world.bentobox.warps.managers.SignCacheManager; import world.bentobox.warps.managers.SignCacheManager;
import world.bentobox.warps.managers.WarpSignsManager; import world.bentobox.warps.managers.WarpSignsManager;
import world.bentobox.warps.objects.PlayerWarp;
import world.bentobox.warps.objects.WarpsData; import world.bentobox.warps.objects.WarpsData;
@ -191,7 +196,7 @@ public class WarpSignsManagerTest {
// Handler // Handler
when(handler.objectExists("warps")).thenReturn(true); when(handler.objectExists("warps")).thenReturn(true);
Map<Location, UUID> warpMap = Collections.singletonMap(location, uuid); Map<PlayerWarp, UUID> warpMap = Collections.singletonMap(new PlayerWarp(location, true), uuid);
when(load.getWarpSigns()).thenReturn(warpMap); when(load.getWarpSigns()).thenReturn(warpMap);
when(handler.loadObject(anyString())).thenReturn(load); when(handler.loadObject(anyString())).thenReturn(load);
@ -271,7 +276,8 @@ public class WarpSignsManagerTest {
*/ */
@Test @Test
public void testGetWarpMapNullLocation() { public void testGetWarpMapNullLocation() {
Map<Location, UUID> warpMap = Collections.singletonMap(null, uuid); PlayerWarp playerWarp = new PlayerWarp(null, true);
Map<PlayerWarp, UUID> warpMap = Collections.singletonMap(playerWarp, uuid);
when(load.getWarpSigns()).thenReturn(warpMap); when(load.getWarpSigns()).thenReturn(warpMap);
wsm = new WarpSignsManager(addon, plugin); wsm = new WarpSignsManager(addon, plugin);
assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty()); assertTrue("Map is not empty", wsm.getWarpMap(world).isEmpty());
@ -349,23 +355,23 @@ public class WarpSignsManagerTest {
public void testAddWarp() { public void testAddWarp() {
Location loc = mock(Location.class); Location loc = mock(Location.class);
assertTrue(wsm.addWarp(uuid, loc)); assertTrue(wsm.addWarp(uuid, loc));
verify(pim).callEvent(any(WarpInitiateEvent.class)); verify(pim).callEvent(any(WarpCreateEvent.class));
} }
/** /**
* Test method for {@link WarpSignsManager#getWarp(org.bukkit.World, java.util.UUID)}. * Test method for {@link WarpSignsManager#getWarpLocation(org.bukkit.World, java.util.UUID)}.
*/ */
@Test @Test
public void testGetWarpWorldWorld() { public void testGetWarpWorldWorld() {
assertNull(wsm.getWarp(mock(World.class), uuid)); assertNull(wsm.getWarpLocation(mock(World.class), uuid));
} }
/** /**
* Test method for {@link WarpSignsManager#getWarp(org.bukkit.World, java.util.UUID)}. * Test method for {@link WarpSignsManager#getWarpLocation(org.bukkit.World, java.util.UUID)}.
*/ */
@Test @Test
public void testGetWarp() { public void testGetWarp() {
assertEquals(location, wsm.getWarp(world, uuid)); assertEquals(location, wsm.getWarpLocation(world, uuid));
} }
/** /**
@ -441,6 +447,38 @@ public class WarpSignsManagerTest {
PowerMockito.verifyStatic(Util.class); PowerMockito.verifyStatic(Util.class);
Util.teleportAsync(eq(p), any(), eq(TeleportCause.COMMAND)); Util.teleportAsync(eq(p), any(), eq(TeleportCause.COMMAND));
verify(player).sendMessage(anyString()); verify(player).sendMessage(anyString());
verify(pim).callEvent(any(WarpInitiateEvent.class));
}
/**
* Test method for {@link WarpSignsManager#warpPlayer(org.bukkit.World, world.bentobox.bentobox.api.user.User, java.util.UUID)}.
*/
@Test
public void testWarpPlayerEventCancelled() {
// Capture the event passed to callEvent
ArgumentCaptor<WarpInitiateEvent> eventCaptor = ArgumentCaptor.forClass(WarpInitiateEvent.class);
// Simulate the event being called and cancelled
doAnswer(invocation -> {
WarpInitiateEvent event = (WarpInitiateEvent) invocation.getArgument(0);
event.setCancelled(true);
return null;
}).when(pim).callEvent(eventCaptor.capture());
Player p = mock(Player.class);
when(p.getUniqueId()).thenReturn(UUID.randomUUID());
when(p.getWorld()).thenReturn(world);
when(p.getName()).thenReturn("tastybento");
when(p.getLocation()).thenReturn(location);
when(p.isOnline()).thenReturn(true);
when(p.canSee(any(Player.class))).thenReturn(true);
@Nullable
User u = User.getInstance(p);
PowerMockito.when(Util.teleportAsync(any(), any(), any())).thenReturn(CompletableFuture.completedFuture(true));
wsm.warpPlayer(world, u, uuid);
PowerMockito.verifyStatic(Util.class, never());
Util.teleportAsync(eq(p), any(), eq(TeleportCause.COMMAND));
verify(player, never()).sendMessage(anyString());
} }
/** /**

View File

@ -50,6 +50,7 @@ import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.LocalesManager; import world.bentobox.bentobox.managers.LocalesManager;
import world.bentobox.bentobox.managers.PlaceholdersManager; import world.bentobox.bentobox.managers.PlaceholdersManager;
import world.bentobox.bentobox.util.Util; import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.objects.PlayerWarp;
import world.bentobox.warps.Warp; import world.bentobox.warps.Warp;
import world.bentobox.warps.managers.WarpSignsManager; import world.bentobox.warps.managers.WarpSignsManager;
import world.bentobox.warps.config.Settings; import world.bentobox.warps.config.Settings;
@ -123,16 +124,16 @@ public class WarpSignsListenerTest {
when(block.getState()).thenReturn(s); when(block.getState()).thenReturn(s);
// warp signs manager // warp signs manager
when(addon.getWarpSignsManager()).thenReturn(wsm); when(addon.getWarpSignsManager()).thenReturn(wsm);
Map<UUID, Location> list = new HashMap<>(); Map<UUID, PlayerWarp> list = new HashMap<>();
Location location = mock(Location.class); Location location = mock(Location.class);
when(location.getBlock()).thenReturn(block); when(location.getBlock()).thenReturn(block);
when(s.getLocation()).thenReturn(location); when(s.getLocation()).thenReturn(location);
when(block.getLocation()).thenReturn(location); when(block.getLocation()).thenReturn(location);
list.put(uuid, location); list.put(uuid, new PlayerWarp(location, true));
// Player is in world // Player is in world
when(wsm.getWarpMap(world)).thenReturn(list); when(wsm.getWarpMap(world)).thenReturn(list);
//Player has a warp sign already here //Player has a warp sign already here
when(wsm.getWarp(any(), any())).thenReturn(location); when(wsm.getWarpLocation(any(), any())).thenReturn(location);
// Unique spot // Unique spot
when(wsm.addWarp(any(), any())).thenReturn(true); when(wsm.addWarp(any(), any())).thenReturn(true);
// Bentobox // Bentobox
@ -339,8 +340,8 @@ public class WarpSignsListenerTest {
when(settings.getRemoveExistingWarpsWhenFlagChanges()).thenReturn(true); when(settings.getRemoveExistingWarpsWhenFlagChanges()).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon); WarpSignsListener wsl = new WarpSignsListener(addon);
Map<UUID, Location> warps = Map.of( Map<UUID, PlayerWarp> warps = Map.of(
player.getUniqueId(), block.getLocation() player.getUniqueId(), new PlayerWarp(block.getLocation(), true)
); );
when(wsm.getWarpMap(any())).thenReturn(warps); when(wsm.getWarpMap(any())).thenReturn(warps);
@ -420,7 +421,7 @@ public class WarpSignsListenerTest {
@Test @Test
public void testCreateNoSignAlreadyUniqueSpot() { public void testCreateNoSignAlreadyUniqueSpot() {
when(wsm.getWarp(any(), any())).thenReturn(null); when(wsm.getWarpLocation(any(), any())).thenReturn(null);
when(player.hasPermission(anyString())).thenReturn(true); when(player.hasPermission(anyString())).thenReturn(true);
WarpSignsListener wsl = new WarpSignsListener(addon); WarpSignsListener wsl = new WarpSignsListener(addon);
SignChangeEvent e = new SignChangeEvent(block, player, lines); SignChangeEvent e = new SignChangeEvent(block, player, lines);