From 152a987c3a1aa300ca566dc58e23dac9426ff659 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 26 Mar 2020 17:19:18 -0400 Subject: [PATCH] Experimental flow display --- core/assets/bundles/bundle.properties | 1 + core/src/mindustry/entities/def/TileComp.java | 56 +++++++++++++++++-- .../ui/dialogs/SettingsMenuDialog.java | 2 + .../ui/fragments/PlacementFragment.java | 3 + .../mindustry/world/modules/ItemModule.java | 50 +++++++++++++++-- .../mindustry/world/modules/LiquidModule.java | 34 ++++++++++- 6 files changed, 133 insertions(+), 13 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index e1570ea8ef..196326762c 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -633,6 +633,7 @@ setting.shadows.name = Shadows setting.blockreplace.name = Automatic Block Suggestions setting.linear.name = Linear Filtering setting.hints.name = Hints +setting.flow.name = Display Resource Flow Rate[scarlet] (experimental) setting.buildautopause.name = Auto-Pause Building setting.animatedwater.name = Animated Water setting.animatedshields.name = Animated Shields diff --git a/core/src/mindustry/entities/def/TileComp.java b/core/src/mindustry/entities/def/TileComp.java index 7e2198b65d..289d09a5c6 100644 --- a/core/src/mindustry/entities/def/TileComp.java +++ b/core/src/mindustry/entities/def/TileComp.java @@ -27,6 +27,7 @@ import mindustry.world.*; import mindustry.world.blocks.environment.*; import mindustry.world.blocks.power.*; import mindustry.world.consumers.*; +import mindustry.world.meta.*; import mindustry.world.modules.*; import static mindustry.Vars.*; @@ -47,6 +48,7 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ transient Tile tile; transient Block block; transient Array proximity = new Array<>(8); + transient boolean updateFlow; PowerModule power; ItemModule items; @@ -764,9 +766,49 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ displayBars(bars); }).growX(); table.row(); - table.table(ctable -> { - displayConsumption(ctable); - }).growX(); + table.table(this::displayConsumption).growX(); + + boolean displayFlow = (block.category == Category.distribution || block.category == Category.liquid) && Core.settings.getBool("flow"); + + if(displayFlow){ + String ps = " " + StatUnit.perSecond.localized(); + + if(items != null){ + table.row(); + table.table(l -> { + Bits presence = new Bits(content.items().size); + l.left(); + + Runnable rebuild = () -> { + l.clearChildren(); + for(Item item : content.items()){ + if(items.flownBits() != null && items.flownBits().get(item.id)){ + l.addImage(item.icon(Cicon.small)).padRight(3f); + l.label(() -> items.getFlowRate(item) < 0 ? "..." : Strings.fixed(items.getFlowRate(item), 1) + ps).color(Color.lightGray); + l.row(); + } + } + }; + + rebuild.run(); + l.update(() -> { + if(items.flownBits() != null && !presence.equals(items.flownBits())){ + presence.set(items.flownBits()); + rebuild.run(); + } + }); + }); + } + + if(liquids != null){ + table.row(); + table.table(l -> { + l.left(); + l.addImage(() -> liquids.current().icon(Cicon.small)).padRight(3f); + l.label(() -> liquids.getFlowRate() < 0 ? "..." : Strings.fixed(liquids.getFlowRate(), 2) + ps).color(Color.lightGray); + }); + } + } table.marginBottom(-5); } @@ -934,8 +976,12 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ updateTile(); + if(items != null){ + items.update(updateFlow); + } + if(liquids != null){ - liquids.update(); + liquids.update(updateFlow); } if(cons != null){ @@ -945,6 +991,8 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ if(power != null){ power.graph.update(); } + + updateFlow = false; } //endregion diff --git a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java index 7f3d886bf0..3a16b70b14 100644 --- a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -360,6 +360,8 @@ public class SettingsMenuDialog extends SettingsDialog{ if(!mobile){ Core.settings.put("swapdiagonal", false); } + + graphics.checkPref("flow", false); } private void back(){ diff --git a/core/src/mindustry/ui/fragments/PlacementFragment.java b/core/src/mindustry/ui/fragments/PlacementFragment.java index 1a6e407495..f9fd17d16d 100644 --- a/core/src/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/mindustry/ui/fragments/PlacementFragment.java @@ -454,6 +454,9 @@ public class PlacementFragment extends Fragment{ //setup hovering tile if(!Core.scene.hasMouse() && topTable.hit(v.x, v.y, false) == null){ hoverTile = world.tileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y); + if(hoverTile != null && hoverTile.entity != null){ + hoverTile.entity.updateFlow(true); + } }else{ hoverTile = null; } diff --git a/core/src/mindustry/world/modules/ItemModule.java b/core/src/mindustry/world/modules/ItemModule.java index d96a0f89c5..8a9ddc40a3 100644 --- a/core/src/mindustry/world/modules/ItemModule.java +++ b/core/src/mindustry/world/modules/ItemModule.java @@ -1,21 +1,54 @@ package mindustry.world.modules; +import arc.math.*; +import arc.struct.*; +import arc.util.*; +import arc.util.ArcAnnotate.*; import arc.util.io.*; -import mindustry.type.Item; -import mindustry.type.ItemStack; +import mindustry.type.*; -import java.util.Arrays; +import java.util.*; import static mindustry.Vars.content; public class ItemModule extends BlockModule{ - private int[] items = new int[content.items().size]; - private int total; + private static final int windowSize = 10; + protected int[] items = new int[content.items().size]; + protected int total; // Make the take() loop persistent so it does not return the same item twice in a row unless there is nothing else to return. protected int takeRotation; - public void forEach(ItemConsumer cons){ + private @Nullable WindowedMean[] flow; + private @Nullable Bits flownIds; + + public void update(boolean showFlow){ + if(showFlow){ + if(flow == null){ + flow = new WindowedMean[items.length]; + flownIds = new Bits(items.length); + } + }else{ + flow = null; + flownIds = null; + } + } + + /** @return a specific item's flow rate in items/s; any value < 0 means not ready.*/ + public float getFlowRate(Item item){ + if(flow == null || flow[item.id] == null || flow[item.id].getValueCount() <= 2){ + return - 1f; + } + + //TODO this isn't very accurate + return 60f / ((flow[item.id].getLatest() - flow[item.id].getOldest()) / (flow[item.id].getValueCount() - 1)); + } + + public @Nullable Bits flownBits(){ + return flownIds; + } + + public void each(ItemConsumer cons){ for(int i = 0; i < items.length; i++){ if(items[i] > 0){ cons.accept(content.item(i), items[i]); @@ -108,6 +141,11 @@ public class ItemModule extends BlockModule{ public void add(Item item, int amount){ items[item.id] += amount; total += amount; + if(flow != null){ + if(flow[item.id] == null) flow[item.id] = new WindowedMean(windowSize); + flow[item.id].addValue(Time.time()); + flownIds.set(item.id); + } } public void addAll(ItemModule items){ diff --git a/core/src/mindustry/world/modules/LiquidModule.java b/core/src/mindustry/world/modules/LiquidModule.java index 7615aad033..8c143c482a 100644 --- a/core/src/mindustry/world/modules/LiquidModule.java +++ b/core/src/mindustry/world/modules/LiquidModule.java @@ -1,21 +1,45 @@ package mindustry.world.modules; import arc.math.*; +import arc.util.*; +import arc.util.ArcAnnotate.*; import arc.util.io.*; -import mindustry.type.Liquid; +import mindustry.type.*; -import java.util.Arrays; +import java.util.*; import static mindustry.Vars.content; public class LiquidModule extends BlockModule{ + private static final int windowSize = 60, updateInterval = 60; + private static Interval flowTimer = new Interval(1); + private float[] liquids = new float[content.liquids().size]; private float total; private Liquid current = content.liquid(0); private float smoothLiquid; - public void update(){ + private @Nullable WindowedMean flow; + private float lastAdded, currentFlowRate; + + public void update(boolean showFlow){ smoothLiquid = Mathf.lerpDelta(smoothLiquid, currentAmount(), 0.1f); + if(showFlow){ + if(flow == null) flow = new WindowedMean(windowSize); + flow.addValue(lastAdded); + lastAdded = 0; + if(currentFlowRate < 0 || flowTimer.get(updateInterval)){ + currentFlowRate = flow.hasEnoughData() ? flow.getMean() : -1f; + } + }else{ + currentFlowRate = -1f; + flow = null; + } + } + + /** @return current liquid's flow rate in u/s; any value < 0 means 'not ready'. */ + public float getFlowRate(){ + return currentFlowRate; } public float smoothAmount(){ @@ -58,6 +82,10 @@ public class LiquidModule extends BlockModule{ liquids[liquid.id] += amount; total += amount; current = liquid; + + if(flow != null){ + lastAdded += Math.max(amount, 0); + } } public void remove(Liquid liquid, float amount){