diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/BlockEnergyCounter.java b/src/main/java/ru/dbotthepony/mc/otm/block/BlockEnergyCounter.java index e8504085b..b89068704 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/block/BlockEnergyCounter.java +++ b/src/main/java/ru/dbotthepony/mc/otm/block/BlockEnergyCounter.java @@ -8,10 +8,14 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.EnumProperty; +import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.block.entity.BlockEntityEnergyCounter; +import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterBottler; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; @@ -28,6 +32,12 @@ public class BlockEnergyCounter extends BlockMattery implements EntityBlock { return new BlockEntityEnergyCounter(blockPos, blockState); } + @Nullable + @Override + public BlockEntityTicker getTicker(Level p_153212_, BlockState p_153213_, BlockEntityType p_153214_) { + return p_153212_.isClientSide || p_153214_ != Registry.BlockEntities.ENERGY_COUNTER ? null : BlockEntityEnergyCounter::tick; + } + @Nullable @Override public BlockState getStateForPlacement(BlockPlaceContext context) { diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityEnergyCounter.java b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityEnergyCounter.java index 660c03d25..d8ccdfc63 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityEnergyCounter.java +++ b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityEnergyCounter.java @@ -3,8 +3,7 @@ package ru.dbotthepony.mc.otm.block.entity; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.*; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.server.level.ServerLevel; @@ -12,11 +11,14 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.energy.IEnergyStorage; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import ru.dbotthepony.mc.otm.OverdriveThatMatters; import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.block.BlockEnergyCounter; @@ -29,11 +31,63 @@ import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; import java.lang.ref.WeakReference; import java.math.BigDecimal; +import java.util.Arrays; @MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault public class BlockEntityEnergyCounter extends BlockEntityMattery { protected BigDecimal passed = BigDecimal.ZERO; + protected final BigDecimal[] history = new BigDecimal[10 * 20]; + protected int history_tick = 0; + + public static void tick(Level level, BlockPos blockPos, BlockState blockState, T t) { + if (t instanceof BlockEntityEnergyCounter tile) { + tile.history_tick = (tile.history_tick + 1) % tile.history.length; + tile.history[tile.history_tick] = BigDecimal.ZERO; + } + } + + public BigDecimal[] getHistory(int ticks) { + if (ticks < 1 || ticks >= history.length) { + throw new IllegalArgumentException("Invalid history length provided"); + } + + final var history = new BigDecimal[ticks]; + + for (int i = 0; i < ticks; i++) { + int index = (history_tick - i) % this.history.length; + + if (index < 0) + index += this.history.length; + + history[i] = this.history[index]; + } + + return history; + } + + public BigDecimal calcAverage(int ticks) { + return sumHistory(ticks).divide(new BigDecimal(ticks), MatteryCapability.ROUND_RULES); + } + + public BigDecimal sumHistory(int ticks) { + if (ticks < 1 || ticks >= history.length) { + throw new IllegalArgumentException("Invalid history length provided"); + } + + var value = BigDecimal.ZERO; + + for (int i = 0; i < ticks; i++) { + int index = (history_tick - i) % this.history.length; + + if (index < 0) + index += this.history.length; + + value = value.add(history[index]); + } + + return value; + } public BigDecimal getPassed() { return passed; @@ -41,20 +95,43 @@ public class BlockEntityEnergyCounter extends BlockEntityMattery { public BlockEntityEnergyCounter(BlockPos p_155229_, BlockState p_155230_) { super(Registry.BlockEntities.ENERGY_COUNTER, p_155229_, p_155230_); + Arrays.fill(history, BigDecimal.ZERO); } @Override public CompoundTag save(CompoundTag nbt) { nbt.putString("passed", passed.toString()); + var list = new ListTag(); + nbt.put("history", list); + nbt.putInt("history_tick", history_tick); + + for (var num : history) + list.add(StringTag.valueOf(num.toString())); + return super.save(nbt); } + private static final Logger LOGGER = LogManager.getLogger(); + @Override public void load(CompoundTag nbt) { super.load(nbt); if (nbt.get("passed") instanceof StringTag tag) passed = new BigDecimal(tag.getAsString()); + + if (nbt.get("history_tick") instanceof IntTag tag) + history_tick = tag.getAsInt(); + + var list = nbt.getList("history", Tag.TAG_STRING); + + for (int i = 0; i < list.size(); i++) { + try { + history[i] = new BigDecimal(list.getString(i)); + } catch(Throwable err) { + LOGGER.error(err); + } + } } private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.energy_counter"); @@ -113,6 +190,8 @@ public class BlockEntityEnergyCounter extends BlockEntityMattery { if (!simulate) { passed = passed.add(value); + history[history_tick] = history[history_tick].add(value); + setChangedLight(); } return value; @@ -123,6 +202,8 @@ public class BlockEntityEnergyCounter extends BlockEntityMattery { if (!simulate) { passed = passed.add(value); + history[history_tick] = history[history_tick].add(value); + setChangedLight(); } return value; @@ -146,6 +227,8 @@ public class BlockEntityEnergyCounter extends BlockEntityMattery { if (!simulate) { passed = passed.add(value); + history[history_tick] = history[history_tick].add(value); + setChangedLight(); } return value; @@ -156,6 +239,8 @@ public class BlockEntityEnergyCounter extends BlockEntityMattery { if (!simulate) { passed = passed.add(value); + history[history_tick] = history[history_tick].add(value); + setChangedLight(); } return value; diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMattery.java b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMattery.java index ac11dc132..6384f450c 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMattery.java +++ b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityMattery.java @@ -174,4 +174,12 @@ public abstract class BlockEntityMattery extends BlockEntity implements MenuProv if (nbt.get("redstone_signal") instanceof ByteTag tag) redstone_signal = tag.getAsByte(); } + + // Just to mark chunk unsaved + public void setChangedLight() { + if (level != null) { + if (level.hasChunkAt(getBlockPos())) + level.getChunkAt(getBlockPos()).markUnsaved(); + } + } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/client/screen/EnergyCounterScreen.java b/src/main/java/ru/dbotthepony/mc/otm/client/screen/EnergyCounterScreen.java index 0e17c1899..50c2871d1 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/client/screen/EnergyCounterScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/client/screen/EnergyCounterScreen.java @@ -22,7 +22,7 @@ public class EnergyCounterScreen extends MatteryScreen { protected FramePanel makeMainFrame() { var frame = super.makeMainFrame(); - var label = new Label(this, frame) { + var label = (Label) new Label(this, frame) { @Override public void tick() { super.tick(); @@ -32,6 +32,31 @@ public class EnergyCounterScreen extends MatteryScreen { }; label.setDock(Dock.TOP); + label.setDockMargin(4, 0, 0, 0); + + label = new Label(this, frame) { + @Override + public void tick() { + super.tick(); + + setText(new TranslatableComponent("otm.item.power.average", FormattingHelper.formatPower(menu.average.getDecimal()))); + } + }; + + label.setDock(Dock.TOP); + label.setDockMargin(4, 0, 0, 0); + + label = new Label(this, frame) { + @Override + public void tick() { + super.tick(); + + setText(new TranslatableComponent("otm.item.power.last_20_ticks", FormattingHelper.formatPower(menu.last_20_ticks.getDecimal()))); + } + }; + + label.setDock(Dock.TOP); + label.setDockMargin(4, 0, 0, 0); return frame; } diff --git a/src/main/java/ru/dbotthepony/mc/otm/menu/EnergyCounterMenu.java b/src/main/java/ru/dbotthepony/mc/otm/menu/EnergyCounterMenu.java index 32fbd7ac8..c564edf21 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/menu/EnergyCounterMenu.java +++ b/src/main/java/ru/dbotthepony/mc/otm/menu/EnergyCounterMenu.java @@ -11,6 +11,10 @@ import javax.annotation.Nullable; public class EnergyCounterMenu extends MatteryMenu { public final BigDecimalDataContainer passed = new BigDecimalDataContainer(); + public final BigDecimalDataContainer average = new BigDecimalDataContainer(); + public final BigDecimalDataContainer last_20_ticks = new BigDecimalDataContainer(); + // TODO: Graph and proper networking for it + private int ticks_passed = 0; public EnergyCounterMenu(int p_38852_, Inventory inventory) { this(p_38852_, inventory, null); @@ -20,12 +24,23 @@ public class EnergyCounterMenu extends MatteryMenu { super(Registry.Menus.ENERGY_COUNTER, p_38852_, inventory, tile); addDataSlots(passed); + addDataSlots(average); + addDataSlots(last_20_ticks); } @Override public void broadcastChanges() { if (tile != null) { - passed.setDecimal(((BlockEntityEnergyCounter) tile).getPassed()); + BlockEntityEnergyCounter tile = (BlockEntityEnergyCounter) this.tile; + + passed.setDecimal(tile.getPassed()); + average.setDecimal(tile.calcAverage(20)); + + if (ticks_passed == 0) { + last_20_ticks.setDecimal(tile.sumHistory(20)); + } + + ticks_passed = (ticks_passed + 1) % 20; } super.broadcastChanges(); diff --git a/src/main/resources/assets/overdrive_that_matters/lang/en_us.json b/src/main/resources/assets/overdrive_that_matters/lang/en_us.json index 1270beabc..dd7f51f32 100644 --- a/src/main/resources/assets/overdrive_that_matters/lang/en_us.json +++ b/src/main/resources/assets/overdrive_that_matters/lang/en_us.json @@ -33,6 +33,8 @@ "otm.item.power.infinite.storage": "Stored energy: Infinity / Infinity", "otm.item.power.infinite.throughput": "Max I/O Infinite / Infinite", "otm.item.power.passed": "Passed energy: %s", + "otm.item.power.average": "Average throughput: %s/t", + "otm.item.power.last_20_ticks": "Last second: %s", "otm.item.power.normal.storage": "Stored energy: %s / %s", "otm.item.power.normal.throughput": "Max I/O %s / %s", @@ -145,6 +147,7 @@ "block.overdrive_that_matters.matter_bottler": "Matter Bottler", "block.overdrive_that_matters.drive_viewer": "Drive Viewer", "block.overdrive_that_matters.black_hole": "Local Anomalous Singular Gravitation Field", + "block.overdrive_that_matters.energy_counter": "Energy Counter", "otm.container.matter_panel.number_input": "Input replication task count",