diff --git a/pom.xml b/pom.xml
index 049b07a..49d45fa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -138,6 +138,11 @@
${spigot.version}
provided
+
+ org.spigotmc
+ plugin-annotations
+ 1.2.3-SNAPSHOT
+
org.mockito
diff --git a/src/main/java/world/bentobox/warps/Warp.java b/src/main/java/world/bentobox/warps/Warp.java
index 5bd6f6f..fc762a8 100644
--- a/src/main/java/world/bentobox/warps/Warp.java
+++ b/src/main/java/world/bentobox/warps/Warp.java
@@ -17,6 +17,9 @@ import world.bentobox.warps.commands.WarpCommand;
import world.bentobox.warps.commands.WarpsCommand;
import world.bentobox.warps.config.Settings;
import world.bentobox.warps.listeners.WarpSignsListener;
+import world.bentobox.warps.managers.SignCacheManager;
+import world.bentobox.warps.managers.WarpSignsManager;
+
/**
* Addin to BentoBox that enables welcome warp signs
@@ -38,16 +41,16 @@ public class Warp extends Addon {
*/
public static final String WELCOME_WARP_SIGNS = "welcomewarpsigns";
- /**
- * Warp panel Manager
- */
- private WarpPanelManager warpPanelManager;
-
/**
* Worlds Sign manager.
*/
private WarpSignsManager warpSignsManager;
+ /**
+ * Sign Cache Manager
+ */
+ private SignCacheManager signCacheManager;
+
/**
* This variable stores in which worlds this addon is working.
*/
@@ -136,7 +139,7 @@ public class Warp extends Addon {
{
// Start warp signs
warpSignsManager = new WarpSignsManager(this, this.getPlugin());
- warpPanelManager = new WarpPanelManager(this);
+ signCacheManager = new SignCacheManager(this);
// Load the listener
this.registerListener(new WarpSignsListener(this));
} else {
@@ -169,17 +172,21 @@ public class Warp extends Addon {
this.setState(State.DISABLED);
return false;
}
+
+ // Save existing panels.
+ this.saveResource("panels/warps_panel.yml", false);
+
settingsConfig.saveConfigObject(settings);
return true;
}
/**
- * Get warp panel manager
- * @return Warp Panel Manager
+ * Get sign cache manager
+ * @return Sign Cache Manager
*/
- public WarpPanelManager getWarpPanelManager() {
- return warpPanelManager;
+ public SignCacheManager getSignCacheManager() {
+ return signCacheManager;
}
public WarpSignsManager getWarpSignsManager() {
diff --git a/src/main/java/world/bentobox/warps/WarpPanelManager.java b/src/main/java/world/bentobox/warps/WarpPanelManager.java
deleted file mode 100644
index 2ef77ea..0000000
--- a/src/main/java/world/bentobox/warps/WarpPanelManager.java
+++ /dev/null
@@ -1,187 +0,0 @@
-package world.bentobox.warps;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Random;
-import java.util.UUID;
-import java.util.concurrent.CompletableFuture;
-
-import org.bukkit.Material;
-import org.bukkit.World;
-import org.bukkit.command.Command;
-import org.bukkit.inventory.ItemStack;
-import org.eclipse.jdt.annotation.NonNull;
-
-import world.bentobox.bentobox.api.panels.PanelItem;
-import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
-import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
-import world.bentobox.bentobox.api.user.User;
-
-public class WarpPanelManager {
-
- private static final int PANEL_MAX_SIZE = 52;
- private final Warp addon;
- // This is a cache of signs
- private final SignCacheManager signCacheManager;
-
- public WarpPanelManager(Warp addon) {
- this.addon = addon;
- signCacheManager = new SignCacheManager(addon);
- }
-
- private PanelItem getPanelItem(World world, UUID warpOwner, SignCacheItem sign) {
-
- PanelItemBuilder pib = new PanelItemBuilder()
- .name(addon.getSettings().getNameFormat() + addon.getPlugin().getPlayers().getName(warpOwner))
- .description(sign.getSignText())
- .clickHandler((panel, clicker, click, slot) -> hander(world, clicker, warpOwner));
- Material icon = sign.getType();
- if (icon.equals(Material.PLAYER_HEAD)) {
- return pib.icon(addon.getPlayers().getName(warpOwner)).build();
- } else {
- return pib.icon(icon).build();
- }
- }
-
- private boolean hander(World world, User clicker, UUID warpOwner) {
- clicker.closeInventory();
- String playerCommand = addon.getPlugin().getIWM().getAddon(world).map(gm -> gm.getPlayerCommand().map(Command::getLabel).orElse("")).orElse("");
- String command = addon.getSettings().getWarpCommand() + " " + addon.getPlayers().getName(warpOwner);
- clicker.getPlayer().performCommand((playerCommand.isEmpty() ? "" : playerCommand + " ") + command);
- return true;
- }
-
- private PanelItem getRandomButton(World world, User user, UUID warpOwner) {
- return new PanelItemBuilder()
- .name(addon.getSettings().getNameFormat() + user.getTranslation("warps.random"))
- .clickHandler((panel, clicker, click, slot) -> hander(world, clicker, warpOwner))
- .icon(Material.END_CRYSTAL).build();
- }
-
- /**
- * Show the warp panel for the user
- * @param world - world
- * @param user - user
- * @param index - page to show - 0 is first
- */
- public void showWarpPanel(World world, User user, int index) {
-
- PanelBuilder panelBuilder = new PanelBuilder()
- .user(user)
- .name(user.getTranslation("warps.title") + " " + (index + 1));
-
- buildPanel(panelBuilder, user, index, world).thenRun(panelBuilder::build);
- }
-
- CompletableFuture buildPanel(PanelBuilder panelBuilder, User user, int index, World world) {
- CompletableFuture r = new CompletableFuture<>();
- processSigns(r, panelBuilder, user, index, world);
- return r;
- }
-
- void processSigns(CompletableFuture r, PanelBuilder panelBuilder, User user, int index, World world) {
- addon.getWarpSignsManager().getSortedWarps(world).thenAccept(warps -> {
- // Cache and clean the signs
- Iterator it = warps.iterator();
- while(it.hasNext()) {
- UUID warpOwner = it.next();
- @NonNull
- SignCacheItem sign = signCacheManager.getSignItem(world, warpOwner);
- if (!sign.isReal()) {
- it.remove();
- addon.getWarpSignsManager().removeWarpFromMap(world, warpOwner);
- }
- }
- // Add random warp
- getRandomWarp(warps);
- // Build the main body
- int i = buildMainBody(panelBuilder, user, index, world, warps);
- // Add navigation
- addNavigation(panelBuilder, user, world, i, index, warps.size());
- r.complete(null);
- });
- }
-
- private void getRandomWarp(List warps) {
- // Add random warp
- if (!warps.isEmpty() && addon.getSettings().isRandomAllowed()) {
- warps.add(0, warps.get(new Random().nextInt(warps.size())));
- }
- }
-
- int buildMainBody(PanelBuilder panelBuilder, User user, int index, World world, List warps) {
- if (index < 0) {
- index = 0;
- } else if (index > (warps.size() / PANEL_MAX_SIZE)) {
- index = warps.size() / PANEL_MAX_SIZE;
- }
-
- int i = index * PANEL_MAX_SIZE;
- for (; panelBuilder.getItems().size() < PANEL_MAX_SIZE && i < warps.size(); i++) {
- UUID warpOwner = warps.get(i);
- if (addon.getSettings().isRandomAllowed() && i == 0) {
- panelBuilder.item(getRandomButton(world, user, warpOwner));
- } else {
- @NonNull
- SignCacheItem sign = signCacheManager.getSignItem(world, warpOwner);
- if (sign.isReal()) {
- panelBuilder.item(getPanelItem(world, warpOwner, sign));
- } else {
- addon.getWarpSignsManager().removeWarpFromMap(world, warpOwner);
- }
- }
- }
- return i;
- }
-
- /**
- * Add Next and Previous icons to navigate
- * @param panelBuilder - the panel builder
- * @param user - user
- * @param world - world
- * @param numOfItems - number of items shown so far including in previous panels
- * @param panelNum - panel number (page)
- * @param totalNum - total number of items in the list
- */
- void addNavigation(PanelBuilder panelBuilder, User user, World world, int numOfItems, int panelNum, int totalNum) {
- // Previous
- if (panelNum > 0 && numOfItems > PANEL_MAX_SIZE) {
- // Previous
- panelBuilder.item(new PanelItemBuilder()
- .name(user.getTranslation("warps.previous"))
- .icon(new ItemStack(Material.COBBLESTONE))
- .clickHandler((panel, clicker, click, slot) -> {
- user.closeInventory();
- showWarpPanel(world, user, panelNum-1);
- return true;
- }).build());
- }
- // Next
- if (numOfItems < totalNum) {
- // Next
- panelBuilder.item(new PanelItemBuilder()
- .name(user.getTranslation("warps.next"))
- .icon(new ItemStack(Material.STONE))
- .clickHandler((panel, clicker, click, slot) -> {
- user.closeInventory();
- showWarpPanel(world, user, panelNum+1);
- return true;
- }).build());
- }
- }
-
- /**
- * Removes sign text from the cache
- * @param world - world
- * @param key - uuid of owner
- * @return true if the item was removed from the cache
- */
- public boolean removeWarp(World world, UUID key) {
- return signCacheManager.removeWarp(world, key);
- }
-
- public void saveCache() {
- signCacheManager.saveCache();
- }
-
-}
diff --git a/src/main/java/world/bentobox/warps/WarpsPladdon.java b/src/main/java/world/bentobox/warps/WarpsPladdon.java
index d27866a..44bd214 100644
--- a/src/main/java/world/bentobox/warps/WarpsPladdon.java
+++ b/src/main/java/world/bentobox/warps/WarpsPladdon.java
@@ -1,8 +1,15 @@
package world.bentobox.warps;
+import org.bukkit.plugin.java.annotation.dependency.Dependency;
+import org.bukkit.plugin.java.annotation.plugin.ApiVersion;
+import org.bukkit.plugin.java.annotation.plugin.Plugin;
+
import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.Pladdon;
+@Plugin(name="Pladdon", version="1.0")
+@ApiVersion(ApiVersion.Target.v1_16)
+@Dependency(value = "BentoBox")
public class WarpsPladdon extends Pladdon {
@Override
diff --git a/src/main/java/world/bentobox/warps/commands/WarpsCommand.java b/src/main/java/world/bentobox/warps/commands/WarpsCommand.java
index ca9f2d8..108a255 100644
--- a/src/main/java/world/bentobox/warps/commands/WarpsCommand.java
+++ b/src/main/java/world/bentobox/warps/commands/WarpsCommand.java
@@ -7,6 +7,8 @@ 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.panels.WarpsPanel;
+
/**
* Handles the warps command
@@ -51,7 +53,9 @@ public class WarpsCommand extends CompositeCommand {
user.sendMessage("warps.warpTip", "[text]", addon.getSettings().getWelcomeLine());
return false;
}
- addon.getWarpPanelManager().showWarpPanel(world, user, 0);
+
+ WarpsPanel.openPanel(this.addon, world, user);
+
return true;
}
diff --git a/src/main/java/world/bentobox/warps/config/Settings.java b/src/main/java/world/bentobox/warps/config/Settings.java
index 7b51024..5e9bfbb 100644
--- a/src/main/java/world/bentobox/warps/config/Settings.java
+++ b/src/main/java/world/bentobox/warps/config/Settings.java
@@ -29,14 +29,6 @@ public class Settings implements ConfigObject
@ConfigEntry(path = "welcomeLine")
private String welcomeLine = "[Welcome]";
- @ConfigComment("")
- @ConfigComment("Icon that will be displayed in Warps list. SIGN counts for any kind of sign and the type of")
- @ConfigComment("wood used will be reflected in the panel if the server supports it.")
- @ConfigComment("It uses native Minecraft material strings, but using string 'PLAYER_HEAD', it is possible to")
- @ConfigComment("use player heads instead. Beware that Mojang API rate limiting may prevent heads from loading.")
- @ConfigEntry(path = "icon")
- private String icon = "SIGN";
-
@ConfigComment("")
@ConfigComment("This list stores GameModes in which Level addon should not work.")
@ConfigComment("To disable addon it is necessary to write its name in new line that starts with -. Example:")
@@ -45,23 +37,12 @@ public class Settings implements ConfigObject
@ConfigEntry(path = "disabled-gamemodes")
private Set disabledGameModes = new HashSet<>();
- @ConfigComment("")
- @ConfigComment("Warp panel name formatting.")
- @ConfigComment("Example: &c will make names red. &f is white")
- @ConfigEntry(path = "name-format")
- private String nameFormat = "&f";
-
@ConfigComment("")
@ConfigComment("Warp panel default lore formatting.")
@ConfigComment("Example: &c will make lore red. &f is white")
@ConfigEntry(path = "lore-format")
private String loreFormat = "&f";
- @ConfigComment("")
- @ConfigComment("Allow random teleport - adds a button to the warp panel that goes to a random warp sign")
- @ConfigEntry(path = "random-allowed")
- private boolean randomAllowed = true;
-
@ConfigComment("")
@ConfigComment("Allow use in other worlds. Players must have the welcomewarpsigns.warp permission.")
@ConfigEntry(path = "allow-in-other-worlds")
@@ -155,42 +136,6 @@ public class Settings implements ConfigObject
}
- /**
- * This method returns the icon object.
- * @return the icon object.
- */
- public String getIcon()
- {
- return icon;
- }
-
-
- /**
- * This method sets the icon object value.
- * @param icon the icon object new value.
- */
- public void setIcon(String icon)
- {
- this.icon = icon;
- }
-
-
- /**
- * @return the nameFormat
- */
- public String getNameFormat() {
- return nameFormat;
- }
-
-
- /**
- * @param nameFormat the nameFormat to set
- */
- public void setNameFormat(String nameFormat) {
- this.nameFormat = nameFormat;
- }
-
-
/**
* @return the loreFormat
*/
@@ -207,22 +152,6 @@ public class Settings implements ConfigObject
}
- /**
- * @return the randomAllowed
- */
- public boolean isRandomAllowed() {
- return randomAllowed;
- }
-
-
- /**
- * @param randomAllowed the randomAllowed to set
- */
- public void setRandomAllowed(boolean randomAllowed) {
- this.randomAllowed = randomAllowed;
- }
-
-
/**
* @return the allowInOtherWorlds
*/
@@ -269,6 +198,4 @@ public class Settings implements ConfigObject
public void setWarpsCommand(String warpsCommand) {
this.warpsCommand = warpsCommand;
}
-
-
}
diff --git a/src/main/java/world/bentobox/warps/listeners/WarpSignsListener.java b/src/main/java/world/bentobox/warps/listeners/WarpSignsListener.java
index a581d69..36d2805 100644
--- a/src/main/java/world/bentobox/warps/listeners/WarpSignsListener.java
+++ b/src/main/java/world/bentobox/warps/listeners/WarpSignsListener.java
@@ -72,7 +72,7 @@ public class WarpSignsListener implements Listener {
&& !Tag.SIGNS.isTagged(location.getBlock().getType())) {
iterator.remove();
// Remove sign from warp panel cache
- addon.getWarpPanelManager().removeWarp(event.getWorld(), uuid);
+ addon.getSignCacheManager().removeWarp(event.getWorld(), uuid);
changed = true;
}
}
diff --git a/src/main/java/world/bentobox/warps/SignCacheItem.java b/src/main/java/world/bentobox/warps/managers/SignCacheItem.java
similarity index 96%
rename from src/main/java/world/bentobox/warps/SignCacheItem.java
rename to src/main/java/world/bentobox/warps/managers/SignCacheItem.java
index 1d0df5f..10e45af 100644
--- a/src/main/java/world/bentobox/warps/SignCacheItem.java
+++ b/src/main/java/world/bentobox/warps/managers/SignCacheItem.java
@@ -1,4 +1,4 @@
-package world.bentobox.warps;
+package world.bentobox.warps.managers;
import java.util.List;
diff --git a/src/main/java/world/bentobox/warps/SignCacheManager.java b/src/main/java/world/bentobox/warps/managers/SignCacheManager.java
similarity index 91%
rename from src/main/java/world/bentobox/warps/SignCacheManager.java
rename to src/main/java/world/bentobox/warps/managers/SignCacheManager.java
index 5c7a03e..596d718 100644
--- a/src/main/java/world/bentobox/warps/SignCacheManager.java
+++ b/src/main/java/world/bentobox/warps/managers/SignCacheManager.java
@@ -1,4 +1,4 @@
-package world.bentobox.warps;
+package world.bentobox.warps.managers;
import java.util.HashMap;
import java.util.Map;
@@ -10,6 +10,7 @@ import org.bukkit.World;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.database.Database;
+import world.bentobox.warps.Warp;
import world.bentobox.warps.objects.SignCache;
public class SignCacheManager {
@@ -36,7 +37,7 @@ public class SignCacheManager {
});
}
- void saveCache() {
+ public void saveCache() {
cachedSigns.forEach((w, m) -> handler.saveObjectAsync(new SignCache(w, m)));
}
@@ -47,7 +48,7 @@ public class SignCacheManager {
* @return SignCacheItem
*/
@NonNull
- SignCacheItem getSignItem(World world, UUID warpOwner) {
+ public SignCacheItem getSignItem(World world, UUID warpOwner) {
// Add the worlds if we haven't seen this before
cachedSigns.putIfAbsent(world, new HashMap<>());
// Get from cache if available
@@ -70,7 +71,7 @@ public class SignCacheManager {
* @param key - uuid of owner
* @return true if item is removed from cache
*/
- boolean removeWarp(World world, UUID key) {
+ public boolean removeWarp(World world, UUID key) {
if (cachedSigns.containsKey(world)) {
return cachedSigns.get(world).remove(key) != null;
}
diff --git a/src/main/java/world/bentobox/warps/WarpSignsManager.java b/src/main/java/world/bentobox/warps/managers/WarpSignsManager.java
similarity index 87%
rename from src/main/java/world/bentobox/warps/WarpSignsManager.java
rename to src/main/java/world/bentobox/warps/managers/WarpSignsManager.java
index b4686f2..e635bfd 100644
--- a/src/main/java/world/bentobox/warps/WarpSignsManager.java
+++ b/src/main/java/world/bentobox/warps/managers/WarpSignsManager.java
@@ -1,4 +1,4 @@
-package world.bentobox.warps;
+package world.bentobox.warps.managers;
import java.util.ArrayList;
import java.util.Arrays;
@@ -25,7 +25,6 @@ import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign;
-import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.eclipse.jdt.annotation.NonNull;
@@ -38,8 +37,11 @@ import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.util.Util;
+import world.bentobox.warps.Warp;
import world.bentobox.warps.event.WarpInitiateEvent;
import world.bentobox.warps.objects.WarpsData;
+import world.bentobox.warps.panels.Utils;
+
/**
* Handles warping. Players can add one sign
@@ -151,7 +153,7 @@ public class WarpSignsManager {
return r;
}
- List processWarpMap(CompletableFuture> r, @NonNull World world) {
+ public List processWarpMap(CompletableFuture> r, @NonNull World world) {
// Remove any null locations - this can happen if an admin changes the name of the world and signs point to old locations
getWarpMap(world).values().removeIf(Objects::isNull);
// Bigger value of time means a more recent login
@@ -191,7 +193,7 @@ public class WarpSignsManager {
/**
* Load the warps and check if they still exist
*/
- void loadWarpList() {
+ public void loadWarpList() {
addon.log("Loading warps...");
worldsWarpList = new HashMap<>();
if (handler.objectExists(WARPS)) {
@@ -246,7 +248,7 @@ public class WarpSignsManager {
.map(User::getInstance)
.ifPresent(user -> user.sendMessage("warps.sign-removed"));
// Remove sign from warp panel cache
- addon.getWarpPanelManager().removeWarp(loc.getWorld(), en.getKey());
+ addon.getSignCacheManager().removeWarp(loc.getWorld(), en.getKey());
it.remove();
}
}
@@ -265,7 +267,7 @@ public class WarpSignsManager {
}
// Remove sign from warp panel cache
- addon.getWarpPanelManager().removeWarp(world, uuid);
+ addon.getSignCacheManager().removeWarp(world, uuid);
saveWarpList();
}
@@ -283,7 +285,7 @@ public class WarpSignsManager {
*/
public void saveWarpList() {
handler.saveObjectAsync(warpsData.save(worldsWarpList));
- addon.getWarpPanelManager().saveCache();
+ addon.getSignCacheManager().saveCache();
}
/**
@@ -311,7 +313,6 @@ public class WarpSignsManager {
result.set(i, ChatColor.translateAlternateColorCodes('&', addon.getSettings().getLoreFormat()) + result.get(i));
}
// Get the sign type
-
String prefix = plugin.getIWM().getAddon(world).map(Addon::getPermissionPrefix).orElse("");
Material icon;
@@ -319,20 +320,21 @@ public class WarpSignsManager {
if (!prefix.isEmpty())
{
icon = Material.matchMaterial(
- this.getPermissionValue(Objects.requireNonNull(User.getInstance(uuid)),
- prefix + "island.warp",
- this.addon.getSettings().getIcon()));
+ Utils.getPermissionValue(User.getInstance(uuid), prefix + "island.warp",
+ Material.OAK_SIGN.name()));
}
else
{
- icon = Material.matchMaterial(this.addon.getSettings().getIcon());
+ icon = null;
}
- if (icon == null || icon.name().contains("SIGN")) {
+ if (icon != null && icon.name().contains("SIGN")) {
return new SignCacheItem(result, Material.valueOf(sign.getType().name().replace("WALL_", "")));
}
- return new SignCacheItem(result, icon);
-
+ else
+ {
+ return new SignCacheItem(result, icon);
+ }
}
/**
@@ -460,54 +462,4 @@ public class WarpSignsManager {
public boolean hasWarp(@NonNull World world, @NonNull UUID playerUUID) {
return getWarpMap(world).containsKey(playerUUID);
}
-
-
- // ---------------------------------------------------------------------
- // Section: Other methods
- // ---------------------------------------------------------------------
-
-
- /**
- * This method gets string value of given permission prefix. If user does not have
- * given permission or it have all (*), then return default value.
- * @param user User who's permission should be checked.
- * @param permissionPrefix Prefix that need to be found.
- * @param defaultValue Default value that will be returned if permission not found.
- * @return String value that follows permissionPrefix.
- */
- private String getPermissionValue(@NonNull User user, @NonNull String permissionPrefix, @NonNull String defaultValue)
- {
- if (user.isPlayer())
- {
- if (permissionPrefix.endsWith("."))
- {
- permissionPrefix = permissionPrefix.substring(0, permissionPrefix.length() - 1);
- }
-
- String permPrefix = permissionPrefix + ".";
-
- List permissions = user.getEffectivePermissions().stream()
- .map(PermissionAttachmentInfo::getPermission)
- .filter(permission -> permission.startsWith(permPrefix))
- .toList();
-
- for (String permission : permissions)
- {
- if (permission.contains(permPrefix + "*"))
- {
- // * means all. So continue to search more specific.
- continue;
- }
-
- String[] parts = permission.split(permPrefix);
-
- if (parts.length > 1)
- {
- return parts[1];
- }
- }
- }
-
- return defaultValue;
- }
}
diff --git a/src/main/java/world/bentobox/warps/objects/SignCache.java b/src/main/java/world/bentobox/warps/objects/SignCache.java
index 8f8e3e6..16b41bc 100644
--- a/src/main/java/world/bentobox/warps/objects/SignCache.java
+++ b/src/main/java/world/bentobox/warps/objects/SignCache.java
@@ -10,7 +10,7 @@ import com.google.gson.annotations.Expose;
import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.bentobox.database.objects.Table;
-import world.bentobox.warps.SignCacheItem;
+import world.bentobox.warps.managers.SignCacheItem;
@Table(name = "WarpSignCache")
public class SignCache implements DataObject {
diff --git a/src/main/java/world/bentobox/warps/panels/Utils.java b/src/main/java/world/bentobox/warps/panels/Utils.java
new file mode 100644
index 0000000..2c4b8c8
--- /dev/null
+++ b/src/main/java/world/bentobox/warps/panels/Utils.java
@@ -0,0 +1,76 @@
+//
+// Created by BONNe
+// Copyright - 2021
+//
+
+
+package world.bentobox.warps.panels;
+
+
+import org.bukkit.permissions.PermissionAttachmentInfo;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import world.bentobox.bentobox.api.user.User;
+
+
+public class Utils
+{
+ /**
+ * This method sends a message to the user with appended "prefix" text before message.
+ * @param user User who receives message.
+ * @param translationText Translation text of the message.
+ * @param parameters Parameters for the translation text.
+ */
+ public static void sendMessage(User user, String translationText, String... parameters)
+ {
+ user.sendMessage(user.getTranslation( "warps.conversations.prefix") +
+ user.getTranslation( translationText, parameters));
+ }
+
+
+ /**
+ * This method gets string value of given permission prefix. If user does not have given permission or it have all
+ * (*), then return default value.
+ *
+ * @param user User who's permission should be checked.
+ * @param permissionPrefix Prefix that need to be found.
+ * @param defaultValue Default value that will be returned if permission not found.
+ * @return String value that follows permissionPrefix.
+ */
+ public static String getPermissionValue(User user, String permissionPrefix, String defaultValue)
+ {
+ if (user.isPlayer())
+ {
+ if (permissionPrefix.endsWith("."))
+ {
+ permissionPrefix = permissionPrefix.substring(0, permissionPrefix.length() - 1);
+ }
+
+ String permPrefix = permissionPrefix + ".";
+
+ List permissions = user.getEffectivePermissions().stream().
+ map(PermissionAttachmentInfo::getPermission).
+ filter(permission -> permission.startsWith(permPrefix)).
+ collect(Collectors.toList());
+
+ for (String permission : permissions)
+ {
+ if (permission.contains(permPrefix + "*"))
+ {
+ // * means all. So continue to search more specific.
+ continue;
+ }
+
+ String[] parts = permission.split(permPrefix);
+
+ if (parts.length > 1)
+ {
+ return parts[1];
+ }
+ }
+ }
+
+ return defaultValue;
+ }
+}
diff --git a/src/main/java/world/bentobox/warps/panels/WarpsPanel.java b/src/main/java/world/bentobox/warps/panels/WarpsPanel.java
new file mode 100644
index 0000000..0942783
--- /dev/null
+++ b/src/main/java/world/bentobox/warps/panels/WarpsPanel.java
@@ -0,0 +1,598 @@
+//
+// Created by BONNe
+// Copyright - 2021
+//
+
+package world.bentobox.warps.panels;
+
+
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.command.Command;
+import org.bukkit.event.inventory.ClickType;
+import org.bukkit.inventory.ItemStack;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import java.io.File;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+
+import world.bentobox.bentobox.api.panels.PanelItem;
+import world.bentobox.bentobox.api.panels.TemplatedPanel;
+import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
+import world.bentobox.bentobox.api.panels.builders.TemplatedPanelBuilder;
+import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord;
+import world.bentobox.bentobox.api.user.User;
+import world.bentobox.warps.managers.SignCacheItem;
+import world.bentobox.warps.managers.SignCacheManager;
+import world.bentobox.warps.Warp;
+
+
+/**
+ * This class shows how to set up easy panel by using BentoBox PanelBuilder API
+ */
+public class WarpsPanel
+{
+// ---------------------------------------------------------------------
+// Section: Constructor
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This is internal constructor. It is used internally in current class to avoid creating objects everywhere.
+ *
+ * @param addon VisitAddon object
+ * @param world World where user will be teleported
+ * @param user User who opens panel
+ */
+ private WarpsPanel(Warp addon,
+ World world,
+ User user)
+ {
+ this.addon = addon;
+ this.manager = this.addon.getSignCacheManager();
+ this.user = user;
+ this.world = world;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method collects and validates sign warps that could be displayed in GUI.
+ * @param completed CompletableFeature that triggers panel opening.
+ */
+ private void collectValidWarps(CompletableFuture completed)
+ {
+ this.addon.getWarpSignsManager().getSortedWarps(this.world).
+ thenAccept(warps ->
+ {
+ // Cache and clean the signs
+ Iterator iterator = warps.iterator();
+
+ while (iterator.hasNext())
+ {
+ UUID warpOwner = iterator.next();
+ @NonNull
+ SignCacheItem sign = this.manager.getSignItem(this.world, warpOwner);
+
+ if (!sign.isReal())
+ {
+ iterator.remove();
+ this.addon.getWarpSignsManager().removeWarpFromMap(this.world, warpOwner);
+ }
+ }
+
+ // Assign warps to element list.
+ this.elementList = warps;
+
+ // Build the main body
+ completed.complete(true);
+ });
+ }
+
+
+ /**
+ * This is wrapper around builder to trigger main GUI building.
+ */
+ private void initBuild()
+ {
+ CompletableFuture collectWarps = new CompletableFuture<>();
+ this.collectValidWarps(collectWarps);
+ collectWarps.thenAccept(done -> {
+ if (done)
+ {
+ this.build();
+ }
+ });
+ }
+
+
+ /**
+ * Build method manages current panel opening. It uses BentoBox PanelAPI that is easy to use and users can get nice
+ * panels.
+ */
+ private void build()
+ {
+ // Do not open gui if there is no magic sticks.
+ if (this.elementList.isEmpty())
+ {
+ this.addon.logError("There are no available islands for visiting!");
+ Utils.sendMessage(this.user, "warps.error.no-warps-yet",
+ "[gamemode]", this.addon.getPlugin().getIWM().getAddon(this.world).
+ map(gamemode -> gamemode.getDescription().getName()).
+ orElse(""));
+ return;
+ }
+
+ // Start building panel.
+ TemplatedPanelBuilder panelBuilder = new TemplatedPanelBuilder();
+
+ // Set main template.
+ panelBuilder.template("warps_panel", new File(this.addon.getDataFolder(), "panels"));
+ panelBuilder.user(this.user);
+ panelBuilder.world(this.user.getWorld());
+
+ // Register button builders
+ panelBuilder.registerTypeBuilder("WARP", this::createWarpButton);
+ panelBuilder.registerTypeBuilder("RANDOM", this::createRandomButton);
+
+ // Register next and previous builders
+ panelBuilder.registerTypeBuilder("NEXT", this::createNextButton);
+ panelBuilder.registerTypeBuilder("PREVIOUS", this::createPreviousButton);
+
+ // Register unknown type builder.
+ panelBuilder.build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Buttons
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Create next button panel item.
+ *
+ * @param template the template
+ * @param slot the slot
+ * @return the panel item
+ */
+ @Nullable
+ private PanelItem createNextButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
+ {
+ int size = this.elementList.size();
+
+ if (size <= slot.amountMap().getOrDefault("WARP", 1) ||
+ 1.0 * size / slot.amountMap().getOrDefault("WARP", 1) <= this.pageIndex + 1)
+ {
+ // There are no next elements
+ return null;
+ }
+
+ int nextPageIndex = this.pageIndex + 2;
+
+ PanelItemBuilder builder = new PanelItemBuilder();
+
+ if (template.icon() != null)
+ {
+ ItemStack clone = template.icon().clone();
+
+ if ((Boolean) template.dataMap().getOrDefault("indexing", false))
+ {
+ clone.setAmount(nextPageIndex);
+ }
+
+ builder.icon(clone);
+ }
+
+ if (template.title() != null)
+ {
+ builder.name(this.user.getTranslation(this.world, template.title()));
+ }
+
+ if (template.description() != null)
+ {
+ builder.description(this.user.getTranslation(this.world, template.description(),
+ "[number]", String.valueOf(nextPageIndex)));
+ }
+
+ // Add ClickHandler
+ builder.clickHandler((panel, user, clickType, i) ->
+ {
+ template.actions().forEach(action -> {
+ if (clickType == action.clickType() || action.clickType() == ClickType.UNKNOWN)
+ {
+ if ("NEXT".equalsIgnoreCase(action.actionType()))
+ {
+ // Next button ignores click type currently.
+ this.pageIndex++;
+ this.build();
+ }
+ }
+ });
+
+ // Always return true.
+ return true;
+ });
+
+ // Collect tooltips.
+ List tooltips = template.actions().stream().
+ filter(action -> action.tooltip() != null).
+ map(action -> this.user.getTranslation(this.world, action.tooltip())).
+ filter(text -> !text.isBlank()).
+ collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
+
+ // Add tooltips.
+ if (!tooltips.isEmpty())
+ {
+ // Empty line and tooltips.
+ builder.description("");
+ builder.description(tooltips);
+ }
+
+ return builder.build();
+ }
+
+
+ /**
+ * Create previous button panel item.
+ *
+ * @param template the template
+ * @param slot the slot
+ * @return the panel item
+ */
+ @Nullable
+ private PanelItem createPreviousButton(@NonNull ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
+ {
+ if (this.pageIndex == 0)
+ {
+ // There are no next elements
+ return null;
+ }
+
+ int previousPageIndex = this.pageIndex;
+
+ PanelItemBuilder builder = new PanelItemBuilder();
+
+ if (template.icon() != null)
+ {
+ ItemStack clone = template.icon().clone();
+
+ if ((Boolean) template.dataMap().getOrDefault("indexing", false))
+ {
+ clone.setAmount(previousPageIndex);
+ }
+
+ builder.icon(clone);
+ }
+
+ if (template.title() != null)
+ {
+ builder.name(this.user.getTranslation(this.world, template.title()));
+ }
+
+ if (template.description() != null)
+ {
+ builder.description(this.user.getTranslation(this.world, template.description(),
+ "[number]", String.valueOf(previousPageIndex)));
+ }
+
+ // Add ClickHandler
+ // Add ClickHandler
+ builder.clickHandler((panel, user, clickType, i) ->
+ {
+ template.actions().forEach(action -> {
+ if (clickType == action.clickType() || action.clickType() == ClickType.UNKNOWN)
+ {
+ if ("PREVIOUS".equalsIgnoreCase(action.actionType()))
+ {
+ // Next button ignores click type currently.
+ this.pageIndex--;
+ this.build();
+ }
+ }
+ });
+
+ // Always return true.
+ return true;
+ });
+
+ // Collect tooltips.
+ List tooltips = template.actions().stream().
+ filter(action -> action.tooltip() != null).
+ map(action -> this.user.getTranslation(this.world, action.tooltip())).
+ filter(text -> !text.isBlank()).
+ collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
+
+ // Add tooltips.
+ if (!tooltips.isEmpty())
+ {
+ // Empty line and tooltips.
+ builder.description("");
+ builder.description(tooltips);
+ }
+
+ return builder.build();
+ }
+
+
+ /**
+ * This method creates and returns warp button.
+ *
+ * @return PanelItem that represents warp button.
+ */
+ @Nullable
+ private PanelItem createWarpButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
+ {
+ if (this.elementList.isEmpty())
+ {
+ // Does not contain any sticks.
+ return null;
+ }
+
+ int index = this.pageIndex * slot.amountMap().getOrDefault("WARP", 1) + slot.slot();
+
+ if (index >= this.elementList.size())
+ {
+ // Out of index.
+ return null;
+ }
+
+ return this.createWarpButton(template, this.elementList.get(index), "warp");
+ }
+
+
+ /**
+ * This method creates and returns random warp button.
+ *
+ * @return PanelItem that represents random warp button.
+ */
+ @Nullable
+ private PanelItem createRandomButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
+ {
+ if (this.elementList.size() < 2)
+ {
+ // Does not contain any sticks.
+ return null;
+ }
+
+ int index = random.nextInt(this.elementList.size());
+ return this.createWarpButton(template, this.elementList.get(index), "random");
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Other methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method creates and returns button that switch to next page in view mode.
+ *
+ * @return PanelItem that allows to select next owner view page.
+ */
+ private PanelItem createWarpButton(ItemTemplateRecord template, UUID ownerUUID, String type)
+ {
+ if (ownerUUID == null)
+ {
+ // return as owner has no owner. Empty button will be created.
+ return null;
+ }
+
+ SignCacheItem signCache = this.manager.getSignItem(this.world, ownerUUID);
+
+ if (!signCache.isReal())
+ {
+ this.addon.getWarpSignsManager().removeWarpFromMap(this.world, ownerUUID);
+ // return as signCache is not real anymore.
+ return null;
+ }
+
+ final String reference = "warps.gui.buttons." + type + ".";
+
+ String ownerName = addon.getPlugin().getPlayers().getName(ownerUUID);
+
+ // Get settings for owner.
+ PanelItemBuilder builder = new PanelItemBuilder();
+
+ if (template.icon() != null)
+ {
+ if (template.icon().getType().equals(Material.PLAYER_HEAD))
+ {
+ builder.icon(ownerName);
+ }
+ else
+ {
+ builder.icon(template.icon().clone());
+ }
+ }
+ else
+ {
+ // Check owner for a specific icon
+ Material material = signCache.getType();
+
+ if (material == null)
+ {
+ // Set oak sign as icon was not specified.
+ material = Material.OAK_SIGN;
+ }
+
+ if (material == Material.PLAYER_HEAD)
+ {
+ builder.icon(ownerName);
+ }
+ else
+ {
+ builder.icon(material);
+ }
+ }
+
+ if (template.title() != null)
+ {
+ builder.name(this.user.getTranslation(this.world, template.title(),
+ "[name]", ownerName));
+ }
+ else
+ {
+ builder.name(this.user.getTranslation(reference + "name",
+ "[name]", ownerName));
+ }
+
+ // Process Description of the button.
+ // Generate [sign_text] text
+
+ String descriptionText;
+
+ if (template.description() != null)
+ {
+ descriptionText = this.user.getTranslationOrNothing(template.description(),
+ "[name]", ownerName,
+ "[sign_text]", String.join("\n", signCache.getSignText())).
+ replaceAll("(?m)^[ \\t]*\\r?\\n", "").
+ replaceAll("(?
+ {
+ template.actions().forEach(action -> {
+ if (clickType == action.clickType() || action.clickType() == ClickType.UNKNOWN)
+ {
+ if ("WARP".equalsIgnoreCase(action.actionType()))
+ {
+ this.runCommandCall(ownerName);
+ }
+ }
+ });
+
+ // Always return true.
+ return true;
+ });
+
+ // Collect tooltips.
+ List tooltips = template.actions().stream().
+ filter(action -> action.tooltip() != null).
+ map(action -> this.user.getTranslation(this.world, action.tooltip())).
+ filter(text -> !text.isBlank()).
+ collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
+
+ // Add tooltips.
+ if (!tooltips.isEmpty())
+ {
+ // Empty line and tooltips.
+ builder.description("");
+ builder.description(tooltips);
+ }
+
+ return builder.build();
+ }
+
+
+ /**
+ * This method runs command call that allows player to visit clicked island.
+ */
+ private void runCommandCall(String ownerName)
+ {
+ // Get first player command label.
+ String command = this.addon.getSettings().getWarpCommand().split(" ")[0];
+
+ String gamemodeCommand = this.addon.getPlugin().getIWM().getAddon(this.world).
+ map(gamemode -> gamemode.getPlayerCommand().map(Command::getLabel).orElse("")).
+ orElse("");
+
+ if (gamemodeCommand.isEmpty())
+ {
+ this.addon.log(this.user.getName() + " called: `" + command + " " + ownerName + "`");
+ this.user.performCommand(command + " " + ownerName);
+ }
+ else
+ {
+ this.addon.log(this.user.getName() + " called: `" + gamemodeCommand + " " + command + " " + ownerName + "`");
+ this.user.performCommand(gamemodeCommand + " " + command + " " + ownerName);
+ }
+
+ // Close inventory
+ this.user.closeInventory();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Static methods
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This method is used to open UserPanel outside this class. It will be much easier to open panel with single method
+ * call then initializing new object.
+ *
+ * @param addon Warps object
+ * @param world World where user will be teleported
+ * @param user User who opens panel
+ */
+ public static void openPanel(Warp addon,
+ World world,
+ User user)
+ {
+ new WarpsPanel(addon, world, user).initBuild();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Variables
+// ---------------------------------------------------------------------
+
+
+ /**
+ * This variable allows to access addon object.
+ */
+ private final Warp addon;
+
+ /**
+ * This variable allows to access addon manager object.
+ */
+ private final SignCacheManager manager;
+
+ /**
+ * This variable holds user who opens panel. Without it panel cannot be opened.
+ */
+ private final User user;
+
+ /**
+ * This variable holds world where panel is opened. Without it panel cannot be opened.
+ */
+ private final World world;
+
+ /**
+ * This variable stores filtered elements.
+ */
+ private List elementList;
+
+ /**
+ * This variable holds current pageIndex for multi-page island choosing.
+ */
+ private int pageIndex;
+
+ /**
+ * Random for finding random warp.
+ */
+ private static final Random random = new Random();
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 3a8818b..a647e5c 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -12,29 +12,16 @@ warplevelrestriction: 10
# Not case sensitive!
welcomeLine: '[Welcome]'
#
-# Icon that will be displayed in Warps list. SIGN counts for any kind of sign and the type of
-# wood used will be reflected in the panel if the server supports it.
-# It uses native Minecraft material strings, but using string 'PLAYER_HEAD', it is possible to
-# use player heads instead. Beware that Mojang API rate limiting may prevent heads from loading.
-icon: 'SIGN'
-#
# This list stores GameModes in which Level addon should not work.
# To disable addon it is necessary to write its name in new line that starts with -. Example:
# disabled-gamemodes:
# - BSkyBlock
disabled-gamemodes: []
#
-# Warp panel name formatting.
-# Example: &c will make names red, &f is white
-name-format: "&f"
-#
# Warp panel default lore formatting.
# Example: &c will make lore red. &f is white
lore-format: "&f"
#
-# Allow random teleport - adds a button to the warp panel that goes to a random warp sign
-random-allowed: true
-#
# Allow use in other worlds. Players must have the welcomewarpsigns.warp permission.
allow-in-other-worlds: false
#
diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml
index 93ae795..757677e 100755
--- a/src/main/resources/locales/en-US.yml
+++ b/src/main/resources/locales/en-US.yml
@@ -20,14 +20,43 @@ warps:
your-level-is: "&c Your island level is only [level] and must be higher than [required]. Run the level command."
help:
description: "open the warps panel"
- next: "&6 Next page"
player-warped: "&2 [name] warped to your warp sign!"
- previous: "&6 Previous page"
- random: "&4 Random Warp"
sign-removed: "&c Warp sign removed!"
success: "&a Success!"
- title: "Warp Signs"
warpTip: "&6 Place a warp sign with [text] on the top"
warpToPlayersSign: "&6 Warping to [player]'s sign"
+ gui:
+ titles:
+ # The title of warp panel
+ warp-title: '&0&l Warp Signs'
+ buttons:
+ # Button that is used in multi-page GUIs which allows to return to previous page.
+ previous:
+ name: "&f&l Previous Page"
+ description: |-
+ &7 Switch to [number] page
+ # Button that is used in multi-page GUIs which allows to go to next page.
+ next:
+ name: "&f&l Next Page"
+ description: |-
+ &7 Switch to [number] page
+ # Button for a warp
+ warp:
+ name: "&f&l [name]"
+ description: |-
+ [sign_text]
+ # Button for a random warp
+ random:
+ name: "&f&l Random Warp"
+ description: |-
+ &7 Hmm, where will I appear?
+ tips:
+ click-to-previous: "&e Click &7 to view previous page."
+ click-to-next: "&e Click &7 to view next page."
+ click-to-warp: "&e Click &7 to warp."
+ conversations:
+ # Prefix for messages that are send from server.
+ prefix: "&l&6 [BentoBox]: &r"
+
diff --git a/src/main/resources/panels/warps_panel.yml b/src/main/resources/panels/warps_panel.yml
new file mode 100644
index 0000000..9a7464f
--- /dev/null
+++ b/src/main/resources/panels/warps_panel.yml
@@ -0,0 +1,79 @@
+warps_panel:
+ title: warps.gui.titles.warp-title
+ type: INVENTORY
+ background:
+ icon: BLACK_STAINED_GLASS_PANE
+ title: "&b&r" # Empty text
+ border:
+ icon: BLACK_STAINED_GLASS_PANE
+ title: "&b&r" # Empty text
+ force-shown: []
+ content:
+ 2:
+ 2: warp_button
+ 3: warp_button
+ 4: warp_button
+ 5: warp_button
+ 6: warp_button
+ 7: warp_button
+ 8: warp_button
+ 3:
+ 1:
+ icon: TIPPED_ARROW:INSTANT_HEAL::::1
+ title: warps.gui.buttons.previous.name
+ description: warps.gui.buttons.previous.description
+ data:
+ type: PREVIOUS
+ indexing: true
+ actions:
+ left:
+ type: PREVIOUS
+ tooltip: warps.gui.tips.click-to-previous
+ 2: warp_button
+ 3: warp_button
+ 4: warp_button
+ 5: warp_button
+ 6: warp_button
+ 7: warp_button
+ 8: warp_button
+ 9:
+ icon: TIPPED_ARROW:JUMP::::1
+ title: warps.gui.buttons.next.name
+ description: warps.gui.buttons.next.description
+ data:
+ type: NEXT
+ indexing: true
+ actions:
+ left:
+ type: NEXT
+ tooltip: warps.gui.tips.click-to-next
+ 4:
+ 2: warp_button
+ 3: warp_button
+ 4: warp_button
+ 5: warp_button
+ 6: warp_button
+ 7: warp_button
+ 8: warp_button
+ 6:
+ 5:
+ icon: DROPPER
+ title: warps.gui.buttons.random.name
+ description: warps.gui.buttons.random.description
+ data:
+ type: RANDOM
+ actions:
+ warp:
+ click-type: left
+ tooltip: warps.gui.tips.click-to-warp
+ reusable:
+ warp_button:
+ icon: PLAYER_HEAD
+ title: warps.gui.buttons.warp.name
+ description: warps.gui.buttons.warp.description
+ data:
+ type: WARP
+ actions:
+ warp:
+ click-type: left
+ tooltip: warps.gui.tips.click-to-warp
\ No newline at end of file
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
deleted file mode 100644
index f26fe60..0000000
--- a/src/main/resources/plugin.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-name: Pladdon
-main: world.bentobox.warps.WarpsPladdon
-version: ${version}
-api-version: 1.16
-description: A Warp Pladdon for BentoBox
-author: tastybento
-depend:
- - BentoBox
diff --git a/src/test/java/world/bentobox/warps/WarpPanelManagerTest.java b/src/test/java/world/bentobox/warps/WarpPanelManagerTest.java
deleted file mode 100644
index d2af1f6..0000000
--- a/src/test/java/world/bentobox/warps/WarpPanelManagerTest.java
+++ /dev/null
@@ -1,329 +0,0 @@
-package world.bentobox.warps;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.CompletableFuture;
-
-import org.bukkit.Bukkit;
-import org.bukkit.Location;
-import org.bukkit.Material;
-import org.bukkit.World;
-import org.bukkit.block.Block;
-import org.bukkit.entity.Player;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemFactory;
-import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.scheduler.BukkitScheduler;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.stubbing.Answer;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-
-import world.bentobox.bentobox.BentoBox;
-import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
-import world.bentobox.bentobox.api.user.User;
-import world.bentobox.bentobox.database.AbstractDatabaseHandler;
-import world.bentobox.bentobox.database.DatabaseSetup;
-import world.bentobox.bentobox.managers.PlayersManager;
-import world.bentobox.warps.config.Settings;
-
-/**
- * @author tastybento
- *
- */
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({Bukkit.class, DatabaseSetup.class})
-public class WarpPanelManagerTest {
-
- @Mock
- private WarpSignsManager wsm;
- @Mock
- private Warp addon;
- @Mock
- private Player player;
- @Mock
- private User user;
- @Mock
- private World world;
- @Mock
- private Inventory top;
- @Mock
- private Settings settings;
- @Mock
- private static AbstractDatabaseHandler