Skip to content
This repository was archived by the owner on Aug 12, 2025. It is now read-only.

Commit 3e11654

Browse files
committed
Refactor CoreScheduler and ScheduledTask to remove Bukkit dependencies and implement a standalone, thread-safe scheduling system
1 parent 67bcfaf commit 3e11654

2 files changed

Lines changed: 58 additions & 221 deletions

File tree

Lines changed: 45 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -1,220 +1,94 @@
11
package gg.nextforge.scheduler;
22

33
import lombok.Getter;
4-
import org.bukkit.Bukkit;
5-
import org.bukkit.plugin.Plugin;
6-
import org.bukkit.scheduler.BukkitTask;
74

8-
import java.util.Collection;
95
import java.util.Map;
10-
import java.util.concurrent.ConcurrentHashMap;
6+
import java.util.concurrent.*;
117
import java.util.concurrent.atomic.AtomicInteger;
128

139
/**
14-
* A wrapper around Bukkit's scheduler to simplify task management.
15-
* <p>
16-
* Features:
17-
* - Static access for convenience (e.g., CoreScheduler.runLater())
18-
* - Automatic task cleanup
19-
* - Cancel tokens for better task control
20-
* - Avoids manual tracking of task IDs
10+
* A standalone, thread-safe scheduler implementation.
11+
* No Bukkit dependencies, suitable for general Java use.
2112
*/
2213
public class CoreScheduler {
2314

24-
private static CoreScheduler instance; // Singleton instance of CoreScheduler
25-
private final Plugin plugin; // Plugin instance for scheduling tasks
15+
private static CoreScheduler instance;
16+
2617
@Getter
27-
private static final Map<Integer, ScheduledTask> activeTasks = new ConcurrentHashMap<>(); // Active tasks map
28-
private final AtomicInteger taskCounter = new AtomicInteger(0); // Counter for task IDs
29-
30-
/**
31-
* Constructs a CoreScheduler instance.
32-
*
33-
* @param plugin The plugin instance.
34-
*/
35-
public CoreScheduler(Plugin plugin) {
36-
this.plugin = plugin;
18+
private static final Map<Integer, ScheduledTask> activeTasks = new ConcurrentHashMap<>();
19+
20+
private final ScheduledExecutorService executorService;
21+
private final AtomicInteger taskCounter = new AtomicInteger(0);
22+
23+
public CoreScheduler() {
24+
this.executorService = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
3725
instance = this;
3826
}
3927

40-
/**
41-
* Runs a task on the next tick.
42-
*
43-
* @param task The task to run.
44-
* @return A ScheduledTask representing the scheduled task.
45-
*/
4628
public static ScheduledTask run(Runnable task) {
47-
return instance.runTask(task);
29+
return instance.schedule(task, 0, false, false);
4830
}
4931

50-
// Static convenience methods for scheduling tasks
51-
52-
/**
53-
* Runs a task after a specified delay.
54-
*
55-
* @param task The task to run.
56-
* @param delay The delay in ticks (20 ticks = 1 second).
57-
* @return A ScheduledTask representing the scheduled task.
58-
*/
59-
public static ScheduledTask runLater(Runnable task, long delay) {
60-
return instance.runTaskLater(task, delay);
32+
public static ScheduledTask runLater(Runnable task, long delayTicks) {
33+
return instance.schedule(task, delayTicks, false, false);
6134
}
6235

63-
/**
64-
* Runs a task repeatedly with a specified delay and interval.
65-
*
66-
* @param task The task to run.
67-
* @param delay The initial delay in ticks.
68-
* @param period The interval between executions in ticks.
69-
* @return A ScheduledTask representing the scheduled task.
70-
*/
71-
public static ScheduledTask runTimer(Runnable task, long delay, long period) {
72-
return instance.runTaskTimer(task, delay, period);
36+
public static ScheduledTask runTimer(Runnable task, long delayTicks, long periodTicks) {
37+
return instance.scheduleRepeating(task, delayTicks, periodTicks, false);
7338
}
7439

75-
/**
76-
* Runs a task asynchronously.
77-
*
78-
* @param task The task to run.
79-
* @return A ScheduledTask representing the scheduled task.
80-
*/
8140
public static ScheduledTask runAsync(Runnable task) {
82-
return instance.runTaskAsync(task);
41+
return instance.schedule(task, 0, true, false);
8342
}
8443

85-
/**
86-
* Runs a task asynchronously after a specified delay.
87-
*
88-
* @param task The task to run.
89-
* @param delay The delay in ticks.
90-
* @return A ScheduledTask representing the scheduled task.
91-
*/
92-
public static ScheduledTask runAsyncLater(Runnable task, long delay) {
93-
return instance.runTaskAsyncLater(task, delay);
44+
public static ScheduledTask runAsyncLater(Runnable task, long delayTicks) {
45+
return instance.schedule(task, delayTicks, true, false);
9446
}
9547

96-
/**
97-
* Runs a task asynchronously and repeatedly.
98-
*
99-
* @param task The task to run.
100-
* @param delay The initial delay in ticks.
101-
* @param period The interval between executions in ticks.
102-
* @return A ScheduledTask representing the scheduled task.
103-
*/
104-
public static ScheduledTask runAsyncTimer(Runnable task, long delay, long period) {
105-
return instance.runTaskAsyncTimer(task, delay, period);
48+
public static ScheduledTask runAsyncTimer(Runnable task, long delayTicks, long periodTicks) {
49+
return instance.scheduleRepeating(task, delayTicks, periodTicks, true);
10650
}
10751

108-
/**
109-
* Cleans up all active tasks.
110-
* Should be called when the plugin is disabled.
111-
*/
11252
public void shutdown() {
11353
activeTasks.values().forEach(ScheduledTask::cancel);
11454
activeTasks.clear();
55+
executorService.shutdownNow();
11556
}
11657

117-
// Instance methods for scheduling tasks
118-
119-
private ScheduledTask runTask(Runnable task) {
120-
int id = taskCounter.incrementAndGet();
121-
ScheduledTask scheduled = new ScheduledTask(id);
122-
123-
BukkitTask bukkitTask = Bukkit.getScheduler().runTask(plugin, () -> {
124-
try {
125-
task.run();
126-
} finally {
127-
activeTasks.remove(id);
128-
}
129-
});
130-
131-
scheduled.setBukkitTask(bukkitTask);
132-
activeTasks.put(id, scheduled);
133-
return scheduled;
134-
}
135-
136-
private ScheduledTask runTaskLater(Runnable task, long delay) {
137-
int id = taskCounter.incrementAndGet();
138-
ScheduledTask scheduled = new ScheduledTask(id);
139-
140-
BukkitTask bukkitTask = Bukkit.getScheduler().runTaskLater(plugin, () -> {
141-
try {
142-
task.run();
143-
} finally {
144-
activeTasks.remove(id);
145-
}
146-
}, delay);
147-
148-
scheduled.setBukkitTask(bukkitTask);
149-
activeTasks.put(id, scheduled);
150-
return scheduled;
151-
}
152-
153-
private ScheduledTask runTaskTimer(Runnable task, long delay, long period) {
154-
int id = taskCounter.incrementAndGet();
155-
ScheduledTask scheduled = new ScheduledTask(id);
156-
157-
BukkitTask bukkitTask = Bukkit.getScheduler().runTaskTimer(plugin, task, delay, period);
158-
159-
scheduled.setBukkitTask(bukkitTask);
160-
activeTasks.put(id, scheduled);
161-
return scheduled;
162-
}
163-
164-
private ScheduledTask runTaskAsync(Runnable task) {
165-
int id = taskCounter.incrementAndGet();
166-
ScheduledTask scheduled = new ScheduledTask(id);
167-
168-
BukkitTask bukkitTask = Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
169-
try {
170-
task.run();
171-
} finally {
172-
activeTasks.remove(id);
173-
}
174-
});
175-
176-
scheduled.setBukkitTask(bukkitTask);
177-
activeTasks.put(id, scheduled);
178-
return scheduled;
179-
}
180-
181-
private ScheduledTask runTaskAsyncLater(Runnable task, long delay) {
58+
private ScheduledTask schedule(Runnable task, long delayTicks, boolean async, boolean repeating) {
18259
int id = taskCounter.incrementAndGet();
183-
ScheduledTask scheduled = new ScheduledTask(id);
60+
ScheduledTask scheduledTask = new ScheduledTask(id);
61+
long delayMillis = ticksToMillis(delayTicks);
18462

185-
BukkitTask bukkitTask = Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> {
63+
ScheduledFuture<?> future = executorService.schedule(() -> {
18664
try {
18765
task.run();
18866
} finally {
189-
activeTasks.remove(id);
67+
if (!repeating) {
68+
activeTasks.remove(id);
69+
}
19070
}
191-
}, delay);
71+
}, delayMillis, TimeUnit.MILLISECONDS);
19272

193-
scheduled.setBukkitTask(bukkitTask);
194-
activeTasks.put(id, scheduled);
195-
return scheduled;
73+
scheduledTask.setFuture(future);
74+
activeTasks.put(id, scheduledTask);
75+
return scheduledTask;
19676
}
19777

198-
private ScheduledTask runTaskAsyncTimer(Runnable task, long delay, long period) {
78+
private ScheduledTask scheduleRepeating(Runnable task, long delayTicks, long periodTicks, boolean async) {
19979
int id = taskCounter.incrementAndGet();
200-
ScheduledTask scheduled = new ScheduledTask(id);
80+
ScheduledTask scheduledTask = new ScheduledTask(id);
81+
long delayMillis = ticksToMillis(delayTicks);
82+
long periodMillis = ticksToMillis(periodTicks);
20183

202-
BukkitTask bukkitTask = Bukkit.getScheduler().runTaskTimerAsynchronously(
203-
plugin, task, delay, period
204-
);
84+
ScheduledFuture<?> future = executorService.scheduleAtFixedRate(task, delayMillis, periodMillis, TimeUnit.MILLISECONDS);
20585

206-
scheduled.setBukkitTask(bukkitTask);
207-
activeTasks.put(id, scheduled);
208-
return scheduled;
86+
scheduledTask.setFuture(future);
87+
activeTasks.put(id, scheduledTask);
88+
return scheduledTask;
20989
}
21090

211-
/**
212-
* Runs a task on the main thread.
213-
* Useful for accessing Bukkit API from asynchronous tasks.
214-
*
215-
* @param task The task to run.
216-
*/
217-
public void runSync(Runnable task) {
218-
Bukkit.getScheduler().runTask(plugin, task);
91+
private long ticksToMillis(long ticks) {
92+
return ticks * 50L; // 20 ticks = 1 second
21993
}
220-
}
94+
}
Lines changed: 13 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,25 @@
11
package gg.nextforge.scheduler;
22

3-
import org.bukkit.Bukkit;
4-
import org.bukkit.scheduler.BukkitTask;
3+
import lombok.Getter;
4+
import lombok.Setter;
5+
6+
import java.util.concurrent.ScheduledFuture;
57

6-
/**
7-
* Represents a scheduled task that can be cancelled.
8-
*/
98
public class ScheduledTask {
10-
private final int id; // Unique ID for the task
11-
private BukkitTask bukkitTask; // Bukkit task instance
12-
private volatile boolean cancelled = false; // Flag indicating if the task is cancelled
139

14-
/**
15-
* Constructs a ScheduledTask instance.
16-
*
17-
* @param id The unique ID for the task.
18-
*/
19-
ScheduledTask(int id) {
20-
this.id = id;
21-
}
10+
@Getter
11+
private final int id;
2212

23-
/**
24-
* Sets the BukkitTask instance for this ScheduledTask.
25-
*
26-
* @param task The BukkitTask instance.
27-
*/
28-
void setBukkitTask(BukkitTask task) {
29-
this.bukkitTask = task;
13+
@Setter
14+
private ScheduledFuture<?> future;
15+
16+
public ScheduledTask(int id) {
17+
this.id = id;
3018
}
3119

32-
/**
33-
* Cancels this task.
34-
* Can be called multiple times safely.
35-
*/
3620
public void cancel() {
37-
if (!cancelled && bukkitTask != null) {
38-
bukkitTask.cancel();
39-
cancelled = true;
40-
CoreScheduler.getActiveTasks().remove(id);
21+
if (future != null) {
22+
future.cancel(false);
4123
}
4224
}
43-
44-
/**
45-
* Checks if this task is still active.
46-
*
47-
* @return True if the task is running, false otherwise.
48-
*/
49-
public boolean isActive() {
50-
return !cancelled && bukkitTask != null &&
51-
Bukkit.getScheduler().isCurrentlyRunning(bukkitTask.getTaskId());
52-
}
53-
54-
/**
55-
* Retrieves the task ID of this ScheduledTask.
56-
*
57-
* @return The task ID, or -1 if the task is not active.
58-
*/
59-
public int getTaskId() {
60-
return bukkitTask != null ? bukkitTask.getTaskId() : -1;
61-
}
6225
}

0 commit comments

Comments
 (0)