001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.util.task; 020 021import org.checkerframework.checker.nullness.qual.NonNull; 022import org.checkerframework.checker.nullness.qual.Nullable; 023 024import java.util.Collection; 025import java.util.HashMap; 026import java.util.HashSet; 027import java.util.Iterator; 028import java.util.Map; 029import java.util.Set; 030import java.util.concurrent.Callable; 031import java.util.concurrent.CompletableFuture; 032import java.util.concurrent.Future; 033import java.util.concurrent.atomic.AtomicInteger; 034 035/** 036 * Task manager that handles scheduling of tasks. 037 * Synchronous methods make no guarantee of being scheduled on the 038 * server thread, instead they guarantee that no two synchronous 039 * operations happen at the same time. Implementations of 040 * the task manager might make other guarantees. All asynchronous 041 * operations will happen on another thread, no matter where 042 * they're scheduled from. 043 */ 044public abstract class TaskManager { 045 046 private static final Set<String> teleportQueue = new HashSet<>(); 047 private static final Map<Integer, PlotSquaredTask> tasks = new HashMap<>(); 048 public static AtomicInteger index = new AtomicInteger(0); 049 050 private static TaskManager platformImplementation; 051 052 /** 053 * Add a string to the teleport queue 054 * 055 * @param string String to add 056 */ 057 public static void addToTeleportQueue(final @NonNull String string) { 058 teleportQueue.add(string); 059 } 060 061 /** 062 * Remove a string from the teleport queue 063 * 064 * @param string String to remove 065 * return {@code true} if the value was stored in the map, or {@code false} 066 * @return if string was actually removed 067 */ 068 public static boolean removeFromTeleportQueue(final @NonNull String string) { 069 return teleportQueue.remove(string); 070 } 071 072 /** 073 * Add a task to the task map 074 * 075 * @param task Task 076 * @param id Task ID 077 */ 078 public static void addTask(final @NonNull PlotSquaredTask task, final int id) { 079 tasks.put(id, task); 080 } 081 082 /** 083 * Remove a task from the task map and return the stored value 084 * 085 * @param id Task ID 086 * @return Task if stored, or {@code null} 087 */ 088 public static @Nullable PlotSquaredTask removeTask(final int id) { 089 return tasks.remove(id); 090 } 091 092 /** 093 * Run a repeating synchronous task. If using a platform scheduler, 094 * this is guaranteed to run on the server thread 095 * 096 * @param runnable Task to run 097 * @param taskTime Task interval 098 * @return Created task object, can be used to cancel the task 099 */ 100 public static @NonNull PlotSquaredTask runTaskRepeat( 101 final @Nullable Runnable runnable, 102 final @NonNull TaskTime taskTime 103 ) { 104 if (runnable != null) { 105 if (getPlatformImplementation() == null) { 106 throw new IllegalArgumentException("disabled"); 107 } 108 return getPlatformImplementation().taskRepeat(runnable, taskTime); 109 } 110 return PlotSquaredTask.nullTask(); 111 } 112 113 /** 114 * Run an asynchronous task. This will never run on the server thread 115 * 116 * @param runnable Task to run 117 */ 118 public static void runTaskAsync(final @Nullable Runnable runnable) { 119 if (runnable != null) { 120 if (getPlatformImplementation() == null) { 121 runnable.run(); 122 return; 123 } 124 getPlatformImplementation().taskAsync(runnable); 125 } 126 } 127 128 /** 129 * Run a synchronous task. If using a platform scheduler, this is guaranteed 130 * to run on the server thread 131 * 132 * @param runnable Task to run 133 */ 134 public static void runTask(final @Nullable Runnable runnable) { 135 if (runnable != null) { 136 if (getPlatformImplementation() == null) { 137 runnable.run(); 138 return; 139 } 140 getPlatformImplementation().task(runnable); 141 } 142 } 143 144 /** 145 * Run a synchronous task after a given delay. 146 * If using a platform scheduler, this is guaranteed to run on the server thread 147 * 148 * @param runnable Task to run 149 * @param taskTime Task delay 150 */ 151 public static void runTaskLater( 152 final @Nullable Runnable runnable, 153 final @NonNull TaskTime taskTime 154 ) { 155 if (runnable != null) { 156 if (getPlatformImplementation() == null) { 157 runnable.run(); 158 return; 159 } 160 getPlatformImplementation().taskLater(runnable, taskTime); 161 } 162 } 163 164 /** 165 * Run an asynchronous task after a given delay. This will never 166 * run on the server thread 167 * 168 * @param runnable Task to run 169 * @param taskTime Task delay 170 */ 171 public static void runTaskLaterAsync( 172 final @Nullable Runnable runnable, 173 final @NonNull TaskTime taskTime 174 ) { 175 if (runnable != null) { 176 if (getPlatformImplementation() == null) { 177 runnable.run(); 178 return; 179 } 180 getPlatformImplementation().taskLaterAsync(runnable, taskTime); 181 } 182 } 183 184 public static @Nullable TaskManager getPlatformImplementation() { 185 return platformImplementation; 186 } 187 188 public static void setPlatformImplementation(final @NonNull TaskManager implementation) { 189 platformImplementation = implementation; 190 } 191 192 /** 193 * Break up a series of tasks so that they can run without lagging the server 194 * 195 * @param objects Objects to perform the task on 196 * @param task Task to perform 197 * @param <T> Object type 198 * @return Future that completes when the tasks are done 199 */ 200 public <T> CompletableFuture<Void> objectTask( 201 final @NonNull Collection<T> objects, 202 final @NonNull RunnableVal<T> task 203 ) { 204 final Iterator<T> iterator = objects.iterator(); 205 final ObjectTaskRunnable<T> taskRunnable = new ObjectTaskRunnable<>(iterator, task); 206 TaskManager.runTask(taskRunnable); 207 return taskRunnable.getCompletionFuture(); 208 } 209 210 /** 211 * Make a synchronous method call and return the result 212 * 213 * @param function Method to call 214 * @param <T> Return type 215 * @return Method result 216 * @throws Exception If the call fails 217 */ 218 public <T> T sync(final @NonNull Callable<T> function) throws Exception { 219 return sync(function, Integer.MAX_VALUE); 220 } 221 222 /** 223 * Make a synchronous method call and return the result 224 * 225 * @param function Method to call 226 * @param timeout Timeout (ms) 227 * @param <T> Return type 228 * @return Method result 229 * @throws Exception If the call fails 230 */ 231 public abstract <T> T sync(final @NonNull Callable<T> function, final int timeout) 232 throws Exception; 233 234 /** 235 * Call a method synchronously and return a future with 236 * the result of the result 237 * 238 * @param method Method to be ran synchronously 239 * @param <T> Return type 240 * @return Future completing with the result 241 */ 242 public abstract <T> Future<T> callMethodSync(final @NonNull Callable<T> method); 243 244 /** 245 * Run a repeating synchronous task. If using a platform scheduler, 246 * this is guaranteed to run on the server thread 247 * 248 * @param runnable Task to run 249 * @param taskTime Task interval 250 * @return Created task object, can be used to cancel the task 251 */ 252 public abstract PlotSquaredTask taskRepeat( 253 @NonNull Runnable runnable, 254 @NonNull TaskTime taskTime 255 ); 256 257 /** 258 * Run a repeating asynchronous task. This will never run on the 259 * server thread 260 * 261 * @param runnable Task to run 262 * @param taskTime Task interval 263 * @return Created task object, can be used to cancel the task 264 */ 265 public abstract PlotSquaredTask taskRepeatAsync( 266 @NonNull Runnable runnable, 267 @NonNull TaskTime taskTime 268 ); 269 270 /** 271 * Run an asynchronous task. This will never run on the server thread 272 * 273 * @param runnable Task to run 274 */ 275 public abstract void taskAsync(@NonNull Runnable runnable); 276 277 /** 278 * Run a synchronous task. If using a platform scheduler, this is guaranteed 279 * to run on the server thread 280 * 281 * @param runnable Task to run 282 */ 283 public abstract void task(@NonNull Runnable runnable); 284 285 /** 286 * Run a synchronous task after a given delay. 287 * If using a platform scheduler, this is guaranteed to run on the server thread 288 * 289 * @param runnable Task to run 290 * @param taskTime Task delay 291 */ 292 public abstract void taskLater(@NonNull Runnable runnable, @NonNull TaskTime taskTime); 293 294 /** 295 * Run an asynchronous task after a given delay. This will never 296 * run on the server thread 297 * 298 * @param runnable Task to run 299 * @param taskTime Task delay 300 */ 301 public abstract void taskLaterAsync(@NonNull Runnable runnable, @NonNull TaskTime taskTime); 302 303}