I recently had to create a countdown for timing some actions (in one of my plugins). So I wrote a class for timing, which uses a BukkitTask to count down and run an action if one is set for the count value. I thought it could be useful for some of you . The Timer class (Move your mouse to reveal the content) The Timer class (open) The Timer class (close) Code:java package de.GameplayJDK.Code.Util; import java.util.HashMap; import org.bukkit.plugin.Plugin;import org.bukkit.scheduler.BukkitRunnable;import org.bukkit.scheduler.BukkitTask; public class Timer { public static interface TimerActionHandler {public void onAction(Timer parent);} public static interface TimerHandler {public void onStart(Timer parent);public void onFinish(Timer parent);public void onCount(Timer parent);} public static enum TimerState {PREINIT,RUNNING,PAUSED,FINISHED} private Plugin plugin;private TimerHandler handler;private Long interval;private Integer length;private HashMap<Integer, TimerActionHandler> actions; private Integer count;private BukkitTask task; private TimerState state; public Timer(Plugin plugin) { this.state = TimerState.PREINIT;this.actions = new HashMap<Integer, TimerActionHandler>();this.plugin = plugin;} public Timer setTimerHandler(TimerHandler handler) { this.handler = handler;return this; } public Timer setInterval(Long interval) { this.interval = interval;return this; } public Timer setLength(Integer length) { this.length = length; this.count = length;return this; } public Timer addTimerAction(Integer at, TimerActionHandler action) { this.actions.put(at, action);return this; } public Timer removeTimerAction(Integer at) { if (this.actions.containsKey(at)) { this.actions.remove(at); }return this; } public Timer start() {this.state = TimerState.RUNNING;handler.onStart(self());this.task = new BukkitRunnable() {@Overridepublic void run() {if (state == TimerState.PAUSED) { return; } else if (state == TimerState.PREINIT) { task.cancel(); return; } else if (state == TimerState.FINISHED) { task.cancel(); return; }if (count <1) {state = TimerState.FINISHED;handler.onFinish(self());task.cancel();}handler.onCount(self());if (actions.containsKey(count)) { actions.get(count).onAction(self()); }count--;}}.runTaskTimer(this.plugin, this.interval, this.interval);return this; } public Timer pause() { this.state = TimerState.PAUSED;return this; } public Timer stop() { if (this.state != TimerState.FINISHED || this.task != null) { this.state = TimerState.FINISHED; this.task.cancel(); }return this; } private Timer self() {return this; } public Plugin getPlugin() {return this.plugin; } public final TimerHandler getTimerHandler() {return this.handler; } public final Long getInterval() {return this.interval; } public final Integer getLength() {return this.length; } public final HashMap<Integer, TimerActionHandler> getActions() {return this.actions; } public final Integer getCount() {return this.count; } public final BukkitTask getTask() {return this.task; } public final TimerState getState() {return this.state; } } View the code as gist (Move your mouse to reveal the content) View the code as gist (open) View the code as gist (close) And how to use it (Move your mouse to reveal the content) And how to use it (open) And how to use it (close) Code:java new de.GameplayJDK.Code.Util.Timer(owner).setTimerHandler(new de.GameplayJDK.Code.Util.Timer.TimerHandler() { // Start, Stop and Tick actions@Overridepublic void onStart(de.GameplayJDK.Code.Util.Timer parent) {// Do something when it starts..}@Overridepublic void onFinish(de.GameplayJDK.Code.Util.Timer parent) {// Or when it's finished..}@Overridepublic void onCount(de.GameplayJDK.Code.Util.Timer parent) {// And do something when it is counting!}}).setInterval(20L) // count -1 down every 20 ticks (servers mainly run with 20 TPS).setLength(60) // count from 60 to 0 --> one minute.addTimerAction(30, new de.GameplayJDK.Code.Util.Timer.TimerActionHandler() { // TimerAction at 30 seconds@Overridepublic void onAction(de.GameplayJDK.Code.Util.Timer parent) {// Now 30s are over.. Time to do something!}}).addTimerAction(5, new de.GameplayJDK.Code.Util.Timer.TimerActionHandler() { // TimerAction at 5 seconds@Overridepublic void onAction(de.GameplayJDK.Code.Util.Timer parent) {// Oh! Only 5 seconds left! Hurry up!!!}}).start(); View the code as gist (Move your mouse to reveal the content) View the code as gist (open) View the code as gist (close)
Pretty cool, but what are the advantages to using this rather than BukkitRunnables built into Bukkit?
ccrama The timer is using a BukkitRunnable too But the advantage is, that you can really "time" actions. If you're using a normally scheduled BukkitTask you'd have to create a new one every time an old one has finished. And if you have more that 10 things to schedule, you'll have 10 different BukkitRunnables.. In my opinion it's easier to have just one main task and just add actions where you want them to happen
This is actually quite very useful. I don't like the complexity with dealing with timers for a minor task so this would definitely come handy.