diff --git a/pom.xml b/pom.xml index 2b23a36d..5bec8026 100644 --- a/pom.xml +++ b/pom.xml @@ -30,11 +30,15 @@ false + + papermc + https://repo.papermc.io/repository/maven-public/ + - org.spigotmc - spigot-api + io.papermc.paper + paper-api ${bukkit.version} provided @@ -74,6 +78,12 @@ 4.4.1 provided + + junit + junit + 4.13.2 + test + http://www.citizensnpcs.co diff --git a/src/main/java/net/citizensnpcs/api/CitizensAPI.java b/src/main/java/net/citizensnpcs/api/CitizensAPI.java index ca161882..f0089328 100644 --- a/src/main/java/net/citizensnpcs/api/CitizensAPI.java +++ b/src/main/java/net/citizensnpcs/api/CitizensAPI.java @@ -2,6 +2,8 @@ import java.io.File; +import net.citizensnpcs.api.util.SpigotUtil; +import net.citizensnpcs.api.util.schedulers.SchedulerAdapter; import org.bukkit.Bukkit; import org.bukkit.event.Listener; import org.bukkit.plugin.Plugin; @@ -20,6 +22,9 @@ * Contains methods used in order to utilize the Citizens API. */ public final class CitizensAPI { + + private static SchedulerAdapter scheduler; + private CitizensAPI() { } @@ -195,6 +200,21 @@ public static void setImplementation(CitizensPlugin implementation) { instance = implementation; } + /** + * The new scheduler that works on Folia and Spigot + * @return scheduler Folia or Spigot + */ + public static SchedulerAdapter getScheduler() { + if (scheduler == null) { + if (SpigotUtil.isFoliaServer()) { + scheduler = new net.citizensnpcs.api.util.schedulers.adapter.FoliaScheduler(getPlugin()); + } else { + scheduler = new net.citizensnpcs.api.util.schedulers.adapter.SpigotScheduler(getPlugin()); + } + } + return scheduler; + } + /** * Shuts down any resources currently being held. */ diff --git a/src/main/java/net/citizensnpcs/api/LocationLookup.java b/src/main/java/net/citizensnpcs/api/LocationLookup.java index 8f079ff9..2abd1838 100644 --- a/src/main/java/net/citizensnpcs/api/LocationLookup.java +++ b/src/main/java/net/citizensnpcs/api/LocationLookup.java @@ -10,6 +10,7 @@ import java.util.concurrent.Future; import java.util.function.BiConsumer; +import net.citizensnpcs.api.util.schedulers.SchedulerRunnable; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; @@ -20,7 +21,6 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.world.WorldUnloadEvent; import org.bukkit.potion.PotionEffectType; -import org.bukkit.scheduler.BukkitRunnable; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; @@ -31,13 +31,13 @@ import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.npc.NPCRegistry; -public class LocationLookup extends BukkitRunnable { - private final Map> metadata = Maps.newHashMap(); +public class LocationLookup extends SchedulerRunnable { + private final Map> metadata = new java.util.concurrent.ConcurrentHashMap<>(); private Future>> npcFuture = null; - private Map> npcWorlds = Maps.newHashMap(); + private Map> npcWorlds = new java.util.concurrent.ConcurrentHashMap<>(); private Future>> playerFuture = null; private final NPCRegistry sourceRegistry; - private Map> worlds = Maps.newHashMap(); + private Map> worlds = new java.util.concurrent.ConcurrentHashMap<>(); public LocationLookup() { this(CitizensAPI.getNPCRegistry()); @@ -123,7 +123,7 @@ public Iterable getNearbyVisiblePlayers(Entity base, Location location, @SuppressWarnings({ "unchecked", "rawtypes" }) public void onJoin(PlayerJoinEvent event) { - Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> { + CitizensAPI.getScheduler().runEntityTask(event.getPlayer(), () -> { updateWorld(event.getPlayer().getWorld()); for (PerPlayerMetadata meta : metadata.values()) { if (meta.onJoin != null) { @@ -134,7 +134,7 @@ public void onJoin(PlayerJoinEvent event) { } public void onQuit(PlayerQuitEvent event) { - Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> { + CitizensAPI.getScheduler().runEntityTask(event.getPlayer(), () -> { updateWorld(event.getPlayer().getWorld()); for (PerPlayerMetadata meta : metadata.values()) { meta.sent.remove(event.getPlayer().getUniqueId()); @@ -170,15 +170,18 @@ public void run() { npcFuture = null; } if (npcFuture == null) { - Map>> map = Maps.newHashMap(); + Map>> map = new java.util.concurrent.ConcurrentHashMap<>(); Location loc = new Location(null, 0, 0, 0); for (NPC npc : sourceRegistry) { - if (!npc.isSpawned()) - continue; - npc.getEntity().getLocation(loc); - Collection> nodes = map.computeIfAbsent(npc.getEntity().getWorld().getUID(), - uid -> Lists.newArrayList()); - nodes.add(new TreeFactory.Node<>(new double[] { loc.getX(), loc.getY(), loc.getZ() }, npc)); + if (npc.getEntity() == null) continue; + CitizensAPI.getScheduler().runEntityTask(npc.getEntity(), () -> { + if (!npc.isSpawned()) + return; + npc.getEntity().getLocation(loc); + Collection> nodes = map.computeIfAbsent(npc.getEntity().getWorld().getUID(), + uid -> Lists.newArrayList()); + nodes.add(new TreeFactory.Node<>(new double[] { loc.getX(), loc.getY(), loc.getZ() }, npc)); + }); } npcFuture = ForkJoinPool.commonPool().submit(new TreeFactory<>(map)); } diff --git a/src/main/java/net/citizensnpcs/api/astar/pathfinder/AsyncChunkSnapshotBlockSource.java b/src/main/java/net/citizensnpcs/api/astar/pathfinder/AsyncChunkSnapshotBlockSource.java index b7011d21..b79f8c63 100644 --- a/src/main/java/net/citizensnpcs/api/astar/pathfinder/AsyncChunkSnapshotBlockSource.java +++ b/src/main/java/net/citizensnpcs/api/astar/pathfinder/AsyncChunkSnapshotBlockSource.java @@ -2,6 +2,8 @@ import java.util.concurrent.Callable; +import net.citizensnpcs.api.CitizensAPI; +import net.citizensnpcs.api.util.SpigotUtil; import org.bukkit.Bukkit; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; @@ -24,10 +26,11 @@ protected ChunkSnapshot getChunkObject(int x, int z) { // TODO: pre-load multiple chunks on cache miss Callable call = () -> world.getChunkAt(x, z).getChunkSnapshot(false, false, false); try { - if (!Bukkit.isPrimaryThread()) { + if (!SpigotUtil.isFoliaServer() && !Bukkit.isPrimaryThread()) { return Bukkit.getScheduler().callSyncMethod(null, call).get(); - } else - return call.call(); + } + return call.call(); + } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/net/citizensnpcs/api/astar/pathfinder/DoorExaminer.java b/src/main/java/net/citizensnpcs/api/astar/pathfinder/DoorExaminer.java index 7ccfbd07..353299f2 100644 --- a/src/main/java/net/citizensnpcs/api/astar/pathfinder/DoorExaminer.java +++ b/src/main/java/net/citizensnpcs/api/astar/pathfinder/DoorExaminer.java @@ -2,6 +2,7 @@ import java.util.List; +import net.citizensnpcs.api.util.schedulers.SchedulerRunnable; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -86,7 +87,7 @@ private void close(NPC npc, Block point) { @Override public void onReached(NPC npc, Block point) { Location doorCentre = point.getLocation().add(0.5, 0, 0.5); - new BukkitRunnable() { + new SchedulerRunnable() { @Override public void run() { if (!npc.getNavigator().isNavigating()) { @@ -101,7 +102,7 @@ public void run() { cancel(); } } - }.runTaskTimer(CitizensAPI.getPlugin(), 3, 1); + }.runRegionTaskTimer(CitizensAPI.getPlugin(), doorCentre, 3, 1); } private void open(NPC npc, Block point, Material type) { diff --git a/src/main/java/net/citizensnpcs/api/gui/InputMenus.java b/src/main/java/net/citizensnpcs/api/gui/InputMenus.java index ef859e19..bf097e68 100644 --- a/src/main/java/net/citizensnpcs/api/gui/InputMenus.java +++ b/src/main/java/net/citizensnpcs/api/gui/InputMenus.java @@ -255,7 +255,7 @@ public void onPlayerChat(AsyncPlayerChatEvent event) { HandlerList.unregisterAll(this); String chat = event.getMessage(); event.setCancelled(true); - Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> { + CitizensAPI.getScheduler().runEntityTask(event.getPlayer(), () -> { if (chat.equals("\"\"") || chat.equals("''") || chat.equals("null")) { callback.accept(""); } else { diff --git a/src/main/java/net/citizensnpcs/api/gui/InventoryMenu.java b/src/main/java/net/citizensnpcs/api/gui/InventoryMenu.java index f300ad97..eefddc8c 100644 --- a/src/main/java/net/citizensnpcs/api/gui/InventoryMenu.java +++ b/src/main/java/net/citizensnpcs/api/gui/InventoryMenu.java @@ -439,7 +439,7 @@ public void run() { private void runViewerModifier(Runnable run) { if (delayViewerChanges) { - Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), run); + CitizensAPI.getScheduler().runTask(run); } else { run.run(); } diff --git a/src/main/java/net/citizensnpcs/api/npc/AbstractNPC.java b/src/main/java/net/citizensnpcs/api/npc/AbstractNPC.java index deb7d467..650e6ff0 100644 --- a/src/main/java/net/citizensnpcs/api/npc/AbstractNPC.java +++ b/src/main/java/net/citizensnpcs/api/npc/AbstractNPC.java @@ -448,17 +448,17 @@ private void teleport(final Entity entity, Location location, int delay, Telepor final Entity passenger = entity.getPassenger(); entity.eject(); if (!location.getWorld().equals(entity.getWorld())) { - Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), - () -> entity.teleport(location, cause), delay++); + CitizensAPI.getScheduler().runEntityTaskLater(entity, + () -> SpigotUtil.teleportAsync(entity, location, cause), delay++); } else { - entity.teleport(location, cause); + SpigotUtil.teleportAsync(entity, location, cause); } if (passenger == null) return; teleport(passenger, location, delay++, cause); Runnable task = () -> entity.setPassenger(passenger); if (!location.getWorld().equals(entity.getWorld())) { - Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), task, delay); + CitizensAPI.getScheduler().runEntityTaskLater(entity, task, delay); } else { task.run(); } diff --git a/src/main/java/net/citizensnpcs/api/persistence/PotionEffectPersister.java b/src/main/java/net/citizensnpcs/api/persistence/PotionEffectPersister.java index 5eea4ee7..3e3118ac 100644 --- a/src/main/java/net/citizensnpcs/api/persistence/PotionEffectPersister.java +++ b/src/main/java/net/citizensnpcs/api/persistence/PotionEffectPersister.java @@ -18,7 +18,10 @@ public PotionEffect create(DataKey root) { @Override public void save(PotionEffect effect, DataKey root) { - root.setString("type", effect.getType().getKeyOrNull().toString()); + String effectTypeKey = effect.getType().getKey() != null + ? effect.getType().getKey().toString() + : null; + root.setString("type", effectTypeKey); root.setInt("amplifier", effect.getAmplifier()); root.setInt("duration", effect.getDuration()); root.setBoolean("particles", effect.hasParticles()); diff --git a/src/main/java/net/citizensnpcs/api/util/SpigotUtil.java b/src/main/java/net/citizensnpcs/api/util/SpigotUtil.java index f76f5510..de2389bf 100644 --- a/src/main/java/net/citizensnpcs/api/util/SpigotUtil.java +++ b/src/main/java/net/citizensnpcs/api/util/SpigotUtil.java @@ -8,17 +8,16 @@ import java.util.Locale; import java.util.Map; import java.util.WeakHashMap; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; -import org.bukkit.Bukkit; -import org.bukkit.Keyed; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.World; +import org.bukkit.*; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.ItemStack; @@ -277,6 +276,18 @@ public static ItemStack parseItemStack(ItemStack base, String item) { return base; } + public static CompletableFuture teleportAsync(Entity entity, Location location) { + return ASYNC_TELEPORT ? entity.teleportAsync(location) : CompletableFuture.completedFuture(entity.teleport(location)); + } + + public static CompletableFuture teleportAsync(Entity entity, Location location, PlayerTeleportEvent.TeleportCause cause) { + return ASYNC_TELEPORT ? entity.teleportAsync(location, cause) : CompletableFuture.completedFuture(entity.teleport(location, cause)); + } + + public static boolean isFoliaServer() { + return FOLIA_SERVER; + } + private static ChronoUnit toChronoUnit(TimeUnit tu) { switch (tu) { case NANOSECONDS: @@ -306,6 +317,8 @@ private static ChronoUnit toChronoUnit(TimeUnit tu) { private static boolean SUPPORT_WORLD_HEIGHT = true; private static boolean SUPPORTS_KEYED; private static Boolean using1_13API; + private static boolean FOLIA_SERVER = false; + private static boolean ASYNC_TELEPORT = false; static { try { @@ -313,5 +326,17 @@ private static ChronoUnit toChronoUnit(TimeUnit tu) { SUPPORTS_KEYED = true; } catch (ClassNotFoundException e) { } + try { + Class.forName("io.papermc.paper.threadedregions.RegionizedServer"); + FOLIA_SERVER = true; + } catch (ClassNotFoundException ignored) { + FOLIA_SERVER = false; + } + try { + Entity.class.getMethod("teleportAsync", Location.class, PlayerTeleportEvent.TeleportCause.class); + ASYNC_TELEPORT = true; + } catch (NoSuchMethodException exception) { + ASYNC_TELEPORT = false; + } } } diff --git a/src/main/java/net/citizensnpcs/api/util/schedulers/SchedulerAdapter.java b/src/main/java/net/citizensnpcs/api/util/schedulers/SchedulerAdapter.java new file mode 100644 index 00000000..75b497ee --- /dev/null +++ b/src/main/java/net/citizensnpcs/api/util/schedulers/SchedulerAdapter.java @@ -0,0 +1,124 @@ +package net.citizensnpcs.api.util.schedulers; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.plugin.Plugin; + +/** + * An abstraction layer for scheduling tasks across different Minecraft server implementations, + * such as Folia and Spigot. + *

