diff --git a/src/com/massivecraft/massivecore/Couple.java b/src/com/massivecraft/massivecore/Couple.java index bd4750a0..4b70eb0d 100644 --- a/src/com/massivecraft/massivecore/Couple.java +++ b/src/com/massivecraft/massivecore/Couple.java @@ -91,7 +91,7 @@ public class Couple implements Entry, Cloneable, Serializable this.getSecond(), that.getSecond() ); } - + // -------------------------------------------- // // CLONE // -------------------------------------------- // diff --git a/src/com/massivecraft/massivecore/Task.java b/src/com/massivecraft/massivecore/Task.java new file mode 100644 index 00000000..cc1f327e --- /dev/null +++ b/src/com/massivecraft/massivecore/Task.java @@ -0,0 +1,113 @@ +package com.massivecraft.massivecore; + +import com.massivecraft.massivecore.collections.MassiveList; +import com.massivecraft.massivecore.util.Txt; + +import java.util.List; +import java.util.function.Supplier; + +/** + * This class is for tasks that are only run infrequently such as once a day + * and whose frequency must stay consistent between server restarts. + * An example is Faction taxing which must happen exactly once a day. + */ +public abstract class Task extends Engine +{ + // -------------------------------------------- // + // FIELDS + // -------------------------------------------- // + + private boolean mustBeTaskServer = false; + public boolean mustBeTaskServer() { return mustBeTaskServer; } + public void setMustBeTaskServer(boolean mustBeTaskServer) { this.mustBeTaskServer = mustBeTaskServer; } + + private boolean logTimeSpent = false; + public boolean isLoggingTimeSpent() { return logTimeSpent; } + public void setLoggingTimeSpent(boolean logTimeSpent) { this.logTimeSpent = logTimeSpent; } + + private List> conditions = new MassiveList<>(); + public List> getConditions() { return conditions; } + public void setConditions(List> conditions) { this.conditions = conditions; } + public void addCondition(Supplier condition) { this.conditions.add(condition); } + public boolean areConditionsMet() + { + return conditions.stream().map(Supplier::get).allMatch(b -> b == true); + } + + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public Task() + { + this.setPeriod(60 * 20L); // Once a minute + } + + // -------------------------------------------- // + // INVOKE + // -------------------------------------------- // + + @Override + public void run() + { + // Should it be the task server? + if (this.mustBeTaskServer() && ! MassiveCore.isTaskServer()) return; + + // So the delay millis is lower than one? (could for example be zero) + // This probably means the task should not be executed at all. + if (this.getPeriodMillis() < 1) return; + + // Other conditions + if (!this.areConditionsMet()) return; + + // INVOCATION + long nowMillis = System.currentTimeMillis(); + long lastMillis = this.getPreviousMillis(); + + long currentInvocation = this.getInvocationFromMillis(nowMillis); + long lastInvocation = this.getInvocationFromMillis(lastMillis); + + if (currentInvocation == lastInvocation) return; + + // Log time spent and invoke + if (this.isLoggingTimeSpent()) + { + String message = Txt.parse("Running %s.", this.getClass().getSimpleName()); + this.getPlugin().log(message); + } + + long startNano = System.nanoTime(); + this.invoke(nowMillis); + this.setPreviousMillis(nowMillis); + long endNano = System.nanoTime(); + + double elapsedSeconds = (endNano - startNano) / 1000_000_000D; + if (this.isLoggingTimeSpent()) + { + String msg = String.format("Took %.2f seconds.", elapsedSeconds); + msg = Txt.parse(msg); + this.getPlugin().log(msg); + } + } + + public abstract void invoke(long now); + + // -------------------------------------------- // + // TASK MILLIS AND INVOCATION + // -------------------------------------------- // + // The invocation is the amount of periods from UNIX time to now. + // It will increment by one when a period has passed. + + public abstract long getPreviousMillis(); + public abstract void setPreviousMillis(long millis); + + public abstract long getPeriodMillis(); + public abstract long getOffsetMillis(); + + // Here we accept millis from inside the period by rounding down. + private long getInvocationFromMillis(long millis) + { + return (millis - this.getOffsetMillis()) / this.getPeriodMillis(); + } + +}