diff --git a/buildSrc/src/main/kotlin/CommonConfig.kt b/buildSrc/src/main/kotlin/CommonConfig.kt index 934e154..f90f824 100644 --- a/buildSrc/src/main/kotlin/CommonConfig.kt +++ b/buildSrc/src/main/kotlin/CommonConfig.kt @@ -27,7 +27,7 @@ fun Project.applyCommonConfiguration() { plugins.withId("java") { the().toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) + languageVersion.set(JavaLanguageVersion.of(21)) } } } diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 8ce708e..2b74d55 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -21,6 +21,7 @@ configurations { dependencies { "compileOnly"("io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT") + "compileOnly"("dev.folia:folia-api:1.20.6-R0.1-SNAPSHOT") "api"(project(":nuvotifier-api")) "api"(project(":nuvotifier-common")) } @@ -53,4 +54,4 @@ tasks.named("shadowJar") { tasks.named("assemble").configure { dependsOn("shadowJar") -} +} \ No newline at end of file diff --git a/bukkit/src/main/java/com/vexsoftware/votifier/BukkitScheduler.java b/bukkit/src/main/java/com/vexsoftware/votifier/BukkitScheduler.java index 397c46e..a2a5e39 100644 --- a/bukkit/src/main/java/com/vexsoftware/votifier/BukkitScheduler.java +++ b/bukkit/src/main/java/com/vexsoftware/votifier/BukkitScheduler.java @@ -2,41 +2,47 @@ import com.vexsoftware.votifier.platform.scheduler.ScheduledVotifierTask; import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler; -import org.bukkit.scheduler.BukkitTask; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; class BukkitScheduler implements VotifierScheduler { private final NuVotifierBukkit plugin; + private final ScheduledExecutorService executorService; public BukkitScheduler(NuVotifierBukkit plugin) { this.plugin = plugin; + this.executorService = Executors.newSingleThreadScheduledExecutor(); } - private int toTicks(int time, TimeUnit unit) { - return (int) (unit.toMillis(time) / 50); + private long toMillis(int time, TimeUnit unit) { + return unit.toMillis(time); } @Override public ScheduledVotifierTask delayedOnPool(Runnable runnable, int delay, TimeUnit unit) { - return new BukkitTaskWrapper(plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, runnable, toTicks(delay, unit))); + ScheduledFuture future = executorService.schedule(runnable, toMillis(delay, unit), TimeUnit.MILLISECONDS); + return new ScheduledVotifierTaskWrapper(future); } @Override public ScheduledVotifierTask repeatOnPool(Runnable runnable, int delay, int repeat, TimeUnit unit) { - return new BukkitTaskWrapper(plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, runnable, toTicks(delay, unit), toTicks(repeat, unit))); + ScheduledFuture future = executorService.scheduleAtFixedRate(runnable, toMillis(delay, unit), toMillis(repeat, unit), TimeUnit.MILLISECONDS); + return new ScheduledVotifierTaskWrapper(future); } - private static class BukkitTaskWrapper implements ScheduledVotifierTask { - private final BukkitTask task; + private static class ScheduledVotifierTaskWrapper implements ScheduledVotifierTask { + private final ScheduledFuture future; - private BukkitTaskWrapper(BukkitTask task) { - this.task = task; + private ScheduledVotifierTaskWrapper(ScheduledFuture future) { + this.future = future; } @Override public void cancel() { - task.cancel(); + future.cancel(false); } } } diff --git a/bukkit/src/main/java/com/vexsoftware/votifier/NuVotifierBukkit.java b/bukkit/src/main/java/com/vexsoftware/votifier/NuVotifierBukkit.java index a5bfc6b..ad6b508 100644 --- a/bukkit/src/main/java/com/vexsoftware/votifier/NuVotifierBukkit.java +++ b/bukkit/src/main/java/com/vexsoftware/votifier/NuVotifierBukkit.java @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2012 Vex Software LLC - * This file is part of Votifier. - * - * Votifier is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Votifier is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Votifier. If not, see . - */ - package com.vexsoftware.votifier; import com.vexsoftware.votifier.cmd.NVReloadCmd; @@ -33,6 +15,10 @@ import com.vexsoftware.votifier.platform.LoggingAdapter; import com.vexsoftware.votifier.platform.VotifierPlugin; import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler; +import com.vexsoftware.votifier.scheduling.FoliaTaskScheduler; +import com.vexsoftware.votifier.scheduling.ScheduledTask; +import com.vexsoftware.votifier.scheduling.TaskScheduler; +import com.vexsoftware.votifier.scheduling.TaskSchedulerAdapter; import com.vexsoftware.votifier.util.IOUtil; import com.vexsoftware.votifier.util.KeyCreator; import com.vexsoftware.votifier.util.TokenUtil; @@ -51,40 +37,23 @@ import java.security.KeyPair; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; /** * The main Votifier plugin class. - * - * @author Blake Beaupain - * @author Kramer Campbell */ public class NuVotifierBukkit extends JavaPlugin implements VoteHandler, VotifierPlugin, ForwardedVoteListener { - /** - * The server bootstrap. - */ private VotifierServerBootstrap bootstrap; - - /** - * The RSA key pair. - */ private KeyPair keyPair; - - /** - * Debug mode flag - */ private boolean debug; - - /** - * Keys used for websites. - */ private Map tokens = new HashMap<>(); - private ForwardingVoteSink forwardingMethod; - private VotifierScheduler scheduler; private LoggingAdapter pluginLogger; private boolean isFolia; + private TaskScheduler scheduler; + private VotifierScheduler votifierScheduler; private boolean loadAndBind() { try { @@ -96,7 +65,8 @@ private boolean loadAndBind() { isFolia = false; } - scheduler = new BukkitScheduler(this); + scheduler = new FoliaTaskScheduler(this); + votifierScheduler = new TaskSchedulerAdapter(scheduler); pluginLogger = new JavaUtilLogger(getLogger()); if (!getDataFolder().exists()) { if (!getDataFolder().mkdir()) { @@ -104,42 +74,24 @@ private boolean loadAndBind() { } } - // Handle configuration. File config = new File(getDataFolder(), "config.yml"); - /* - * Use IP address from server.properties as a default for - * configurations. Do not use InetAddress.getLocalHost() as it most - * likely will return the main server address instead of the address - * assigned to the server. - */ String hostAddr = Bukkit.getServer().getIp(); if (hostAddr == null || hostAddr.length() == 0) hostAddr = "0.0.0.0"; - /* - * Create configuration file if it does not exists; otherwise, load it - */ if (!config.exists()) { try { - // First time run - do some initialization. getLogger().info("Configuring Votifier for the first time..."); - - // Initialize the configuration file. if (!config.createNewFile()) { throw new IOException("Unable to create the config file at " + config); } - // Load and manually replace variables in the configuration. String cfgStr = new String(IOUtil.readAllBytes(getResource("bukkitConfig.yml")), StandardCharsets.UTF_8); String token = TokenUtil.newToken(); cfgStr = cfgStr.replace("%default_token%", token).replace("%ip%", hostAddr); Files.copy(new ByteArrayInputStream(cfgStr.getBytes(StandardCharsets.UTF_8)), config.toPath(), StandardCopyOption.REPLACE_EXISTING); - /* - * Remind hosted server admins to be sure they have the right - * port number. - */ getLogger().info("------------------------------------------------------------------------------"); getLogger().info("Assigning NuVotifier to listen on port 8192. If you are hosting Craftbukkit on a"); getLogger().info("shared server please check with your hosting provider to verify that this port"); @@ -159,13 +111,8 @@ private boolean loadAndBind() { YamlConfiguration cfg; File rsaDirectory = new File(getDataFolder(), "rsa"); - // Load configuration. cfg = YamlConfiguration.loadConfiguration(config); - /* - * Create RSA directory and keys if it does not exist; otherwise, read - * keys. - */ try { if (!rsaDirectory.exists()) { if (!rsaDirectory.mkdir()) { @@ -177,20 +124,16 @@ private boolean loadAndBind() { keyPair = RSAIO.load(rsaDirectory); } } catch (Exception ex) { - getLogger().log(Level.SEVERE, - "Error reading configuration file or RSA tokens", ex); + getLogger().log(Level.SEVERE, "Error reading configuration file or RSA tokens", ex); return false; } - // the quiet flag always runs priority to the debug flag if (cfg.isBoolean("quiet")) { debug = !cfg.getBoolean("quiet"); } else { - // otherwise, default to being noisy debug = cfg.getBoolean("debug", true); } - // Load Votifier tokens. ConfigurationSection tokenSection = cfg.getConfigurationSection("tokens"); if (tokenSection != null) { @@ -207,8 +150,7 @@ private boolean loadAndBind() { try { cfg.save(config); } catch (IOException e) { - getLogger().log(Level.SEVERE, - "Error generating Votifier token", e); + getLogger().log(Level.SEVERE, "Error generating Votifier token", e); return false; } getLogger().info("------------------------------------------------------------------------------"); @@ -219,7 +161,6 @@ private boolean loadAndBind() { getLogger().info("------------------------------------------------------------------------------"); } - // Initialize the receiver. final String host = cfg.getString("host", hostAddr); final int port = cfg.getInt("port", 8192); if (!debug) @@ -246,7 +187,7 @@ private boolean loadAndBind() { ConfigurationSection forwardingConfig = cfg.getConfigurationSection("forwarding"); if (forwardingConfig != null) { - String method = forwardingConfig.getString("method", "none").toLowerCase(); //Default to lower case for case-insensitive searches + String method = forwardingConfig.getString("method", "none").toLowerCase(); if ("none".equals(method)) { getLogger().info("Method none selected for vote forwarding: Votes will not be received from a forwarder."); } else if ("pluginmessaging".equals(method)) { @@ -265,7 +206,6 @@ private boolean loadAndBind() { } private void halt() { - // Shut down the network handlers. if (bootstrap != null) { bootstrap.shutdown(); bootstrap = null; @@ -284,7 +224,7 @@ public void onEnable() { if (!loadAndBind()) { gracefulExit(); - setEnabled(false); // safer to just bomb out + setEnabled(false); } } @@ -326,7 +266,7 @@ public LoggingAdapter getPluginLogger() { @Override public VotifierScheduler getScheduler() { - return scheduler; + return votifierScheduler; } public boolean isDebug() { @@ -381,13 +321,9 @@ private void fireVotifierEvent(Vote vote) { } if (!isFolia) { - getServer().getScheduler().runTask( - this, () -> getServer().getPluginManager().callEvent(new VotifierEvent(vote)) - ); + votifierScheduler.delayedOnPool(() -> getServer().getPluginManager().callEvent(new VotifierEvent(vote)), 0, TimeUnit.MILLISECONDS); } else { - getServer().getScheduler().runTaskAsynchronously( - this, () -> getServer().getPluginManager().callEvent(new VotifierEvent(vote, true)) - ); + votifierScheduler.delayedOnPool(() -> getServer().getPluginManager().callEvent(new VotifierEvent(vote, true)), 0, TimeUnit.MILLISECONDS); } } -} +} \ No newline at end of file diff --git a/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/FoliaScheduledTask.java b/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/FoliaScheduledTask.java new file mode 100644 index 0000000..63b454b --- /dev/null +++ b/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/FoliaScheduledTask.java @@ -0,0 +1,39 @@ +package com.vexsoftware.votifier.scheduling; + +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +public class FoliaScheduledTask implements com.vexsoftware.votifier.scheduling.ScheduledTask { + private final ScheduledTask task; + + public FoliaScheduledTask(final ScheduledTask task) { + this.task = task; + } + + @Override + public void cancel() { + this.task.cancel(); + } + + @Override + public boolean isCancelled() { + return this.task.isCancelled(); + } + + @Override + public @NotNull Plugin getOwningPlugin() { + return this.task.getOwningPlugin(); + } + + @Override + public boolean isCurrentlyRunning() { + final ScheduledTask.ExecutionState state = this.task.getExecutionState(); + return state == ScheduledTask.ExecutionState.RUNNING || state == ScheduledTask.ExecutionState.CANCELLED_RUNNING; + } + + @Override + public boolean isRepeatingTask() { + return this.task.isRepeatingTask(); + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/FoliaTaskScheduler.java b/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/FoliaTaskScheduler.java new file mode 100644 index 0000000..1a35403 --- /dev/null +++ b/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/FoliaTaskScheduler.java @@ -0,0 +1,181 @@ +package com.vexsoftware.votifier.scheduling; + +import com.vexsoftware.votifier.scheduling.ScheduledTask; +import com.vexsoftware.votifier.scheduling.TaskScheduler; +import io.papermc.paper.threadedregions.scheduler.AsyncScheduler; +import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler; +import io.papermc.paper.threadedregions.scheduler.RegionScheduler; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.plugin.Plugin; +import org.checkerframework.framework.qual.DefaultQualifier; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; + +@DefaultQualifier(NotNull.class) +public class FoliaTaskScheduler implements TaskScheduler { + private static final long MS_PER_TICK = 50L; // in an ideal world + private final RegionScheduler regionScheduler = Bukkit.getServer().getRegionScheduler(); + final GlobalRegionScheduler globalRegionScheduler = Bukkit.getServer().getGlobalRegionScheduler(); + private final AsyncScheduler asyncScheduler = Bukkit.getServer().getAsyncScheduler(); + final Plugin plugin; + + public FoliaTaskScheduler(final Plugin plugin) { + this.plugin = plugin; + } + + @Override + public boolean isGlobalThread() { + return Bukkit.getServer().isGlobalTickThread(); + } + + @Override + public boolean isTickThread() { + return Bukkit.getServer().isPrimaryThread(); // The Paper implementation checks whether this is a tick thread, this method exists to avoid confusion. + } + + @Override + public boolean isEntityThread(final Entity entity) { + return Bukkit.getServer().isOwnedByCurrentRegion(entity); + } + + @Override + public boolean isRegionThread(final Location location) { + return Bukkit.getServer().isOwnedByCurrentRegion(location); + } + + @Override + public ScheduledTask run(final Consumer task) { + return runAsync(task); + } + + @Override + public ScheduledTask run(final Entity entity, final Consumer task) { + final AtomicReference taskRef = new AtomicReference<>(); + taskRef.set(new FoliaScheduledTask(entity.getScheduler().run(this.plugin, t -> task.accept(taskRef.get()), null))); + + return taskRef.get(); + } + + @Override + public ScheduledTask run(final Location location, final Consumer task) { + final AtomicReference taskRef = new AtomicReference<>(); + taskRef.set(new FoliaScheduledTask(regionScheduler.run(this.plugin, location, t -> task.accept(taskRef.get())))); + + return taskRef.get(); + } + + @Override + public ScheduledTask runLater(final Consumer task, final long delay) { + if (delay == 0) + return run(task); + + return runAsyncLater(task, delay * MS_PER_TICK, TimeUnit.MILLISECONDS); + } + + @Override + public ScheduledTask runLater(final Entity entity, final Consumer task, final long delay) { + if (delay == 0) + return run(entity, task); + + final AtomicReference taskRef = new AtomicReference<>(); + taskRef.set(new FoliaScheduledTask(entity.getScheduler().runDelayed(this.plugin, t -> task.accept(taskRef.get()), null, delay))); + + return taskRef.get(); + } + + @Override + public ScheduledTask runLater(final Location location, final Consumer task, final long delay) { + if (delay == 0) + return run(location, task); + + final AtomicReference taskRef = new AtomicReference<>(); + taskRef.set(new FoliaScheduledTask(regionScheduler.runDelayed(this.plugin, location, t -> task.accept(taskRef.get()), delay))); + + return taskRef.get(); + } + + @Override + public ScheduledTask runRepeating(final Consumer task, final long delay, final long period) { + return runAsyncRepeating(task, delay * MS_PER_TICK, period * MS_PER_TICK, TimeUnit.MILLISECONDS); + } + + @Override + public ScheduledTask runRepeating(final Entity entity, final Consumer task, final long delay, final long period) { + final AtomicReference taskRef = new AtomicReference<>(); + taskRef.set(new FoliaScheduledTask(entity.getScheduler().runAtFixedRate(this.plugin, t -> task.accept(taskRef.get()), null, delay, period))); + + return taskRef.get(); + } + + @Override + public ScheduledTask runRepeating(final Location location, final Consumer task, final long delay, final long period) { + final AtomicReference taskRef = new AtomicReference<>(); + taskRef.set(new FoliaScheduledTask(regionScheduler.runAtFixedRate(this.plugin, location, t -> task.accept(taskRef.get()), delay, period))); + + return taskRef.get(); + } + + @Override + public ScheduledTask runAsync(final Consumer task) { + final AtomicReference taskRef = new AtomicReference<>(); + taskRef.set(new FoliaScheduledTask(this.asyncScheduler.runNow(this.plugin, t -> task.accept(taskRef.get())))); + + return taskRef.get(); + } + + @Override + public ScheduledTask runAsyncLater(final Consumer task, final long delay, TimeUnit timeUnit) { + if (delay == 0) + return runAsync(task); + + final AtomicReference taskRef = new AtomicReference<>(); + taskRef.set(new FoliaScheduledTask(this.asyncScheduler.runDelayed(this.plugin, t -> task.accept(taskRef.get()), delay, timeUnit))); + + return taskRef.get(); + } + + @Override + public ScheduledTask runAsyncRepeating(final Consumer task, final long delay, final long period, TimeUnit timeUnit) { + final AtomicReference taskRef = new AtomicReference<>(); + taskRef.set(new FoliaScheduledTask(this.asyncScheduler.runAtFixedRate(this.plugin, t -> task.accept(taskRef.get()), delay, period, timeUnit))); + + return taskRef.get(); + } + + @Override + public ScheduledTask runGlobal(final Consumer task) { + final AtomicReference taskRef = new AtomicReference<>(); + taskRef.set(new FoliaScheduledTask(this.globalRegionScheduler.run(this.plugin, t -> task.accept(taskRef.get())))); + + return taskRef.get(); + } + + @Override + public ScheduledTask runGlobalLater(final Consumer task, final long delay) { + final AtomicReference taskRef = new AtomicReference<>(); + taskRef.set(new FoliaScheduledTask(this.globalRegionScheduler.runDelayed(this.plugin, t -> task.accept(taskRef.get()), delay))); + + return taskRef.get(); + } + + @Override + public ScheduledTask runGlobalRepeating(final Consumer task, final long delay, final long period) { + final AtomicReference taskRef = new AtomicReference<>(); + taskRef.set(new FoliaScheduledTask(this.globalRegionScheduler.runAtFixedRate(this.plugin, t -> task.accept(taskRef.get()), delay, period))); + + return taskRef.get(); + } + + /** + * Cancels all active tasks that have been scheduled by {@code this.plugin} + */ + public void cancelTasks() { + this.asyncScheduler.cancelTasks(this.plugin); + this.globalRegionScheduler.cancelTasks(this.plugin); + } +} diff --git a/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/ScheduledTask.java b/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/ScheduledTask.java new file mode 100644 index 0000000..4aba5c2 --- /dev/null +++ b/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/ScheduledTask.java @@ -0,0 +1,16 @@ +package com.vexsoftware.votifier.scheduling; + +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +public interface ScheduledTask { + void cancel(); + + boolean isCancelled(); + + @NotNull Plugin getOwningPlugin(); + + boolean isCurrentlyRunning(); + + boolean isRepeatingTask(); +} \ No newline at end of file diff --git a/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/TaskScheduler.java b/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/TaskScheduler.java new file mode 100644 index 0000000..e5ed4ed --- /dev/null +++ b/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/TaskScheduler.java @@ -0,0 +1,124 @@ +package com.vexsoftware.votifier.scheduling; + +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.checkerframework.framework.qual.DefaultQualifier; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +@DefaultQualifier(NotNull.class) +public interface TaskScheduler { + boolean isGlobalThread(); + + boolean isTickThread(); + + boolean isEntityThread(Entity entity); + + boolean isRegionThread(Location location); + + ScheduledTask run(Consumer task); + + default ScheduledTask run(Entity entity, Consumer task) { + return run(task); + } + + default ScheduledTask run(Location location, Consumer task) { + return run(task); + } + + ScheduledTask runLater(Consumer task, long delay); + + default ScheduledTask runLater(Entity entity, Consumer task, long delay) { + return runLater(task, delay); + } + + default ScheduledTask runLater(Location location, Consumer task, long delay) { + return runLater(task, delay); + } + + ScheduledTask runRepeating(Consumer task, long delay, long period); + + default ScheduledTask runRepeating(Entity entity, Consumer task, long delay, long period) { + return runRepeating(task, delay, period); + } + + default ScheduledTask runRepeating(Location location, Consumer task, long delay, long period) { + return runRepeating(task, delay, period); + } + + ScheduledTask runAsync(Consumer task); + + ScheduledTask runAsyncLater(Consumer task, long delay, TimeUnit timeUnit); + + ScheduledTask runAsyncRepeating(Consumer task, long delay, long period, TimeUnit timeUnit); + + @ApiStatus.Experimental + default ScheduledTask runGlobal(final Consumer task) { + return run(task); + } + + @ApiStatus.Experimental + default ScheduledTask runGlobalLater(final Consumer task, final long delay) { + return runLater(task, delay); + } + + @ApiStatus.Experimental + default ScheduledTask runGlobalRepeating(final Consumer task, final long delay, final long period) { + return runRepeating(task, delay, period); + } + + /* + * Runnable methods + */ + + default ScheduledTask run(Runnable runnable) { + return run(task -> runnable.run()); + } + + default ScheduledTask run(Entity entity, Runnable runnable) { + return run(entity, task -> runnable.run()); + } + + default ScheduledTask run(Location location, Runnable runnable) { + return run(location, task -> runnable.run()); + } + + default ScheduledTask runLater(Runnable runnable, long delay) { + return runLater(task -> runnable.run(), delay); + } + + default ScheduledTask runLater(Entity entity, Runnable runnable, long delay) { + return runLater(entity, task -> runnable.run(), delay); + } + + default ScheduledTask runLater(Location location, Runnable runnable, long delay) { + return runLater(location, task -> runnable.run(), delay); + } + + default ScheduledTask runRepeating(Runnable runnable, long delay, long period) { + return runRepeating(task -> runnable.run(), delay, period); + } + + default ScheduledTask runRepeating(Entity entity, Runnable runnable, long delay, long period) { + return runRepeating(entity, task -> runnable.run(), delay, period); + } + + default ScheduledTask runRepeating(Location location, Runnable runnable, long delay, long period) { + return runRepeating(location, task -> runnable.run(), delay, period); + } + + default ScheduledTask runAsync(Runnable runnable) { + return runAsync(task -> runnable.run()); + } + + default ScheduledTask runAsyncLater(Runnable runnable, long delay) { + return runAsyncLater(task -> runnable.run(), delay * 50, TimeUnit.MILLISECONDS); + } + + default ScheduledTask runAsyncRepeating(Runnable runnable, long delay, long period) { + return runAsyncRepeating(task -> runnable.run(), delay * 50, period * 50, TimeUnit.MILLISECONDS); + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/TaskSchedulerAdapter.java b/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/TaskSchedulerAdapter.java new file mode 100644 index 0000000..fe88b4e --- /dev/null +++ b/bukkit/src/main/java/com/vexsoftware/votifier/scheduling/TaskSchedulerAdapter.java @@ -0,0 +1,36 @@ +package com.vexsoftware.votifier.scheduling; + +import com.vexsoftware.votifier.platform.scheduler.ScheduledVotifierTask; +import com.vexsoftware.votifier.platform.scheduler.VotifierScheduler; +import java.util.concurrent.TimeUnit; + +public class TaskSchedulerAdapter implements VotifierScheduler { + private final TaskScheduler taskScheduler; + + public TaskSchedulerAdapter(TaskScheduler taskScheduler) { + this.taskScheduler = taskScheduler; + } + + @Override + public ScheduledVotifierTask delayedOnPool(Runnable runnable, int delay, TimeUnit unit) { + return new ScheduledVotifierTaskAdapter(taskScheduler.runAsyncLater(task -> runnable.run(), delay, unit)); + } + + @Override + public ScheduledVotifierTask repeatOnPool(Runnable runnable, int delay, int repeat, TimeUnit unit) { + return new ScheduledVotifierTaskAdapter(taskScheduler.runAsyncRepeating(task -> runnable.run(), delay, repeat, unit)); + } + + private static class ScheduledVotifierTaskAdapter implements ScheduledVotifierTask { + private final ScheduledTask scheduledTask; + + ScheduledVotifierTaskAdapter(ScheduledTask scheduledTask) { + this.scheduledTask = scheduledTask; + } + + @Override + public void cancel() { + scheduledTask.cancel(); + } + } +} \ No newline at end of file diff --git a/universal/build.gradle.kts b/universal/build.gradle.kts index c2da0ab..057dfc4 100644 --- a/universal/build.gradle.kts +++ b/universal/build.gradle.kts @@ -16,7 +16,7 @@ dependencies { "implementation"(project(":nuvotifier-common")) "implementation"(project(":nuvotifier-bukkit")) "implementation"(project(":nuvotifier-bungeecord")) - "implementation"(project(":nuvotifier-sponge")) + //"implementation"(project(":nuvotifier-sponge")) "implementation"(project(":nuvotifier-fabric")) "implementation"(project(":nuvotifier-velocity")) }