+ * Allows seamless compatibility by abstracting scheduling methods. + */ +public interface SchedulerAdapter { + + /** + * Executes a task on the global server thread. + */ + SchedulerTask runTask(Runnable runnable); + + /** + * Executes a task on the global server thread after a specified delay. + * + * @param delayTicks Delay before execution, measured in server ticks (1 tick = 50ms). + */ + SchedulerTask runTaskLater(Runnable runnable, long delayTicks); + + /** + * Executes a repeating task on the global server thread. + * + * @param delayTicks Initial delay before the first execution (in ticks). + * @param periodTicks Period between each subsequent execution (in ticks). + */ + SchedulerTask runTaskTimer(Runnable runnable, long delayTicks, long periodTicks); + + /** + * Executes a task associated with a specific region or chunk. + * On Spigot, this defaults to the global thread. + */ + SchedulerTask runRegionTask(Location location, Runnable runnable); + + /** + * Executes a task associated with a specific region or chunk after a delay. + * On Spigot, this defaults to the global thread. + * + * @param delayTicks Delay before execution, measured in ticks. + */ + SchedulerTask runRegionTaskLater(Location location, Runnable runnable, long delayTicks); + + /** + * Executes a repeating task associated with a specific region or chunk. + * On Spigot, this defaults to the global thread. + * + * @param delayTicks Initial delay before the first execution (in ticks). + * @param periodTicks Period between each subsequent execution (in ticks). + */ + SchedulerTask runRegionTaskTimer(Location location, Runnable runnable, long delayTicks, long periodTicks); + + /** + * Executes a task associated with a specific region or chunk. + * On Spigot, this defaults to the global thread. + */ + SchedulerTask runRegionTask(World world, int chunkX, int chunkZ, Runnable runnable); + + /** + * Executes a task associated with a specific region or chunk after a delay. + * On Spigot, this defaults to the global thread. + * + * @param delayTicks Delay before execution, measured in ticks. + */ + SchedulerTask runRegionTaskLater(World world, int chunkX, int chunkZ, Runnable runnable, long delayTicks); + + /** + * Executes a repeating task associated with a specific region or chunk. + * On Spigot, this defaults to the global thread. + * + * @param delayTicks Initial delay before the first execution (in ticks). + * @param periodTicks Period between each subsequent execution (in ticks). + */ + SchedulerTask runRegionTaskTimer(World world, int chunkX, int chunkZ, Runnable runnable, long delayTicks, long periodTicks); + + /** + * Executes a task specifically linked to an entity immediately. + * On Spigot, this defaults to the global thread. + */ + SchedulerTask runEntityTask(Entity entity, Runnable runnable); + + /** + * Executes a task specifically linked to an entity after a delay. + * On Spigot, this defaults to the global thread. + * + * @param delayTicks Delay before execution, measured in ticks. + */ + SchedulerTask runEntityTaskLater(Entity entity, Runnable runnable, long delayTicks); + + /** + * Executes a repeating task specifically linked to an entity. + * On Spigot, this defaults to the global thread. + * + * @param delayTicks Initial delay before the first execution (in ticks). + * @param periodTicks Period between each subsequent execution (in ticks). + */ + SchedulerTask runEntityTaskTimer(Entity entity, Runnable runnable, long delayTicks, long periodTicks); + + /** + * Executes a task asynchronously immediately, off the main server thread. + */ + SchedulerTask runTaskAsynchronously(Runnable runnable); + + /** + * Executes an asynchronous task after a specified delay. + * + * @param delayTicks Delay before execution, measured in ticks. + */ + SchedulerTask runTaskLaterAsynchronously(Runnable runnable, long delayTicks); + + /** + * Executes an asynchronous repeating task. + * + * @param delayTicks Initial delay before the first execution (in ticks). + * @param periodTicks Period between each subsequent execution (in ticks). + */ + SchedulerTask runTaskTimerAsynchronously(Runnable runnable, long delayTicks, long periodTicks); +} diff --git a/src/main/java/net/citizensnpcs/api/util/schedulers/SchedulerRunnable.java b/src/main/java/net/citizensnpcs/api/util/schedulers/SchedulerRunnable.java new file mode 100644 index 00000000..f8648971 --- /dev/null +++ b/src/main/java/net/citizensnpcs/api/util/schedulers/SchedulerRunnable.java @@ -0,0 +1,142 @@ +package net.citizensnpcs.api.util.schedulers; + +import net.citizensnpcs.api.util.SpigotUtil; +import net.citizensnpcs.api.util.schedulers.runnables.FoliaSchedulerRunnable; +import net.citizensnpcs.api.util.schedulers.runnables.SpigotSchedulerRunnable; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.plugin.Plugin; + +public abstract class SchedulerRunnable implements Runnable { + private SchedulerTask task; + + public abstract void run(); + + public boolean isCancelled() { + checkScheduled(); + return task.isCancelled(); + } + + public void cancel() { + checkScheduled(); + task.cancel(); + } + + public SchedulerTask getTask() { + checkScheduled(); + return task; + } + + public int getTaskId() { + checkScheduled(); + return task.getOriginalTask().hashCode(); + } + + protected SchedulerTask setupTask(SchedulerTask task) { + this.task = task; + return task; + } + + private void checkScheduled() { + if (task == null) throw new IllegalStateException("Task not yet scheduled"); + } + + public SchedulerTask runTask(Plugin plugin) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runTask(plugin) : new SpigotSchedulerRunnableImpl(this).runTask(plugin); + } + + public SchedulerTask runTaskLater(Plugin plugin, long delayTicks) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runTaskLater(plugin, delayTicks) : new SpigotSchedulerRunnableImpl(this).runTaskLater(plugin, delayTicks); + } + + public SchedulerTask runTaskTimer(Plugin plugin, long delayTicks, long periodTicks) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runTaskTimer(plugin, delayTicks, periodTicks) : new SpigotSchedulerRunnableImpl(this).runTaskTimer(plugin, delayTicks, periodTicks); + } + + public SchedulerTask runTaskAsynchronously(Plugin plugin) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runTaskAsynchronously(plugin) : new SpigotSchedulerRunnableImpl(this).runTaskAsynchronously(plugin); + } + + public SchedulerTask runTaskLaterAsynchronously(Plugin plugin, long delayTicks) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runTaskLaterAsynchronously(plugin, delayTicks) : new SpigotSchedulerRunnableImpl(this).runTaskLaterAsynchronously(plugin, delayTicks); + } + + public SchedulerTask runTaskTimerAsynchronously(Plugin plugin, long delayTicks, long periodTicks) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runTaskTimerAsynchronously(plugin, delayTicks, periodTicks) : new SpigotSchedulerRunnableImpl(this).runTaskTimerAsynchronously(plugin, delayTicks, periodTicks); + } + + public SchedulerTask runRegionTask(Plugin plugin, Location location) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runRegionTask(plugin, location) : new SpigotSchedulerRunnableImpl(this).runRegionTask(plugin, location); + } + + public SchedulerTask runRegionTask(Plugin plugin, World world, int chunkX, int chunkZ) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runRegionTask(plugin, world, chunkX, chunkZ) : new SpigotSchedulerRunnableImpl(this).runRegionTask(plugin, world, chunkX, chunkZ); + } + + public SchedulerTask runRegionTaskLater(Plugin plugin, Location location, long delayTicks) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runRegionTaskLater(plugin, location, delayTicks) : new SpigotSchedulerRunnableImpl(this).runRegionTaskLater(plugin, location, delayTicks); + } + + public SchedulerTask runRegionTaskLater(Plugin plugin, World world, int chunkX, int chunkZ, long delayTicks) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runRegionTaskLater(plugin, world, chunkX, chunkZ, delayTicks) : new SpigotSchedulerRunnableImpl(this).runRegionTaskLater(plugin, world, chunkX, chunkZ, delayTicks); + } + + public SchedulerTask runRegionTaskTimer(Plugin plugin, Location location, long delayTicks, long periodTicks) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runRegionTaskTimer(plugin, location, delayTicks, periodTicks) : new SpigotSchedulerRunnableImpl(this).runRegionTaskTimer(plugin, location, delayTicks, periodTicks); + } + + public SchedulerTask runRegionTaskTimer(Plugin plugin, World world, int chunkX, int chunkZ, long delayTicks, long periodTicks) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runRegionTaskTimer(plugin, world, chunkX, chunkZ, delayTicks, periodTicks) : new SpigotSchedulerRunnableImpl(this).runRegionTaskTimer(plugin, world, chunkX, chunkZ, delayTicks, periodTicks); + } + + public SchedulerTask runEntityTask(Plugin plugin, Entity entity, Runnable retired) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runEntityTask(plugin, entity, retired) : new SpigotSchedulerRunnableImpl(this).runEntityTask(plugin, entity, retired); + } + + public SchedulerTask runEntityTaskLater(Plugin plugin, Entity entity, Runnable retired, long delayTicks) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runEntityTaskLater(plugin, entity, retired, delayTicks) : new SpigotSchedulerRunnableImpl(this).runEntityTaskLater(plugin, entity, retired, delayTicks); + } + + public SchedulerTask runEntityTaskTimer(Plugin plugin, Entity entity, Runnable retired, long delayTicks, long periodTicks) { + return SpigotUtil.isFoliaServer() ? new FoliaSchedulerRunnableImpl(this).runEntityTaskTimer(plugin, entity, retired, delayTicks, periodTicks) : new SpigotSchedulerRunnableImpl(this).runEntityTaskTimer(plugin, entity, retired, delayTicks, periodTicks); + } + + private static final class FoliaSchedulerRunnableImpl extends FoliaSchedulerRunnable { + private final SchedulerRunnable delegate; + + private FoliaSchedulerRunnableImpl(SchedulerRunnable delegate) { + this.delegate = delegate; + } + + @Override + protected SchedulerTask setupTask(SchedulerTask task) { + delegate.setupTask(task); + return task; + } + + @Override + public void run() { + delegate.run(); + } + } + + private static final class SpigotSchedulerRunnableImpl extends SpigotSchedulerRunnable { + private final SchedulerRunnable delegate; + + private SpigotSchedulerRunnableImpl(SchedulerRunnable delegate) { + this.delegate = delegate; + } + + @Override + protected SchedulerTask setupTask(SchedulerTask task) { + delegate.setupTask(task); + return task; + } + + @Override + public void run() { + delegate.run(); + } + } +} diff --git a/src/main/java/net/citizensnpcs/api/util/schedulers/SchedulerTask.java b/src/main/java/net/citizensnpcs/api/util/schedulers/SchedulerTask.java new file mode 100644 index 00000000..a2a7dd17 --- /dev/null +++ b/src/main/java/net/citizensnpcs/api/util/schedulers/SchedulerTask.java @@ -0,0 +1,16 @@ +package net.citizensnpcs.api.util.schedulers; + +import org.bukkit.plugin.Plugin; + +public interface SchedulerTask { + + Plugin getPlugin(); + + boolean isCancelled(); + + boolean isRepeating(); + + void cancel(); + + Object getOriginalTask(); +} \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/api/util/schedulers/adapter/FoliaScheduler.java b/src/main/java/net/citizensnpcs/api/util/schedulers/adapter/FoliaScheduler.java new file mode 100644 index 00000000..44ba8d21 --- /dev/null +++ b/src/main/java/net/citizensnpcs/api/util/schedulers/adapter/FoliaScheduler.java @@ -0,0 +1,143 @@ +package net.citizensnpcs.api.util.schedulers.adapter; + +import io.papermc.paper.threadedregions.scheduler.AsyncScheduler; +import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler; +import io.papermc.paper.threadedregions.scheduler.RegionScheduler; +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import net.citizensnpcs.api.util.schedulers.SchedulerAdapter; +import net.citizensnpcs.api.util.schedulers.SchedulerTask; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.plugin.Plugin; + +import java.util.concurrent.TimeUnit; + +public class FoliaScheduler implements SchedulerAdapter { + + private final Plugin plugin; + private final GlobalRegionScheduler globalScheduler; + private final AsyncScheduler asyncScheduler; + private final RegionScheduler regionScheduler; + + public FoliaScheduler(Plugin plugin) { + this.plugin = plugin; + globalScheduler = Bukkit.getGlobalRegionScheduler(); + asyncScheduler = Bukkit.getAsyncScheduler(); + regionScheduler = Bukkit.getRegionScheduler(); + } + + private long ticksToMillis(long ticks) { + return ticks * 50L; + } + + private SchedulerTask wrap(ScheduledTask task) { + return new FoliaSchedulerTask(task); + } + + @Override + public SchedulerTask runTask(Runnable runnable) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = globalScheduler.run(plugin, t -> runnable.run()); + return wrap(task); + } + + @Override + public SchedulerTask runTaskLater(Runnable runnable, long delayTicks) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = globalScheduler.runDelayed(plugin, t -> runnable.run(), Math.max(1, delayTicks)); + return wrap(task); + } + + @Override + public SchedulerTask runTaskTimer(Runnable runnable, long delayTicks, long periodTicks) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = globalScheduler.runAtFixedRate(plugin, t -> runnable.run(), Math.max(1, delayTicks), Math.max(1, periodTicks)); + return wrap(task); + } + + @Override + public SchedulerTask runRegionTask(Location location, Runnable runnable) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = regionScheduler.run(plugin, location, t -> runnable.run()); + return wrap(task); + } + + @Override + public SchedulerTask runRegionTaskLater(Location location, Runnable runnable, long delayTicks) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = regionScheduler.runDelayed(plugin, location, t -> runnable.run(), Math.max(1, delayTicks)); + return wrap(task); + } + + @Override + public SchedulerTask runRegionTaskTimer(Location location, Runnable runnable, long delayTicks, long periodTicks) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = regionScheduler.runAtFixedRate(plugin, location, t -> runnable.run(), Math.max(1, delayTicks), Math.max(1, periodTicks)); + return wrap(task); + } + + @Override + public SchedulerTask runRegionTask(World world, int chunkX, int chunkZ, Runnable runnable) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = regionScheduler.run(plugin, world, chunkX, chunkZ, t -> runnable.run()); + return wrap(task); + } + + @Override + public SchedulerTask runRegionTaskLater(World world, int chunkX, int chunkZ, Runnable runnable, long delayTicks) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = regionScheduler.runDelayed(plugin, world, chunkX, chunkZ, t -> runnable.run(), Math.max(1, delayTicks)); + return wrap(task); + } + + @Override + public SchedulerTask runRegionTaskTimer(World world, int chunkX, int chunkZ, Runnable runnable, long delayTicks, long periodTicks) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = regionScheduler.runAtFixedRate(plugin, world, chunkX, chunkZ, t -> runnable.run(), Math.max(1, delayTicks), Math.max(1, periodTicks)); + return wrap(task); + } + + @Override + public SchedulerTask runEntityTask(Entity entity, Runnable runnable) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = entity.getScheduler().run(plugin, t -> runnable.run(), null); + return wrap(task); + } + + @Override + public SchedulerTask runEntityTaskLater(Entity entity, Runnable runnable, long delayTicks) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = entity.getScheduler().runDelayed(plugin, t -> runnable.run(), null, Math.max(1, delayTicks)); + return wrap(task); + } + + @Override + public SchedulerTask runEntityTaskTimer(Entity entity, Runnable runnable, long delayTicks, long periodTicks) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = entity.getScheduler().runAtFixedRate(plugin, t -> runnable.run(), null, Math.max(1, delayTicks), Math.max(1, periodTicks)); + return wrap(task); + } + + @Override + public SchedulerTask runTaskAsynchronously(Runnable runnable) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = asyncScheduler.runNow(plugin, t -> runnable.run()); + return wrap(task); + } + + @Override + public SchedulerTask runTaskLaterAsynchronously(Runnable runnable, long delayTicks) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = asyncScheduler.runDelayed(plugin, t -> runnable.run(), ticksToMillis(Math.max(1, delayTicks)), TimeUnit.MILLISECONDS); + return wrap(task); + } + + @Override + public SchedulerTask runTaskTimerAsynchronously(Runnable runnable, long delayTicks, long periodTicks) { + if (!plugin.isEnabled()) return null; + ScheduledTask task = asyncScheduler.runAtFixedRate(plugin, t -> runnable.run(), ticksToMillis(Math.max(1, delayTicks)), ticksToMillis(Math.max(1, periodTicks)), TimeUnit.MILLISECONDS); + return wrap(task); + } +} diff --git a/src/main/java/net/citizensnpcs/api/util/schedulers/adapter/FoliaSchedulerTask.java b/src/main/java/net/citizensnpcs/api/util/schedulers/adapter/FoliaSchedulerTask.java new file mode 100644 index 00000000..687cfd3b --- /dev/null +++ b/src/main/java/net/citizensnpcs/api/util/schedulers/adapter/FoliaSchedulerTask.java @@ -0,0 +1,39 @@ +package net.citizensnpcs.api.util.schedulers.adapter; + +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import net.citizensnpcs.api.util.schedulers.SchedulerTask; +import org.bukkit.plugin.Plugin; + +public class FoliaSchedulerTask implements SchedulerTask { + + private final ScheduledTask task; + + public FoliaSchedulerTask(ScheduledTask task) { + this.task = task; + } + + @Override + public Plugin getPlugin() { + return task.getOwningPlugin(); + } + + @Override + public boolean isCancelled() { + return task.isCancelled(); + } + + @Override + public boolean isRepeating() { + return task.isRepeatingTask(); + } + + @Override + public void cancel() { + task.cancel(); + } + + @Override + public ScheduledTask getOriginalTask() { + return task; + } +} diff --git a/src/main/java/net/citizensnpcs/api/util/schedulers/adapter/SpigotScheduler.java b/src/main/java/net/citizensnpcs/api/util/schedulers/adapter/SpigotScheduler.java new file mode 100644 index 00000000..7abd9af1 --- /dev/null +++ b/src/main/java/net/citizensnpcs/api/util/schedulers/adapter/SpigotScheduler.java @@ -0,0 +1,98 @@ +package net.citizensnpcs.api.util.schedulers.adapter; + +import net.citizensnpcs.api.util.schedulers.SchedulerAdapter; +import net.citizensnpcs.api.util.schedulers.SchedulerTask; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitTask; + +public class SpigotScheduler implements SchedulerAdapter { + + private final Plugin plugin; + + public SpigotScheduler(Plugin plugin) { + this.plugin = plugin; + } + + private SchedulerTask wrap(BukkitTask task) { + return new SpigotSchedulerTask(task); + } + + @Override + public SchedulerTask runTask(Runnable runnable) { + return wrap(Bukkit.getScheduler().runTask(plugin, runnable)); + } + + @Override + public SchedulerTask runTaskLater(Runnable runnable, long delayTicks) { + return wrap(Bukkit.getScheduler().runTaskLater(plugin, runnable, delayTicks)); + } + + @Override + public SchedulerTask runTaskTimer(Runnable runnable, long delayTicks, long periodTicks) { + return wrap(Bukkit.getScheduler().runTaskTimer(plugin, runnable, delayTicks, periodTicks)); + } + + @Override + public SchedulerTask runRegionTask(Location location, Runnable runnable) { + return runTask(runnable); + } + + @Override + public SchedulerTask runRegionTaskLater(Location location, Runnable runnable, long delayTicks) { + return runTaskLater(runnable, delayTicks); + } + + @Override + public SchedulerTask runRegionTaskTimer(Location location, Runnable runnable, long delayTicks, long periodTicks) { + return runTaskTimer(runnable, delayTicks, periodTicks); + } + + @Override + public SchedulerTask runRegionTask(World world, int chunkX, int chunkZ, Runnable runnable) { + return runTask(runnable); + } + + @Override + public SchedulerTask runRegionTaskLater(World world, int chunkX, int chunkZ, Runnable runnable, long delayTicks) { + return runTaskLater(runnable, delayTicks); + } + + @Override + public SchedulerTask runRegionTaskTimer(World world, int chunkX, int chunkZ, Runnable runnable, long delayTicks, long periodTicks) { + return runTaskTimer(runnable, delayTicks, periodTicks); + } + + @Override + public SchedulerTask runEntityTask(Entity entity, Runnable runnable) { + return runTask(runnable); + } + + @Override + public SchedulerTask runEntityTaskLater(Entity entity, Runnable runnable, long delayTicks) { + return runTaskLater(runnable, delayTicks); + } + + @Override + public SchedulerTask runEntityTaskTimer(Entity entity, Runnable runnable, long delayTicks, long periodTicks) { + return runTaskTimer(runnable, delayTicks, periodTicks); + } + + @Override + public SchedulerTask runTaskAsynchronously(Runnable runnable) { + return wrap(Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable)); + } + + @Override + public SchedulerTask runTaskLaterAsynchronously(Runnable runnable, long delayTicks) { + return wrap(Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delayTicks)); + } + + @Override + public SchedulerTask runTaskTimerAsynchronously(Runnable runnable, long delayTicks, long periodTicks) { + return wrap(Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, runnable, delayTicks, periodTicks)); + } +} diff --git a/src/main/java/net/citizensnpcs/api/util/schedulers/adapter/SpigotSchedulerTask.java b/src/main/java/net/citizensnpcs/api/util/schedulers/adapter/SpigotSchedulerTask.java new file mode 100644 index 00000000..d53466a8 --- /dev/null +++ b/src/main/java/net/citizensnpcs/api/util/schedulers/adapter/SpigotSchedulerTask.java @@ -0,0 +1,40 @@ +package net.citizensnpcs.api.util.schedulers.adapter; + +import net.citizensnpcs.api.util.schedulers.SchedulerTask; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitTask; + +public class SpigotSchedulerTask implements SchedulerTask { + + private final BukkitTask task; + + public SpigotSchedulerTask(BukkitTask task) { + this.task = task; + } + + @Override + public Plugin getPlugin() { + return task.getOwner(); + } + + @Override + public boolean isCancelled() { + return task.isCancelled(); + } + + @Override + public boolean isRepeating() { + return false; + } + + @Override + public void cancel() { + task.cancel(); + } + + @Override + public BukkitTask getOriginalTask() { + return task; + } +} + diff --git a/src/main/java/net/citizensnpcs/api/util/schedulers/runnables/FoliaSchedulerRunnable.java b/src/main/java/net/citizensnpcs/api/util/schedulers/runnables/FoliaSchedulerRunnable.java new file mode 100644 index 00000000..5e5c56de --- /dev/null +++ b/src/main/java/net/citizensnpcs/api/util/schedulers/runnables/FoliaSchedulerRunnable.java @@ -0,0 +1,91 @@ +package net.citizensnpcs.api.util.schedulers.runnables; + +import net.citizensnpcs.api.util.schedulers.SchedulerRunnable; +import net.citizensnpcs.api.util.schedulers.SchedulerTask; +import net.citizensnpcs.api.util.schedulers.adapter.FoliaSchedulerTask; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.plugin.Plugin; + +import java.util.concurrent.TimeUnit; + +public abstract class FoliaSchedulerRunnable extends SchedulerRunnable { + + @Override + public SchedulerTask runTask(Plugin plugin) { + return setupTask(new FoliaSchedulerTask(Bukkit.getGlobalRegionScheduler().run(plugin, t -> run()))); + } + + @Override + public SchedulerTask runTaskLater(Plugin plugin, long delayTicks) { + return setupTask(new FoliaSchedulerTask(Bukkit.getGlobalRegionScheduler().runDelayed(plugin, t -> run(), Math.max(1, delayTicks)))); + } + + @Override + public SchedulerTask runTaskTimer(Plugin plugin, long delayTicks, long periodTicks) { + return setupTask(new FoliaSchedulerTask(Bukkit.getGlobalRegionScheduler().runAtFixedRate(plugin, t -> run(), Math.max(1, delayTicks), Math.max(1, periodTicks)))); + } + + @Override + public SchedulerTask runTaskAsynchronously(Plugin plugin) { + return setupTask(new FoliaSchedulerTask(Bukkit.getAsyncScheduler().runNow(plugin, t -> run()))); + } + + @Override + public SchedulerTask runTaskLaterAsynchronously(Plugin plugin, long delayTicks) { + return setupTask(new FoliaSchedulerTask(Bukkit.getAsyncScheduler().runDelayed(plugin, t -> run(), Math.max(1, delayTicks) * 50L, TimeUnit.MILLISECONDS))); + } + + @Override + public SchedulerTask runTaskTimerAsynchronously(Plugin plugin, long delayTicks, long periodTicks) { + return setupTask(new FoliaSchedulerTask(Bukkit.getAsyncScheduler().runAtFixedRate(plugin, t -> run(), Math.max(1, delayTicks) * 50L, Math.max(1, periodTicks) * 50L, TimeUnit.MILLISECONDS))); + } + + @Override + public SchedulerTask runRegionTask(Plugin plugin, Location location) { + return setupTask(new FoliaSchedulerTask(Bukkit.getRegionScheduler().run(plugin, location, t -> run()))); + } + + + @Override + public SchedulerTask runRegionTask(Plugin plugin, World world, int chunkX, int chunkZ) { + return setupTask(new FoliaSchedulerTask(Bukkit.getRegionScheduler().run(plugin, world, chunkX, chunkZ, t -> run()))); + } + + @Override + public SchedulerTask runRegionTaskLater(Plugin plugin, Location location, long delayTicks) { + return setupTask(new FoliaSchedulerTask(Bukkit.getRegionScheduler().runDelayed(plugin, location, t -> run(), Math.max(1, delayTicks)))); + } + + @Override + public SchedulerTask runRegionTaskLater(Plugin plugin, World world, int chunkX, int chunkZ, long delayTicks) { + return setupTask(new FoliaSchedulerTask(Bukkit.getRegionScheduler().runDelayed(plugin, world, chunkX, chunkZ, t -> run(), Math.max(1, delayTicks)))); + } + + @Override + public SchedulerTask runRegionTaskTimer(Plugin plugin, World world, int chunkX, int chunkZ, long delayTicks, long periodTicks) { + return setupTask(new FoliaSchedulerTask(Bukkit.getRegionScheduler().runAtFixedRate(plugin, world, chunkX, chunkZ, t -> run(), Math.max(1, delayTicks), Math.max(1, periodTicks)))); + } + + @Override + public SchedulerTask runRegionTaskTimer(Plugin plugin, Location location, long delayTicks, long periodTicks) { + return setupTask(new FoliaSchedulerTask(Bukkit.getRegionScheduler().runAtFixedRate(plugin, location, t -> run(), Math.max(1, delayTicks), Math.max(1, periodTicks)))); + } + + @Override + public SchedulerTask runEntityTask(Plugin plugin, Entity entity, Runnable retired) { + return setupTask(new FoliaSchedulerTask(entity.getScheduler().run(plugin, t -> run(), retired))); + } + + @Override + public SchedulerTask runEntityTaskLater(Plugin plugin, Entity entity, Runnable retired, long delayTicks) { + return setupTask(new FoliaSchedulerTask(entity.getScheduler().runDelayed(plugin, t -> run(), retired, Math.max(1, delayTicks)))); + } + + @Override + public SchedulerTask runEntityTaskTimer(Plugin plugin, Entity entity, Runnable retired, long delayTicks, long periodTicks) { + return setupTask(new FoliaSchedulerTask(entity.getScheduler().runAtFixedRate(plugin, t -> run(), retired, Math.max(1, delayTicks), Math.max(1, periodTicks)))); + } +} diff --git a/src/main/java/net/citizensnpcs/api/util/schedulers/runnables/SpigotSchedulerRunnable.java b/src/main/java/net/citizensnpcs/api/util/schedulers/runnables/SpigotSchedulerRunnable.java new file mode 100644 index 00000000..1c4867da --- /dev/null +++ b/src/main/java/net/citizensnpcs/api/util/schedulers/runnables/SpigotSchedulerRunnable.java @@ -0,0 +1,87 @@ +package net.citizensnpcs.api.util.schedulers.runnables; + +import net.citizensnpcs.api.util.schedulers.SchedulerRunnable; +import net.citizensnpcs.api.util.schedulers.SchedulerTask; +import net.citizensnpcs.api.util.schedulers.adapter.SpigotSchedulerTask; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.plugin.Plugin; + +public abstract class SpigotSchedulerRunnable extends SchedulerRunnable { + @Override + public SchedulerTask runTask(Plugin plugin) { + return setupTask(new SpigotSchedulerTask(Bukkit.getScheduler().runTask(plugin, this))); + } + + @Override + public SchedulerTask runTaskLater(Plugin plugin, long delayTicks) { + return setupTask(new SpigotSchedulerTask(Bukkit.getScheduler().runTaskLater(plugin, this, delayTicks))); + } + + @Override + public SchedulerTask runTaskTimer(Plugin plugin, long delayTicks, long periodTicks) { + return setupTask(new SpigotSchedulerTask(Bukkit.getScheduler().runTaskTimer(plugin, this, delayTicks, periodTicks))); + } + + @Override + public SchedulerTask runTaskAsynchronously(Plugin plugin) { + return setupTask(new SpigotSchedulerTask(Bukkit.getScheduler().runTaskAsynchronously(plugin, this))); + } + + @Override + public SchedulerTask runTaskLaterAsynchronously(Plugin plugin, long delayTicks) { + return setupTask(new SpigotSchedulerTask(Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, this, delayTicks))); + } + + @Override + public SchedulerTask runTaskTimerAsynchronously(Plugin plugin, long delayTicks, long periodTicks) { + return setupTask(new SpigotSchedulerTask(Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, this, delayTicks, periodTicks))); + } + + @Override + public SchedulerTask runRegionTask(Plugin plugin, Location location) { + return runTask(plugin); + } + + @Override + public SchedulerTask runRegionTask(Plugin plugin, World world, int chunkX, int chunkZ) { + return runTask(plugin); + } + + @Override + public SchedulerTask runRegionTaskLater(Plugin plugin, Location location, long delayTicks) { + return runTaskLater(plugin, delayTicks); + } + + @Override + public SchedulerTask runRegionTaskTimer(Plugin plugin, Location location, long delayTicks, long periodTicks) { + return runTaskTimer(plugin, delayTicks, periodTicks); + } + + @Override + public SchedulerTask runRegionTaskLater(Plugin plugin, World world, int chunkX, int chunkZ, long delayTicks) { + return runTaskLater(plugin, delayTicks); + } + + @Override + public SchedulerTask runRegionTaskTimer(Plugin plugin, World world, int chunkX, int chunkZ, long delayTicks, long periodTicks) { + return runTaskTimer(plugin, delayTicks, periodTicks); + } + + @Override + public SchedulerTask runEntityTask(Plugin plugin, Entity entity, Runnable retired) { + return runTask(plugin); + } + + @Override + public SchedulerTask runEntityTaskLater(Plugin plugin, Entity entity, Runnable retired, long delayTicks) { + return runTaskLater(plugin, delayTicks); + } + + @Override + public SchedulerTask runEntityTaskTimer(Plugin plugin, Entity entity, Runnable retired, long delayTicks, long periodTicks) { + return runTaskTimer(plugin, delayTicks, periodTicks); + } +}