aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/me/xmrvizzy/skyblocker/utils/scheduler/Scheduler.java
blob: 3f578899a336cb79d0d81ba294fa256af45a6434 (plain)
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
package me.xmrvizzy.skyblocker.utils.scheduler;

import com.mojang.brigadier.Command;
import me.xmrvizzy.skyblocker.SkyblockerMod;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.PriorityQueue;
import java.util.function.Supplier;

/**
 * A scheduler for running tasks at a later time. Tasks will be run synchronously on the main client thread. Use the instance stored in {@link SkyblockerMod#scheduler}. Do not instantiate this class.
 */
public class Scheduler {
    private static final Logger LOGGER = LoggerFactory.getLogger(Scheduler.class);
    private int currentTick = 0;
    private final PriorityQueue<ScheduledTask> tasks = new PriorityQueue<>();

    /**
     * Do not instantiate this class. Use {@link SkyblockerMod#scheduler} instead.
     */
    @SuppressWarnings("DeprecatedIsStillUsed")
    @Deprecated
    public Scheduler() {
    }

    /**
     * Schedules a task to run after a delay.
     *
     * @param task  the task to run
     * @param delay the delay in ticks
     */
    public void schedule(Runnable task, int delay) {
        if (delay < 0) {
            LOGGER.warn("Scheduled a task with negative delay");
        }
        tasks.add(new ScheduledTask(task, currentTick + delay));
    }

    /**
     * Schedules a task to run every period ticks.
     *
     * @param task   the task to run
     * @param period the period in ticks
     */
    public void scheduleCyclic(Runnable task, int period) {
        if (period <= 0) {
            LOGGER.error("Attempted to schedule a cyclic task with period lower than 1");
        } else {
            tasks.add(new CyclicTask(this, task, period));
        }
    }

    public static Command<FabricClientCommandSource> queueOpenScreenCommand(Supplier<Screen> screenSupplier) {
        return context -> SkyblockerMod.getInstance().scheduler.queueOpenScreen(screenSupplier);
    }

    /**
     * Schedules a screen to open in the next tick. Used in commands to avoid screen immediately closing after the command is executed.
     *
     * @param screenSupplier the supplier of the screen to open
     * @see #queueOpenScreenCommand(Supplier)
     */
    public int queueOpenScreen(Supplier<Screen> screenSupplier) {
        MinecraftClient.getInstance().send(() -> MinecraftClient.getInstance().setScreen(screenSupplier.get()));
        return Command.SINGLE_SUCCESS;
    }

    public void tick() {
        currentTick += 1;
        ScheduledTask task;
        while ((task = tasks.peek()) != null && task.schedule <= currentTick && runTask(task)) {
            tasks.poll();
            if (task instanceof CyclicTask) tasks.add(task);
        }
    }

    /**
     * Runs the task if able.
     *
     * @param task the task to run
     * @return {@code true} if the task is run, and {@link false} if task is not run.
     */
    protected boolean runTask(Runnable task) {
        task.run();
        return true;
    }

    /**
     * A task that runs every period ticks. More specifically, this task reschedules itself to run again after period ticks every time it runs.
     */
    protected static class CyclicTask extends ScheduledTask {
        private final Scheduler scheduler;
        private final int period;

        CyclicTask(Scheduler scheduler, Runnable inner, int period) {
            super(inner, scheduler.currentTick);
            this.scheduler = scheduler;
            this.period = period;
        }

        @Override
        public void run() {
            super.run();
            schedule = scheduler.currentTick + period;
        }
    }

    /**
     * A task that runs at a specific tick, relative to {@link #currentTick}.
     */
    protected static class ScheduledTask implements Comparable<ScheduledTask>, Runnable {
        private final Runnable inner;
        protected int schedule;

        public ScheduledTask(Runnable inner, int schedule) {
            this.inner = inner;
            this.schedule = schedule;
        }

        @Override
        public int compareTo(ScheduledTask o) {
            return schedule - o.schedule;
        }

        @Override
        public void run() {
            inner.run();
        }
    }
}