diff options
Diffstat (limited to 'src/main/java/gregtech/api/util/AveragePerTickCounter.java')
-rw-r--r-- | src/main/java/gregtech/api/util/AveragePerTickCounter.java | 139 |
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; + } + } +} |