Back

TaskSchedulerImpl.java

java
src/main/java/com/scriptslab/core/scheduler/TaskSchedulerImpl.java
package com.scriptslab.core.scheduler;

import com.scriptslab.api.scheduler.ScheduledTask;
import com.scriptslab.api.scheduler.TaskScheduler;

import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;

import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

/**
 * Implementation of TaskScheduler wrapping BukkitScheduler.
 * Thread-safe.
 */
public final class TaskSchedulerImpl implements TaskScheduler {
    
    private final Plugin plugin;
    private final BukkitScheduler scheduler;
    private final Map<Integer, ScheduledTaskImpl> tasks;
    private final AtomicInteger taskCounter;
    
    public TaskSchedulerImpl(Plugin plugin) {
        this.plugin = plugin;
        this.scheduler = Bukkit.getScheduler();
        this.tasks = new ConcurrentHashMap<>();
        this.taskCounter = new AtomicInteger(0);
    }
    
    @Override
    public ScheduledTask runTask(Runnable task) {
        BukkitTask bukkitTask = scheduler.runTask(plugin, task);
        return wrapTask(bukkitTask, task, true);
    }
    
    @Override
    public ScheduledTask runTaskAsync(Runnable task) {
        BukkitTask bukkitTask = scheduler.runTaskAsynchronously(plugin, task);
        return wrapTask(bukkitTask, task, false);
    }
    
    @Override
    public ScheduledTask runTaskLater(Runnable task, long delay, TimeUnit unit) {
        long ticks = toTicks(delay, unit);
        BukkitTask bukkitTask = scheduler.runTaskLater(plugin, task, ticks);
        return wrapTask(bukkitTask, task, true);
    }
    
    @Override
    public ScheduledTask runTaskLaterAsync(Runnable task, long delay, TimeUnit unit) {
        long ticks = toTicks(delay, unit);
        BukkitTask bukkitTask = scheduler.runTaskLaterAsynchronously(plugin, task, ticks);
        return wrapTask(bukkitTask, task, false);
    }
    
    @Override
    public ScheduledTask runTaskTimer(Runnable task, long delay, long period, TimeUnit unit) {
        long delayTicks = toTicks(delay, unit);
        long periodTicks = toTicks(period, unit);
        BukkitTask bukkitTask = scheduler.runTaskTimer(plugin, task, delayTicks, periodTicks);
        return wrapTask(bukkitTask, task, true);
    }
    
    @Override
    public ScheduledTask runTaskTimerAsync(Runnable task, long delay, long period, TimeUnit unit) {
        long delayTicks = toTicks(delay, unit);
        long periodTicks = toTicks(period, unit);
        BukkitTask bukkitTask = scheduler.runTaskTimerAsynchronously(plugin, task, delayTicks, periodTicks);
        return wrapTask(bukkitTask, task, false);
    }
    
    @Override
    public <T> CompletableFuture<T> supply(Supplier<T> task) {
        CompletableFuture<T> future = new CompletableFuture<>();
        runTask(() -> {
            try {
                future.complete(task.get());
            } catch (Exception e) {
                future.completeExceptionally(e);
            }
        });
        return future;
    }
    
    @Override
    public <T> CompletableFuture<T> supplyAsync(Supplier<T> task) {
        CompletableFuture<T> future = new CompletableFuture<>();
        runTaskAsync(() -> {
            try {
                future.complete(task.get());
            } catch (Exception e) {
                future.completeExceptionally(e);
            }
        });
        return future;
    }
    
    @Override
    public void cancelTasks(Object owner) {
        tasks.values().removeIf(task -> {
            if (task.getOwner() == owner) {
                task.cancel();
                return true;
            }
            return false;
        });
    }
    
    @Override
    public void cancelAllTasks() {
        tasks.values().forEach(ScheduledTask::cancel);
        tasks.clear();
    }
    
    @Override
    public int getActiveTaskCount() {
        return (int) tasks.values().stream()
                .filter(task -> !task.isCancelled())
                .count();
    }
    
    /**
     * Converts time to Minecraft ticks (20 ticks = 1 second).
     */
    private long toTicks(long time, TimeUnit unit) {
        long millis = unit.toMillis(time);
        return millis / 50; // 1 tick = 50ms
    }
    
    /**
     * Wraps a BukkitTask into our ScheduledTask.
     */
    private ScheduledTask wrapTask(BukkitTask bukkitTask, Runnable task, boolean sync) {
        int id = taskCounter.incrementAndGet();
        ScheduledTaskImpl scheduledTask = new ScheduledTaskImpl(
                id, bukkitTask, task, sync);
        tasks.put(id, scheduledTask);
        return scheduledTask;
    }
    
    /**
     * Internal task implementation.
     */
    private class ScheduledTaskImpl implements ScheduledTask {
        
        private final int taskId;
        private final BukkitTask bukkitTask;
        private final Object owner;
        private final boolean sync;
        
        ScheduledTaskImpl(int taskId, BukkitTask bukkitTask, Object owner, boolean sync) {
            this.taskId = taskId;
            this.bukkitTask = bukkitTask;
            this.owner = owner;
            this.sync = sync;
        }
        
        @Override
        public int getTaskId() {
            return taskId;
        }
        
        @Override
        public boolean isCancelled() {
            return bukkitTask.isCancelled();
        }
        
        @Override
        public void cancel() {
            bukkitTask.cancel();
            tasks.remove(taskId);
        }
        
        @Override
        public boolean isRunning() {
            return !isCancelled();
        }
        
        @Override
        public boolean isSync() {
            return sync;
        }
        
        @Override
        public Object getOwner() {
            return owner;
        }
    }
}