package ch.njol.skript.util; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.Skript; import ch.njol.util.Closeable; /** * @author Peter Güttinger */ public abstract class Task implements Runnable, Closeable { private final Plugin plugin; private final boolean async; private long period = -1; private int taskID = -1; public Task(final Plugin plugin, final long delay, final long period) { this(plugin, delay, period, false); } public Task(final Plugin plugin, final long delay, final long period, final boolean async) { this.plugin = plugin; this.period = period; this.async = async; schedule(delay); } public Task(final Plugin plugin, final long delay) { this(plugin, delay, false); } public Task(final Plugin plugin, final long delay, final boolean async) { this.plugin = plugin; this.async = async; schedule(delay); } /** * Only call this if the task is not alive. * * @param delay */ @SuppressWarnings("deprecation") private void schedule(final long delay) { assert !isAlive(); if (period == -1) { if (async) { taskID = Skript.isRunningMinecraft(1, 4, 6) ? Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, this, delay).getTaskId() : Bukkit.getScheduler().scheduleAsyncDelayedTask(plugin, this, delay); } else { taskID = Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, this, delay); } } else { if (async) { taskID = Skript.isRunningMinecraft(1, 4, 6) ? Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, this, delay, period).getTaskId() : Bukkit.getScheduler().scheduleAsyncRepeatingTask(plugin, this, delay, period); } else { taskID = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, this, delay, period); } } assert taskID != -1; } /** * @return Whether this task is still running, i.e. whether it will run later or is currently running. */ public final boolean isAlive() { if (taskID == -1) return false; return Bukkit.getScheduler().isQueued(taskID) || Bukkit.getScheduler().isCurrentlyRunning(taskID); } /** * Cancels this task. */ public final void cancel() { if (taskID != -1) { Bukkit.getScheduler().cancelTask(taskID); taskID = -1; } } @Override public void close() { cancel(); } /** * Re-schedules the task to run next after the given delay. If this task was repeating it will continue so using the same period as before. * * @param delay */ public void setNextExecution(final long delay) { assert delay >= 0; cancel(); schedule(delay); } /** * Sets the period of this task. This will re-schedule the task to be run next after the given period if the task is still running. * * @param period Period in ticks or -1 to cancel the task and make it non-repeating */ public void setPeriod(final long period) { assert period == -1 || period > 0; if (period == this.period) return; this.period = period; if (isAlive()) { cancel(); if (period != -1) schedule(period); } } /** * Equivalent to <tt>{@link #callSync(Callable, Plugin) callSync}(c, {@link Skript#getInstance()})</tt> */ @Nullable public final static <T> T callSync(final Callable<T> c) { return callSync(c, Skript.getInstance()); } /** * Calls a method on Bukkit's main thread. * <p> * Hint: Use a Callable<Void> to make a task which blocks your current thread until it is completed. * * @param c The method * @param p The plugin that owns the task. Must be enabled. * @return What the method returned or null if it threw an error or was stopped (usually due to the server shutting down) */ @Nullable public final static <T> T callSync(final Callable<T> c, final Plugin p) { if (Bukkit.isPrimaryThread()) { try { return c.call(); } catch (final Exception e) { Skript.exception(e); } } final Future<T> f = Bukkit.getScheduler().callSyncMethod(p, c); try { while (true) { try { return f.get(); } catch (final InterruptedException e) {} } } catch (final ExecutionException e) { Skript.exception(e); } catch (final CancellationException e) {} catch (final ThreadDeath e) {}// server shutting down return null; } }