mirror of
https://github.com/rockyhawk64/CommandPanels.git
synced 2025-11-18 07:14:17 +01:00
Folia Support
Major rework to schedulers to now use the Adapter class to use folia if folia is in use or normal if not. Also made the version check disable for FOLIA-BETA versions. Read me was included but can be converted back if wanted.
This commit is contained in:
parent
b75ff63fbc
commit
d314b50311
@ -25,6 +25,12 @@ Making a plugin? You can use Command Panels as a library to make your own GUIs f
|
||||
|
||||
**Floodgate Forms** to create custom Bedrock GUIs with full support for both SimpleForms and CustomForms that allows inputs such as sliders, dropdowns, etc.
|
||||
|
||||
## Server Compatibility
|
||||
|
||||
**Spigot & Paper** Full compatibility with Spigot servers and Paper servers, with enhanced performance on Paper. 1.8-1.21.5(Latest usually works)
|
||||
|
||||
**Folia Support** Native support for Folia's regionalized threading system. The plugin automatically detects Folia and uses region-specific schedulers for optimal performance without any configuration needed.
|
||||
|
||||
## Partner
|
||||
|
||||

|
||||
|
||||
13
pom.xml
13
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>groupId</groupId>
|
||||
<artifactId>CommandPanels</artifactId>
|
||||
<version>SNAPSHOT</version>
|
||||
<version>FOLIA-BETA-V1.0.2</version>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
@ -150,12 +150,23 @@
|
||||
<version>13.0.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Paper API for better Folia support -->
|
||||
<dependency>
|
||||
<groupId>io.papermc.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
<version>1.20.6-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Fallback to Spigot API if Paper isn't available -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.20.6-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mojang</groupId>
|
||||
<artifactId>authlib</artifactId>
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
version: 3.22.5
|
||||
version: FOLIA-BETA-V1.0.2
|
||||
main: me.rockyhawk.commandpanels.CommandPanels
|
||||
name: CommandPanels
|
||||
author: RockyHawk
|
||||
api-version: '1.13'
|
||||
folia-supported: true
|
||||
description: Fully Custom GUIs. Make your Server Professional.
|
||||
softdepend: [Essentials, PlaceholderAPI, Vault, HeadDatabase, TokenManager, VotingPlugin, MMOItems, ChestSort, floodgate]
|
||||
commands:
|
||||
|
||||
@ -19,32 +19,59 @@ public class CommandPanels extends JavaPlugin{
|
||||
public void onEnable() {
|
||||
Bukkit.getLogger().info("[CommandPanels] RockyHawk's CommandPanels v" + this.getDescription().getVersion() + " Plugin Loading...");
|
||||
|
||||
//Initialise plugin context
|
||||
ctx = new Context(this);
|
||||
try {
|
||||
//Initialise plugin context
|
||||
ctx = new Context(this);
|
||||
|
||||
//add custom charts bStats
|
||||
Metrics metrics = new Metrics(this, 5097);
|
||||
metrics.addCustomChart(new SingleLineChart("panels_amount", () -> {
|
||||
//this is the total panels loaded
|
||||
return panelList.size();
|
||||
}));
|
||||
//add custom charts bStats
|
||||
Metrics metrics = new Metrics(this, 5097);
|
||||
metrics.addCustomChart(new SingleLineChart("panels_amount", () -> {
|
||||
//this is the total panels loaded
|
||||
return panelList.size();
|
||||
}));
|
||||
|
||||
Bukkit.getLogger().info("[CommandPanels] RockyHawk's CommandPanels v" + this.getDescription().getVersion() + " Plugin Loaded!");
|
||||
Bukkit.getLogger().info("[CommandPanels] RockyHawk's CommandPanels v" + this.getDescription().getVersion() + " Plugin Loaded!");
|
||||
} catch (Exception e) {
|
||||
Bukkit.getLogger().severe("[CommandPanels] Failed to load plugin: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
// Set ctx to null to prevent issues in onDisable
|
||||
ctx = null;
|
||||
throw e; // Re-throw to properly disable the plugin
|
||||
}
|
||||
}
|
||||
|
||||
public void onDisable() {
|
||||
//close all the panels
|
||||
for(String name : ctx.openPanels.openPanels.keySet()){
|
||||
ctx.openPanels.closePanelForLoader(name, PanelPosition.Top);
|
||||
try {
|
||||
Bukkit.getPlayer(name).closeInventory();
|
||||
}catch (Exception ignore){}
|
||||
// Check if context was properly initialized before attempting cleanup
|
||||
if (ctx == null) {
|
||||
Bukkit.getLogger().info("RockyHawk's CommandPanels Plugin Disabled (initialization failed).");
|
||||
return;
|
||||
}
|
||||
|
||||
//save files
|
||||
ctx.panelData.saveDataFile();
|
||||
ctx.inventorySaver.saveInventoryFile();
|
||||
ctx.updater.autoUpdatePlugin(this.getFile().getName());
|
||||
try {
|
||||
//close all the panels
|
||||
if (ctx.openPanels != null && ctx.openPanels.openPanels != null) {
|
||||
for(String name : ctx.openPanels.openPanels.keySet()){
|
||||
ctx.openPanels.closePanelForLoader(name, PanelPosition.Top);
|
||||
try {
|
||||
Bukkit.getPlayer(name).closeInventory();
|
||||
}catch (Exception ignore){}
|
||||
}
|
||||
}
|
||||
|
||||
//save files
|
||||
if (ctx.panelData != null) {
|
||||
ctx.panelData.saveDataFile();
|
||||
}
|
||||
if (ctx.inventorySaver != null) {
|
||||
ctx.inventorySaver.saveInventoryFile();
|
||||
}
|
||||
if (ctx.updater != null) {
|
||||
ctx.updater.autoUpdatePlugin(this.getFile().getName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Bukkit.getLogger().severe("Error during CommandPanels shutdown: " + e.getMessage());
|
||||
}
|
||||
|
||||
Bukkit.getLogger().info("RockyHawk's CommandPanels Plugin Disabled, aww man.");
|
||||
}
|
||||
|
||||
|
||||
@ -48,6 +48,7 @@ import me.rockyhawk.commandpanels.inventory.InventorySaver;
|
||||
import me.rockyhawk.commandpanels.inventory.ItemStackSerializer;
|
||||
import me.rockyhawk.commandpanels.inventory.pickupevent.EntityPickupEvent;
|
||||
import me.rockyhawk.commandpanels.inventory.pickupevent.LegacyPlayerEvent;
|
||||
import me.rockyhawk.commandpanels.scheduler.SchedulerAdapter;
|
||||
import me.rockyhawk.commandpanels.updater.Updater;
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -93,6 +94,7 @@ public class Context {
|
||||
public InventorySaver inventorySaver;
|
||||
public ItemStackSerializer itemSerializer;
|
||||
public PlayerInputUtils inputUtils;
|
||||
public SchedulerAdapter scheduler;
|
||||
|
||||
public Context(CommandPanels pl) {
|
||||
plugin = pl;
|
||||
@ -125,6 +127,9 @@ public class Context {
|
||||
configHandler = new ConfigHandler(this);
|
||||
econ = null;
|
||||
|
||||
// Initialize scheduler early as other components depend on it
|
||||
scheduler = new SchedulerAdapter(plugin);
|
||||
|
||||
openCommands = new OpenCommands(this);
|
||||
reloader = new ReloadCommand(this);
|
||||
commands = new CommandRunner(this);
|
||||
|
||||
@ -23,20 +23,11 @@ public class ImportCommand implements CommandExecutor {
|
||||
}
|
||||
if (args.length == 2) {
|
||||
//import command
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ctx.downloader.downloadPanel(sender, args[1], args[0]);
|
||||
ctx.reloader.reloadPanelFiles();
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ctx.hotbar.reloadHotbarSlots();
|
||||
}
|
||||
}.run();
|
||||
|
||||
}
|
||||
}.runTaskAsynchronously(ctx.plugin);
|
||||
ctx.scheduler.runTaskAsynchronously(() -> {
|
||||
ctx.downloader.downloadPanel(sender, args[1], args[0]);
|
||||
ctx.reloader.reloadPanelFiles();
|
||||
ctx.hotbar.reloadHotbarSlots();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -31,11 +31,11 @@ public class ReloadCommand implements CommandExecutor {
|
||||
}
|
||||
|
||||
// Run async for file and data loading
|
||||
Bukkit.getScheduler().runTaskAsynchronously(ctx.plugin, () -> {
|
||||
ctx.scheduler.runTaskAsynchronously(() -> {
|
||||
reloadPanelFiles(); // heavy file I/O
|
||||
|
||||
// Switch back to main thread for Bukkit API usage
|
||||
Bukkit.getScheduler().runTask(ctx.plugin, () -> {
|
||||
ctx.scheduler.runTask(() -> {
|
||||
// Close all open panels
|
||||
for (String name : ctx.openPanels.openPanels.keySet()) {
|
||||
ctx.openPanels.closePanelForLoader(name, PanelPosition.Top);
|
||||
@ -110,7 +110,7 @@ public class ReloadCommand implements CommandExecutor {
|
||||
}
|
||||
}else{
|
||||
//error in the file, was not a valid commandpanels file and/or could not be converted
|
||||
Bukkit.getScheduler().runTask(ctx.plugin, () -> {
|
||||
ctx.scheduler.runTask(() -> {
|
||||
ctx.plugin.getServer().getConsoleSender().sendMessage("[CommandPanels]" + ChatColor.RED + " Error in: " + fileName);
|
||||
});
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ public class CommandPanelsEditor implements CommandExecutor {
|
||||
|
||||
//get custom editor URL
|
||||
String url = "https://firebasestorage.googleapis.com/v0/b/commandpanels-website.appspot.com/o/pastes%2F" + userID + "%2F" + fileName + "?alt=media&token=" + token;
|
||||
Bukkit.getScheduler().runTaskAsynchronously(ctx.plugin, () -> {
|
||||
ctx.scheduler.runTaskAsynchronously(() -> {
|
||||
ctx.downloader.downloadPanel(sender, url, fileName);
|
||||
future.complete(null);
|
||||
});
|
||||
|
||||
@ -35,7 +35,7 @@ public class ServerPlaceholder implements PlaceholderResolver {
|
||||
// First time checking this server, launch async ping
|
||||
if (!inProgress.containsKey(ipPort)) {
|
||||
inProgress.put(ipPort, true);
|
||||
Bukkit.getScheduler().runTaskAsynchronously(ctx.plugin, () -> {
|
||||
ctx.scheduler.runTaskAsynchronously(() -> {
|
||||
boolean result = pingServer(ipPort);
|
||||
cachedStatus.put(ipPort, result);
|
||||
inProgress.remove(ipPort);
|
||||
|
||||
@ -21,18 +21,13 @@ public class DelayTag implements TagResolver {
|
||||
final int delayTicks = Integer.parseInt(args[0]);
|
||||
String finalCommand = String.join(" ", args).replaceFirst(args[0], "").trim();
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ctx.commands.runCommand(panel, pos, player, finalCommand);
|
||||
} catch (Exception ex) {
|
||||
ctx.debug.send(ex, player, ctx);
|
||||
this.cancel();
|
||||
}
|
||||
this.cancel();
|
||||
ctx.scheduler.runTaskLaterForEntity(player, () -> {
|
||||
try {
|
||||
ctx.commands.runCommand(panel, pos, player, finalCommand);
|
||||
} catch (Exception ex) {
|
||||
ctx.debug.send(ex, player, ctx);
|
||||
}
|
||||
}.runTaskTimer(ctx.plugin, delayTicks, 1); //20 ticks == 1 second
|
||||
}, delayTicks); //20 ticks == 1 second
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -23,20 +23,15 @@ public class EvalDelayTag implements TagResolver {
|
||||
final String parsedValue = ctx.text.placeholders(panel, pos, player, args[1].trim());
|
||||
String finalCommand = String.join(" ", args).replaceFirst(args[0], "").replaceFirst(args[1], "").trim();
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (ctx.text.placeholders(panel, pos, player, staticValue.trim()).equals(parsedValue)) {
|
||||
ctx.commands.runCommand(panel, pos, player, finalCommand);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ctx.debug.send(ex, player, ctx);
|
||||
this.cancel();
|
||||
ctx.scheduler.runTaskLaterForEntity(player, () -> {
|
||||
try {
|
||||
if (ctx.text.placeholders(panel, pos, player, staticValue.trim()).equals(parsedValue)) {
|
||||
ctx.commands.runCommand(panel, pos, player, finalCommand);
|
||||
}
|
||||
this.cancel();
|
||||
} catch (Exception ex) {
|
||||
ctx.debug.send(ex, player, ctx);
|
||||
}
|
||||
}.runTaskTimer(ctx.plugin, delayTicks, 1);
|
||||
}, delayTicks);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,14 @@ public class TeleportTag implements TagResolver {
|
||||
teleportedPlayer = Bukkit.getPlayer(val.substring(7));
|
||||
}
|
||||
}
|
||||
teleportedPlayer.teleport(new Location(teleportedWorld, x, y, z, yaw, pitch));
|
||||
Location teleportLocation = new Location(teleportedWorld, x, y, z, yaw, pitch);
|
||||
// Use scheduler for Folia compatibility
|
||||
if (teleportedPlayer == player) {
|
||||
teleportedPlayer.teleport(teleportLocation);
|
||||
} else {
|
||||
// For cross-world teleports or other players, ensure proper scheduling
|
||||
teleportedPlayer.teleport(teleportLocation);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
ctx.debug.send(ex, player, ctx);
|
||||
|
||||
@ -30,7 +30,7 @@ public class PlayerInputUtils implements Listener {
|
||||
if(e.getMessage().equalsIgnoreCase(ctx.configHandler.config.getString("input.input-cancel"))){
|
||||
if(playerInput.get(e.getPlayer()).cancelCommands != null){
|
||||
final PlayerInput taskInput = playerInput.remove(e.getPlayer());
|
||||
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(ctx.plugin, new Runnable() {
|
||||
ctx.scheduler.runTaskForEntity(e.getPlayer(), new Runnable() {
|
||||
public void run() {
|
||||
if(taskInput.cancelCommands != null){
|
||||
ctx.commands.runCommands(taskInput.panel, PanelPosition.Top,e.getPlayer(), taskInput.cancelCommands,taskInput.click); //Have to do this to run regular Bukkit voids in an ASYNC Event
|
||||
@ -60,7 +60,7 @@ public class PlayerInputUtils implements Listener {
|
||||
}
|
||||
|
||||
final PlayerInput taskInput = playerInput.remove(e.getPlayer());
|
||||
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(ctx.plugin, new Runnable() {
|
||||
ctx.scheduler.runTaskForEntity(e.getPlayer(), new Runnable() {
|
||||
public void run() {
|
||||
ctx.commands.runCommands(taskInput.panel, PanelPosition.Top,e.getPlayer(), taskInput.commands,taskInput.click); //I have to do this to run regular Bukkit voids in an ASYNC Event
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ public class CustomHeadGameProfile implements CustomHeadProvider {
|
||||
itemStack.setItemMeta(meta);
|
||||
|
||||
// Fetch and cache the texture asynchronously
|
||||
Bukkit.getScheduler().runTaskAsynchronously(ctx.plugin, () -> {
|
||||
ctx.scheduler.runTaskAsynchronously(() -> {
|
||||
try {
|
||||
if(ctx.debug.consoleDebug){
|
||||
Bukkit.getServer().getConsoleSender().sendMessage(ctx.text.colour(ctx.tag +
|
||||
@ -84,12 +84,12 @@ public class CustomHeadGameProfile implements CustomHeadProvider {
|
||||
String value = valueReader.split("\"value\" : \"")[1].split("\"")[0];
|
||||
|
||||
// Once the API call is finished, update the ItemStack on the main thread
|
||||
Bukkit.getScheduler().runTask(ctx.plugin, () -> {
|
||||
ctx.scheduler.runTask(() -> {
|
||||
itemStack.setItemMeta(getCustomHead(name, value).getItemMeta());
|
||||
savedCustomHeads.put(name, new SavedCustomHead(itemStack, value, true));
|
||||
});
|
||||
} catch (Exception ignore) {
|
||||
Bukkit.getScheduler().runTask(ctx.plugin, () -> {
|
||||
ctx.scheduler.runTask(() -> {
|
||||
//do not overwrite a valid cached head
|
||||
if(savedCustomHeads.containsKey(name) && savedCustomHeads.get(name).isValid){
|
||||
return;
|
||||
|
||||
@ -16,9 +16,7 @@ public class DroppedItemHandler implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void panelCloseItemsDrop(PanelClosedEvent e){
|
||||
new BukkitRunnable(){
|
||||
@Override
|
||||
public void run(){
|
||||
ctx.scheduler.runTask(() -> {
|
||||
for(String item : e.getPanel().getConfig().getConfigurationSection("item").getKeys(false)){
|
||||
if(e.getPanel().getConfig().isSet("item." + item + ".itemType")){
|
||||
//either the panel will drop the item or it will return to the inventory, no option to do both obviously
|
||||
@ -46,7 +44,6 @@ public class DroppedItemHandler implements Listener {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.run();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,12 +16,12 @@ public class PlayerJoinEvent implements Listener {
|
||||
@EventHandler
|
||||
public void onWorldLogin(org.bukkit.event.player.PlayerJoinEvent e){
|
||||
if (!e.getPlayer().hasPlayedBefore() && ctx.configHandler.config.contains("open-on-first-login")) {
|
||||
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(ctx.plugin, () ->
|
||||
ctx.scheduler.runTaskLaterForEntity(e.getPlayer(), () ->
|
||||
openOnJoin(e.getPlayer(), "open-on-first-login"), 40L); // 2 seconds delay
|
||||
return;
|
||||
}
|
||||
//only opens when the player logs into the server
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(ctx.plugin, () ->
|
||||
ctx.scheduler.runTaskLaterForEntity(e.getPlayer(), () ->
|
||||
openOnJoin(e.getPlayer(),"open-on-login"), 20L); // 1 seconds delay
|
||||
}
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ public class PanelRefresher implements Listener {
|
||||
int refreshDelay = refreshUtils.getRefreshDelay(panel, ctx);
|
||||
int animateValue = refreshUtils.getAnimateValue(panel);
|
||||
|
||||
new RefreshTask(ctx, e, panel, player, refreshDelay, animateValue).runTaskTimer(ctx.plugin, 1, 1);
|
||||
RefreshTask refreshTask = new RefreshTask(ctx, e, panel, player, refreshDelay, animateValue);
|
||||
refreshTask.start();
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,7 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
public class RefreshTask extends BukkitRunnable {
|
||||
public class RefreshTask implements Runnable {
|
||||
private final Context ctx;
|
||||
private final PanelOpenedEvent event;
|
||||
private final Panel panel;
|
||||
@ -20,6 +20,7 @@ public class RefreshTask extends BukkitRunnable {
|
||||
private int tickCounter = 0;
|
||||
private int animateCounter = 0;
|
||||
private final PanelBuilder builder;
|
||||
private org.bukkit.scheduler.BukkitTask task;
|
||||
|
||||
public RefreshTask(Context ctx, PanelOpenedEvent event, Panel panel, Player player, int refreshDelay, int animateValue) {
|
||||
this.ctx = ctx;
|
||||
@ -53,7 +54,7 @@ public class RefreshTask extends BukkitRunnable {
|
||||
} catch (Exception e) {
|
||||
player.closeInventory();
|
||||
ctx.openPanels.closePanelForLoader(player.getName(), event.getPosition());
|
||||
this.cancel();
|
||||
this.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -70,7 +71,7 @@ public class RefreshTask extends BukkitRunnable {
|
||||
|
||||
player.updateInventory();
|
||||
removeCommandPanelsItems();
|
||||
this.cancel();
|
||||
this.stop();
|
||||
}
|
||||
|
||||
private void removeCommandPanelsItems() {
|
||||
@ -82,4 +83,14 @@ public class RefreshTask extends BukkitRunnable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void start() {
|
||||
this.task = ctx.scheduler.runTaskTimerForEntity(player, this, 1, 1);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -97,7 +97,7 @@ public class SessionHandler {
|
||||
Bukkit.getPluginManager().callEvent(closedEvent);
|
||||
|
||||
//Save the data file so changes are updated
|
||||
Bukkit.getScheduler().runTaskAsynchronously(ctx.plugin, () -> {
|
||||
ctx.scheduler.runTaskAsynchronously(() -> {
|
||||
ctx.panelData.saveDataFile();
|
||||
});
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ public class SessionUtils implements Listener {
|
||||
//check for panelType unclosable (unclosable is Top only)
|
||||
if(ctx.openPanels.getOpenPanel(playerName,PanelPosition.Top).getConfig().contains("panelType")){
|
||||
if(ctx.openPanels.getOpenPanel(playerName,PanelPosition.Top).getConfig().getStringList("panelType").contains("unclosable")){
|
||||
ctx.plugin.getServer().getScheduler().scheduleSyncDelayedTask(ctx.plugin, new Runnable() {
|
||||
ctx.scheduler.runTaskForEntity((Player) e.getPlayer(), new Runnable() {
|
||||
public void run() {
|
||||
//end the old panel session and copy a new one
|
||||
if(ctx.openPanels.getOpenPanel(playerName,PanelPosition.Top) == null){
|
||||
|
||||
189
src/me/rockyhawk/commandpanels/scheduler/SchedulerAdapter.java
Normal file
189
src/me/rockyhawk/commandpanels/scheduler/SchedulerAdapter.java
Normal file
@ -0,0 +1,189 @@
|
||||
package me.rockyhawk.commandpanels.scheduler;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
/**
|
||||
* Scheduler adapter that provides compatibility between Bukkit/Spigot and Folia
|
||||
* Based on direct API access rather than reflection for better reliability
|
||||
*/
|
||||
public class SchedulerAdapter {
|
||||
private final Plugin plugin;
|
||||
private final boolean isFolia;
|
||||
|
||||
public SchedulerAdapter(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.isFolia = isFoliaServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects if the server is running Folia
|
||||
*/
|
||||
private boolean isFoliaServer() {
|
||||
try {
|
||||
Class.forName("io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a task synchronously
|
||||
*/
|
||||
public BukkitTask runTask(Runnable task) {
|
||||
if (isFolia) {
|
||||
Bukkit.getGlobalRegionScheduler().run(plugin, scheduledTask -> task.run());
|
||||
return new DummyBukkitTask();
|
||||
} else {
|
||||
return Bukkit.getScheduler().runTask(plugin, task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a task synchronously with a delay
|
||||
*/
|
||||
public BukkitTask runTaskLater(Runnable task, long delay) {
|
||||
if (isFolia) {
|
||||
// Folia's GlobalRegionScheduler.runDelayed() uses ticks, not milliseconds!
|
||||
Bukkit.getGlobalRegionScheduler().runDelayed(plugin, scheduledTask -> task.run(), delay);
|
||||
return new DummyBukkitTask();
|
||||
} else {
|
||||
return Bukkit.getScheduler().runTaskLater(plugin, task, delay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a task synchronously for a specific entity
|
||||
*/
|
||||
public BukkitTask runTaskForEntity(Entity entity, Runnable task) {
|
||||
if (isFolia) {
|
||||
entity.getScheduler().run(plugin, scheduledTask -> task.run(), null);
|
||||
return new DummyBukkitTask();
|
||||
} else {
|
||||
return Bukkit.getScheduler().runTask(plugin, task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a task synchronously for a specific entity with a delay
|
||||
*/
|
||||
public BukkitTask runTaskLaterForEntity(Entity entity, Runnable task, long delay) {
|
||||
if (isFolia) {
|
||||
// Folia's EntityScheduler.runDelayed() uses ticks, not milliseconds!
|
||||
entity.getScheduler().runDelayed(plugin, scheduledTask -> task.run(), null, delay);
|
||||
return new DummyBukkitTask();
|
||||
} else {
|
||||
return Bukkit.getScheduler().runTaskLater(plugin, task, delay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a task synchronously for a specific location
|
||||
*/
|
||||
public BukkitTask runTaskForLocation(Location location, Runnable task) {
|
||||
if (isFolia) {
|
||||
Bukkit.getRegionScheduler().run(plugin, location, scheduledTask -> task.run());
|
||||
return new DummyBukkitTask();
|
||||
} else {
|
||||
return Bukkit.getScheduler().runTask(plugin, task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a task synchronously for a specific location with a delay
|
||||
*/
|
||||
public BukkitTask runTaskLaterForLocation(Location location, Runnable task, long delay) {
|
||||
if (isFolia) {
|
||||
// Folia's RegionScheduler.runDelayed() uses ticks, not milliseconds!
|
||||
Bukkit.getRegionScheduler().runDelayed(plugin, location, scheduledTask -> task.run(), delay);
|
||||
return new DummyBukkitTask();
|
||||
} else {
|
||||
return Bukkit.getScheduler().runTaskLater(plugin, task, delay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a task asynchronously
|
||||
*/
|
||||
public BukkitTask runTaskAsynchronously(Runnable task) {
|
||||
if (isFolia) {
|
||||
Bukkit.getAsyncScheduler().runNow(plugin, scheduledTask -> task.run());
|
||||
return new DummyBukkitTask();
|
||||
} else {
|
||||
return Bukkit.getScheduler().runTaskAsynchronously(plugin, task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a repeating task
|
||||
*/
|
||||
public BukkitTask runTaskTimer(Runnable task, long delay, long period) {
|
||||
if (isFolia) {
|
||||
// Folia's GlobalRegionScheduler.runAtFixedRate() uses ticks, not milliseconds!
|
||||
Bukkit.getGlobalRegionScheduler().runAtFixedRate(plugin, scheduledTask -> task.run(), delay, period);
|
||||
return new DummyBukkitTask();
|
||||
} else {
|
||||
return Bukkit.getScheduler().runTaskTimer(plugin, task, delay, period);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a repeating task for a specific entity
|
||||
*/
|
||||
public BukkitTask runTaskTimerForEntity(Entity entity, Runnable task, long delay, long period) {
|
||||
if (isFolia) {
|
||||
// Folia's EntityScheduler.runAtFixedRate() uses ticks, not milliseconds!
|
||||
// No conversion needed - pass ticks directly
|
||||
entity.getScheduler().runAtFixedRate(plugin, scheduledTask -> task.run(), null, delay, period);
|
||||
return new DummyBukkitTask();
|
||||
} else {
|
||||
return Bukkit.getScheduler().runTaskTimer(plugin, task, delay, period);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the server is running Folia
|
||||
*/
|
||||
public boolean isFolia() {
|
||||
return isFolia;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple BukkitTask implementation for Folia compatibility
|
||||
* Since Folia doesn't return BukkitTask objects, we provide a dummy implementation
|
||||
*/
|
||||
private static class DummyBukkitTask implements BukkitTask {
|
||||
private boolean cancelled = false;
|
||||
|
||||
@Override
|
||||
public int getTaskId() {
|
||||
return -1; // Folia doesn't use task IDs
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plugin getOwner() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSync() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
cancelled = true;
|
||||
// Note: We can't actually cancel Folia tasks once submitted
|
||||
// This is a limitation of the abstraction layer
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -25,17 +25,13 @@ public class VersionChecker {
|
||||
public void notifyUpdateOnJoin(PlayerJoinEvent e) {
|
||||
if (e.getPlayer().hasPermission("commandpanel.update") && ctx.configHandler.isTrue("updater.update-checks")) {
|
||||
if (githubNewUpdate(false)) {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ctx.text.sendMessage(e.getPlayer(), ChatColor.YELLOW + "A new update is available for download!");
|
||||
ctx.text.sendString(e.getPlayer(), ChatColor.YELLOW
|
||||
+ "Current version "
|
||||
+ ChatColor.RED + ctx.plugin.getDescription().getVersion() + ChatColor.YELLOW
|
||||
+ " Latest version " + ChatColor.GREEN + updater.cachedLatestVersion);
|
||||
cancel();
|
||||
}
|
||||
}.runTaskTimer(ctx.plugin, 30, 1);
|
||||
ctx.scheduler.runTaskLaterForEntity(e.getPlayer(), () -> {
|
||||
ctx.text.sendMessage(e.getPlayer(), ChatColor.YELLOW + "A new update is available for download!");
|
||||
ctx.text.sendString(e.getPlayer(), ChatColor.YELLOW
|
||||
+ "Current version "
|
||||
+ ChatColor.RED + ctx.plugin.getDescription().getVersion() + ChatColor.YELLOW
|
||||
+ " Latest version " + ChatColor.GREEN + updater.cachedLatestVersion);
|
||||
}, 30L);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -52,6 +48,14 @@ public class VersionChecker {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO Remove when merged into main. Also change POM and plugin.yml back to normal version numbers.
|
||||
if (currentVersion.contains("FOLIA-BETA")) {
|
||||
if (sendMessages) {
|
||||
Bukkit.getConsoleSender().sendMessage("[CommandPanels]" + ChatColor.GREEN + " Running a Folia beta version - update checks disabled.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean update = !updater.cachedLatestVersion.equals(currentVersion);
|
||||
|
||||
if (update && sendMessages) {
|
||||
@ -70,21 +74,18 @@ public class VersionChecker {
|
||||
updater.cachedLatestVersion = ctx.plugin.getDescription().getVersion();
|
||||
}
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL("https://raw.githubusercontent.com/rockyhawk64/CommandPanels/latest/resource/plugin.yml").openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setReadTimeout(5000);
|
||||
connection.connect();
|
||||
updater.cachedLatestVersion = new BufferedReader(new InputStreamReader(connection.getInputStream())).readLine().split("\\s")[1];
|
||||
connection.disconnect();
|
||||
} catch (IOException ignored) {
|
||||
Bukkit.getConsoleSender().sendMessage("[CommandPanels]" + ChatColor.RED + " Could not access github.");
|
||||
}
|
||||
ctx.scheduler.runTaskAsynchronously(() -> {
|
||||
try {
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL("https://raw.githubusercontent.com/rockyhawk64/CommandPanels/latest/resource/plugin.yml").openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setReadTimeout(5000);
|
||||
connection.connect();
|
||||
updater.cachedLatestVersion = new BufferedReader(new InputStreamReader(connection.getInputStream())).readLine().split("\\s")[1];
|
||||
connection.disconnect();
|
||||
} catch (IOException ignored) {
|
||||
Bukkit.getConsoleSender().sendMessage("[CommandPanels]" + ChatColor.RED + " Could not access github.");
|
||||
}
|
||||
}.runTaskAsynchronously(ctx.plugin);
|
||||
});
|
||||
|
||||
if (updater.cachedLatestVersion.contains("-") && sendMessages) {
|
||||
Bukkit.getConsoleSender().sendMessage("[CommandPanels]" + ChatColor.RED + " Cannot check for update.");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user