aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/api/util/AveragePerTickCounter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/gregtech/api/util/AveragePerTickCounter.java')
-rw-r--r--src/main/java/gregtech/api/util/AveragePerTickCounter.java139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/main/java/gregtech/api/util/AveragePerTickCounter.java b/src/main/java/gregtech/api/util/AveragePerTickCounter.java
new file mode 100644
index 0000000000..c9b1275deb
--- /dev/null
+++ b/src/main/java/gregtech/api/util/AveragePerTickCounter.java
@@ -0,0 +1,139 @@
+package gregtech.api.util;
+
+import java.security.InvalidParameterException;
+import java.util.ArrayDeque;
+
+import net.minecraft.server.MinecraftServer;
+
+public class AveragePerTickCounter {
+
+ /**
+ * Averages a value over a certain amount of ticks
+ *
+ * @param period amount of ticks to average (20 for 1 second)
+ *
+ */
+ public AveragePerTickCounter(int period) throws InvalidParameterException {
+
+ if (period <= 0) throw new InvalidParameterException("period should be a positive non-zero number");
+
+ this.period = period;
+ values = new ArrayDeque<>(period);
+ }
+
+ public void addValue(long value) {
+
+ if (value == 0) return;
+
+ final int currTick = getWorldTimeInTicks();
+
+ if (values.isEmpty()) {
+ values.addLast(new Measurement(currTick, value));
+ isCachedAverageValid = false;
+ return;
+ }
+
+ Measurement lastMeasurement = values.peekLast();
+ final int lastMeasurementTick = lastMeasurement.TimestampInWorldTicks;
+
+ /// sums up values added in the same tick
+ /// for example a cable had an amp running through it multiple times in the same tick
+ if (currTick == lastMeasurementTick) {
+ lastMeasurement.Value = lastMeasurement.Value + value;
+ isCachedAverageValid = false;
+ return;
+ }
+
+ if (currTick > lastMeasurementTick) {
+ trimIrrelevantData(currTick);
+
+ values.addLast(new Measurement(currTick, value));
+ isCachedAverageValid = false;
+ return;
+ }
+ }
+
+ public double getAverage() {
+
+ if (values.isEmpty()) return 0;
+
+ final int currTick = getWorldTimeInTicks();
+
+ Measurement lastMeasurement = values.peekLast();
+ final int lastMeasurementTick = lastMeasurement.TimestampInWorldTicks;
+
+ if (currTick < lastMeasurementTick) return 0;
+
+ if (currTick > lastMeasurementTick) {
+ trimIrrelevantData(currTick);
+ }
+
+ if (isCachedAverageValid) return cachedAverage;
+
+ return calculateAverage();
+ }
+
+ public long getLast() {
+
+ if (values.isEmpty()) return 0;
+
+ final int currTick = getWorldTimeInTicks();
+
+ Measurement lastMeasurement = values.peekLast();
+ final int lastMeasurementTick = lastMeasurement.TimestampInWorldTicks;
+
+ if (currTick == lastMeasurementTick) return values.getLast().Value;
+
+ return 0;
+ }
+
+ private double calculateAverage() {
+
+ isCachedAverageValid = true;
+ long sum = 0;
+
+ for (Measurement measurement : values) {
+ sum += measurement.Value;
+ }
+
+ return sum / (double) period;
+ }
+
+ private void trimIrrelevantData(int currWorldTimeInTicks) {
+
+ if (values.isEmpty()) return;
+
+ int firstMeasurementTick = values.peekFirst().TimestampInWorldTicks;
+
+ while (currWorldTimeInTicks - firstMeasurementTick >= period) {
+ values.removeFirst();
+ isCachedAverageValid = false;
+
+ if (values.isEmpty()) return;
+
+ firstMeasurementTick = values.peekFirst().TimestampInWorldTicks;
+ }
+ }
+
+ private int getWorldTimeInTicks() {
+ return MinecraftServer.getServer()
+ .getTickCounter();
+ }
+
+ private ArrayDeque<Measurement> values;
+ private int period;
+
+ private double cachedAverage = 0;
+ private boolean isCachedAverageValid = true;
+
+ private class Measurement {
+
+ public int TimestampInWorldTicks;
+ public long Value;
+
+ public Measurement(int timestampInWorldTicks, long value) {
+ this.TimestampInWorldTicks = timestampInWorldTicks;
+ this.Value = value;
+ }
+ }
+}