diff --git a/pom.xml b/pom.xml index 772a8e0..e65e08a 100644 --- a/pom.xml +++ b/pom.xml @@ -36,6 +36,10 @@ spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + papermc + https://repo.papermc.io/repository/maven-public/ + @@ -46,6 +50,13 @@ 1.21.3-R0.1-SNAPSHOT provided + + + dev.folia + folia-api + 1.21.4-R0.1-SNAPSHOT + provided + @@ -93,12 +104,6 @@ bukkit-server-version 0.0.2 - - - community.leaf.tasks - tasks-bukkit - 0.0.2 - org.bstats diff --git a/src/main/java/community/leaf/survival/concretemixer/CauldronPowderDropListener.java b/src/main/java/community/leaf/survival/concretemixer/CauldronPowderDropListener.java index 41cdd92..f32707b 100644 --- a/src/main/java/community/leaf/survival/concretemixer/CauldronPowderDropListener.java +++ b/src/main/java/community/leaf/survival/concretemixer/CauldronPowderDropListener.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -13,8 +13,8 @@ import community.leaf.eventful.bukkit.annotations.CancelledEvents; import community.leaf.eventful.bukkit.annotations.EventListener; import community.leaf.survival.concretemixer.metrics.TransformationsPerHour; +import community.leaf.survival.concretemixer.util.folia.FoliaRunnable; import community.leaf.survival.concretemixer.util.internal.ConcreteDebug; -import community.leaf.tasks.TaskContext; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; @@ -27,7 +27,6 @@ import org.bukkit.event.entity.ItemMergeEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitTask; import org.bukkit.util.Vector; import pl.tlinkowski.annotation.basic.NullOr; @@ -37,7 +36,7 @@ import java.util.UUID; public class CauldronPowderDropListener implements Listener { - private final Map> transformationTasksByItemUuid = new HashMap<>(); + private final Map transformationTasksByItemUuid = new HashMap<>(); private final ConcreteMixerPlugin plugin; private final TransformationsPerHour counter; @@ -117,22 +116,17 @@ public void onCauldronLevelChange(CauldronLevelChangeEvent event) { } private boolean cancelExistingTransformation(Item item) { - @NullOr TaskContext task = + @NullOr FoliaRunnable runnable = transformationTasksByItemUuid.remove(item.getUniqueId()); - if (task != null) { - task.cancel(); + if (runnable != null) { + runnable.cancel(); return true; } return false; } - private void cancel(Item item, TaskContext task) { - transformationTasksByItemUuid.remove(item.getUniqueId()); - task.cancel(); - } - private @NullOr Entity entity(@NullOr UUID uuid) { return (uuid == null) ? null : plugin.getServer().getEntity(uuid); } @@ -144,113 +138,120 @@ class IterationCounter { } IterationCounter iterations = new IterationCounter(); - transformationTasksByItemUuid.put( item.getUniqueId(), - plugin.sync().delay(2).ticks().every(2).ticks().run(task -> + plugin.getScheduler().runTaskTimer(item.getLocation(), new FoliaRunnable() { - Block cauldron = item.getLocation().getBlock(); - Material material = item.getItemStack().getType(); - - // Outside the cauldron, dropping in ... (or not) - if (cauldron.getType() != Material.WATER_CAULDRON) { - iterations.outside++; - - // Took too long to drop in, might not even be a cauldron nearby for all we know - if (iterations.outside > 20) { - cancel(item, task); - } - - return; + private void cancel(Item item) { + transformationTasksByItemUuid.remove(item.getUniqueId()); + cancel(); } - - // Inside the cauldron - iterations.inside++; - boolean lowerWaterLevel = plugin.config().getOrDefault(Config.LOWER_WATER_LEVEL); - - // Check if player is allowed to use this specific cauldron - // (only if water level gets lowered, since that could be considered griefing) - if (lowerWaterLevel && entity(item.getThrower()) instanceof Player player) { - if (!plugin.permissions().canAccessCauldron(player, cauldron)) { - cancel(item, task); + + @Override + public void run() { + Block cauldron = item.getLocation().getBlock(); + Material material = item.getItemStack().getType(); + + // Outside the cauldron, dropping in ... (or not) + if (cauldron.getType() != Material.WATER_CAULDRON) { + iterations.outside++; + + // Took too long to drop in, might not even be a cauldron nearby for all we know + if (iterations.outside > 20) { + cancel(item); + } + return; } - } - - // TODO: more sophisticated merging - // Attempt to merge item stacks - if (experimentalItemMerging && item.getItemStack().getAmount() == 1) { - for (Entity nearby : item.getNearbyEntities(0.5, 0.5, 0.5)) { - if (!(nearby instanceof Item cooking)) { - continue; - } - if (!transformationTasksByItemUuid.containsKey(cooking.getUniqueId())) { - continue; - } - if (!Objects.equals(item.getThrower(), cooking.getThrower())) { - continue; - } - - ItemStack cooked = cooking.getItemStack(); - if (cooked.getAmount() >= 64 || cooked.getType() != material) { - continue; + + // Inside the cauldron + iterations.inside++; + boolean lowerWaterLevel = plugin.config().getOrDefault(Config.LOWER_WATER_LEVEL); + + // Check if player is allowed to use this specific cauldron + // (only if water level gets lowered, since that could be considered griefing) + if (lowerWaterLevel && entity(item.getThrower()) instanceof Player player) { + if (!plugin.permissions().canAccessCauldron(player, cauldron)) { + cancel(item); + return; } - if (plugin.events().call(new ItemMergeEvent(item, cooking)).isCancelled()) { - continue; // merge cancelled, try another neighbor + } + + // TODO: more sophisticated merging + // Attempt to merge item stacks + if (experimentalItemMerging && item.getItemStack().getAmount() == 1) { + for (Entity nearby : item.getNearbyEntities(0.5, 0.5, 0.5)) { + if (!(nearby instanceof Item cooking)) { + continue; + } + if (!transformationTasksByItemUuid.containsKey(cooking.getUniqueId())) { + continue; + } + if (!Objects.equals(item.getThrower(), cooking.getThrower())) { + continue; + } + + ItemStack cooked = cooking.getItemStack(); + if (cooked.getAmount() >= 64 || cooked.getType() != material) { + continue; + } + if (plugin.events().call(new ItemMergeEvent(item, cooking)).isCancelled()) { + continue; // merge cancelled, try another neighbor + } + + cooked.setAmount(cooked.getAmount() + 1); + item.remove(); + + cancel(item); + return; } - - cooked.setAmount(cooked.getAmount() + 1); - item.remove(); - - cancel(item, task); + } + + if (iterations.inside == 1) { + item.setPickupDelay(40); + plugin.effects().cauldronSplashSound(item.getLocation()); + } + + if (iterations.inside < 15) { + plugin.effects().cauldronSplashParticles(cauldron); return; } + + // Done with this task... it's finally time to transform the powder! + cancel(item); + + @NullOr Concrete concrete = Concrete.ofPowder(material).orElse(null); + if (concrete == null) { + return; + } + + ItemStack stack = item.getItemStack(); + stack.setType(concrete.concrete()); + item.setItemStack(stack); + + item.setVelocity(new Vector(0, 0.3, 0)); + item.setPickupDelay(10); + + plugin.effects().concreteTransform(cauldron); + counter.transformed(stack.getAmount()); + + if (!lowerWaterLevel) { + return; + } + if (!(cauldron.getBlockData() instanceof Levelled levelled)) { + return; + } + + int level = levelled.getLevel() - 1; + + if (level <= 0) { + cauldron.setType(Material.CAULDRON); + } else { + levelled.setLevel(level); + cauldron.setBlockData(levelled); + } } - - if (iterations.inside == 1) { - item.setPickupDelay(40); - plugin.effects().cauldronSplashSound(item.getLocation()); - } - - if (iterations.inside < 15) { - plugin.effects().cauldronSplashParticles(cauldron); - return; - } - - // Done with this task... it's finally time to transform the powder! - cancel(item, task); - - @NullOr Concrete concrete = Concrete.ofPowder(material).orElse(null); - if (concrete == null) { - return; - } - - ItemStack stack = item.getItemStack(); - stack.setType(concrete.concrete()); - item.setItemStack(stack); - - item.setVelocity(new Vector(0, 0.3, 0)); - item.setPickupDelay(10); - - plugin.effects().concreteTransform(cauldron); - counter.transformed(stack.getAmount()); - - if (!lowerWaterLevel) { - return; - } - if (!(cauldron.getBlockData() instanceof Levelled levelled)) { - return; - } - - int level = levelled.getLevel() - 1; - - if (level <= 0) { - cauldron.setType(Material.CAULDRON); - } else { - levelled.setLevel(level); - cauldron.setBlockData(levelled); - } - }) + }, 2, 2) ); } diff --git a/src/main/java/community/leaf/survival/concretemixer/Concrete.java b/src/main/java/community/leaf/survival/concretemixer/Concrete.java index ed69699..6c830c1 100644 --- a/src/main/java/community/leaf/survival/concretemixer/Concrete.java +++ b/src/main/java/community/leaf/survival/concretemixer/Concrete.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/ConcreteMixerCommand.java b/src/main/java/community/leaf/survival/concretemixer/ConcreteMixerCommand.java index 98706cd..dd26f36 100644 --- a/src/main/java/community/leaf/survival/concretemixer/ConcreteMixerCommand.java +++ b/src/main/java/community/leaf/survival/concretemixer/ConcreteMixerCommand.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/ConcreteMixerPlugin.java b/src/main/java/community/leaf/survival/concretemixer/ConcreteMixerPlugin.java index 49978e7..58da321 100644 --- a/src/main/java/community/leaf/survival/concretemixer/ConcreteMixerPlugin.java +++ b/src/main/java/community/leaf/survival/concretemixer/ConcreteMixerPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -11,7 +11,7 @@ import community.leaf.eventful.bukkit.BukkitEventSource; import community.leaf.survival.concretemixer.hooks.HookHandler; import community.leaf.survival.concretemixer.metrics.TransformationsPerHour; -import community.leaf.tasks.bukkit.BukkitTaskSource; +import community.leaf.survival.concretemixer.util.folia.SchedulerUtils; import org.bstats.bukkit.Metrics; import org.bstats.charts.SingleLineChart; import org.bukkit.command.PluginCommand; @@ -21,7 +21,10 @@ import java.nio.file.Path; -public class ConcreteMixerPlugin extends JavaPlugin implements BukkitEventSource, BukkitTaskSource { +public class ConcreteMixerPlugin extends JavaPlugin implements BukkitEventSource { + private boolean usingFolia = false; + + private @NullOr SchedulerUtils scheduler; private @NullOr Version version; private @NullOr Path directory; private @NullOr Config config; @@ -29,6 +32,17 @@ public class ConcreteMixerPlugin extends JavaPlugin implements BukkitEventSource private @NullOr HookHandler hooks; private @NullOr PermissionHandler permissions; private @NullOr UpdateChecker updates; + + @Override + public void onLoad() { + try { + Class.forName("io.papermc.paper.threadedregions.scheduler.RegionScheduler"); + usingFolia = true; + } catch (ClassNotFoundException e) { + usingFolia = false; + } + scheduler = new SchedulerUtils(this); + } @Override public void onEnable() { @@ -69,6 +83,14 @@ private static T initialized(@NullOr T thing) { public Plugin plugin() { return this; } + + public boolean isFolia() { + return usingFolia; + } + + public SchedulerUtils getScheduler() { + return scheduler; + } public Version version() { return initialized(version); diff --git a/src/main/java/community/leaf/survival/concretemixer/Config.java b/src/main/java/community/leaf/survival/concretemixer/Config.java index 9f66762..d9bc4e4 100644 --- a/src/main/java/community/leaf/survival/concretemixer/Config.java +++ b/src/main/java/community/leaf/survival/concretemixer/Config.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/EffectHandler.java b/src/main/java/community/leaf/survival/concretemixer/EffectHandler.java index eddd107..2791a2d 100644 --- a/src/main/java/community/leaf/survival/concretemixer/EffectHandler.java +++ b/src/main/java/community/leaf/survival/concretemixer/EffectHandler.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/PermissionHandler.java b/src/main/java/community/leaf/survival/concretemixer/PermissionHandler.java index 1f87b71..6f352ae 100644 --- a/src/main/java/community/leaf/survival/concretemixer/PermissionHandler.java +++ b/src/main/java/community/leaf/survival/concretemixer/PermissionHandler.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/UpdateChecker.java b/src/main/java/community/leaf/survival/concretemixer/UpdateChecker.java index 743b197..ea2ac92 100644 --- a/src/main/java/community/leaf/survival/concretemixer/UpdateChecker.java +++ b/src/main/java/community/leaf/survival/concretemixer/UpdateChecker.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -16,9 +16,8 @@ import community.leaf.evergreen.bukkit.versions.MinecraftVersion; import community.leaf.survival.concretemixer.util.Strings; import community.leaf.survival.concretemixer.util.Versions; -import community.leaf.tasks.TaskContext; +import community.leaf.survival.concretemixer.util.folia.FoliaRunnable; import net.md_5.bungee.api.ChatColor; -import org.bukkit.scheduler.BukkitTask; import pl.tlinkowski.annotation.basic.NullOr; import java.net.URI; @@ -40,7 +39,7 @@ public class UpdateChecker { private final String userAgent; private final URI modrinthProjectVersionsUri; - private @NullOr TaskContext task; + private @NullOr FoliaRunnable runnable; private volatile @NullOr Version latestAvailableVersion; public UpdateChecker(ConcreteMixerPlugin plugin) { @@ -60,7 +59,7 @@ public UpdateChecker(ConcreteMixerPlugin plugin) { } public boolean isRunningUpdateCheckTask() { - return task != null && !task.isCancelled(); + return runnable != null && !runnable.isCancelled(); } public Optional latestAvailableVersion() { @@ -82,16 +81,22 @@ public Optional latestUpdateUrl() { } public void end() { - if (task != null) { - task.cancel(); + if (runnable != null) { + runnable.cancel(); } } public void reload() { if (plugin.config().getOrDefault(Config.UPDATES)) { - if (task == null || task.isCancelled()) { - int duration = ThreadLocalRandom.current().nextInt(6, 12); - this.task = plugin.async().delay(10).ticks().every(duration).hours().run(this::checkForUpdates); + if (runnable == null || runnable.isCancelled()) { + long duration = ThreadLocalRandom.current().nextInt(6, 12)*1000L*60L*60L; + runnable = new FoliaRunnable() { + @Override + public void run() { + checkForUpdates(); + } + }; + plugin.getScheduler().runTaskTimerAsynchronously(runnable, 10, duration); } } else { latestAvailableVersion = null; @@ -166,8 +171,8 @@ private void checkForUpdates() { this.latestAvailableVersion = latest; } catch (Exception ignored) { } - - plugin.sync().run(this::notifyConsoleIfUpdateAvailable); + + plugin.getScheduler().runTaskAsynchronously(this::notifyConsoleIfUpdateAvailable); } private void print(String text) { diff --git a/src/main/java/community/leaf/survival/concretemixer/hooks/CauldronAccessHook.java b/src/main/java/community/leaf/survival/concretemixer/hooks/CauldronAccessHook.java index b9b6952..3a8353d 100644 --- a/src/main/java/community/leaf/survival/concretemixer/hooks/CauldronAccessHook.java +++ b/src/main/java/community/leaf/survival/concretemixer/hooks/CauldronAccessHook.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/hooks/Hook.java b/src/main/java/community/leaf/survival/concretemixer/hooks/Hook.java index f9c06e6..060d2b1 100644 --- a/src/main/java/community/leaf/survival/concretemixer/hooks/Hook.java +++ b/src/main/java/community/leaf/survival/concretemixer/hooks/Hook.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/hooks/HookHandler.java b/src/main/java/community/leaf/survival/concretemixer/hooks/HookHandler.java index b27a678..7d889b4 100644 --- a/src/main/java/community/leaf/survival/concretemixer/hooks/HookHandler.java +++ b/src/main/java/community/leaf/survival/concretemixer/hooks/HookHandler.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/hooks/RegisteredHook.java b/src/main/java/community/leaf/survival/concretemixer/hooks/RegisteredHook.java index 88d63cc..42010ab 100644 --- a/src/main/java/community/leaf/survival/concretemixer/hooks/RegisteredHook.java +++ b/src/main/java/community/leaf/survival/concretemixer/hooks/RegisteredHook.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/hooks/impl/GriefPreventionCauldronAccessHook.java b/src/main/java/community/leaf/survival/concretemixer/hooks/impl/GriefPreventionCauldronAccessHook.java index af5de03..83a4978 100644 --- a/src/main/java/community/leaf/survival/concretemixer/hooks/impl/GriefPreventionCauldronAccessHook.java +++ b/src/main/java/community/leaf/survival/concretemixer/hooks/impl/GriefPreventionCauldronAccessHook.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/hooks/impl/UniversalCauldronAccessHook.java b/src/main/java/community/leaf/survival/concretemixer/hooks/impl/UniversalCauldronAccessHook.java index ff5f53c..2e948ed 100644 --- a/src/main/java/community/leaf/survival/concretemixer/hooks/impl/UniversalCauldronAccessHook.java +++ b/src/main/java/community/leaf/survival/concretemixer/hooks/impl/UniversalCauldronAccessHook.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/hooks/impl/package-info.java b/src/main/java/community/leaf/survival/concretemixer/hooks/impl/package-info.java index 1816522..1d94d43 100644 --- a/src/main/java/community/leaf/survival/concretemixer/hooks/impl/package-info.java +++ b/src/main/java/community/leaf/survival/concretemixer/hooks/impl/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/hooks/package-info.java b/src/main/java/community/leaf/survival/concretemixer/hooks/package-info.java index b12a78c..8a5aee6 100644 --- a/src/main/java/community/leaf/survival/concretemixer/hooks/package-info.java +++ b/src/main/java/community/leaf/survival/concretemixer/hooks/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/metrics/TransformationsPerHour.java b/src/main/java/community/leaf/survival/concretemixer/metrics/TransformationsPerHour.java index 48c7ca1..431a67c 100644 --- a/src/main/java/community/leaf/survival/concretemixer/metrics/TransformationsPerHour.java +++ b/src/main/java/community/leaf/survival/concretemixer/metrics/TransformationsPerHour.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/metrics/package-info.java b/src/main/java/community/leaf/survival/concretemixer/metrics/package-info.java index f2c6711..5a234de 100644 --- a/src/main/java/community/leaf/survival/concretemixer/metrics/package-info.java +++ b/src/main/java/community/leaf/survival/concretemixer/metrics/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/package-info.java b/src/main/java/community/leaf/survival/concretemixer/package-info.java index fc21617..40328a4 100644 --- a/src/main/java/community/leaf/survival/concretemixer/package-info.java +++ b/src/main/java/community/leaf/survival/concretemixer/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/util/Strings.java b/src/main/java/community/leaf/survival/concretemixer/util/Strings.java index a943538..db4e8cc 100644 --- a/src/main/java/community/leaf/survival/concretemixer/util/Strings.java +++ b/src/main/java/community/leaf/survival/concretemixer/util/Strings.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/util/Versions.java b/src/main/java/community/leaf/survival/concretemixer/util/Versions.java index 0c683fd..b218628 100644 --- a/src/main/java/community/leaf/survival/concretemixer/util/Versions.java +++ b/src/main/java/community/leaf/survival/concretemixer/util/Versions.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/util/folia/FoliaRunnable.java b/src/main/java/community/leaf/survival/concretemixer/util/folia/FoliaRunnable.java new file mode 100644 index 0000000..7ab7a02 --- /dev/null +++ b/src/main/java/community/leaf/survival/concretemixer/util/folia/FoliaRunnable.java @@ -0,0 +1,29 @@ +/* + * Copyright © 2022-2025, RezzedUp and Contributors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package community.leaf.survival.concretemixer.util.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/community/leaf/survival/concretemixer/util/folia/SchedulerUtils.java b/src/main/java/community/leaf/survival/concretemixer/util/folia/SchedulerUtils.java new file mode 100644 index 0000000..768a105 --- /dev/null +++ b/src/main/java/community/leaf/survival/concretemixer/util/folia/SchedulerUtils.java @@ -0,0 +1,182 @@ +/* + * Copyright © 2022-2025, RezzedUp and Contributors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package community.leaf.survival.concretemixer.util.folia; + +import community.leaf.survival.concretemixer.ConcreteMixerPlugin; +import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler; +import io.papermc.paper.threadedregions.scheduler.RegionScheduler; +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import org.bukkit.Location; + +import java.lang.reflect.Method; + +/** + * Utility class for scheduling tasks in a Paper/Folia server. + */ +public class SchedulerUtils { + + private final ConcreteMixerPlugin plugin; + + public SchedulerUtils(ConcreteMixerPlugin plugin) { + this.plugin = plugin; + } + + /** + * 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 void runTaskLater(Location loc, Runnable task, long delay) { + if (plugin.isFolia()) { + 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 + ); + } + } catch (Exception e) { + e.printStackTrace(); + } + return; + } + plugin.getServer().getScheduler().runTaskLater(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. + * @return + */ + public FoliaRunnable runTaskTimer(Location loc, FoliaRunnable runnable, long delay, long period) { + if (plugin.isFolia()) { + 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; + } + runnable.runTaskTimer(plugin, delay, period); + return runnable; + } + + /** + * 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. + * @return + */ + public FoliaRunnable runTaskTimerAsynchronously(FoliaRunnable runnable, long delay, long period) { + if (plugin.isFolia()) { + 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; + } + runnable.runTaskTimerAsynchronously(plugin, delay, period); + return runnable; + } + + /** + * Runs a task asynchronously on the main server thread. + * @param task The task to run. + */ + public void runTaskAsynchronously(Runnable task) { + if (plugin.isFolia()) { + try { + Method getGlobalScheduler = plugin.getServer().getClass().getMethod("getGlobalRegionScheduler"); + GlobalRegionScheduler globalScheduler = (GlobalRegionScheduler) getGlobalScheduler.invoke(plugin.getServer()); + globalScheduler.execute(plugin, task); + } catch (Exception e) { + e.printStackTrace(); + } + return; + } + 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 void runTask(Location loc, Runnable task) { + if (plugin.isFolia()) { + 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); + } + } catch (Exception e) { + e.printStackTrace(); + } + return; + } + plugin.getServer().getScheduler().runTask(plugin, task); + } +} diff --git a/src/main/java/community/leaf/survival/concretemixer/util/internal/ConcreteDebug.java b/src/main/java/community/leaf/survival/concretemixer/util/internal/ConcreteDebug.java index 0dab1b2..1891516 100644 --- a/src/main/java/community/leaf/survival/concretemixer/util/internal/ConcreteDebug.java +++ b/src/main/java/community/leaf/survival/concretemixer/util/internal/ConcreteDebug.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/util/internal/package-info.java b/src/main/java/community/leaf/survival/concretemixer/util/internal/package-info.java index 9974a74..ce28d34 100644 --- a/src/main/java/community/leaf/survival/concretemixer/util/internal/package-info.java +++ b/src/main/java/community/leaf/survival/concretemixer/util/internal/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/java/community/leaf/survival/concretemixer/util/package-info.java b/src/main/java/community/leaf/survival/concretemixer/util/package-info.java index 10c2ee4..953a950 100644 --- a/src/main/java/community/leaf/survival/concretemixer/util/package-info.java +++ b/src/main/java/community/leaf/survival/concretemixer/util/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright © 2022-2024, RezzedUp and Contributors + * Copyright © 2022-2025, RezzedUp and Contributors * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index f9b5f97..61ee50b 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -3,6 +3,7 @@ name: ${project.name} version: ${project.version} api-version: 1.17 softdepend: [ GriefPrevention ] +folia-supported: true authors: [ RezzedUp ] description: ${project.description}