package emu.grasscutter.task; import emu.grasscutter.Grasscutter; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import org.reflections.Reflections; import java.util.*; @SuppressWarnings({"UnusedReturnValue", "unused"}) public final class TaskMap { private final Map tasks = new HashMap<>(); private final Map annotations = new HashMap<>(); private final Map afterReset = new HashMap<>(); private final SchedulerFactory schedulerFactory = new StdSchedulerFactory(); public TaskMap() { this(false); } public TaskMap(boolean scan) { if (scan) this.scan(); } public static TaskMap getInstance() { return Grasscutter.getGameServer().getTaskMap(); } public void resetNow() { // Unregister all tasks for (TaskHandler task : this.tasks.values()) { unregisterTask(task); } // Run all afterReset tasks for (TaskHandler task : this.afterReset.values()) { try { task.restartExecute(); } catch (Exception e) { e.printStackTrace(); } } // Remove all afterReset tasks this.afterReset.clear(); // Register all tasks for (TaskHandler task : this.tasks.values()) { registerTask(task.getClass().getAnnotation(Task.class).taskName(), task); } } public TaskMap unregisterTask(TaskHandler task) { this.tasks.remove(task.getClass().getAnnotation(Task.class).taskName()); this.annotations.remove(task.getClass().getAnnotation(Task.class).taskName()); try { Scheduler scheduler = schedulerFactory.getScheduler(); scheduler.deleteJob(new JobKey(task.getClass().getAnnotation(Task.class).taskName())); } catch (SchedulerException e) { e.printStackTrace(); } task.onDisable(); return this; } public boolean pauseTask(String taskName) { try { Scheduler scheduler = schedulerFactory.getScheduler(); scheduler.pauseJob(new JobKey(taskName)); } catch (SchedulerException e) { e.printStackTrace(); return false; } return true; } public boolean resumeTask(String taskName) { try { Scheduler scheduler = schedulerFactory.getScheduler(); scheduler.resumeJob(new JobKey(taskName)); } catch (SchedulerException e) { e.printStackTrace(); return false; } return true; } public boolean cancelTask(String taskName) { Task task = this.annotations.get(taskName); if (task == null) return false; try { this.unregisterTask(this.tasks.get(taskName)); } catch (Exception e) { e.printStackTrace(); return false; } return true; } public TaskMap registerTask(String taskName, TaskHandler task) { Task annotation = task.getClass().getAnnotation(Task.class); this.annotations.put(taskName, annotation); this.tasks.put(taskName, task); // register task try { Scheduler scheduler = schedulerFactory.getScheduler(); JobDetail job = JobBuilder .newJob(task.getClass()) .withIdentity(taskName) .build(); Trigger convTrigger = TriggerBuilder.newTrigger() .withIdentity(annotation.triggerName()) .withSchedule(CronScheduleBuilder.cronSchedule(annotation.taskCronExpression())) .build(); scheduler.scheduleJob(job, convTrigger); if (annotation.executeImmediately()) { task.execute(null); } task.onEnable(); } catch (SchedulerException e) { e.printStackTrace(); } return this; } public List getHandlersAsList() { return new ArrayList<>(this.tasks.values()); } public HashMap getHandlers() { return new LinkedHashMap<>(this.tasks); } public TaskHandler getHandler(String taskName) { return this.tasks.get(taskName); } private void scan() { Reflections reflector = Grasscutter.reflector; Set> classes = reflector.getTypesAnnotatedWith(Task.class); classes.forEach(annotated -> { try { Task taskData = annotated.getAnnotation(Task.class); Object object = annotated.getDeclaredConstructor().newInstance(); if (object instanceof TaskHandler) { this.registerTask(taskData.taskName(), (TaskHandler) object); if (taskData.executeImmediatelyAfterReset()) { this.afterReset.put(taskData.taskName(), (TaskHandler) object); } } else { Grasscutter.getLogger().error("Class " + annotated.getName() + " is not a TaskHandler!"); } } catch (Exception exception) { Grasscutter.getLogger().error("Failed to register task handler for " + annotated.getSimpleName(), exception); } }); try { Scheduler scheduler = schedulerFactory.getScheduler(); scheduler.start(); } catch (SchedulerException e) { e.printStackTrace(); } } }