ServerTaskScheduler.java 4.75 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package emu.grasscutter.server.scheduler;

import java.util.concurrent.ConcurrentHashMap;

/**
 * A class to manage all time-based tasks scheduled on the server.
 * This handles both synchronous and asynchronous tasks.
 *
 * Developers note: A server tick is ONE REAL-TIME SECOND.
 */
public final class ServerTaskScheduler {
    /* A map to contain all running tasks. */
    private final ConcurrentHashMap<Integer, ServerTask> tasks
        = new ConcurrentHashMap<>();
    /* A map to contain all async tasks. */
    private final ConcurrentHashMap<Integer, AsyncServerTask> asyncTasks
        = new ConcurrentHashMap<>();

    /* The ID assigned to the next runnable. */
    private int nextTaskId = 0;

    /**
     * Ran every server tick.
     * Attempts to run all scheduled tasks.
     * This method is synchronous and will block until all tasks are complete.
     */
    public void runTasks() {
        // Skip if there are no tasks.
        if(this.tasks.size() == 0)
            return;

        // Run all tasks.
        for(ServerTask task : this.tasks.values()) {
            // Check if the task should run.
            if (task.shouldRun()) {
                // Run the task.
                task.run();
            }

            // Check if the task should be canceled.
            if (task.shouldCancel()) {
                // Cancel the task.
                this.cancelTask(task.getTaskId());
            }
        }

        // Run all async tasks.
        for(AsyncServerTask task : this.asyncTasks.values()) {
            if(!task.hasStarted()) {
                // Create a thread for the task.
                Thread thread = new Thread(task);
                // Start the thread.
                thread.start();
            } else if(task.isFinished()) {
                // Cancel the task.
                this.asyncTasks.remove(task.getTaskId());
                // Run the task's callback.
                task.complete();
            }
        }
    }

    /**
     * Gets a task from the scheduler.
     * @param taskId The ID of the task to get.
     * @return The task, or null if it does not exist.
     */
    public ServerTask getTask(int taskId) {
        return this.tasks.get(taskId);
    }

    /**
     * Gets an async task from the scheduler.
     * @param taskId The ID of the task to get.
     * @return The task, or null if it does not exist.
     */
    public AsyncServerTask getAsyncTask(int taskId) {
        return this.asyncTasks.get(taskId);
    }

    /**
     * Removes a task from the scheduler.
     * @param taskId The ID of the task to remove.
     */
    public void cancelTask(int taskId) {
        this.tasks.remove(taskId);
    }

    /**
     * Schedules a task to be run on a separate thread.
     * The task runs on the next server tick.
     * @param runnable The runnable to run.
     * @return The ID of the task.
     */
    public int scheduleAsyncTask(Runnable runnable) {
        // Get the next task ID.
        var taskId = this.nextTaskId++;
        // Create a new task.
        this.asyncTasks.put(taskId, new AsyncServerTask(runnable, taskId));
        // Return the task ID.
        return taskId;
    }

    /**
     * Schedules a task to be run on the next server tick.
     * @param runnable The runnable to run.
     * @return The ID of the task.
     */
    public int scheduleTask(Runnable runnable) {
        return this.scheduleDelayedRepeatingTask(runnable, -1, -1);
    }

    /**
     * Schedules a task to be run after the amount of ticks has passed.
     * @param runnable The runnable to run.
     * @param delay The amount of ticks to wait before running.
     * @return The ID of the task.
     */
    public int scheduleDelayedTask(Runnable runnable, int delay) {
        return this.scheduleDelayedRepeatingTask(runnable, -1, delay);
    }

    /**
     * Schedules a task to be run every amount of ticks.
     * @param runnable The runnable to run.
     * @param period The amount of ticks to wait before running again.
     * @return The ID of the task.
     */
    public int scheduleRepeatingTask(Runnable runnable, int period) {
        return this.scheduleDelayedRepeatingTask(runnable, period, 0);
    }

    /**
     * Schedules a task to be run after the amount of ticks has passed.
     * @param runnable The runnable to run.
     * @param period The amount of ticks to wait before running again.
     * @param delay The amount of ticks to wait before running the first time.
     * @return The ID of the task.
     */
    public int scheduleDelayedRepeatingTask(Runnable runnable, int period, int delay) {
        // Get the next task ID.
        var taskId = this.nextTaskId++;
        // Create a new task.
        this.tasks.put(taskId, new ServerTask(runnable, taskId, period, delay));
        // Return the task ID.
        return taskId;
    }
}