diff --git a/pom.xml b/pom.xml index 824a373..9ce4e30 100644 --- a/pom.xml +++ b/pom.xml @@ -64,13 +64,6 @@ ${project.basedir}/lib/spigot-1.19.3.jar true --> - - org.spigotmc - spigot - 1.20.5-R0.1-SNAPSHOT - true - provided - org.bstats @@ -85,6 +78,12 @@ 1.0.6 compile + + dev.folia + folia-api + 1.21.4-R0.1-SNAPSHOT + provided + org.jetbrains annotations diff --git a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/InventoryRollbackPlus.java b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/InventoryRollbackPlus.java index 7ca7e06..7f22d50 100644 --- a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/InventoryRollbackPlus.java +++ b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/InventoryRollbackPlus.java @@ -2,6 +2,7 @@ import com.nuclyon.technicallycoded.inventoryrollback.UpdateChecker.UpdateResult; import com.nuclyon.technicallycoded.inventoryrollback.commands.Commands; +import com.nuclyon.technicallycoded.inventoryrollback.folia.SchedulerUtils; import com.nuclyon.technicallycoded.inventoryrollback.util.TimeZoneUtil; import com.nuclyon.technicallycoded.inventoryrollback.util.test.SelfTestSerialization; import com.tcoded.lightlibs.bukkitversion.BukkitVersion; @@ -30,6 +31,7 @@ public class InventoryRollbackPlus extends InventoryRollback { private static InventoryRollbackPlus instancePlus; + public static boolean usingFolia = false; private TimeZoneUtil timeZoneUtil = null; @@ -42,6 +44,16 @@ public static InventoryRollbackPlus getInstance() { return instancePlus; } + @Override + public void onLoad() { + try { + Class.forName("io.papermc.paper.threadedregions.scheduler.RegionScheduler"); + usingFolia = true; + } catch (ClassNotFoundException e) { + usingFolia = false; + } + } + @Override public void onEnable() { instancePlus = this; @@ -89,7 +101,7 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new ClickGUI(), this); getServer().getPluginManager().registerEvents(new EventLogs(), this); // Run after all plugin enable - getServer().getScheduler().runTask(this, EventLogs::patchLowestHandlers); + SchedulerUtils.runTask(null, EventLogs::patchLowestHandlers); // PaperLib if (!PaperLib.isPaper()) { @@ -124,7 +136,7 @@ public void onDisable() { HandlerList.unregisterAll(this); // Cancel tasks - this.getServer().getScheduler().cancelTasks(this); + if(!usingFolia) this.getServer().getScheduler().cancelTasks(this); // Clear instance references instancePlus = null; @@ -149,7 +161,7 @@ public boolean isCompatibleCb(String cbVersion) { } public void checkUpdate() { - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), () -> { + SchedulerUtils.runTaskAsynchronously(() -> { InventoryRollbackPlus.getInstance().getConsoleSender().sendMessage(MessageData.getPluginPrefix() + "Checking for updates..."); final UpdateResult result = new UpdateChecker(getInstance(), 85811).getResult(); diff --git a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/commands/Commands.java b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/commands/Commands.java index 47d02d4..d4bc726 100644 --- a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/commands/Commands.java +++ b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/commands/Commands.java @@ -4,8 +4,8 @@ import com.nuclyon.technicallycoded.inventoryrollback.commands.inventoryrollback.*; import me.danjono.inventoryrollback.config.MessageData; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -20,7 +20,7 @@ public class Commands implements CommandExecutor, TabCompleter { private String[] backupOptions = new String[] {"all", "player"}; private String[] importOptions = new String[] {"confirm"}; - private HashMap subCommands = new HashMap<>(); + private ConcurrentHashMap subCommands = new ConcurrentHashMap<>(); public Commands(InventoryRollbackPlus mainIn) { this.main = mainIn; diff --git a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/commands/inventoryrollback/ImportSubCmd.java b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/commands/inventoryrollback/ImportSubCmd.java index af926d9..aac06d8 100644 --- a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/commands/inventoryrollback/ImportSubCmd.java +++ b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/commands/inventoryrollback/ImportSubCmd.java @@ -2,6 +2,7 @@ import com.nuclyon.technicallycoded.inventoryrollback.InventoryRollbackPlus; import com.nuclyon.technicallycoded.inventoryrollback.commands.IRPCommand; +import com.nuclyon.technicallycoded.inventoryrollback.folia.SchedulerUtils; import com.nuclyon.technicallycoded.inventoryrollback.util.LegacyBackupConversionUtil; import me.danjono.inventoryrollback.config.MessageData; import org.bukkit.Bukkit; @@ -32,7 +33,7 @@ public void onCommand(CommandSender sender, Command cmd, String label, String[] suggestConfirm.set(true); // Reset suggestion availability after 10 seconds - this.main.getServer().getScheduler().runTaskLaterAsynchronously(this.main, () -> { + SchedulerUtils.runTaskLaterAsynchronously(null, () -> { suggestConfirm.set(false); }, 10 * 20); @@ -40,7 +41,7 @@ public void onCommand(CommandSender sender, Command cmd, String label, String[] } // Execute import - Bukkit.getScheduler().runTaskAsynchronously(main, LegacyBackupConversionUtil::convertOldBackupData); + SchedulerUtils.runTaskAsynchronously(LegacyBackupConversionUtil::convertOldBackupData); // Reset suggestion to not visible suggestConfirm.set(false); diff --git a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/commands/inventoryrollback/RestoreSubCmd.java b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/commands/inventoryrollback/RestoreSubCmd.java index d5e7e23..cde277d 100644 --- a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/commands/inventoryrollback/RestoreSubCmd.java +++ b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/commands/inventoryrollback/RestoreSubCmd.java @@ -2,6 +2,7 @@ import com.nuclyon.technicallycoded.inventoryrollback.InventoryRollbackPlus; import com.nuclyon.technicallycoded.inventoryrollback.commands.IRPCommand; +import com.nuclyon.technicallycoded.inventoryrollback.folia.SchedulerUtils; import me.danjono.inventoryrollback.InventoryRollback; import me.danjono.inventoryrollback.config.ConfigData; import me.danjono.inventoryrollback.config.MessageData; @@ -90,14 +91,14 @@ private void openMainMenu(Player staff) { MainMenu menu = new MainMenu(staff, 1); staff.openInventory(menu.getInventory()); - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), menu::getMainMenu); + SchedulerUtils.runTaskAsynchronously(menu::getMainMenu); } private void openPlayerMenu(Player staff, OfflinePlayer offlinePlayer) { PlayerMenu menu = new PlayerMenu(staff, offlinePlayer); staff.openInventory(menu.getInventory()); - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), menu::getPlayerMenu); + SchedulerUtils.runTaskAsynchronously(menu::getPlayerMenu); } } diff --git a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/folia/FoliaRunnable.java b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/folia/FoliaRunnable.java new file mode 100644 index 0000000..b467021 --- /dev/null +++ b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/folia/FoliaRunnable.java @@ -0,0 +1,22 @@ +package com.nuclyon.technicallycoded.inventoryrollback.folia; + +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import org.bukkit.scheduler.BukkitRunnable; + +public class FoliaRunnable extends BukkitRunnable { + + private ScheduledTask foliaTask; + + @Override + public synchronized void cancel() throws IllegalStateException { + if(foliaTask != null) foliaTask.cancel(); + } + + @Override + public void run() { + } + + public void setScheduledTask(ScheduledTask task) { + this.foliaTask = task; + } +} diff --git a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/folia/SchedulerUtils.java b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/folia/SchedulerUtils.java new file mode 100644 index 0000000..56932da --- /dev/null +++ b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/folia/SchedulerUtils.java @@ -0,0 +1,261 @@ +package com.nuclyon.technicallycoded.inventoryrollback.folia; + +import com.nuclyon.technicallycoded.inventoryrollback.InventoryRollbackPlus; +import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler; +import io.papermc.paper.threadedregions.scheduler.RegionScheduler; +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Method; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; + +import static com.nuclyon.technicallycoded.inventoryrollback.InventoryRollbackPlus.usingFolia; + +/** + * Utility class for scheduling tasks in a Paper/Folia server. + */ +public abstract class SchedulerUtils { + + /** + * Schedules a task to run later on the main server thread. + * @param loc The location where the task should run, or null for the main thread. + * @param task The task to run. + * @param delay The delay in ticks before the task runs. + */ + public static void runTaskLater(@Nullable Location loc, @NotNull Runnable task, long delay) { + JavaPlugin plugin = InventoryRollbackPlus.getInstance(); + if (usingFolia) { + try { + if (loc != null) { + Method getRegionScheduler = plugin.getServer().getClass().getMethod("getRegionScheduler"); + RegionScheduler regionScheduler = (RegionScheduler) getRegionScheduler.invoke(plugin.getServer()); + regionScheduler.runDelayed( + plugin, + loc, + (ScheduledTask scheduledTask) -> task.run(), + delay + ); + } else { + Method getGlobalScheduler = plugin.getServer().getClass().getMethod("getGlobalRegionScheduler"); + GlobalRegionScheduler globalScheduler = (GlobalRegionScheduler) getGlobalScheduler.invoke(plugin.getServer()); + globalScheduler.runDelayed( + plugin, + (ScheduledTask scheduledTask) -> task.run(), + delay + ); + } + return; + } catch (Exception e) { + e.printStackTrace(); + } + } + plugin.getServer().getScheduler().runTaskLater(plugin, task, delay); + } + + /** + * Schedules a task to run later asynchronously on the main server thread. + * @param loc The location where the task should run, or null for the main thread. + * @param task The task to run. + * @param delay The delay in ticks before the task runs. + */ + public static void runTaskLaterAsynchronously(@Nullable Location loc, @NotNull Runnable task, long delay) { + JavaPlugin plugin = InventoryRollbackPlus.getInstance(); + if (usingFolia) { + try { + if (loc != null) { + Method getRegionScheduler = plugin.getServer().getClass().getMethod("getRegionScheduler"); + RegionScheduler regionScheduler = (RegionScheduler) getRegionScheduler.invoke(plugin.getServer()); + regionScheduler.runDelayed( + plugin, + loc, + (ScheduledTask scheduledTask) -> task.run(), + delay + ); + } else { + Method getGlobalScheduler = plugin.getServer().getClass().getMethod("getGlobalRegionScheduler"); + GlobalRegionScheduler globalScheduler = (GlobalRegionScheduler) getGlobalScheduler.invoke(plugin.getServer()); + globalScheduler.runDelayed( + plugin, + (ScheduledTask scheduledTask) -> task.run(), + delay + ); + } + return; + } catch (Exception e) { + e.printStackTrace(); + } + } + plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, task, delay); + } + + /** + * Schedules a task to run repeatedly on the main server thread. + * @param loc The location where the task should run, or null for the main thread. + * @param runnable The BukkitRunnable to run. + * @param delay The delay in ticks before the task runs. + * @param period The period in ticks between subsequent runs of the task. + */ + public static void runTaskTimer(@Nullable Location loc, @NotNull FoliaRunnable runnable, long delay, long period) { + JavaPlugin plugin = InventoryRollbackPlus.getInstance(); + if (usingFolia) { + try { + ScheduledTask task; + if (loc != null) { + Method getRegionScheduler = plugin.getServer().getClass().getMethod("getRegionScheduler"); + RegionScheduler regionScheduler = (RegionScheduler) getRegionScheduler.invoke(plugin.getServer()); + task = regionScheduler.runAtFixedRate( + plugin, + loc, + (ScheduledTask t) -> runnable.run(), + delay, + period + ); + } else { + Method getGlobalScheduler = plugin.getServer().getClass().getMethod("getGlobalRegionScheduler"); + GlobalRegionScheduler globalScheduler = (GlobalRegionScheduler) getGlobalScheduler.invoke(plugin.getServer()); + task = globalScheduler.runAtFixedRate( + plugin, + (ScheduledTask t) -> runnable.run(), + delay, + period + ); + } + runnable.setScheduledTask(task); + } catch (Exception e) { + e.printStackTrace(); + } + return; + } + runnable.runTaskTimer(plugin, delay, period); + } + + /** + * Schedules a task to run repeatedly on the main server thread asynchronously. + * @param runnable The FoliaRunnable to run. + * @param delay The delay in ticks before the task runs. + * @param period The period in ticks between subsequent runs of the task. + */ + public static void runTaskTimerAsynchronously(@NotNull FoliaRunnable runnable, long delay, long period) { + JavaPlugin plugin = InventoryRollbackPlus.getInstance(); + if (usingFolia) { + try { + Method getGlobalScheduler = plugin.getServer().getClass().getMethod("getGlobalRegionScheduler"); + GlobalRegionScheduler globalScheduler = (GlobalRegionScheduler) getGlobalScheduler.invoke(plugin.getServer()); + class AsyncRepeatingTask { + private ScheduledTask task; + void start(long initialDelay) { + task = globalScheduler.runDelayed(plugin, (ScheduledTask t) -> { + runnable.run(); + start(period); + }, initialDelay); + runnable.setScheduledTask(task); + } + } + new AsyncRepeatingTask().start(delay); + } catch (Exception e) { + e.printStackTrace(); + } + return; + } + runnable.runTaskTimerAsynchronously(plugin, delay, period); + } + + /** + * Runs a task asynchronously on the main server thread. + * @param task The task to run. + */ + public static void runTaskAsynchronously(@NotNull Runnable task) { + JavaPlugin plugin = InventoryRollbackPlus.getInstance(); + if (usingFolia) { + try { + Method getGlobalScheduler = plugin.getServer().getClass().getMethod("getGlobalRegionScheduler"); + GlobalRegionScheduler globalScheduler = (GlobalRegionScheduler) getGlobalScheduler.invoke(plugin.getServer()); + globalScheduler.execute(plugin, task); + return; + } catch (Exception e) { + e.printStackTrace(); + } + } + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, task); + } + + /** + * Runs a task on the main server thread at a specific location or globally. + * @param loc The location where the task should run, or null for the main thread. + * @param task The task to run. + */ + public static void runTask(@Nullable Location loc, @NotNull Runnable task) { + JavaPlugin plugin = InventoryRollbackPlus.getInstance(); + if (usingFolia) { + try { + if (loc != null) { + Method getRegionScheduler = plugin.getServer().getClass().getMethod("getRegionScheduler"); + RegionScheduler regionScheduler = (RegionScheduler) getRegionScheduler.invoke(plugin.getServer()); + regionScheduler.execute(plugin, loc, task); + } else { + Method getGlobalScheduler = plugin.getServer().getClass().getMethod("getGlobalRegionScheduler"); + GlobalRegionScheduler globalScheduler = (GlobalRegionScheduler) getGlobalScheduler.invoke(plugin.getServer()); + globalScheduler.execute(plugin, task); + } + return; + } catch (Exception e) { + e.printStackTrace(); + } + } + plugin.getServer().getScheduler().runTask(plugin, task); + } + + public static CompletableFuture callSyncMethod(@Nullable Location loc, @NotNull Callable task) { + JavaPlugin plugin = InventoryRollbackPlus.getInstance(); + if (usingFolia) { + CompletableFuture future = new CompletableFuture<>(); + try { + if (loc != null) { + Method getRegionScheduler = plugin.getServer().getClass().getMethod("getRegionScheduler"); + RegionScheduler regionScheduler = (RegionScheduler) getRegionScheduler.invoke(plugin.getServer()); + regionScheduler.execute(plugin, loc, () -> { + try { + future.complete(task.call()); + } catch (Exception e) { + future.completeExceptionally(e); + } + }); + } else { + Method getGlobalScheduler = plugin.getServer().getClass().getMethod("getGlobalRegionScheduler"); + GlobalRegionScheduler globalScheduler = (GlobalRegionScheduler) getGlobalScheduler.invoke(plugin.getServer()); + globalScheduler.execute(plugin, () -> { + try { + future.complete(task.call()); + } catch (Exception e) { + future.completeExceptionally(e); + } + }); + } + } catch (Exception e) { + future.completeExceptionally(e); + } + return future; + } + CompletableFuture cf = new CompletableFuture<>(); + try { + Future bukkitFuture = plugin.getServer().getScheduler().callSyncMethod(plugin, task); + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + try { + T result = bukkitFuture.get(); + cf.complete(result); + } catch (Throwable ex) { + cf.completeExceptionally(ex); + } + }); + } catch (Throwable e) { + cf.completeExceptionally(e); + } + return cf; + } +} diff --git a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/util/TimeZoneUtil.java b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/util/TimeZoneUtil.java index b4fc373..3be2104 100644 --- a/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/util/TimeZoneUtil.java +++ b/src/main/java/com/nuclyon/technicallycoded/inventoryrollback/util/TimeZoneUtil.java @@ -4,7 +4,7 @@ import java.time.Instant; import java.util.Date; -import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; public class TimeZoneUtil { @@ -125,8 +125,8 @@ public String getTimeZoneFullName(String shortCode) { // INIT DATA public void loadDefaultData() { - HashMap offsetsMapBuilder = new HashMap<>(); - HashMap shortCodeNamesBuilder = new HashMap<>(); + ConcurrentHashMap offsetsMapBuilder = new ConcurrentHashMap<>(); + ConcurrentHashMap shortCodeNamesBuilder = new ConcurrentHashMap<>(); offsetsMapBuilder.put("ACDT", "GMT+10:30"); offsetsMapBuilder.put("ACST", "GMT+09:30"); diff --git a/src/main/java/me/danjono/inventoryrollback/InventoryRollback.java b/src/main/java/me/danjono/inventoryrollback/InventoryRollback.java index e4e98b7..63b5caf 100644 --- a/src/main/java/me/danjono/inventoryrollback/InventoryRollback.java +++ b/src/main/java/me/danjono/inventoryrollback/InventoryRollback.java @@ -1,6 +1,7 @@ package me.danjono.inventoryrollback; import com.nuclyon.technicallycoded.inventoryrollback.InventoryRollbackPlus; +import com.nuclyon.technicallycoded.inventoryrollback.folia.SchedulerUtils; import me.danjono.inventoryrollback.UpdateChecker.UpdateResult; import me.danjono.inventoryrollback.commands.Commands; import me.danjono.inventoryrollback.config.ConfigData; @@ -165,7 +166,7 @@ public void bStats() { } public void checkUpdate() { - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), () -> { + SchedulerUtils.runTaskAsynchronously(() -> { logger.log(Level.INFO, MessageData.getPluginPrefix() + "Checking for updates..."); final UpdateResult result = new UpdateChecker(getInstance(), 85811).getResult(); diff --git a/src/main/java/me/danjono/inventoryrollback/commands/Commands.java b/src/main/java/me/danjono/inventoryrollback/commands/Commands.java index 591ce15..e6368cb 100644 --- a/src/main/java/me/danjono/inventoryrollback/commands/Commands.java +++ b/src/main/java/me/danjono/inventoryrollback/commands/Commands.java @@ -1,5 +1,6 @@ package me.danjono.inventoryrollback.commands; +import com.nuclyon.technicallycoded.inventoryrollback.folia.SchedulerUtils; import me.danjono.inventoryrollback.InventoryRollback; import me.danjono.inventoryrollback.config.ConfigData; import me.danjono.inventoryrollback.config.MessageData; @@ -114,14 +115,14 @@ private void openMainMenu(Player staff) { MainMenu menu = new MainMenu(staff, 1); staff.openInventory(menu.getInventory()); - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), menu::getMainMenu); + SchedulerUtils.runTaskAsynchronously(menu::getMainMenu); } private void openPlayerMenu(Player staff, OfflinePlayer offlinePlayer) { PlayerMenu menu = new PlayerMenu(staff, offlinePlayer); staff.openInventory(menu.getInventory()); - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), menu::getPlayerMenu); + SchedulerUtils.runTaskAsynchronously(menu::getPlayerMenu); } private void forceBackupCommand(CommandSender sender, String[] args) { @@ -220,13 +221,13 @@ private void versionCommand(CommandSender sender) { private void convertMySQL(CommandSender sender) { if (sender instanceof ConsoleCommandSender && sender.isOp()) { - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), MySQL::convertYAMLToMySQL); + SchedulerUtils.runTaskAsynchronously(MySQL::convertYAMLToMySQL); } } private void convertYAML(CommandSender sender) { if (sender instanceof ConsoleCommandSender && sender.isOp()) { - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), YAML::convertOldBackupData); + SchedulerUtils.runTaskAsynchronously(YAML::convertOldBackupData); } } diff --git a/src/main/java/me/danjono/inventoryrollback/data/PlayerData.java b/src/main/java/me/danjono/inventoryrollback/data/PlayerData.java index dd717b7..54bcb6c 100644 --- a/src/main/java/me/danjono/inventoryrollback/data/PlayerData.java +++ b/src/main/java/me/danjono/inventoryrollback/data/PlayerData.java @@ -9,6 +9,8 @@ import java.util.concurrent.CompletableFuture; import com.nuclyon.technicallycoded.inventoryrollback.InventoryRollbackPlus; +import com.nuclyon.technicallycoded.inventoryrollback.folia.FoliaRunnable; +import com.nuclyon.technicallycoded.inventoryrollback.folia.SchedulerUtils; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.inventory.ItemStack; @@ -16,7 +18,6 @@ import me.danjono.inventoryrollback.InventoryRollback; import me.danjono.inventoryrollback.config.ConfigData; import me.danjono.inventoryrollback.config.ConfigData.SaveType; -import org.bukkit.scheduler.BukkitRunnable; public class PlayerData { @@ -134,7 +135,7 @@ public CompletableFuture purgeExcessSaves(boolean shouldSaveAsync) { }; InventoryRollbackPlus instance = InventoryRollbackPlus.getInstance(); - if (saveAsync) instance.getServer().getScheduler().runTaskAsynchronously(instance, purgeTask); + if (saveAsync) SchedulerUtils.runTaskAsynchronously(purgeTask); else purgeTask.run(); return future; @@ -263,7 +264,7 @@ public void getRollbackMenuData() { public CompletableFuture getAllBackupData() { CompletableFuture future = new CompletableFuture<>(); if (ConfigData.getSaveType() == SaveType.MYSQL) { - new BukkitRunnable() { + SchedulerUtils.runTaskAsynchronously(new FoliaRunnable() { @Override public void run() { try { @@ -273,7 +274,7 @@ public void run() { } future.complete(null); } - }.runTaskAsynchronously(InventoryRollbackPlus.getInstance()); + }); } return future; } @@ -437,7 +438,7 @@ public void saveData(boolean shouldSaveAsync) { } }; - if (saveAsync) Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(),saveDataTask); + if (saveAsync) SchedulerUtils.runTaskAsynchronously(saveDataTask); else saveDataTask.run(); } diff --git a/src/main/java/me/danjono/inventoryrollback/gui/menu/EnderChestBackupMenu.java b/src/main/java/me/danjono/inventoryrollback/gui/menu/EnderChestBackupMenu.java index 7b6f9bb..abf3149 100644 --- a/src/main/java/me/danjono/inventoryrollback/gui/menu/EnderChestBackupMenu.java +++ b/src/main/java/me/danjono/inventoryrollback/gui/menu/EnderChestBackupMenu.java @@ -1,6 +1,8 @@ package me.danjono.inventoryrollback.gui.menu; import com.nuclyon.technicallycoded.inventoryrollback.InventoryRollbackPlus; +import com.nuclyon.technicallycoded.inventoryrollback.folia.FoliaRunnable; +import com.nuclyon.technicallycoded.inventoryrollback.folia.SchedulerUtils; import me.danjono.inventoryrollback.config.ConfigData; import me.danjono.inventoryrollback.config.MessageData; import me.danjono.inventoryrollback.data.LogType; @@ -11,7 +13,6 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; import java.util.ArrayList; import java.util.List; @@ -85,7 +86,7 @@ public void showEnderChestItems() { try { // Add items, 5 per tick - new BukkitRunnable() { + SchedulerUtils.runTaskTimer(null, new FoliaRunnable() { int invPosition = 0; int itemPos = (pageNumber - 1) * 27; @@ -111,7 +112,7 @@ public void run() { itemPos++; } } - }.runTaskTimer(InventoryRollbackPlus.getInstance(), 0, 1); + }, 1, 1); } catch (NullPointerException e) { staff.sendMessage(MessageData.getPluginPrefix() + MessageData.getErrorInventory()); return; diff --git a/src/main/java/me/danjono/inventoryrollback/gui/menu/MainInventoryBackupMenu.java b/src/main/java/me/danjono/inventoryrollback/gui/menu/MainInventoryBackupMenu.java index ab75e59..592f008 100644 --- a/src/main/java/me/danjono/inventoryrollback/gui/menu/MainInventoryBackupMenu.java +++ b/src/main/java/me/danjono/inventoryrollback/gui/menu/MainInventoryBackupMenu.java @@ -1,6 +1,8 @@ package me.danjono.inventoryrollback.gui.menu; import com.nuclyon.technicallycoded.inventoryrollback.InventoryRollbackPlus; +import com.nuclyon.technicallycoded.inventoryrollback.folia.FoliaRunnable; +import com.nuclyon.technicallycoded.inventoryrollback.folia.SchedulerUtils; import me.danjono.inventoryrollback.config.ConfigData; import me.danjono.inventoryrollback.config.MessageData; import me.danjono.inventoryrollback.data.LogType; @@ -11,11 +13,11 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicInteger; public class MainInventoryBackupMenu { @@ -78,12 +80,12 @@ public void showBackupItems() { assert !Bukkit.isPrimaryThread(); int item = 0; - int position = 0; + AtomicInteger position = new AtomicInteger(); //If the backup file is invalid it will return null, we want to catch it here try { // Add items, 5 per tick - new BukkitRunnable() { + SchedulerUtils.runTaskTimer(null, new FoliaRunnable() { int invPosition = 0; int itemPos = 0; @@ -108,7 +110,7 @@ public void run() { itemPos++; } } - }.runTaskTimer(main, 0, 1); + }, 1, 1); } catch (Exception ex) { ex.printStackTrace(); staff.sendMessage(MessageData.getPluginPrefix() + MessageData.getErrorInventory()); @@ -116,47 +118,43 @@ public void run() { } item = 36; - position = 44; + position.set(44); //Add armour if (armour != null && armour.length > 0) { - try { - for (int i = 0; i < armour.length; i++) { - // Place item safely - final int finalPos = position; - final int finalItem = i; - Future placeItemFuture = main.getServer().getScheduler().callSyncMethod(main, - () -> { - inventory.setItem(finalPos, armour[finalItem]); - return null; - }); - placeItemFuture.get(); - position--; - } - } catch (ExecutionException | InterruptedException ex) { - ex.printStackTrace(); - } - } else { - try { - for (int i = 36; i < mainInvLen; i++) { - if (mainInventory[item] != null) { - // Place item safely - final int finalPos = position; - final int finalItem = item; - Future placeItemFuture = main.getServer().getScheduler().callSyncMethod(main, - () -> { - inventory.setItem(finalPos, mainInventory[finalItem]); - return null; - }); - placeItemFuture.get(); - position--; - } - item++; - } - } catch (ExecutionException | InterruptedException ex) { - ex.printStackTrace(); - } - } + for (int i = 0; i < armour.length; i++) { + // Place item safely + final int finalPos = position.get(); + final int finalItem = i; + SchedulerUtils.callSyncMethod(null, () -> { + inventory.setItem(finalPos, armour[finalItem]); + return null; + }).whenComplete((res, ex) -> { + if (ex != null) ex.printStackTrace(); + else position.getAndDecrement(); + }); + + } + } else { + for (int i = 36; i < mainInvLen; i++) { + if (mainInventory[item] != null) { + // Place item safely + final int finalPos = position.get(); + final int finalItem = item; + SchedulerUtils.callSyncMethod(null, () -> { + inventory.setItem(finalPos, mainInventory[finalItem]); + return null; + }).whenComplete((res, ex) -> { + if (ex != null) { + ex.printStackTrace(); + } else { + position.getAndDecrement(); + } + }); + } + item++; + } + } // Add restore all player inventory button if (ConfigData.isRestoreToPlayerButton()) diff --git a/src/main/java/me/danjono/inventoryrollback/inventory/SaveInventory.java b/src/main/java/me/danjono/inventoryrollback/inventory/SaveInventory.java index 431fc6d..06ed422 100644 --- a/src/main/java/me/danjono/inventoryrollback/inventory/SaveInventory.java +++ b/src/main/java/me/danjono/inventoryrollback/inventory/SaveInventory.java @@ -1,6 +1,7 @@ package me.danjono.inventoryrollback.inventory; import com.nuclyon.technicallycoded.inventoryrollback.InventoryRollbackPlus; +import com.nuclyon.technicallycoded.inventoryrollback.folia.SchedulerUtils; import com.nuclyon.technicallycoded.inventoryrollback.util.UserLogRateLimiter; import com.nuclyon.technicallycoded.inventoryrollback.util.serialization.ItemStackSerialization; import com.tcoded.lightlibs.bukkitversion.BukkitVersion; @@ -16,13 +17,13 @@ import org.jetbrains.annotations.Nullable; import java.util.Arrays; -import java.util.HashMap; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; public class SaveInventory { - private static final HashMap rateLimiters = new HashMap<>(); + private static final ConcurrentHashMap rateLimiters = new ConcurrentHashMap<>(); private final InventoryRollbackPlus main; @@ -97,7 +98,7 @@ public void save(PlayerDataSnapshot snapshot, boolean async) { purgeTask.thenRun(() -> data.saveData(saveAsync)); }; - if (saveAsync) main.getServer().getScheduler().runTaskAsynchronously(main, saveTask); + if (saveAsync) SchedulerUtils.runTaskAsynchronously(saveTask); else saveTask.run(); } diff --git a/src/main/java/me/danjono/inventoryrollback/listeners/ClickGUI.java b/src/main/java/me/danjono/inventoryrollback/listeners/ClickGUI.java index 2480efc..bdf91af 100644 --- a/src/main/java/me/danjono/inventoryrollback/listeners/ClickGUI.java +++ b/src/main/java/me/danjono/inventoryrollback/listeners/ClickGUI.java @@ -2,9 +2,10 @@ import com.nuclyon.technicallycoded.inventoryrollback.InventoryRollbackPlus; import com.nuclyon.technicallycoded.inventoryrollback.customdata.CustomDataItemEditor; +import com.nuclyon.technicallycoded.inventoryrollback.folia.FoliaRunnable; +import com.nuclyon.technicallycoded.inventoryrollback.folia.SchedulerUtils; import com.tcoded.lightlibs.bukkitversion.BukkitVersion; import io.papermc.lib.PaperLib; -import me.danjono.inventoryrollback.InventoryRollback; import me.danjono.inventoryrollback.config.ConfigData; import me.danjono.inventoryrollback.config.MessageData; import me.danjono.inventoryrollback.config.SoundData; @@ -22,7 +23,6 @@ import org.bukkit.event.inventory.InventoryDragEvent; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; import java.util.UUID; import java.util.concurrent.ExecutionException; @@ -134,7 +134,7 @@ private void mainMenu(InventoryClickEvent e, Player staff, ItemStack icon) { MainMenu menu = new MainMenu(staff, page); staff.openInventory(menu.getInventory()); - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), menu::getMainMenu); + SchedulerUtils.runTaskAsynchronously(menu::getMainMenu); } //Clicked a player head else { @@ -142,7 +142,7 @@ private void mainMenu(InventoryClickEvent e, Player staff, ItemStack icon) { PlayerMenu menu = new PlayerMenu(staff, offlinePlayer); staff.openInventory(menu.getInventory()); - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), menu::getPlayerMenu); + SchedulerUtils.runTaskAsynchronously(menu::getPlayerMenu); } } else { if (e.getRawSlot() >= e.getInventory().getSize() && !e.isShiftClick()) { @@ -168,13 +168,13 @@ private void playerMenu(InventoryClickEvent e, Player staff, ItemStack icon) { MainMenu menu = new MainMenu(staff, 1); staff.openInventory(menu.getInventory()); - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), menu::getMainMenu); + SchedulerUtils.runTaskAsynchronously(menu::getMainMenu); } else { LogType logType = LogType.valueOf(nbt.getString("logType")); RollbackListMenu menu = new RollbackListMenu(staff, offlinePlayer, logType, 1); staff.openInventory(menu.getInventory()); - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), menu::showBackups); + SchedulerUtils.runTaskAsynchronously(menu::showBackups); } } else { @@ -200,7 +200,7 @@ private void rollbackMenu(InventoryClickEvent e, Player staff, ItemStack icon) { String location = nbt.getString("location"); // Run all data retrieval operations async to avoid tick lag - new BukkitRunnable() { + SchedulerUtils.runTaskAsynchronously(new FoliaRunnable() { @Override public void run() { // Init from MySQL or, if YAML, init & load config file @@ -218,20 +218,21 @@ public void run() { // Create inventory MainInventoryBackupMenu menu = new MainInventoryBackupMenu(staff, data, location); - // Display inventory to player - Future inventoryViewFuture = - main.getServer().getScheduler().callSyncMethod(main, - () -> staff.openInventory(menu.getInventory())); - //If the backup file is invalid it will return null, we want to catch it here - try { - inventoryViewFuture.get(); - // Start placing items in the inventory async + SchedulerUtils.callSyncMethod( + e.getWhoClicked().getLocation(), + () -> staff.openInventory(menu.getInventory()) + ).whenComplete((view, ex) -> { + if (ex != null) { + ex.printStackTrace(); + return; + } + if (view == null) { + return; + } menu.showBackupItems(); - } catch (NullPointerException | ExecutionException | InterruptedException ex) { - ex.printStackTrace(); - } + }); } - }.runTaskAsynchronously(main); + }); } //Player has selected a page icon @@ -244,13 +245,13 @@ else if (icon.getType().equals(Buttons.getPageSelectorIcon())) { PlayerMenu menu = new PlayerMenu(staff, player); staff.openInventory(menu.getInventory()); - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), menu::getPlayerMenu); + SchedulerUtils.runTaskAsynchronously(menu::getPlayerMenu); } else { LogType logType = LogType.valueOf(nbt.getString("logType")); RollbackListMenu menu = new RollbackListMenu(staff, player, logType, page); staff.openInventory(menu.getInventory()); - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), menu::showBackups); + SchedulerUtils.runTaskAsynchronously(menu::showBackups); } } } else { @@ -278,7 +279,7 @@ private void mainBackupMenu(InventoryClickEvent e, Player staff, ItemStack icon) RollbackListMenu menu = new RollbackListMenu(staff, offlinePlayer, logType, 1); staff.openInventory(menu.getInventory()); - Bukkit.getScheduler().runTaskAsynchronously(InventoryRollback.getInstance(), menu::showBackups); + SchedulerUtils.runTaskAsynchronously(menu::showBackups); } //Clicked icon to overwrite player inventory with backup data @@ -292,7 +293,7 @@ else if (icon.getType().equals(Buttons.getRestoreAllInventoryIcon())) { if (offlinePlayer.isOnline()) { Player player = (Player) offlinePlayer; - new BukkitRunnable() { + SchedulerUtils.runTaskAsynchronously(new FoliaRunnable() { @Override public void run() { // Init from MySQL or, if YAML, init & load config file @@ -311,35 +312,36 @@ public void run() { ItemStack[] armour = data.getArmour(); // Place inventory items sync (compressed code) - Future futureSetInv = main.getServer().getScheduler().callSyncMethod(main, - () -> { player.getInventory().setContents(inventory); return null; }); - try { futureSetInv.get(); } - catch (ExecutionException | InterruptedException ex) { ex.printStackTrace(); } - - // If 1.8, place armor contents separately - if (main.getVersion().lessOrEqThan(BukkitVersion.v1_8_R3)) { - // Place items sync (compressed code) - Future futureSetArmor = main.getServer().getScheduler().callSyncMethod(main, - () -> { player.getInventory().setArmorContents(armour); return null; }); - try { futureSetArmor.get(); } - catch (ExecutionException | InterruptedException ex) { ex.printStackTrace(); } - } - - // Play sound effect is enabled - if (SoundData.isInventoryRestoreEnabled()) { - // Play sound sync (compressed code) - Future futurePlaySound = main.getServer().getScheduler().callSyncMethod(main, - () -> { player.playSound(player.getLocation(), SoundData.getInventoryRestored(), 1, 1); return null; }); - try { futurePlaySound.get(); } - catch (ExecutionException | InterruptedException ex) { ex.printStackTrace(); } - } - - // Send player & staff feedback - player.sendMessage(MessageData.getPluginPrefix() + MessageData.getMainInventoryRestoredPlayer(staff.getName())); - if (!staff.getUniqueId().equals(player.getUniqueId())) - staff.sendMessage(MessageData.getPluginPrefix() + MessageData.getMainInventoryRestored(offlinePlayer.getName())); + SchedulerUtils.callSyncMethod(e.getWhoClicked().getLocation(), () -> { + player.getInventory().setContents(inventory); + return null; + }).whenComplete((res, ex) -> { + if (ex != null) ex.printStackTrace(); + else { + if (main.getVersion().lessOrEqThan(BukkitVersion.v1_8_R3)) { + SchedulerUtils.callSyncMethod(e.getWhoClicked().getLocation(), () -> { + player.getInventory().setArmorContents(armour); + return null; + }).whenComplete((r, e) -> { + if (e != null) e.printStackTrace(); + }); + } + if (SoundData.isInventoryRestoreEnabled()) { + SchedulerUtils.callSyncMethod(e.getWhoClicked().getLocation(), () -> { + player.playSound(player.getLocation(), SoundData.getInventoryRestored(), 1, 1); + return null; + }).whenComplete((r, e) -> { + if (e != null) e.printStackTrace(); + }); + } + + player.sendMessage(MessageData.getPluginPrefix() + MessageData.getMainInventoryRestoredPlayer(staff.getName())); + if (!staff.getUniqueId().equals(player.getUniqueId())) + staff.sendMessage(MessageData.getPluginPrefix() + MessageData.getMainInventoryRestored(offlinePlayer.getName())); + } + }); } - }.runTaskAsynchronously(main); + }); } else { staff.sendMessage(MessageData.getPluginPrefix() + MessageData.getMainInventoryNotOnline(offlinePlayer.getName())); @@ -370,7 +372,7 @@ else if (icon.getType().equals(Buttons.getTeleportLocationIcon())) { .add(0.5, 0.5, 0.5); // Teleport player on a slight delay to block the teleport icon glitching out into the player inventory - Bukkit.getScheduler().runTaskLater(InventoryRollback.getInstance(), () -> { + SchedulerUtils.runTaskLater(e.getWhoClicked().getLocation(), () -> { e.getWhoClicked().closeInventory(); PaperLib.teleportAsync(staff,loc).thenAccept((result) -> { if (SoundData.isTeleportEnabled()) @@ -384,7 +386,7 @@ else if (icon.getType().equals(Buttons.getTeleportLocationIcon())) { // Clicked icon to restore backup players ender chest else if (icon.getType().equals(Buttons.getEnderChestIcon())) { - new BukkitRunnable() { + SchedulerUtils.runTaskAsynchronously(new FoliaRunnable() { @Override public void run() { // Init from MySQL or, if YAML, init & load config file @@ -403,21 +405,17 @@ public void run() { EnderChestBackupMenu menu = new EnderChestBackupMenu(staff, data, 1); // Open inventory sync (compressed code) - Future futureOpenInv = main.getServer().getScheduler().callSyncMethod(main, - () -> { - staff.openInventory(menu.getInventory()); - return null; - }); - try { - futureOpenInv.get(); - } catch (ExecutionException | InterruptedException ex) { - ex.printStackTrace(); - } - - // Place items async - menu.showEnderChestItems(); + SchedulerUtils.callSyncMethod(e.getWhoClicked().getLocation(), () -> { + staff.openInventory(menu.getInventory()); + return null; + }).whenComplete((res, ex) -> { + if (ex != null) ex.printStackTrace(); + else { + menu.showEnderChestItems(); + } + }); } - }.runTaskAsynchronously(this.main); + }); } // Clicked icon to restore backup players health @@ -545,7 +543,7 @@ private void enderChestBackupMenu(InventoryClickEvent e, Player staff, ItemStack if (page == 0) { // Run all data retrieval operations async to avoid tick lag - new BukkitRunnable() { + SchedulerUtils.runTaskAsynchronously(new FoliaRunnable() { @Override public void run() { // Init from MySQL or, if YAML, init & load config file @@ -567,22 +565,24 @@ public void run() { MainInventoryBackupMenu menu = new MainInventoryBackupMenu(staff, data, location); // Display inventory to player - Future inventoryViewFuture = main.getServer().getScheduler().callSyncMethod(main, - () -> staff.openInventory(menu.getInventory())); - //If the backup file is invalid it will return null, we want to catch it here - try { - inventoryViewFuture.get(); - // Start placing items in the inventory async - menu.showBackupItems(); - } catch (NullPointerException | ExecutionException | InterruptedException ex) { - ex.printStackTrace(); - } + SchedulerUtils.callSyncMethod(e.getWhoClicked().getLocation(), () -> staff.openInventory(menu.getInventory())) + .whenComplete((view, ex) -> { + if (ex != null) { + ex.printStackTrace(); + return; + } + if (view == null) { + // backup inválido, tratar aqui se quiser + return; + } + menu.showBackupItems(); + }); } - }.runTaskAsynchronously(main); + }); } else { - new BukkitRunnable() { + SchedulerUtils.runTaskAsynchronously(new FoliaRunnable() { @Override public void run() { // Init from MySQL or, if YAML, init & load config file @@ -601,21 +601,17 @@ public void run() { EnderChestBackupMenu menu = new EnderChestBackupMenu(staff, data, page); // Open inventory sync (compressed code) - Future futureOpenInv = main.getServer().getScheduler().callSyncMethod(main, - () -> { - staff.openInventory(menu.getInventory()); - return null; - }); - try { - futureOpenInv.get(); - } catch (ExecutionException | InterruptedException ex) { - ex.printStackTrace(); - } - - // Place items async - menu.showEnderChestItems(); + SchedulerUtils.callSyncMethod(e.getWhoClicked().getLocation(), () -> { + staff.openInventory(menu.getInventory()); + return null; + }).whenComplete((res, ex) -> { + if (ex != null) ex.printStackTrace(); + else { + menu.showEnderChestItems(); + } + }); } - }.runTaskAsynchronously(this.main); + }); } } @@ -631,7 +627,7 @@ else if (icon.getType().equals(Buttons.getRestoreAllInventoryIcon())) { Player player = (Player) offlinePlayer; // Run all data retrieval operations async to avoid tick lag - new BukkitRunnable() { + SchedulerUtils.runTaskAsynchronously(new FoliaRunnable() { @Override public void run() { // Init from MySQL or, if YAML, init & load config file @@ -647,22 +643,14 @@ public void run() { } // Display inventory to player - Future inventoryReplaceFuture = main.getServer().getScheduler().callSyncMethod(main, - () -> { - ItemStack[] enderChest = data.getEnderChest(); - if (enderChest == null) enderChest = new ItemStack[0]; - player.getEnderChest().setContents(enderChest); - return null; - }); - - //If the backup file is invalid it will return null, we want to catch it here - try { - inventoryReplaceFuture.get(); - } catch (NullPointerException | ExecutionException | InterruptedException ex) { - ex.printStackTrace(); - } + SchedulerUtils.callSyncMethod(e.getWhoClicked().getLocation(), () -> { + player.getEnderChest().setContents(data.getEnderChest() != null ? data.getEnderChest() : new ItemStack[0]); + return null; + }).whenComplete((res, ex) -> { + if (ex != null) ex.printStackTrace(); + }); } - }.runTaskAsynchronously(main); + }); if (SoundData.isInventoryRestoreEnabled()) player.playSound(player.getLocation(), SoundData.getInventoryRestored(), 1, 1); diff --git a/src/main/java/me/danjono/inventoryrollback/listeners/EventLogs.java b/src/main/java/me/danjono/inventoryrollback/listeners/EventLogs.java index 170ddc2..d6cfab7 100644 --- a/src/main/java/me/danjono/inventoryrollback/listeners/EventLogs.java +++ b/src/main/java/me/danjono/inventoryrollback/listeners/EventLogs.java @@ -1,6 +1,7 @@ package me.danjono.inventoryrollback.listeners; import com.nuclyon.technicallycoded.inventoryrollback.InventoryRollbackPlus; +import com.nuclyon.technicallycoded.inventoryrollback.folia.SchedulerUtils; import com.tcoded.lightlibs.bukkitversion.BukkitVersion; import me.danjono.inventoryrollback.config.ConfigData; import me.danjono.inventoryrollback.data.LogType; @@ -93,7 +94,7 @@ private void playerQuit(PlayerQuitEvent e) { // Run the cleanup 1 tick later in case the rate limiter should need to provide debug data. // If the cleanup would run and the event is being spammed, this cleanup would delete the rate limiter's data // before it has a chance to act. - main.getServer().getScheduler().runTaskLater(main, () -> { + SchedulerUtils.runTaskLater(e.getPlayer().getLocation(), () -> { // Double check that the player is offline if (main.getServer().getPlayer(uuid) != null) return; // Cleanup the player's data diff --git a/src/main/java/me/danjono/inventoryrollback/reflections/LegacyNBTWrapper.java b/src/main/java/me/danjono/inventoryrollback/reflections/LegacyNBTWrapper.java index 78cb39a..85e22e4 100644 --- a/src/main/java/me/danjono/inventoryrollback/reflections/LegacyNBTWrapper.java +++ b/src/main/java/me/danjono/inventoryrollback/reflections/LegacyNBTWrapper.java @@ -9,7 +9,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; public class LegacyNBTWrapper implements CustomDataItemEditor { @@ -17,8 +17,8 @@ public class LegacyNBTWrapper implements CustomDataItemEditor { private ItemStack item; private final NMSHandler nmsHandler; - private static HashMap, String> getTagElementMethodNames; - private static HashMap, String> setTagElementMethodNames; + private static ConcurrentHashMap, String> getTagElementMethodNames; + private static ConcurrentHashMap, String> setTagElementMethodNames; // 1.8 - 1.20.4 private static String getTagMethodName; @@ -104,8 +104,8 @@ else if (nmsVersion.greaterOrEqThan(BukkitVersion.v1_18_R2)) { } private void resolveNbtTagCompoundReflectionNames(BukkitVersion nmsVersion) { - getTagElementMethodNames = new HashMap<>(); - setTagElementMethodNames = new HashMap<>(); + getTagElementMethodNames = new ConcurrentHashMap<>(); + setTagElementMethodNames = new ConcurrentHashMap<>(); if (nmsVersion.greaterOrEqThan(BukkitVersion.v1_18_R1)) { getTagElementMethodNames.put(Integer.class, "h"); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 9d56c25..03b5306 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -5,6 +5,7 @@ description: ${project.description} author: ${project.organization.name} authors: [${project.organization.name}, danjono] api-version: 1.13 +folia-supported: true loadbefore: - DeluxeCombat