diff --git a/pom.xml b/pom.xml
index 6352619..f23ad2b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,6 +56,10 @@
net.kyori
com.drtshock.playervaults.lib.net.kyori
+
+ com.tcoded.folialib
+ com.drtshock.playervaults.lib.folialib
+
org.kitteh
com.drtshock.playervaults.lib.org.kitteh
@@ -95,6 +99,10 @@
spigot-repo
https://hub.spigotmc.org/nexus/content/groups/public/
+
+ tcoded-releases
+ https://repo.tcoded.com/releases
+
placeholderapi
https://repo.extendedclip.com/content/repositories/placeholderapi/
@@ -119,7 +127,7 @@
net.kyori
adventure-text-serializer-gson
- 4.25.0
+ 4.26.1
compile
true
@@ -144,7 +152,7 @@
net.kyori
adventure-text-serializer-legacy
- 4.25.0
+ 4.26.1
compile
true
@@ -161,7 +169,7 @@
net.kyori
adventure-text-minimessage
- 4.25.0
+ 4.26.1
compile
true
@@ -190,9 +198,15 @@
org.spigotmc
spigot-api
- 1.21.10-R0.1-SNAPSHOT
+ 1.21.11-R0.2-SNAPSHOT
provided
+
+ com.tcoded
+ FoliaLib
+ 0.5.1
+ compile
+
com.googlecode.json-simple
json-simple
@@ -208,7 +222,7 @@
me.clip
placeholderapi
- 2.11.6
+ 2.12.2
provided
diff --git a/src/main/java/com/drtshock/playervaults/Metrics.java b/src/main/java/com/drtshock/playervaults/Metrics.java
index caf9f92..7ef5b32 100644
--- a/src/main/java/com/drtshock/playervaults/Metrics.java
+++ b/src/main/java/com/drtshock/playervaults/Metrics.java
@@ -190,7 +190,7 @@ public void run() {
}
// Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler
// Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;)
- Bukkit.getScheduler().runTask(plugin, () -> submitData());
+ PlayerVaults.scheduler().runNextTick(task -> submitData());
}
}, 1000 * 60 * 5, 1000 * 60 * 30);
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
diff --git a/src/main/java/com/drtshock/playervaults/PlayerVaults.java b/src/main/java/com/drtshock/playervaults/PlayerVaults.java
index cace052..03c48a6 100644
--- a/src/main/java/com/drtshock/playervaults/PlayerVaults.java
+++ b/src/main/java/com/drtshock/playervaults/PlayerVaults.java
@@ -38,8 +38,11 @@
import com.drtshock.playervaults.vaultmanagement.EconomyOperations;
import com.drtshock.playervaults.vaultmanagement.VaultManager;
import com.drtshock.playervaults.vaultmanagement.VaultViewInfo;
+import com.google.common.collect.Sets;
import com.google.gson.Gson;
-import net.kyori.adventure.audience.Audience;
+import com.tcoded.folialib.FoliaLib;
+import com.tcoded.folialib.impl.PlatformScheduler;
+import dev.kitteh.cardboardbox.CardboardBox;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
@@ -59,8 +62,6 @@
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
-import org.bukkit.scheduler.BukkitRunnable;
-import dev.kitteh.cardboardbox.CardboardBox;
import sun.misc.Unsafe;
import java.io.BufferedReader;
@@ -87,6 +88,7 @@
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;
import java.util.logging.Level;
@@ -96,13 +98,15 @@
public class PlayerVaults extends JavaPlugin {
public static boolean DEBUG;
private static PlayerVaults instance;
- private final HashMap setSign = new HashMap<>();
+ private static FoliaLib foliaLib;
+ private static PlatformScheduler scheduler;
+ private final ConcurrentHashMap setSign = new ConcurrentHashMap<>();
// Player name - VaultViewInfo
- private final HashMap inVault = new HashMap<>();
+ private final ConcurrentHashMap inVault = new ConcurrentHashMap<>();
// VaultViewInfo - Inventory
- private final HashMap openInventories = new HashMap<>();
- private final Set blockedMats = new HashSet<>();
- private final Set blockedEnchs = new HashSet<>();
+ private final ConcurrentHashMap openInventories = new ConcurrentHashMap<>();
+ private final Set blockedMats = Sets.newConcurrentHashSet();
+ private final Set blockedEnchs = Sets.newConcurrentHashSet();
private boolean blockWithModelData = false;
private boolean blockWithoutModelData = false;
private boolean useVault;
@@ -126,6 +130,14 @@ public static PlayerVaults getInstance() {
return instance;
}
+ public static FoliaLib foliaLib() {
+ return foliaLib;
+ }
+
+ public static PlatformScheduler scheduler() {
+ return scheduler;
+ }
+
public static void debug(String s, long start) {
if (DEBUG) {
instance.getLogger().log(Level.INFO, "{0} took {1}ms", new Object[]{s, (System.currentTimeMillis() - start)});
@@ -146,6 +158,8 @@ public void onEnable() {
return;
}
instance = this;
+ foliaLib = new FoliaLib(this);
+ scheduler = foliaLib.getScheduler();
long start = System.currentTimeMillis();
long time = System.currentTimeMillis();
UpdateCheck update = new UpdateCheck("PlayerVaultsX", this.getDescription().getVersion(), this.getServer().getName(), this.getServer().getVersion());
@@ -186,17 +200,15 @@ public void onEnable() {
debug("setup economy", time);
if (getConf().getPurge().isEnabled()) {
- getServer().getScheduler().runTaskAsynchronously(this, new Cleanup(getConf().getPurge().getDaysSinceLastEdit()));
+ final int days = getConf().getPurge().getDaysSinceLastEdit();
+ PlayerVaults.scheduler().runLaterAsync(new Cleanup(days), 1L);
}
- new BukkitRunnable() {
- @Override
- public void run() {
- if (saveQueued) {
- saveSignsFile();
- }
+ PlayerVaults.scheduler().runTimer(() -> {
+ if (saveQueued) {
+ saveSignsFile();
}
- }.runTaskTimer(this, 20, 20);
+ }, 20, 20);
this.metrics = new Metrics(this, 6905);
Plugin vault = getServer().getPluginManager().getPlugin("Vault");
@@ -296,42 +308,40 @@ public void run() {
this.updateCheck = new Gson().toJson(update);
if (!HelpMeCommand.likesCats) return;
- new BukkitRunnable() {
- @Override
- public void run() {
- try {
- URL url = new URL("https://update.plugin.party/check");
- HttpURLConnection con = (HttpURLConnection) url.openConnection();
- con.setRequestMethod("POST");
- con.setDoOutput(true);
- con.setRequestProperty("Content-Type", "application/json");
- con.setRequestProperty("Accept", "application/json");
- try (OutputStream out = con.getOutputStream()) {
- out.write(PlayerVaults.this.updateCheck.getBytes(StandardCharsets.UTF_8));
- }
- String reply = new BufferedReader(new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8)).lines().collect(Collectors.joining("\n"));
- Response response = new Gson().fromJson(reply, Response.class);
- if (response.isSuccess()) {
- if (response.isUpdateAvailable()) {
- PlayerVaults.this.updateResponse = response;
- if (response.isUrgent()) {
- PlayerVaults.this.getServer().getOnlinePlayers().forEach(PlayerVaults.this::updateNotification);
- }
- PlayerVaults.this.getLogger().warning("Update available: " + response.getLatestVersion() + (response.getMessage() == null ? "" : (" - " + response.getMessage())));
+ PlayerVaults.scheduler().runTimerAsync(task -> {
+ try {
+ URL url = new URL("https://update.plugin.party/check");
+ HttpURLConnection con = (HttpURLConnection) url.openConnection();
+ con.setRequestMethod("POST");
+ con.setDoOutput(true);
+ con.setRequestProperty("Content-Type", "application/json");
+ con.setRequestProperty("Accept", "application/json");
+ try (OutputStream out = con.getOutputStream()) {
+ out.write(PlayerVaults.this.updateCheck.getBytes(StandardCharsets.UTF_8));
+ }
+ String reply = new BufferedReader(new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8)).lines().collect(Collectors.joining("\n"));
+ Response response = new Gson().fromJson(reply, Response.class);
+ if (response.isSuccess()) {
+ if (response.isUpdateAvailable()) {
+ PlayerVaults.this.updateResponse = response;
+ if (response.isUrgent()) {
+ PlayerVaults.this.getServer().getOnlinePlayers().forEach(PlayerVaults.this::updateNotification);
}
+ PlayerVaults.this.getLogger().warning("Update available: " + response.getLatestVersion() + (response.getMessage() == null ? "" : (" - " + response.getMessage())));
+ }
+ } else {
+ if (response.getMessage().equals("INVALID")) {
+ task.cancel();
+ } else if (response.getMessage().equals("TOO_FAST")) {
+ // Nothing for now
} else {
- if (response.getMessage().equals("INVALID")) {
- this.cancel();
- } else if (response.getMessage().equals("TOO_FAST")) {
- // Nothing for now
- } else {
- PlayerVaults.this.getLogger().warning("Failed to check for updates: " + response.getMessage());
- }
+ PlayerVaults.this.getLogger().warning("Failed to check for updates: " + response.getMessage());
}
- } catch (Exception ignored) {
}
+ } catch (Exception ignored) {
+ // Ignored case/handler.
}
- }.runTaskTimerAsynchronously(this, 1, 20 /* ticks */ * 60 /* seconds in a minute */ * 60 /* minutes in an hour*/);
+ }, 1, 20 /* ticks */ * 60 /* seconds in a minute */ * 60 /* minutes in an hour*/);
}
private void metricsLine(String name, Callable callable) {
@@ -365,15 +375,15 @@ public void onDisable() {
Inventory inventory = player.getOpenInventory().getTopInventory();
if (inventory.getViewers().size() == 1) {
VaultViewInfo info = this.inVault.get(player.getUniqueId().toString());
- VaultManager.getInstance().saveVault(inventory, player.getUniqueId().toString(), info.getNumber());
+ VaultManager.getInstance().saveVault(inventory, info.getVaultName(), info.getNumber());
this.openInventories.remove(info.toString());
// try this to make sure that they can't make further edits if the process hangs.
- player.closeInventory();
+ PlayerVaults.scheduler().runAtEntity(player, task -> player.closeInventory());
}
this.inVault.remove(player.getUniqueId().toString());
debug("Closing vault for " + player.getName());
- player.closeInventory();
+ PlayerVaults.scheduler().runAtEntity(player, task -> player.closeInventory());
}
}
@@ -542,15 +552,15 @@ private void saveSignsFile() {
}
}
- public HashMap getSetSign() {
+ public ConcurrentHashMap getSetSign() {
return this.setSign;
}
- public HashMap getInVault() {
+ public ConcurrentHashMap getInVault() {
return this.inVault;
}
- public HashMap getOpenInventories() {
+ public ConcurrentHashMap getOpenInventories() {
return this.openInventories;
}
@@ -731,7 +741,7 @@ public Component getComponent() {
}
}
- private final Set told = new HashSet<>();
+ private final Set told = Sets.newConcurrentHashSet();
public void updateNotification(Player player) {
if (updateResponse == null || !player.hasPermission(Permission.ADMIN)) {
@@ -759,7 +769,7 @@ public T addException(T t) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
t.printStackTrace(printWriter);
- builder.append(stringWriter.toString());
+ builder.append(stringWriter);
this.exceptions.add(builder.toString());
}
return t;
diff --git a/src/main/java/com/drtshock/playervaults/commands/ConvertCommand.java b/src/main/java/com/drtshock/playervaults/commands/ConvertCommand.java
index b6c88f9..207b2a8 100644
--- a/src/main/java/com/drtshock/playervaults/commands/ConvertCommand.java
+++ b/src/main/java/com/drtshock/playervaults/commands/ConvertCommand.java
@@ -72,7 +72,7 @@ public boolean onCommand(final CommandSender sender, Command command, String lab
} else {
// Fork into background
this.plugin.getTL().convertBackground().title().send(sender);
- PlayerVaults.getInstance().getServer().getScheduler().runTaskLaterAsynchronously(PlayerVaults.getInstance(), () -> {
+ PlayerVaults.scheduler().runLaterAsync(() -> {
int converted = 0;
VaultOperations.setLocked(true);
for (Converter converter : applicableConverters) {
@@ -88,4 +88,4 @@ public boolean onCommand(final CommandSender sender, Command command, String lab
}
return true;
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/drtshock/playervaults/commands/HelpMeCommand.java b/src/main/java/com/drtshock/playervaults/commands/HelpMeCommand.java
index 9e0f2fc..fce829f 100644
--- a/src/main/java/com/drtshock/playervaults/commands/HelpMeCommand.java
+++ b/src/main/java/com/drtshock/playervaults/commands/HelpMeCommand.java
@@ -30,7 +30,6 @@
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
-import org.bukkit.scheduler.BukkitRunnable;
import org.kitteh.pastegg.PasteBuilder;
import org.kitteh.pastegg.PasteContent;
import org.kitteh.pastegg.PasteFile;
@@ -43,6 +42,8 @@
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Arrays;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
import java.util.logging.Level;
public class HelpMeCommand implements CommandExecutor {
@@ -77,61 +78,52 @@ public boolean onCommand(final CommandSender sender, Command command, String lab
mainInfo.append(" ").append(plugin.getDescription().getAuthors()).append('\n');
}
- new BukkitRunnable() {
- private final PasteBuilder builder = new PasteBuilder().name("PlayerVaultsX Debug")
- .visibility(Visibility.UNLISTED)
- .expires(ZonedDateTime.now(ZoneOffset.UTC).plusDays(3));
- private int i = 0;
+ PlayerVaults.scheduler().runAsync(task -> {
+ try {
+ final PasteBuilder builder = new PasteBuilder().name("PlayerVaultsX Debug")
+ .visibility(Visibility.UNLISTED)
+ .expires(ZonedDateTime.now(ZoneOffset.UTC).plusDays(3));
+ final int[] i = new int[]{0};
- private void add(String name, String content) {
- builder.addFile(new PasteFile(i++ + name, new PasteContent(PasteContent.ContentType.TEXT, content)));
- }
+ final BiConsumer add = (name, content) ->
+ builder.addFile(new PasteFile(i[0]++ + name, new PasteContent(PasteContent.ContentType.TEXT, content)));
+ final Function getFile = (file) -> {
+ try {
+ return new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ return e.getMessage();
+ }
+ };
- private String getFile(Path file) {
- try {
- return new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
- } catch (IOException e) {
- return e.getMessage();
+ Path dataPath = plugin.getDataFolder().toPath();
+ add.accept("info.txt", mainInfo.toString());
+ String exceptionLog = plugin.getExceptions();
+ if (exceptionLog != null) {
+ add.accept("exceptions.txt", exceptionLog);
}
- }
+ add.accept("config.conf", getFile.apply(dataPath.resolve("config.conf")));
- @Override
- public void run() {
- try {
- Path dataPath = plugin.getDataFolder().toPath();
- add("info.txt", mainInfo.toString());
- String exceptionLog = plugin.getExceptions();
- if (exceptionLog != null) {
- add("exceptions.txt", exceptionLog);
+ PasteBuilder.PasteResult result = builder.build();
+
+ PlayerVaults.scheduler().runNextTick(t -> {
+ if (result.getPaste().isPresent()) {
+ String delKey = result.getPaste().get().getDeletionKey().orElse("No deletion key");
+ String url = "https://paste.gg/anonymous/" + result.getPaste().get().getId();
+ ComponentDispatcher.send(sender, Component.text("URL generated: ").append(Component.text().clickEvent(ClickEvent.openUrl(url)).content(url)));
+ ComponentDispatcher.send(sender, MiniMessage.miniMessage().deserialize((sender instanceof Player ? "" : "") + "Deletion key: " + delKey));
+ } else {
+ ComponentDispatcher.send(sender, MiniMessage.miniMessage().deserialize("Failed to generate output. See console for details."));
+ PlayerVaults.getInstance().getLogger().warning("Received: " + result.getMessage());
}
- add("config.conf", getFile(dataPath.resolve("config.conf")));
- PasteBuilder.PasteResult result = builder.build();
- new BukkitRunnable() {
- @Override
- public void run() {
- if (result.getPaste().isPresent()) {
- String delKey = result.getPaste().get().getDeletionKey().orElse("No deletion key");
- String url = "https://paste.gg/anonymous/" + result.getPaste().get().getId();
- ComponentDispatcher.send(sender, Component.text("URL generated: ").append(Component.text().clickEvent(ClickEvent.openUrl(url)).content(url)));
- ComponentDispatcher.send(sender, MiniMessage.miniMessage().deserialize((sender instanceof Player ? "" : "") + "Deletion key: " + delKey));
- } else {
- ComponentDispatcher.send(sender, MiniMessage.miniMessage().deserialize("Failed to generate output. See console for details."));
- PlayerVaults.getInstance().getLogger().warning("Received: " + result.getMessage());
- }
- }
- }.runTask(PlayerVaults.getInstance());
- } catch (Exception e) {
- PlayerVaults.getInstance().getLogger().log(Level.SEVERE, "Failed to execute debug command", e);
- new BukkitRunnable() {
- @Override
- public void run() {
- ComponentDispatcher.send(sender, MiniMessage.miniMessage().deserialize("Failed to generate output. See console for details."));
- }
- }.runTask(PlayerVaults.getInstance());
- }
+ });
+ } catch (Exception e) {
+ PlayerVaults.getInstance().getLogger().log(Level.SEVERE, "Failed to execute debug command", e);
+ PlayerVaults.scheduler().runNextTick(t ->
+ ComponentDispatcher.send(sender, MiniMessage.miniMessage().deserialize("Failed to generate output. See console for details."))
+ );
}
- }.runTaskAsynchronously(PlayerVaults.getInstance());
+ });
}
return true;
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/drtshock/playervaults/listeners/Listeners.java b/src/main/java/com/drtshock/playervaults/listeners/Listeners.java
index 5e60897..1165a3b 100644
--- a/src/main/java/com/drtshock/playervaults/listeners/Listeners.java
+++ b/src/main/java/com/drtshock/playervaults/listeners/Listeners.java
@@ -227,4 +227,4 @@ private boolean isBlocked(Player player, ItemStack item, VaultViewInfo info) {
}
return false;
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/drtshock/playervaults/listeners/VaultPreloadListener.java b/src/main/java/com/drtshock/playervaults/listeners/VaultPreloadListener.java
index 14467a0..d1136f8 100644
--- a/src/main/java/com/drtshock/playervaults/listeners/VaultPreloadListener.java
+++ b/src/main/java/com/drtshock/playervaults/listeners/VaultPreloadListener.java
@@ -25,7 +25,6 @@
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
-import org.bukkit.scheduler.BukkitRunnable;
import java.util.UUID;
@@ -37,12 +36,7 @@ public class VaultPreloadListener implements Listener {
public void onPlayerJoin(PlayerJoinEvent event) {
PlayerVaults.getInstance().updateNotification(event.getPlayer());
final UUID uuid = event.getPlayer().getUniqueId();
- new BukkitRunnable() {
- @Override
- public void run() {
- vm.cachePlayerVaultFile(uuid.toString());
- }
- }.runTaskAsynchronously(PlayerVaults.getInstance());
+ PlayerVaults.scheduler().runAsync(task -> vm.cachePlayerVaultFile(uuid.toString()));
}
@EventHandler(priority = EventPriority.MONITOR)
diff --git a/src/main/java/com/drtshock/playervaults/vaultmanagement/EconomyOperations.java b/src/main/java/com/drtshock/playervaults/vaultmanagement/EconomyOperations.java
index 8418ada..5f1b1e0 100644
--- a/src/main/java/com/drtshock/playervaults/vaultmanagement/EconomyOperations.java
+++ b/src/main/java/com/drtshock/playervaults/vaultmanagement/EconomyOperations.java
@@ -123,7 +123,7 @@ public static boolean refundOnDelete(Player player, int number) {
return true;
}
- File playerFile = new File(PlayerVaults.getInstance().getVaultData(), player.getUniqueId().toString() + ".yml");
+ File playerFile = new File(PlayerVaults.getInstance().getVaultData(), player.getUniqueId() + ".yml");
if (playerFile.exists()) {
YamlConfiguration playerData = YamlConfiguration.loadConfiguration(playerFile);
if (playerData.getString("vault" + number) == null) {
diff --git a/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultManager.java b/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultManager.java
index 742ac8c..6656edc 100644
--- a/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultManager.java
+++ b/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultManager.java
@@ -27,17 +27,21 @@
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
+import static com.drtshock.playervaults.vaultmanagement.VaultOperations.VaultGate;
+
public class VaultManager {
private static final String VAULTKEY = "vault%d";
@@ -60,6 +64,35 @@ public static VaultManager getInstance() {
return instance;
}
+ /**
+ * Resolve a stable, UUID-first key for a holder.
+ */
+ public static String normalizeHolderKey(String input) {
+ if (input == null) {
+ return null;
+ }
+
+ File dataDir = PlayerVaults.getInstance().getVaultData();
+ File legacy = new File(dataDir, input + ".yml");
+ if (legacy.exists()) {
+ return input;
+ }
+
+ try {
+ UUID uuid = UUID.fromString(input);
+ return uuid.toString();
+ } catch (Exception ignored) {
+ // Ignored case/handler.
+ }
+
+ OfflinePlayer byName = Bukkit.getOfflinePlayer(input);
+ if (byName != null && byName.getUniqueId() != null) {
+ return byName.getUniqueId().toString();
+ }
+
+ return input;
+ }
+
/**
* Saves the inventory to the specified player and vault number.
*
@@ -68,11 +101,14 @@ public static VaultManager getInstance() {
* @param number The vault number.
*/
public void saveVault(Inventory inventory, String target, int number) {
- YamlConfiguration yaml = getPlayerVaultFile(target, true);
- int size = VaultOperations.getMaxVaultSize(target);
- String serialized = CardboardBoxSerialization.toStorage(inventory, target);
- yaml.set(String.format(VAULTKEY, number), serialized);
- saveFileSync(target, yaml);
+ final String holderKey = normalizeHolderKey(target);
+ VaultGate.withLock(new VaultGate.VaultKey(holderKey, number), () -> {
+ YamlConfiguration yaml = getPlayerVaultFile(holderKey, true);
+ VaultOperations.getMaxVaultSize(holderKey);
+ String serialized = CardboardBoxSerialization.toStorage(inventory, holderKey);
+ yaml.set(String.format(VAULTKEY, number), serialized);
+ saveFileSync(holderKey, yaml);
+ });
}
/**
@@ -118,28 +154,19 @@ public Inventory loadOtherVault(String name, int number, int size) {
size = PlayerVaults.getInstance().getDefaultVaultSize();
}
- PlayerVaults.debug("Loading other vault for " + name);
-
- String holder = name;
-
- try {
- UUID uuid = UUID.fromString(name);
- OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid);
- holder = offlinePlayer.getUniqueId().toString();
- } catch (Exception e) {
- // Not a player
- }
+ final String holderKey = normalizeHolderKey(name);
+ PlayerVaults.debug("Loading other vault for " + holderKey);
String title = PlayerVaults.getInstance().getVaultTitle(String.valueOf(number));
- VaultViewInfo info = new VaultViewInfo(name, number);
+ VaultViewInfo info = new VaultViewInfo(holderKey, number);
Inventory inv;
VaultHolder vaultHolder = new VaultHolder(number);
if (PlayerVaults.getInstance().getOpenInventories().containsKey(info.toString())) {
PlayerVaults.debug("Already open");
inv = PlayerVaults.getInstance().getOpenInventories().get(info.toString());
} else {
- YamlConfiguration playerFile = getPlayerVaultFile(holder, true);
- Inventory i = getInventory(vaultHolder, holder, playerFile, size, number, title);
+ YamlConfiguration playerFile = getPlayerVaultFile(holderKey, true);
+ Inventory i = getInventory(vaultHolder, holderKey, playerFile, size, number, title);
if (i == null) {
return null;
} else {
@@ -172,7 +199,7 @@ private Inventory getInventory(InventoryHolder owner, String ownerName, YamlConf
// Happens on change of permission or if people used the broken version.
// In this case, players will lose items.
if (deserialized.length > size) {
- PlayerVaults.debug("Loaded vault for " + ownerName + " and got " + deserialized.length + " items for allowed size of " + size+". Attempting to rescue!");
+ PlayerVaults.debug("Loaded vault for " + ownerName + " and got " + deserialized.length + " items for allowed size of " + size + ". Attempting to rescue!");
for (ItemStack stack : deserialized) {
if (stack != null) {
inventory.addItem(stack);
@@ -194,11 +221,14 @@ private Inventory getInventory(InventoryHolder owner, String ownerName, YamlConf
* @return The inventory of the specified holder and vault number. Can be null.
*/
public Inventory getVault(String holder, int number) {
- YamlConfiguration playerFile = getPlayerVaultFile(holder, true);
+ String holderKey = normalizeHolderKey(holder);
+ YamlConfiguration playerFile = getPlayerVaultFile(holderKey, true);
String serialized = playerFile.getString(String.format(VAULTKEY, number));
- ItemStack[] contents = CardboardBoxSerialization.fromStorage(serialized, holder);
- Inventory inventory = Bukkit.createInventory(null, contents.length, holder + " vault " + number);
- inventory.setContents(contents);
+ ItemStack[] contents = CardboardBoxSerialization.fromStorage(serialized, holderKey);
+ int size = Math.max(9, ((contents.length + 8) / 9) * 9);
+ Inventory inventory = Bukkit.createInventory(null, size, holderKey + " vault " + number);
+ ItemStack[] copy = Arrays.copyOf(contents, size);
+ inventory.setContents(copy);
return inventory;
}
@@ -210,12 +240,13 @@ public Inventory getVault(String holder, int number) {
* @return true if the vault file and vault number exist in that file, otherwise false.
*/
public boolean vaultExists(String holder, int number) {
- File file = new File(directory, holder + ".yml");
+ String holderKey = normalizeHolderKey(holder);
+ File file = new File(directory, holderKey + ".yml");
if (!file.exists()) {
return false;
}
- return getPlayerVaultFile(holder, true).contains(String.format(VAULTKEY, number));
+ return getPlayerVaultFile(holderKey, true).contains(String.format(VAULTKEY, number));
}
/**
@@ -226,7 +257,8 @@ public boolean vaultExists(String holder, int number) {
*/
public Set getVaultNumbers(String holder) {
Set vaults = new HashSet<>();
- YamlConfiguration file = getPlayerVaultFile(holder, true);
+ String holderKey = normalizeHolderKey(holder);
+ YamlConfiguration file = getPlayerVaultFile(holderKey, true);
if (file == null) {
return vaults;
}
@@ -241,13 +273,32 @@ public Set getVaultNumbers(String holder) {
}
}
-
return vaults;
}
public void deleteAllVaults(String holder) {
- removeCachedPlayerVaultFile(holder);
- deletePlayerVaultFile(holder);
+ String holderKey = normalizeHolderKey(holder);
+ removeCachedPlayerVaultFile(holderKey);
+ deletePlayerVaultFile(holderKey);
+
+ List toRemove = new ArrayList<>();
+ PlayerVaults.getInstance().getInVault().forEach((viewerId, info) -> {
+ if (holderKey.equals(info.getVaultName())) {
+ toRemove.add(viewerId);
+ Player p = null;
+ try {
+ p = Bukkit.getPlayer(UUID.fromString(viewerId));
+ } catch (Exception ignored) {
+ // Ignored try actionable.
+ }
+ if (p != null) {
+ Player finalP = p;
+ PlayerVaults.scheduler().runAtEntity(finalP, task -> finalP.closeInventory());
+ }
+ PlayerVaults.getInstance().getOpenInventories().remove(info.toString());
+ }
+ });
+ toRemove.forEach(id -> PlayerVaults.getInstance().getInVault().remove(id));
}
/**
@@ -258,51 +309,82 @@ public void deleteAllVaults(String holder) {
* @param number The vault number.
*/
public void deleteVault(CommandSender sender, final String holder, final int number) {
- new BukkitRunnable() {
- @Override
- public void run() {
- File file = new File(directory, holder + ".yml");
+ final String holderKey = normalizeHolderKey(holder);
+ final VaultGate.VaultKey gateKey = new VaultGate.VaultKey(holderKey, number);
+
+ PlayerVaults.scheduler().runAsync(task ->
+ VaultGate.withLock(gateKey, () -> {
+ File file = new File(directory, holderKey + ".yml");
if (!file.exists()) {
return;
}
YamlConfiguration playerFile = YamlConfiguration.loadConfiguration(file);
- if (file.exists()) {
- playerFile.set(String.format(VAULTKEY, number), null);
- if (cachedVaultFiles.containsKey(holder)) {
- cachedVaultFiles.put(holder, playerFile);
- }
- try {
- playerFile.save(file);
- } catch (IOException ignored) {
- }
+ playerFile.set(String.format(VAULTKEY, number), null);
+ cachedVaultFiles.put(holderKey, playerFile);
+ try {
+ playerFile.save(file);
+ } catch (IOException ignored) {
}
- }
- }.runTaskAsynchronously(PlayerVaults.getInstance());
- OfflinePlayer player = Bukkit.getPlayer(holder);
- if (player != null) {
- if (sender.getName().equalsIgnoreCase(player.getName())) {
+ String key = new VaultViewInfo(holderKey, number).toString();
+ PlayerVaults.getInstance().getOpenInventories().remove(key);
+
+ List toRemove = new ArrayList<>();
+ PlayerVaults.getInstance().getInVault().forEach((viewerId, info) -> {
+ if (holderKey.equals(info.getVaultName()) && info.getNumber() == number) {
+ toRemove.add(viewerId);
+ Player p = null;
+ try {
+ p = Bukkit.getPlayer(UUID.fromString(viewerId));
+ } catch (Exception ignored) {
+ // Ignored try actionable.
+ }
+ if (p != null) {
+ Player finalP = p;
+ PlayerVaults.scheduler().runAtEntity(finalP, t -> finalP.closeInventory());
+ }
+ }
+ });
+ toRemove.forEach(id -> PlayerVaults.getInstance().getInVault().remove(id));
+ })
+ );
+
+ OfflinePlayer target = null;
+ try {
+ target = Bukkit.getOfflinePlayer(UUID.fromString(holderKey));
+ } catch (Exception ignored) {
+ // Ignored try actionable.
+ }
+ if (target != null && target.getName() != null) {
+ if (sender.getName().equalsIgnoreCase(target.getName())) {
+ this.plugin.getTL().deleteVault().title().with("vault", String.valueOf(number)).send(sender);
+ } else {
+ this.plugin.getTL().deleteOtherVault().title().with("vault", String.valueOf(number)).with("player", target.getName()).send(sender);
+ }
+ } else {
+ if (sender.getName().equalsIgnoreCase(holder)) {
this.plugin.getTL().deleteVault().title().with("vault", String.valueOf(number)).send(sender);
} else {
- this.plugin.getTL().deleteOtherVault().title().with("vault", String.valueOf(number)).with("player", player.getName()).send(sender);
+ this.plugin.getTL().deleteOtherVault().title().with("vault", String.valueOf(number)).with("player", holder).send(sender);
}
}
- String vaultName = sender instanceof Player ? ((Player) sender).getUniqueId().toString() : holder;
- PlayerVaults.getInstance().getOpenInventories().remove(new VaultViewInfo(vaultName, number).toString());
+ PlayerVaults.getInstance().getOpenInventories().remove(new VaultViewInfo(holderKey, number).toString());
}
// Should only be run asynchronously
public void cachePlayerVaultFile(String holder) {
- YamlConfiguration config = this.loadPlayerVaultFile(holder, false);
+ String holderKey = normalizeHolderKey(holder);
+ YamlConfiguration config = this.loadPlayerVaultFile(holderKey, false);
if (config != null) {
- this.cachedVaultFiles.put(holder, config);
+ this.cachedVaultFiles.put(holderKey, config);
}
}
public void removeCachedPlayerVaultFile(String holder) {
- cachedVaultFiles.remove(holder);
+ String holderKey = normalizeHolderKey(holder);
+ cachedVaultFiles.remove(holderKey);
}
/**
@@ -312,10 +394,8 @@ public void removeCachedPlayerVaultFile(String holder) {
* @return The holder's vault config file.
*/
public YamlConfiguration getPlayerVaultFile(String holder, boolean createIfNotFound) {
- if (cachedVaultFiles.containsKey(holder)) {
- return cachedVaultFiles.get(holder);
- }
- return loadPlayerVaultFile(holder, createIfNotFound);
+ String holderKey = resolveFileKey(holder);
+ return cachedVaultFiles.computeIfAbsent(holderKey, key -> loadPlayerVaultFile(key, createIfNotFound));
}
public YamlConfiguration loadPlayerVaultFile(String holder) {
@@ -328,7 +408,8 @@ public YamlConfiguration loadPlayerVaultFile(String holder) {
* @param holder UUID of the holder.
*/
public void deletePlayerVaultFile(String holder) {
- File file = new File(this.directory, holder + ".yml");
+ String holderKey = resolveFileKey(holder);
+ File file = new File(this.directory, holderKey + ".yml");
if (file.exists()) {
file.delete();
}
@@ -356,22 +437,38 @@ public YamlConfiguration loadPlayerVaultFile(String uniqueId, boolean createIfNo
}
public void saveFileSync(final String holder, final YamlConfiguration yaml) {
- if (cachedVaultFiles.containsKey(holder)) {
- cachedVaultFiles.put(holder, yaml);
+ String holderKey = resolveFileKey(holder);
+ if (cachedVaultFiles.containsKey(holderKey)) {
+ cachedVaultFiles.put(holderKey, yaml);
}
final boolean backups = PlayerVaults.getInstance().isBackupsEnabled();
final File backupsFolder = PlayerVaults.getInstance().getBackupsFolder();
- final File file = new File(directory, holder + ".yml");
+ final File file = new File(directory, holderKey + ".yml");
if (file.exists() && backups) {
- file.renameTo(new File(backupsFolder, holder + ".yml"));
+ file.renameTo(new File(backupsFolder, holderKey + ".yml"));
}
+
try {
yaml.save(file);
} catch (IOException e) {
- PlayerVaults.getInstance().addException(new IllegalStateException("Failed to save vault file for: " + holder, e));
- PlayerVaults.getInstance().getLogger().log(Level.SEVERE, "Failed to save vault file for: " + holder, e);
+ PlayerVaults.getInstance().addException(new IllegalStateException("Failed to save vault file for: " + holderKey, e));
+ PlayerVaults.getInstance().getLogger().log(Level.SEVERE, "Failed to save vault file for: " + holderKey, e);
}
- PlayerVaults.debug("Saved vault for " + holder);
+
+ PlayerVaults.debug("Saved vault for " + holderKey);
+ }
+
+ private String resolveFileKey(String holder) {
+ if (holder == null) {
+ return null;
+ }
+
+ File legacy = new File(this.directory, holder + ".yml");
+ if (legacy.exists()) {
+ return holder;
+ }
+
+ return normalizeHolderKey(holder);
}
}
diff --git a/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultOperations.java b/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultOperations.java
index 9134795..c844cd9 100644
--- a/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultOperations.java
+++ b/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultOperations.java
@@ -34,11 +34,48 @@
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Supplier;
public class VaultOperations {
private static final AtomicBoolean LOCKED = new AtomicBoolean(false);
+ public static final class VaultGate {
+
+ private static final ConcurrentHashMap LOCKS = new ConcurrentHashMap<>();
+
+ public static T withLock(VaultKey key, Supplier body) {
+ ReentrantLock lock = LOCKS.computeIfAbsent(key, k -> new ReentrantLock());
+ lock.lock();
+ try {
+ return body.get();
+ } finally {
+ try {
+ lock.unlock();
+ } finally {
+ if (!lock.hasQueuedThreads()) {
+ LOCKS.remove(key, lock);
+ }
+ }
+ }
+ }
+
+ public static void withLock(VaultKey key, Runnable body) {
+ withLock(key, () -> {
+ body.run();
+ return null;
+ });
+ }
+
+ public record VaultKey(String ownerKey, int number) {
+ @Override
+ public String toString() {
+ return ownerKey + " " + number;
+ }
+ }
+ }
+
/**
* Gets whether or not player vaults are locked
*
@@ -59,12 +96,10 @@ public static void setLocked(boolean locked) {
if (locked) {
for (Player player : PlayerVaults.getInstance().getServer().getOnlinePlayers()) {
- if (player.getOpenInventory() != null) {
- InventoryView view = player.getOpenInventory();
- if (view.getTopInventory().getHolder() instanceof VaultHolder) {
- player.closeInventory();
- PlayerVaults.getInstance().getTL().locked().title().send(player);
- }
+ InventoryView view = player.getOpenInventory();
+ if (view != null && view.getTopInventory() != null && view.getTopInventory().getHolder() instanceof VaultHolder) {
+ PlayerVaults.scheduler().runAtEntity(player, task -> player.closeInventory());
+ PlayerVaults.getInstance().getTL().locked().title().send(player);
}
}
}
@@ -143,7 +178,7 @@ private static boolean openOwnVaultE(Player player, String arg, boolean free, bo
if (player.isSleeping() || player.isDead() || !player.isOnline()) {
return false;
}
- int number;
+ final int number;
try {
number = Integer.parseInt(arg);
if (number < 1) {
@@ -154,37 +189,46 @@ private static boolean openOwnVaultE(Player player, String arg, boolean free, bo
return false;
}
- if (checkPerms(player, number)) {
- if (free || EconomyOperations.payToOpen(player, number)) {
- Inventory inv = VaultManager.getInstance().loadOwnVault(player, number, getMaxVaultSize(player));
- if (inv == null) {
- PlayerVaults.debug(String.format("Failed to open null vault %d for %s. This is weird.", number, player.getName()));
- return false;
- }
+ if (!checkPerms(player, number)) {
+ PlayerVaults.getInstance().getTL().noPerms().title().send(player);
+ return false;
+ }
- player.openInventory(inv);
+ if (!free && !EconomyOperations.payToOpen(player, number)) {
+ PlayerVaults.getInstance().getTL().insufficientFunds().title().send(player);
+ return false;
+ }
- // Check if the inventory was actually opened
- if (player.getOpenInventory().getTopInventory() instanceof CraftingInventory || player.getOpenInventory().getTopInventory() == null) {
- PlayerVaults.debug(String.format("Cancelled opening vault %s for %s from an outside source.", arg, player.getName()));
- return false; // inventory open event was cancelled.
- }
+ final String ownerKey = player.getUniqueId().toString();
+ final VaultViewInfo info = new VaultViewInfo(ownerKey, number);
+ final VaultGate.VaultKey gateKey = new VaultGate.VaultKey(ownerKey, number);
- VaultViewInfo info = new VaultViewInfo(player.getUniqueId().toString(), number);
- PlayerVaults.getInstance().getOpenInventories().put(info.toString(), inv);
+ Inventory inv = VaultGate.withLock(gateKey, () ->
+ PlayerVaults.getInstance().getOpenInventories().computeIfAbsent(info.toString(), key ->
+ VaultManager.getInstance().loadOwnVault(player, number, getMaxVaultSize(player))
+ )
+ );
- if (send) {
- PlayerVaults.getInstance().getTL().openVault().title().with("vault", arg).send(player);
- }
- return true;
- } else {
- PlayerVaults.getInstance().getTL().insufficientFunds().title().send(player);
- return false;
- }
+ if (inv == null) {
+ PlayerVaults.debug(String.format("Failed to open null vault %d for %s. This is weird.", number, player.getName()));
+ return false;
+ }
+
+ PlayerVaults.scheduler().runAtEntity(player, task -> player.openInventory(inv));
+
+ // Check if the inventory was actually opened
+ if (player.getOpenInventory().getTopInventory() instanceof CraftingInventory) {
+ PlayerVaults.debug(String.format("Cancelled opening vault %s for %s from an outside source.", arg, player.getName()));
+ PlayerVaults.getInstance().getOpenInventories().remove(info.toString());
+ return false; // inventory open event was cancelled.
} else {
- PlayerVaults.getInstance().getTL().noPerms().title().send(player);
+ player.getOpenInventory().getTopInventory();
}
- return false;
+
+ if (send) {
+ PlayerVaults.getInstance().getTL().openVault().title().with("vault", arg).send(player);
+ }
+ return true;
}
/**
@@ -207,7 +251,7 @@ public static boolean openOwnVault(Player player, String arg, boolean isCommand)
* Open another player's vault.
*
* @param player The player to open to.
- * @param vaultOwner The name of the vault owner.
+ * @param vaultOwner The name or UUID of the vault owner.
* @param arg The vault number to open.
* @return Whether or not the player was allowed to open it.
*/
@@ -224,9 +268,7 @@ public static boolean openOtherVault(Player player, String vaultOwner, String ar
return false;
}
- long time = System.currentTimeMillis();
-
- int number = 0;
+ final int number;
try {
number = Integer.parseInt(arg);
if (number < 1) {
@@ -235,41 +277,63 @@ public static boolean openOtherVault(Player player, String vaultOwner, String ar
}
} catch (NumberFormatException nfe) {
PlayerVaults.getInstance().getTL().mustBeNumber().title().send(player);
+ return false;
}
- Inventory inv = VaultManager.getInstance().loadOtherVault(vaultOwner, number, getMaxVaultSize(vaultOwner));
- String name = vaultOwner;
+ final String holderKey = VaultManager.normalizeHolderKey(vaultOwner);
+ final VaultViewInfo info = new VaultViewInfo(holderKey, number);
+ final VaultGate.VaultKey gateKey = new VaultGate.VaultKey(holderKey, number);
+
+ long time = System.currentTimeMillis();
+
+ Inventory inv = VaultGate.withLock(gateKey, () -> {
+ Inventory cached = PlayerVaults.getInstance().getOpenInventories().get(info.toString());
+ if (cached != null) {
+ return cached;
+ }
+ Inventory loaded = VaultManager.getInstance().loadOtherVault(holderKey, number, getMaxVaultSize(holderKey));
+ if (loaded != null) {
+ PlayerVaults.getInstance().getOpenInventories().put(info.toString(), loaded);
+ }
+ return loaded;
+ });
+
+ // Resolve a nice display name if possible
+ String displayName = holderKey;
try {
- OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(UUID.fromString(vaultOwner));
- name = offlinePlayer.getName();
+ UUID uuid = UUID.fromString(holderKey);
+ OfflinePlayer op = Bukkit.getOfflinePlayer(uuid);
+ if (op.getName() != null) {
+ displayName = op.getName();
+ }
} catch (Exception e) {
// not a player
}
if (inv == null) {
PlayerVaults.getInstance().getTL().vaultDoesNotExist().title().send(player);
- } else {
- player.openInventory(inv);
+ PlayerVaults.debug("Opening other vault that does not fully exist.", time);
+ return false;
+ }
- // Check if the inventory was actually opened
- if (player.getOpenInventory().getTopInventory() instanceof CraftingInventory || player.getOpenInventory().getTopInventory() == null) {
- PlayerVaults.debug(String.format("Cancelled opening vault %s for %s from an outside source.", arg, player.getName()));
- return false; // inventory open event was cancelled.
- }
- if (send) {
- PlayerVaults.getInstance().getTL().openOtherVault().title().with("vault", arg).with("player", name).send(player);
- }
- PlayerVaults.debug("opening other vault", time);
+ PlayerVaults.scheduler().runAtEntity(player, task -> player.openInventory(inv));
- // Need to set ViewInfo for a third party vault for the opening player.
- VaultViewInfo info = new VaultViewInfo(vaultOwner, number);
- PlayerVaults.getInstance().getInVault().put(player.getUniqueId().toString(), info);
- PlayerVaults.getInstance().getOpenInventories().put(player.getUniqueId().toString(), inv);
- return true;
+ // Check if the inventory was actually opened
+ if (player.getOpenInventory().getTopInventory() instanceof CraftingInventory) {
+ PlayerVaults.debug(String.format("Cancelled opening vault %s for %s from an outside source.", arg, player.getName()));
+ return false; // inventory open event was cancelled.
+ } else {
+ player.getOpenInventory().getTopInventory();
}
- PlayerVaults.debug("opening other vault returning false", time);
- return false;
+ if (send) {
+ PlayerVaults.getInstance().getTL().openOtherVault().title().with("vault", arg).with("player", displayName).send(player);
+ }
+ PlayerVaults.debug("opening other vault", time);
+
+ // Track which vault this viewer is in
+ PlayerVaults.getInstance().getInVault().put(player.getUniqueId().toString(), info);
+ return true;
}
/**
@@ -282,25 +346,27 @@ public static void deleteOwnVault(Player player, String arg) {
if (isLocked()) {
return;
}
- if (isNumber(arg)) {
- int number = 0;
- try {
- number = Integer.parseInt(arg);
- if (number == 0) {
- PlayerVaults.getInstance().getTL().mustBeNumber().title().send(player);
- return;
- }
- } catch (NumberFormatException nfe) {
- PlayerVaults.getInstance().getTL().mustBeNumber().title().send(player);
- }
- if (EconomyOperations.refundOnDelete(player, number)) {
- VaultManager.getInstance().deleteVault(player, player.getUniqueId().toString(), number);
- PlayerVaults.getInstance().getTL().deleteVault().title().with("vault", arg).send(player);
- }
+ if (!isNumber(arg)) {
+ PlayerVaults.getInstance().getTL().mustBeNumber().title().send(player);
+ return;
+ }
- } else {
+ final int number;
+ try {
+ number = Integer.parseInt(arg);
+ if (number == 0) {
+ PlayerVaults.getInstance().getTL().mustBeNumber().title().send(player);
+ return;
+ }
+ } catch (NumberFormatException nfe) {
PlayerVaults.getInstance().getTL().mustBeNumber().title().send(player);
+ return;
+ }
+
+ if (EconomyOperations.refundOnDelete(player, number)) {
+ VaultManager.getInstance().deleteVault(player, player.getUniqueId().toString(), number);
+ PlayerVaults.getInstance().getTL().deleteVault().title().with("vault", arg).send(player);
}
}
@@ -315,27 +381,37 @@ public static void deleteOtherVault(CommandSender sender, String holder, String
if (isLocked()) {
return;
}
- if (sender.hasPermission(Permission.DELETE)) {
- if (isNumber(arg)) {
- int number = 0;
- try {
- number = Integer.parseInt(arg);
- if (number == 0) {
- PlayerVaults.getInstance().getTL().mustBeNumber().title().send(sender);
- return;
- }
- } catch (NumberFormatException nfe) {
- PlayerVaults.getInstance().getTL().mustBeNumber().title().send(sender);
- }
+ if (!sender.hasPermission(Permission.DELETE)) {
+ PlayerVaults.getInstance().getTL().noPerms().title().send(sender);
+ return;
+ }
+ if (!isNumber(arg)) {
+ PlayerVaults.getInstance().getTL().mustBeNumber().title().send(sender);
+ return;
+ }
- VaultManager.getInstance().deleteVault(sender, holder, number);
- PlayerVaults.getInstance().getTL().deleteOtherVault().title().with("vault", arg).with("player", holder).send(sender);
- } else {
+ final int number;
+ try {
+ number = Integer.parseInt(arg);
+ if (number == 0) {
PlayerVaults.getInstance().getTL().mustBeNumber().title().send(sender);
+ return;
}
- } else {
- PlayerVaults.getInstance().getTL().noPerms().title().send(sender);
+ } catch (NumberFormatException nfe) {
+ PlayerVaults.getInstance().getTL().mustBeNumber().title().send(sender);
+ return;
+ }
+
+ VaultManager.getInstance().deleteVault(sender, holder, number);
+ String display = holder;
+ try {
+ UUID uuid = UUID.fromString(holder);
+ OfflinePlayer op = Bukkit.getOfflinePlayer(uuid);
+ if (op.getName() != null) display = op.getName();
+ } catch (Exception e) {
+ // The return instance here can be suppressed
}
+ PlayerVaults.getInstance().getTL().deleteOtherVault().title().with("vault", arg).with("player", display).send(sender);
}
/**
@@ -369,15 +445,15 @@ private static boolean isNumber(String check) {
private record PlayerCount(int count, Instant time) {
}
- private static Map countCache = new ConcurrentHashMap<>();
+ private static final Map countCache = new ConcurrentHashMap<>();
private static final int secondsToLive = 2;
public static int countVaults(Player player) {
UUID uuid = player.getUniqueId();
- PlayerCount count = countCache.get(uuid);
- if (count != null && count.time().isAfter(Instant.now().plus(secondsToLive, ChronoUnit.SECONDS))) {
- return count.count;
+ PlayerCount cached = countCache.get(uuid);
+ if (cached != null && Instant.now().isBefore(cached.time().plus(secondsToLive, ChronoUnit.SECONDS))) {
+ return cached.count;
}
int vaultCount = 0;
for (int x = 1; x <= PlayerVaults.getInstance().getMaxVaultAmountPermTest(); x++) {
@@ -387,7 +463,7 @@ public static int countVaults(Player player) {
}
PlayerCount newCount = new PlayerCount(vaultCount, Instant.now());
countCache.put(uuid, newCount);
- PlayerVaults.getInstance().getServer().getScheduler().runTaskLater(PlayerVaults.getInstance(), () -> {
+ PlayerVaults.scheduler().runLater(() -> {
if (countCache.get(uuid) == newCount) {
countCache.remove(uuid); // Do a lil cleanup to avoid the world's smallest memory leak
}
diff --git a/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultViewInfo.java b/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultViewInfo.java
index 756b9d2..0dbf646 100644
--- a/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultViewInfo.java
+++ b/src/main/java/com/drtshock/playervaults/vaultmanagement/VaultViewInfo.java
@@ -29,6 +29,7 @@ public class VaultViewInfo {
/**
* Makes a VaultViewInfo object. Used for opening a vault owned by the opener.
*
+ * @param vaultName UUID (string) or legacy key
* @param i vault number.
*/
public VaultViewInfo(String vaultName, int i) {
@@ -58,4 +59,4 @@ public int getNumber() {
public String toString() {
return this.vaultName + " " + this.number;
}
-}
\ No newline at end of file
+}
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index a2fb0e9..39eed43 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -6,6 +6,7 @@ version: ${project.version}
main: com.drtshock.playervaults.PlayerVaults
softdepend: [Vault, Multiverse-Inventories, PlaceholderAPI]
api-version: 1.21.11
+folia-supported: true
commands:
pv: