diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 9231476..0000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-
----
-
-**Description**
-
-
-**Steps to reproduce the behavior:**
-1. Go to '...'
-2. Click on '....'
-3. Scroll down to '....'
-4. See error
-
-**Expected behavior**
-
-
-**Screenshots**
-
-
-**Server Information:**
-Do `bbox version` in the console and paste the result here:
-
-**Additional context**
-
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 066b2d9..0000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..c13f2b9
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,38 @@
+name: Build
+on:
+ push:
+ branches:
+ - develop
+ - master
+ pull_request:
+ types: [opened, synchronize, reopened]
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Set up JDK 16
+ uses: actions/setup-java@v2
+ with:
+ distribution: 'adopt'
+ java-version: '16'
+ - name: Cache SonarCloud packages
+ uses: actions/cache@v2
+ with:
+ path: ~/.sonar/cache
+ key: ${{ runner.os }}-sonar
+ restore-keys: ${{ runner.os }}-sonar
+ - name: Cache Maven packages
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: ${{ runner.os }}-m2
+ - name: Build and analyze
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 9c5b6e9..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-language: java
-sudo: false
-addons:
- sonarcloud:
- organization: "bentobox-world"
-
-jdk:
- - openjdk8
- - openjdk11
-
-matrix:
- allow_failures:
- - jdk: openjdk11
-
-script:
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent install sonar:sonar -Dsonar.projectKey=BentoBoxWorld_Warps
-
-cache:
- directories:
- - '$HOME/.m2/repository'
- - '$HOME/.sonar/cache'
diff --git a/README.md b/README.md
index 607674a..ca11081 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,8 @@ to disable use by gamemode.
## How to use
+### Note: Java 16 and Minecraft 17, or later are required.
+
1. Place the jar in the addons folder of the BentoBox plugin
2. Restart the server
3. The addon will create a data folder and inside the folder will be a config.yml
diff --git a/pom.xml b/pom.xml
index 30aa0d5..3f946aa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,19 +54,23 @@
UTF-8
UTF-8
- 1.8
+ 16
- 2.0.2
+ 2.0.9
- 1.16.3-R0.1-SNAPSHOT
- 1.15.4
- 1.5.0
+ 1.17-R0.1-SNAPSHOT
+ 1.17.0
+ 2.7.0-SNAPSHOT
${build.version}-SNAPSHOT
-LOCAL
- 1.10.2
+ 1.11.1
+
+ BentoBoxWorld_Warps
+ bentobox-world
+ https://sonarcloud.io
@@ -109,30 +113,6 @@
-
- sonar
-
- https://sonarcloud.io
- bentobox-world
-
-
-
-
- org.sonarsource.scanner.maven
- sonar-maven-plugin
- 3.6.0.1398
-
-
- verify
-
- sonar
-
-
-
-
-
-
-
@@ -162,7 +142,7 @@
org.mockito
mockito-core
- 3.0.0
+ 3.11.1
test
@@ -196,7 +176,7 @@
org.eclipse.jdt
org.eclipse.jdt.annotation
- 2.2.200
+ 2.2.600
@@ -246,7 +226,12 @@
org.apache.maven.plugins
maven-surefire-plugin
- 2.22.0
+ 3.0.0-M5
+
+
+ --illegal-access=permit
+
+
org.apache.maven.plugins
@@ -256,15 +241,18 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 3.0.1
+ 3.1.1
- public
+
+ private
false
-Xdoclint:none
+ ${java.home}/bin/javadoc
attach-javadocs
+ install
jar
@@ -284,14 +272,6 @@
-
- org.apache.maven.plugins
- maven-shade-plugin
- 3.1.1
-
- false
-
-
org.apache.maven.plugins
maven-install-plugin
diff --git a/src/main/java/world/bentobox/warps/SignCacheItem.java b/src/main/java/world/bentobox/warps/SignCacheItem.java
index fb938bb..1d0df5f 100644
--- a/src/main/java/world/bentobox/warps/SignCacheItem.java
+++ b/src/main/java/world/bentobox/warps/SignCacheItem.java
@@ -12,18 +12,28 @@
*
*/
public class SignCacheItem {
+
@Expose
private final List signText;
@Expose
private final Material type;
/**
- * @param signText
- * @param type
+ * @param signText sign text
+ * @param type material of sign
*/
public SignCacheItem(List signText, Material type) {
this.signText = signText;
this.type = type;
}
+
+ /**
+ * This sign is not real
+ */
+ public SignCacheItem() {
+ this.signText = null;
+ this.type = null;
+ }
+
/**
* @return the signText
*/
@@ -36,5 +46,12 @@ public List getSignText() {
public Material getType() {
return type;
}
+ /**
+ * @return the isReal
+ */
+ public boolean isReal() {
+ return getType() != null;
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/world/bentobox/warps/SignCacheManager.java b/src/main/java/world/bentobox/warps/SignCacheManager.java
index 8e971d2..5c7a03e 100644
--- a/src/main/java/world/bentobox/warps/SignCacheManager.java
+++ b/src/main/java/world/bentobox/warps/SignCacheManager.java
@@ -1,22 +1,22 @@
package world.bentobox.warps;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
+import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.database.Database;
import world.bentobox.warps.objects.SignCache;
public class SignCacheManager {
- private Map> cachedSigns = new HashMap<>();
- private Warp addon;
+ private final Map> cachedSigns = new HashMap<>();
+ private final Warp addon;
// Database handler for level data
- private Database handler;
+ private final Database handler;
public SignCacheManager(Warp addon) {
this.addon = addon;
@@ -26,9 +26,11 @@ public SignCacheManager(Warp addon) {
}
private void loadCache() {
+ cachedSigns.clear();
handler.loadObjects().forEach(w -> {
World world = Bukkit.getWorld(w.getUniqueId());
if (world != null) {
+ w.getSigns().values().removeIf(sci -> sci.getType().equals(Material.AIR));
cachedSigns.put(world, w.getSigns());
}
});
@@ -38,43 +40,41 @@ void saveCache() {
cachedSigns.forEach((w, m) -> handler.saveObjectAsync(new SignCache(w, m)));
}
- Material getSignIcon(World world, UUID warpOwner) {
- // Add the worlds if we haven't seen this before
- cachedSigns.putIfAbsent(world, new HashMap<>());
- if (cachedSigns.get(world).containsKey(warpOwner)) {
- return cachedSigns.get(world).get(warpOwner).getType();
- }
- // Not in cache
- SignCacheItem sc = addon.getWarpSignsManager().getSignInfo(world, warpOwner);
- cachedSigns.get(world).put(warpOwner, sc);
- return sc.getType();
- }
-
/**
- * Gets sign text and cache it
- * @param playerUUID
- * @return sign text in a list
+ * Get the sign item from cache or get it from the world if it is not in the cache
+ * @param world - world
+ * @param warpOwner - warp owner
+ * @return SignCacheItem
*/
- List getSign(World world, UUID playerUUID) {
+ @NonNull
+ SignCacheItem getSignItem(World world, UUID warpOwner) {
// Add the worlds if we haven't seen this before
cachedSigns.putIfAbsent(world, new HashMap<>());
- if (cachedSigns.get(world).containsKey(playerUUID)) {
- return cachedSigns.get(world).get(playerUUID).getSignText();
+ // Get from cache if available
+ if (cachedSigns.get(world).containsKey(warpOwner)) {
+ return cachedSigns.get(world).get(warpOwner);
+ }
+ // Generate and add to cache
+ SignCacheItem result = addon.getWarpSignsManager().getSignInfo(world, warpOwner);
+ if (result.isReal()) {
+ cachedSigns.get(world).put(warpOwner, result);
+ } else {
+ cachedSigns.get(world).remove(warpOwner);
}
- SignCacheItem result = addon.getWarpSignsManager().getSignInfo(world, playerUUID);
- cachedSigns.get(world).put(playerUUID, result);
- return result.getSignText();
+ return result;
}
/**
* Removes sign text from the cache
* @param world - world
* @param key - uuid of owner
+ * @return true if item is removed from cache
*/
- void removeWarp(World world, UUID key) {
+ boolean removeWarp(World world, UUID key) {
if (cachedSigns.containsKey(world)) {
- cachedSigns.get(world).remove(key);
+ return cachedSigns.get(world).remove(key) != null;
}
+ return false;
}
}
diff --git a/src/main/java/world/bentobox/warps/Warp.java b/src/main/java/world/bentobox/warps/Warp.java
index 3ffceac..5bd6f6f 100644
--- a/src/main/java/world/bentobox/warps/Warp.java
+++ b/src/main/java/world/bentobox/warps/Warp.java
@@ -104,7 +104,7 @@ public void onReload()
this.warpSignsManager.saveWarpList();
this.loadSettings();
- this.getLogger().info("WelcomeWarp addon reloaded.");
+ this.getLogger().info("Warps addon reloaded.");
}
}
@@ -149,10 +149,9 @@ public void onEnable() {
@Override
public void onDisable(){
// Save the warps
- if (warpSignsManager != null)
+ if (warpSignsManager != null) {
warpSignsManager.saveWarpList();
- if (warpPanelManager != null)
- warpPanelManager.saveCache();
+ }
}
@@ -211,10 +210,18 @@ public Settings getSettings() {
* Get the island level
* @param world - world
* @param uniqueId - player's UUID
- * @return island level or null if there is no level plugin
+ * @return island level or null if there is no level plugin or Level is not operating in this world
*/
public Long getLevel(World world, UUID uniqueId) {
- return this.getPlugin().getAddonsManager().getAddonByName(LEVEL_ADDON_NAME).map(l -> ((Level) l).getIslandLevel(world, uniqueId)).orElse(null);
+ // Get name of the game mode
+ String name = this.getPlugin().getIWM().getAddon(world).map(g -> g.getDescription().getName()).orElse("");
+ return this.getPlugin().getAddonsManager().getAddonByName(LEVEL_ADDON_NAME)
+ .map(l -> {
+ if (!name.isEmpty() && ((Level) l).getSettings().getGameModes().contains(name)) {
+ return ((Level) l).getIslandLevel(world, uniqueId);
+ }
+ return null;
+ }).orElse(null);
}
/* (non-Javadoc)
@@ -241,20 +248,14 @@ public Object request(String requestLabel, Map metaData) {
return null;
}
}
- switch(requestLabel) {
- case "getSortedWarps":
- return getWarpSignsManager().getSortedWarps(world);
- case "getWarp":
- return uuid == null ? null : getWarpSignsManager().getWarp(world, uuid);
- case "getWarpMap":
- return getWarpSignsManager().getWarpMap(world);
- case "hasWarp":
- return uuid == null ? null : getWarpSignsManager().hasWarp(world, uuid);
- case "listWarps":
- return getWarpSignsManager().listWarps(world);
- default:
- return null;
- }
+ return switch (requestLabel) {
+ case "getSortedWarps" -> getWarpSignsManager().getSortedWarps(world);
+ case "getWarp" -> uuid == null ? null : getWarpSignsManager().getWarp(world, uuid);
+ case "getWarpMap" -> getWarpSignsManager().getWarpMap(world);
+ case "hasWarp" -> uuid == null ? null : getWarpSignsManager().hasWarp(world, uuid);
+ case "listWarps" -> getWarpSignsManager().listWarps(world);
+ default -> null;
+ };
}
diff --git a/src/main/java/world/bentobox/warps/WarpPanelManager.java b/src/main/java/world/bentobox/warps/WarpPanelManager.java
index 95984c7..2ef77ea 100644
--- a/src/main/java/world/bentobox/warps/WarpPanelManager.java
+++ b/src/main/java/world/bentobox/warps/WarpPanelManager.java
@@ -1,13 +1,16 @@
package world.bentobox.warps;
-import java.util.ArrayList;
+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;
@@ -17,21 +20,22 @@
public class WarpPanelManager {
private static final int PANEL_MAX_SIZE = 52;
- private Warp addon;
+ private final Warp addon;
// This is a cache of signs
- private SignCacheManager signCacheManager;
+ private final SignCacheManager signCacheManager;
public WarpPanelManager(Warp addon) {
this.addon = addon;
signCacheManager = new SignCacheManager(addon);
}
- private PanelItem getPanelItem(World world, UUID warpOwner) {
+ private PanelItem getPanelItem(World world, UUID warpOwner, SignCacheItem sign) {
+
PanelItemBuilder pib = new PanelItemBuilder()
.name(addon.getSettings().getNameFormat() + addon.getPlugin().getPlayers().getName(warpOwner))
- .description(signCacheManager.getSign(world, warpOwner))
+ .description(sign.getSignText())
.clickHandler((panel, clicker, click, slot) -> hander(world, clicker, warpOwner));
- Material icon = signCacheManager.getSignIcon(world, warpOwner);
+ Material icon = sign.getType();
if (icon.equals(Material.PLAYER_HEAD)) {
return pib.icon(addon.getPlayers().getName(warpOwner)).build();
} else {
@@ -41,15 +45,13 @@ private PanelItem getPanelItem(World world, UUID warpOwner) {
private boolean hander(World world, User clicker, UUID warpOwner) {
clicker.closeInventory();
- String playerCommand = addon.getPlugin().getIWM().getAddon(world).map(gm -> gm.getPlayerCommand().map(c -> c.getLabel()).orElse("")).orElse("");
+ 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);
- //addon.getWarpSignsManager().warpPlayer(world, clicker, warpOwner);
return true;
}
private PanelItem getRandomButton(World world, User user, UUID warpOwner) {
- ///give @p minecraft:player_head{display:{Name:"{\"text\":\"Question Mark\"}"},SkullOwner:"MHF_Question"} 1
return new PanelItemBuilder()
.name(addon.getSettings().getNameFormat() + user.getTranslation("warps.random"))
.clickHandler((panel, clicker, click, slot) -> hander(world, clicker, warpOwner))
@@ -63,68 +65,123 @@ private PanelItem getRandomButton(World world, User user, UUID warpOwner) {
* @param index - page to show - 0 is first
*/
public void showWarpPanel(World world, User user, int index) {
- List warps = new ArrayList<>(addon.getWarpSignsManager().getSortedWarps(world));
- UUID randomWarp = null;
- // Add random UUID
+
+ 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()) {
- randomWarp = warps.get(new Random().nextInt(warps.size()));
- warps.add(0, randomWarp);
+ 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;
}
- PanelBuilder panelBuilder = new PanelBuilder()
- .user(user)
- .name(user.getTranslation("warps.title") + " " + (index + 1));
int i = index * PANEL_MAX_SIZE;
- for (; i < (index * PANEL_MAX_SIZE + PANEL_MAX_SIZE) && i < warps.size(); i++) {
- if (i == 0 && randomWarp != null) {
- panelBuilder.item(getRandomButton(world, user, randomWarp));
+ 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 {
- panelBuilder.item(getPanelItem(world, warps.get(i)));
+ @NonNull
+ SignCacheItem sign = signCacheManager.getSignItem(world, warpOwner);
+ if (sign.isReal()) {
+ panelBuilder.item(getPanelItem(world, warpOwner, sign));
+ } else {
+ addon.getWarpSignsManager().removeWarpFromMap(world, warpOwner);
+ }
}
}
- final int panelNum = index;
- // Add signs
- if (i < warps.size()) {
- // Next
+ 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.next"))
- .icon(new ItemStack(Material.STONE))
+ .name(user.getTranslation("warps.previous"))
+ .icon(new ItemStack(Material.COBBLESTONE))
.clickHandler((panel, clicker, click, slot) -> {
user.closeInventory();
- showWarpPanel(world, user, panelNum+1);
+ showWarpPanel(world, user, panelNum-1);
return true;
}).build());
}
- if (i > PANEL_MAX_SIZE) {
- // Previous
+ // Next
+ if (numOfItems < totalNum) {
+ // Next
panelBuilder.item(new PanelItemBuilder()
- .name(user.getTranslation("warps.previous"))
- .icon(new ItemStack(Material.COBBLESTONE))
+ .name(user.getTranslation("warps.next"))
+ .icon(new ItemStack(Material.STONE))
.clickHandler((panel, clicker, click, slot) -> {
user.closeInventory();
- showWarpPanel(world, user, panelNum-1);
+ showWarpPanel(world, user, panelNum+1);
return true;
}).build());
}
- panelBuilder.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 void removeWarp(World world, UUID key) {
- signCacheManager.removeWarp(world, key);
+ public boolean removeWarp(World world, UUID key) {
+ return signCacheManager.removeWarp(world, key);
}
public void saveCache() {
- signCacheManager.saveCache();
+ signCacheManager.saveCache();
}
}
diff --git a/src/main/java/world/bentobox/warps/WarpSignsManager.java b/src/main/java/world/bentobox/warps/WarpSignsManager.java
index 87ddae1..9164886 100644
--- a/src/main/java/world/bentobox/warps/WarpSignsManager.java
+++ b/src/main/java/world/bentobox/warps/WarpSignsManager.java
@@ -3,16 +3,17 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
@@ -37,7 +38,6 @@
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.util.Util;
import world.bentobox.warps.event.WarpInitiateEvent;
-import world.bentobox.warps.event.WarpListEvent;
import world.bentobox.warps.objects.WarpsData;
/**
@@ -49,13 +49,13 @@
public class WarpSignsManager {
private static final int MAX_WARPS = 600;
private static final String WARPS = "warps";
- private BentoBox plugin;
+ private final BentoBox plugin;
// Map of all warps stored as player, warp sign Location
private Map> worldsWarpList;
// Database handler for level data
- private Database handler;
+ private final Database handler;
- private Warp addon;
+ private final Warp addon;
private WarpsData warpsData = new WarpsData();
/**
@@ -75,6 +75,7 @@ public Map getWarpMap(@Nullable World world) {
public WarpSignsManager(Warp addon, BentoBox plugin) {
this.addon = addon;
this.plugin = plugin;
+ this.worldsWarpList = new HashMap<>();
// Set up the database handler
// Note that these are saved by the BentoBox database
handler = new Database<>(addon, WarpsData.class);
@@ -129,18 +130,32 @@ public String getWarpOwner(Location location) {
.findFirst().map(en -> plugin.getPlayers().getName(en.getKey())).orElse("");
}
+ /**
+ * Get the optional UUID of the warp owner by location
+ * @param location to search
+ * @return Optional UUID of warp owner or empty if there is none
+ */
+ public Optional getWarpOwnerUUID(Location location) {
+ return getWarpMap(location.getWorld()).entrySet().stream().filter(en -> en.getValue().equals(location))
+ .findFirst().map(Map.Entry::getKey);
+ }
+
/**
* Get sorted list of warps with most recent players listed first
* @return UUID list
*/
- @NonNull
- public List getSortedWarps(@NonNull World world) {
+ public CompletableFuture> getSortedWarps(@NonNull World world) {
+ CompletableFuture> r = new CompletableFuture<>();
+ Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> processWarpMap(r, world));
+ return r;
+ }
+
+ 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
TreeMap map = new TreeMap<>();
- getWarpMap(world).entrySet().forEach(en -> {
- UUID uuid = en.getKey();
+ getWarpMap(world).forEach((uuid, value) -> {
// If never played, will be zero
long lastPlayed = addon.getServer().getOfflinePlayer(uuid).getLastPlayed();
// This aims to avoid the chance that players logged off at exactly the same time
@@ -154,11 +169,8 @@ public List getSortedWarps(@NonNull World world) {
if (list.size() > MAX_WARPS) {
list.subList(0, MAX_WARPS).clear();
}
- // Fire event
- WarpListEvent event = new WarpListEvent(addon, list);
- Bukkit.getPluginManager().callEvent(event);
- // Get the result of any changes by listeners
- list = event.getWarps();
+ // Return to main thread
+ Bukkit.getScheduler().runTask(plugin, () -> r.complete(list));
return list;
}
@@ -172,7 +184,7 @@ public List getSortedWarps(@NonNull World world) {
public Set listWarps(@NonNull World world) {
// Remove any null locations
getWarpMap(world).values().removeIf(Objects::isNull);
- return getWarpMap(world).entrySet().stream().filter(e -> Util.sameWorld(world, e.getValue().getWorld())).map(Map.Entry::getKey).collect(Collectors.toSet());
+ return getWarpMap(world).entrySet().stream().filter(e -> Util.sameWorld(world, Objects.requireNonNull(e.getValue().getWorld()))).map(Map.Entry::getKey).collect(Collectors.toSet());
}
/**
@@ -204,7 +216,7 @@ void loadWarpList() {
/**
* Changes the sign to red if it exists
- * @param loc
+ * @param loc location to pop
*/
private void popSign(Location loc) {
Block b = loc.getBlock();
@@ -220,7 +232,7 @@ private void popSign(Location loc) {
/**
* Removes a warp at a location.
*
- * @param loc
+ * @param loc location to remove
*/
public void removeWarp(Location loc) {
popSign(loc);
@@ -245,19 +257,28 @@ public void removeWarp(Location loc) {
/**
* Remove warp sign owned by UUID
*
- * @param uuid
+ * @param uuid UUID of owner to remove
*/
public void removeWarp(World world, UUID uuid) {
if (getWarpMap(world).containsKey(uuid)) {
popSign(getWarpMap(world).get(uuid));
getWarpMap(world).remove(uuid);
-
+
}
// Remove sign from warp panel cache
addon.getWarpPanelManager().removeWarp(world, uuid);
saveWarpList();
}
+ /**
+ * Remove the warp from the warp map
+ * @param world - world
+ * @param uuid - uuid of owner
+ */
+ public void removeWarpFromMap(World world, UUID uuid) {
+ getWarpMap(world).remove(uuid);
+ }
+
/**
* Saves the warp lists to the database
*/
@@ -275,47 +296,44 @@ public void saveWarpList() {
*/
@NonNull
public SignCacheItem getSignInfo(@NonNull World world, @NonNull UUID uuid) {
- List result = new ArrayList<>();
//get the sign info
Location signLocation = getWarp(world, uuid);
- if (signLocation != null && signLocation.getBlock().getType().name().contains("SIGN")) {
- Sign sign = (Sign)signLocation.getBlock().getState();
- result.addAll(Arrays.asList(sign.getLines()));
- // Clean up - remove the [WELCOME] line
- result.remove(0);
- // Remove any trailing blank lines
- result.removeIf(String::isEmpty);
- // Set the initial color per lore setting
- for (int i = 0; i< result.size(); i++) {
- result.set(i, ChatColor.translateAlternateColorCodes('&', addon.getSettings().getLoreFormat()) + result.get(i));
- }
- // Get the sign type
+ if (signLocation == null || !signLocation.getBlock().getType().name().contains("SIGN")) {
+ return new SignCacheItem();
+ }
+ Sign sign = (Sign)signLocation.getBlock().getState();
+ List result = new ArrayList<>(Arrays.asList(sign.getLines()));
+ // Clean up - remove the [WELCOME] line
+ result.remove(0);
+ // Remove any trailing blank lines
+ result.removeIf(String::isEmpty);
+ // Set the initial color per lore setting
+ for (int i = 0; i< result.size(); i++) {
+ 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("");
+ String prefix = plugin.getIWM().getAddon(world).map(Addon::getPermissionPrefix).orElse("");
- Material icon;
+ Material icon;
- if (!prefix.isEmpty())
- {
- icon = Material.matchMaterial(
- this.getPermissionValue(User.getInstance(uuid),
- prefix + "island.warp",
- this.addon.getSettings().getIcon()));
- }
- else
- {
- icon = Material.matchMaterial(this.addon.getSettings().getIcon());
- }
+ if (!prefix.isEmpty())
+ {
+ icon = Material.matchMaterial(
+ this.getPermissionValue(Objects.requireNonNull(User.getInstance(uuid)),
+ prefix + "island.warp",
+ this.addon.getSettings().getIcon()));
+ }
+ else
+ {
+ icon = Material.matchMaterial(this.addon.getSettings().getIcon());
+ }
- if (icon == null || icon.name().contains("SIGN")) {
- return new SignCacheItem(result, Material.valueOf(sign.getType().name().replace("WALL_", "")));
- } else {
- return new SignCacheItem(result, icon);
- }
- } else {
- addon.getWarpSignsManager().removeWarp(world, uuid);
+ if (icon == null || icon.name().contains("SIGN")) {
+ return new SignCacheItem(result, Material.valueOf(sign.getType().name().replace("WALL_", "")));
}
- return new SignCacheItem(Collections.emptyList(), Material.AIR);
+ return new SignCacheItem(result, icon);
+
}
/**
@@ -332,17 +350,17 @@ private void warpPlayer(@NonNull User user, @NonNull Location inFront, @NonNull
final Location actualWarp = new Location(inFront.getWorld(), inFront.getBlockX() + 0.5D, inFront.getBlockY(),
inFront.getBlockZ() + 0.5D, yaw, 30F);
Util.teleportAsync(user.getPlayer(), actualWarp, TeleportCause.COMMAND);
- User warpOwner = User.getInstance(signOwner);
+ User warpOwner = Objects.requireNonNull(User.getInstance(signOwner));
// Hide invisible players
if (warpOwner.isOnline() && !warpOwner.getPlayer().canSee(user.getPlayer())) {
return;
}
if (pvp) {
- user.sendMessage("protection.flags.PVP_OVERWORLD.active");
- user.getWorld().playSound(user.getLocation(), Sound.ENTITY_ARROW_HIT, 1F, 1F);
+ user.sendMessage("protection.flags.PVP_OVERWORLD.enabled");
+ user.getWorld().playSound(Objects.requireNonNull(user.getLocation()), Sound.ENTITY_ARROW_HIT, 1F, 1F);
} else {
- user.getWorld().playSound(user.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F);
- }
+ user.getWorld().playSound(Objects.requireNonNull(user.getLocation()), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F);
+ }
if (!warpOwner.equals(user)) {
warpOwner.sendMessage("warps.player-warped", "[name]", user.getName());
}
@@ -376,7 +394,7 @@ public void warpPlayer(@NonNull World world, @NonNull User user, @NonNull UUID o
boolean pvp = false;
if (island != null) {
// Check for PVP
- switch (warpSpot.getWorld().getEnvironment()) {
+ switch (Objects.requireNonNull(warpSpot.getWorld()).getEnvironment()) {
case NETHER:
pvp = island.isAllowed(Flags.PVP_NETHER);
break;
@@ -426,10 +444,10 @@ public void warpPlayer(@NonNull World world, @NonNull User user, @NonNull UUID o
final Location actualWarp = new Location(warpSpot.getWorld(), warpSpot.getBlockX() + 0.5D, warpSpot.getBlockY(),
warpSpot.getBlockZ() + 0.5D);
if (pvp) {
- user.sendMessage("protection.flags.PVP_OVERWORLD.active");
- user.getWorld().playSound(user.getLocation(), Sound.ENTITY_ARROW_HIT, 1F, 1F);
+ user.sendMessage("protection.flags.PVP_OVERWORLD.enabled");
+ user.getWorld().playSound(Objects.requireNonNull(user.getLocation()), Sound.ENTITY_ARROW_HIT, 1F, 1F);
} else {
- user.getWorld().playSound(user.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F);
+ user.getWorld().playSound(Objects.requireNonNull(user.getLocation()), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F);
}
Util.teleportAsync(user.getPlayer(), actualWarp, TeleportCause.COMMAND);
}
@@ -469,10 +487,10 @@ private String getPermissionValue(@NonNull User user, @NonNull String permission
String permPrefix = permissionPrefix + ".";
- List permissions = user.getEffectivePermissions().stream().
- map(PermissionAttachmentInfo::getPermission).
- filter(permission -> permission.startsWith(permPrefix)).
- collect(Collectors.toList());
+ List permissions = user.getEffectivePermissions().stream()
+ .map(PermissionAttachmentInfo::getPermission)
+ .filter(permission -> permission.startsWith(permPrefix))
+ .toList();
for (String permission : permissions)
{
diff --git a/src/main/java/world/bentobox/warps/WarpsPladdon.java b/src/main/java/world/bentobox/warps/WarpsPladdon.java
new file mode 100644
index 0000000..d27866a
--- /dev/null
+++ b/src/main/java/world/bentobox/warps/WarpsPladdon.java
@@ -0,0 +1,12 @@
+package world.bentobox.warps;
+
+import world.bentobox.bentobox.api.addons.Addon;
+import world.bentobox.bentobox.api.addons.Pladdon;
+
+public class WarpsPladdon extends Pladdon {
+
+ @Override
+ public Addon getAddon() {
+ return new Warp();
+ }
+}
diff --git a/src/main/java/world/bentobox/warps/commands/WarpCommand.java b/src/main/java/world/bentobox/warps/commands/WarpCommand.java
index d593192..53af311 100644
--- a/src/main/java/world/bentobox/warps/commands/WarpCommand.java
+++ b/src/main/java/world/bentobox/warps/commands/WarpCommand.java
@@ -4,7 +4,6 @@
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
-import java.util.stream.Collectors;
import org.bukkit.World;
@@ -20,7 +19,7 @@
*/
public class WarpCommand extends DelayedTeleportCommand {
- private Warp addon;
+ private final Warp addon;
public WarpCommand(Warp addon, CompositeCommand bsbIslandCmd) {
super(bsbIslandCmd, addon.getSettings().getWarpCommand());
@@ -81,7 +80,7 @@ public boolean execute(User user, String label, List args) {
@Override
public Optional> tabComplete(User user, String alias, List args) {
World world = getWorld() == null ? user.getWorld() : getWorld();
- return Optional.of(addon.getWarpSignsManager().listWarps(world).stream().map(getPlayers()::getName).collect(Collectors.toList()));
+ return Optional.of(addon.getWarpSignsManager().listWarps(world).stream().map(getPlayers()::getName).toList());
}
diff --git a/src/main/java/world/bentobox/warps/commands/WarpsCommand.java b/src/main/java/world/bentobox/warps/commands/WarpsCommand.java
index 5e5b86e..ca9f2d8 100644
--- a/src/main/java/world/bentobox/warps/commands/WarpsCommand.java
+++ b/src/main/java/world/bentobox/warps/commands/WarpsCommand.java
@@ -4,9 +4,9 @@
import org.bukkit.World;
-import world.bentobox.warps.Warp;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.user.User;
+import world.bentobox.warps.Warp;
/**
* Handles the warps command
@@ -15,7 +15,7 @@
*/
public class WarpsCommand extends CompositeCommand {
- private Warp addon;
+ private final Warp addon;
public WarpsCommand(Warp addon, CompositeCommand bsbIslandCmd) {
super(bsbIslandCmd, addon.getSettings().getWarpsCommand());
diff --git a/src/main/java/world/bentobox/warps/event/WarpCreateEvent.java b/src/main/java/world/bentobox/warps/event/WarpCreateEvent.java
index cdf7b81..d9430b9 100644
--- a/src/main/java/world/bentobox/warps/event/WarpCreateEvent.java
+++ b/src/main/java/world/bentobox/warps/event/WarpCreateEvent.java
@@ -18,13 +18,13 @@
public class WarpCreateEvent extends Event{
private static final HandlerList handlers = new HandlerList();
- private Location warpLoc;
- private UUID creator;
+ private final Location warpLoc;
+ private final UUID creator;
/**
* @param plugin - BSkyBlock plugin objects
- * @param warpLoc
- * @param creator
+ * @param warpLoc warp location
+ * @param creator UUID of creator
*/
public WarpCreateEvent(Warp plugin, Location warpLoc, UUID creator){
this.warpLoc = warpLoc;
diff --git a/src/main/java/world/bentobox/warps/event/WarpInitiateEvent.java b/src/main/java/world/bentobox/warps/event/WarpInitiateEvent.java
index 1e50a3b..31e99b1 100644
--- a/src/main/java/world/bentobox/warps/event/WarpInitiateEvent.java
+++ b/src/main/java/world/bentobox/warps/event/WarpInitiateEvent.java
@@ -40,7 +40,7 @@ public WarpInitiateEvent(Warp plugin, Location warpLoc, UUID player){
/**
* Set a different location to where the player will go
- * @param warpLoc
+ * @param warpLoc warp location
*/
public void setWarpLoc(Location warpLoc) {
this.warpLoc = warpLoc;
diff --git a/src/main/java/world/bentobox/warps/event/WarpListEvent.java b/src/main/java/world/bentobox/warps/event/WarpListEvent.java
deleted file mode 100644
index 869750c..0000000
--- a/src/main/java/world/bentobox/warps/event/WarpListEvent.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*******************************************************************************
- * This file is part of ASkyBlock.
- *
- * ASkyBlock is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * ASkyBlock is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with ASkyBlock. If not, see .
- *******************************************************************************/
-
-package world.bentobox.warps.event;
-
-import java.util.List;
-import java.util.UUID;
-
-import org.bukkit.event.Event;
-import org.bukkit.event.HandlerList;
-
-import world.bentobox.warps.Warp;
-
-/**
- * This event is fired when request is made for a sorted list of warps or when
- * the API updateWarpPanel method is called.
- * A listener to this event can reorder or rewrite the warp list by using setWarps.
- * This new order will then be used in the warp panel.
- *
- * @author tastybento
- *
- */
-public class WarpListEvent extends Event {
- private static final HandlerList handlers = new HandlerList();
- private List warps;
-
- /**
- * @param plugin - BSkyBlock plugin objects
- * @param warps
- */
- public WarpListEvent(Warp plugin, List warps) {
- this.warps = warps;
- }
-
-
- /**
- *The warp list is a collection of player UUID's and the default order is
- * that players with the most recent login will be first.
- * @return the warps
- */
- public List getWarps() {
- return warps;
- }
-
- /**
- * @param warps the warps to set
- */
- public void setWarps(List warps) {
- this.warps = warps;
- }
-
-
- @Override
- public HandlerList getHandlers() {
- return handlers;
- }
-
- public static HandlerList getHandlerList() {
- return handlers;
- }
-}
diff --git a/src/main/java/world/bentobox/warps/event/WarpRemoveEvent.java b/src/main/java/world/bentobox/warps/event/WarpRemoveEvent.java
index 54837f0..ccbd369 100644
--- a/src/main/java/world/bentobox/warps/event/WarpRemoveEvent.java
+++ b/src/main/java/world/bentobox/warps/event/WarpRemoveEvent.java
@@ -5,8 +5,8 @@
import org.bukkit.Location;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
-
-import world.bentobox.warps.Warp;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
/**
* This event is fired when a Warp is removed (when a warp sign is broken)
@@ -18,32 +18,48 @@
public class WarpRemoveEvent extends Event{
private static final HandlerList handlers = new HandlerList();
- private Location warpLoc;
- private UUID remover;
+ private final Location warpLoc;
+ private final UUID remover;
+ private final UUID owner;
/**
- * @param plugin - BSkyBlock plugin objects
- * @param warpLoc
- * @param remover
+ * @param warpLoc - Warp location
+ * @param remover - UUID of remover
+ * @param owner - UUID of warp owner - rarely, may be null
*/
- public WarpRemoveEvent(Warp plugin, Location warpLoc, UUID remover){
+ public WarpRemoveEvent(@NonNull Location warpLoc, UUID remover, @Nullable UUID owner){
this.warpLoc = warpLoc;
this.remover = remover;
+ this.owner = owner;
}
/**
* Get the location of the removed Warp
* @return removed warp's location
*/
- public Location getWarpLocation(){return this.warpLoc;}
+ @NonNull
+ public Location getWarpLocation(){
+ return this.warpLoc;
+ }
/**
* Get who has removed the warp
* @return the warp's remover
*/
- public UUID getRemover(){return this.remover;}
+ @NonNull
+ public UUID getRemover(){
+ return this.remover;
+ }
- @Override
+ /**
+ * @return the owner
+ */
+ @Nullable
+ protected UUID getOwner() {
+ return owner;
+ }
+
+ @Override
public HandlerList getHandlers() {
return handlers;
}
diff --git a/src/main/java/world/bentobox/warps/listeners/WarpSignsListener.java b/src/main/java/world/bentobox/warps/listeners/WarpSignsListener.java
index f16f48c..a581d69 100644
--- a/src/main/java/world/bentobox/warps/listeners/WarpSignsListener.java
+++ b/src/main/java/world/bentobox/warps/listeners/WarpSignsListener.java
@@ -3,9 +3,14 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.Objects;
import java.util.UUID;
-import org.bukkit.*;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.Tag;
+import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
@@ -14,9 +19,10 @@
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.SignChangeEvent;
-
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.scheduler.BukkitRunnable;
+import org.eclipse.jdt.annotation.Nullable;
+
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.events.addon.AddonEvent;
import world.bentobox.bentobox.api.events.team.TeamKickEvent;
@@ -34,9 +40,11 @@
*/
public class WarpSignsListener implements Listener {
- private BentoBox plugin;
+ private static final String WARPS_DEACTIVATE = "warps.deactivate";
+
+ private final BentoBox plugin;
- private Warp addon;
+ private final Warp addon;
/**
* @param addon - addon
@@ -79,14 +87,14 @@ public void run() {
public void onPlayerLeave(TeamLeaveEvent e) {
// Remove any warp signs from this game mode
addon.getWarpSignsManager().removeWarp(e.getIsland().getWorld(), e.getPlayerUUID());
- User.getInstance(e.getPlayerUUID()).sendMessage("warps.deactivate");
+ Objects.requireNonNull(User.getInstance(e.getPlayerUUID())).sendMessage(WARPS_DEACTIVATE);
}
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onPlayerLeave(TeamKickEvent e) {
// Remove any warp signs from this game mode
addon.getWarpSignsManager().removeWarp(e.getIsland().getWorld(), e.getPlayerUUID());
- User.getInstance(e.getPlayerUUID()).sendMessage("warps.deactivate");
+ Objects.requireNonNull(User.getInstance(e.getPlayerUUID())).sendMessage(WARPS_DEACTIVATE);
}
/**
@@ -99,21 +107,22 @@ public void onSignBreak(BlockBreakEvent e) {
boolean inWorld = addon.getPlugin().getIWM().inWorld(b.getWorld());
// Signs only
// FIXME: When we drop support for 1.13, switch to Tag.SIGNS
- if (!e.getBlock().getType().name().contains("SIGN")
+ if (!b.getType().name().contains("SIGN")
|| (inWorld && !addon.inRegisteredWorld(b.getWorld()))
- || (!inWorld && !addon.getSettings().isAllowInOtherWorlds()) ) {
+ || (!inWorld && !addon.getSettings().isAllowInOtherWorlds())
+ || !isWarpSign(b)) {
return;
}
User user = User.getInstance(e.getPlayer());
- if (isWarpSign(b)) {
- if (isPlayersSign(e.getPlayer(), b, inWorld)) {
- addon.getWarpSignsManager().removeWarp(b.getLocation());
- Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(addon, b.getLocation(), user.getUniqueId()));
- } else {
- // Someone else's sign - not allowed
- user.sendMessage("warps.error.no-remove");
- e.setCancelled(true);
- }
+ if (user == null) return;
+ UUID owner = addon.getWarpSignsManager().getWarpOwnerUUID(b.getLocation()).orElse(null);
+ if (isPlayersSign(e.getPlayer(), b, inWorld)) {
+ addon.getWarpSignsManager().removeWarp(b.getLocation());
+ Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(b.getLocation(), user.getUniqueId(), owner));
+ } else {
+ // Someone else's sign - not allowed
+ user.sendMessage("warps.error.no-remove");
+ e.setCancelled(true);
}
}
@@ -144,9 +153,9 @@ public void onSignWarpCreate(SignChangeEvent e) {
return;
}
String title = e.getLine(0);
- User user = User.getInstance(e.getPlayer());
+ User user = Objects.requireNonNull(User.getInstance(e.getPlayer()));
// Check if someone is changing their own sign
- if (title.equalsIgnoreCase(addon.getSettings().getWelcomeLine())) {
+ if (title != null && title.equalsIgnoreCase(addon.getSettings().getWelcomeLine())) {
// Welcome sign detected - check permissions
if (noPerms(user, b.getWorld(), inWorld)) {
return;
@@ -157,11 +166,7 @@ public void onSignWarpCreate(SignChangeEvent e) {
}
// Check if the player already has a sign
final Location oldSignLoc = addon.getWarpSignsManager().getWarp(b.getWorld(), user.getUniqueId());
- if (oldSignLoc == null) {
- // First time the sign has been placed or this is a new
- // sign
- addSign(e, user, b);
- } else {
+ if (oldSignLoc != null) {
// A sign already exists. Check if it still there and if
// so,
// deactivate it
@@ -173,14 +178,16 @@ public void onSignWarpCreate(SignChangeEvent e) {
if (oldSign.getLine(0).equalsIgnoreCase(ChatColor.GREEN + addon.getSettings().getWelcomeLine())) {
oldSign.setLine(0, ChatColor.RED + addon.getSettings().getWelcomeLine());
oldSign.update(true, false);
- user.sendMessage("warps.deactivate");
+ user.sendMessage(WARPS_DEACTIVATE);
addon.getWarpSignsManager().removeWarp(oldSignBlock.getWorld(), user.getUniqueId());
- Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(addon, oldSign.getLocation(), user.getUniqueId()));
+ @Nullable
+ UUID owner = addon.getWarpSignsManager().getWarpOwnerUUID(oldSignLoc).orElse(null);
+ Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(oldSign.getLocation(), user.getUniqueId(), owner));
}
}
// Set up the new warp sign
- addSign(e, user, b);
}
+ addSign(e, user, b);
}
}
@@ -226,7 +233,10 @@ private void addSign(SignChangeEvent e, User user, Block b) {
user.sendMessage("warps.success");
e.setLine(0, ChatColor.GREEN + addon.getSettings().getWelcomeLine());
for (int i = 1; i<4; i++) {
- e.setLine(i, ChatColor.translateAlternateColorCodes('&', e.getLine(i)));
+ String line = e.getLine(i);
+ if (line != null) {
+ e.setLine(i, ChatColor.translateAlternateColorCodes('&', line));
+ }
}
Map keyValues = new HashMap<>();
diff --git a/src/main/java/world/bentobox/warps/objects/WarpsData.java b/src/main/java/world/bentobox/warps/objects/WarpsData.java
index db85455..a09f22d 100644
--- a/src/main/java/world/bentobox/warps/objects/WarpsData.java
+++ b/src/main/java/world/bentobox/warps/objects/WarpsData.java
@@ -46,10 +46,11 @@ public void setWarpSigns(Map warpSigns) {
/**
* Puts all the data from the map into this objects ready for saving
- * @param worldsWarpList
+ * @param worldsWarpList 2D map of warp locations by world vs UUID
* @return this class filled with data
*/
public WarpsData save(Map> worldsWarpList) {
+ getWarpSigns().clear();
worldsWarpList.values().forEach(world -> world.forEach((uuid,location) -> warpSigns.put(location, uuid)));
return this;
}
diff --git a/src/main/resources/addon.yml b/src/main/resources/addon.yml
index 0d3b925..09642b4 100755
--- a/src/main/resources/addon.yml
+++ b/src/main/resources/addon.yml
@@ -2,7 +2,7 @@ name: Warps
main: world.bentobox.warps.Warp
version: ${version}${build.number}
icon: OAK_SIGN
-api-version: 1.15.4
+api-version: 1.17
authors: tastybento
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index a723f46..3a8818b 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -26,11 +26,11 @@ disabled-gamemodes: []
#
# Warp panel name formatting.
# Example: &c will make names red, &f is white
-name-format: &f
+name-format: "&f"
#
# Warp panel default lore formatting.
# Example: &c will make lore red. &f is white
-lore-format: &f
+lore-format: "&f"
#
# Allow random teleport - adds a button to the warp panel that goes to a random warp sign
random-allowed: true
diff --git a/src/main/resources/locales/vi.yml b/src/main/resources/locales/vi.yml
new file mode 100644
index 0000000..45c76ea
--- /dev/null
+++ b/src/main/resources/locales/vi.yml
@@ -0,0 +1,29 @@
+#
+# 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:
+ help:
+ description: đi đến điểm dịch chuyển của người chơi
+ parameters:
+warps:
+ deactivate: '&cBảng cũ đã vô hiệu hóa!'
+ error:
+ does-not-exist: '&cUầy! Điểm dịch chuyển đó không tồn tại!'
+ no-permission: '&cBạn không có quyền làm điều đó!'
+ no-remove: '&cBạn không thể xóa bảng đó!'
+ no-warps-yet: '&cChưa có điểm dịch chuyển nào'
+ not-enough-level: '&cCấp đảo của bạn không đủ cao!'
+ not-on-island: '&cBạn phải ở đảo của bạn để làm điều đó!'
+ not-safe: '&cĐiểm dịch chuyển không an toàn!'
+ your-level-is: '&cCấp đảo của bạn là [level] và phải cao hơn [required]. Hãy dùng lệnh xem cấp đảo.'
+ help:
+ description: mở bảng dịch chuyển
+ next: '&6Trang kế'
+ player-warped: '&2[name] đã vào điểm dịch chuyển của bạn!'
+ previous: '&6Trang trước'
+ random: '&4Điểm dịch chuyển ngẫu nhiên'
+ sign-removed: '&cĐã xóa bảng dịch chuyển!'
+ success: '&aThành công!'
+ title: Bảng Dịch Chuyển
+ warpTip: '&6Đặt bảng với dòng chữ [text] ở dòng đầu tiên'
+ warpToPlayersSign: '&6Đang dịch chuyển đến chỗ của [player]'
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..8e0bfec
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,8 @@
+name: Warps
+main: world.bentobox.warps.WarpsPladdon
+version: ${version}
+api-version: 1.17
+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
index 0521627..d2af1f6 100644
--- a/src/test/java/world/bentobox/warps/WarpPanelManagerTest.java
+++ b/src/test/java/world/bentobox/warps/WarpPanelManagerTest.java
@@ -5,6 +5,8 @@
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;
@@ -12,6 +14,7 @@
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;
@@ -21,22 +24,21 @@
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFactory;
-import org.bukkit.inventory.ItemStack;
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.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
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;
@@ -63,12 +65,17 @@ public class WarpPanelManagerTest {
private World world;
@Mock
private Inventory top;
- private UUID uuid;
@Mock
private Settings settings;
@Mock
private static AbstractDatabaseHandler