Better multi-liquid support / Reinforced pump progress

This commit is contained in:
Anuken
2021-11-16 10:25:59 -05:00
parent bf1909295e
commit eefcce5cf1
16 changed files with 182 additions and 109 deletions

View File

@@ -447,25 +447,26 @@ public class Block extends UnlockableContent{
if(hasItems && itemCapacity > 0) stats.add(Stat.itemCapacity, itemCapacity, StatUnit.items);
}
public void addLiquidBar(Liquid liq){
bars.add("liquid-" + liq.name, entity -> new Bar(
() -> liq.localizedName,
liq::barColor,
() -> entity.liquids.get(liq) / liquidCapacity)
);
}
/** Adds a liquid bar that dynamically displays a liquid type. */
public <T extends Building> void addLiquidBar(Func<T, Liquid> current){
bars.add("liquid", entity -> new Bar(
() -> current.get((T)entity) == null || entity.liquids.get(current.get((T)entity)) <= 0.001f ? Core.bundle.get("bar.liquid") : current.get((T)entity).localizedName,
() -> current.get((T)entity) == null ? Color.clear : current.get((T)entity).barColor(),
() -> current.get((T)entity) == null ? 0f : entity.liquids.get(current.get((T)entity)) / liquidCapacity)
);
}
public void setBars(){
bars.add("health", entity -> new Bar("stat.health", Pal.health, entity::healthf).blink(Color.white));
if(hasLiquids){
Func<Building, Liquid> current;
if(consumes.has(ConsumeType.liquid) && consumes.get(ConsumeType.liquid) instanceof ConsumeLiquid){
Liquid liquid = consumes.<ConsumeLiquid>get(ConsumeType.liquid).liquid;
current = entity -> liquid;
}else{
current = entity -> entity.liquids.current();
}
bars.add("liquid", entity -> new Bar(
() -> entity.liquids.get(current.get(entity)) <= 0.001f ? Core.bundle.get("bar.liquid") : current.get(entity).localizedName,
() -> current.get(entity).barColor(),
() -> entity.liquids.get(current.get(entity)) / liquidCapacity)
);
}
if(hasPower && consumes.hasPower()){
ConsumePower cons = consumes.getPower();
boolean buffered = cons.buffered;
@@ -490,6 +491,38 @@ public class Block extends UnlockableContent{
if(unitCapModifier != 0){
stats.add(Stat.maxUnits, (unitCapModifier < 0 ? "-" : "+") + Math.abs(unitCapModifier));
}
//liquids added last
if(hasLiquids){
//TODO liquids need to be handled VERY carefully. there are several potential possibilities:
//1. no consumption or output (conduit/tank)
// - display current(), 1 bar
//2. static set of inputs and outputs
// - create bars for each input/output, straightforward
//3. TODO dynamic input/output combo???
// - confusion
boolean added = false;
//add bars for *specific* consumed liquids
if(consumes.has(ConsumeType.liquid)){
var consl = consumes.get(ConsumeType.liquid);
if(consl instanceof ConsumeLiquid liq){
added = true;
addLiquidBar(liq.liquid);
}else if(consl instanceof ConsumeLiquids multi){
added = true;
for(var stack : multi.liquids){
addLiquidBar(stack.liquid);
}
}
}
//nothing was added, so it's safe to add a dynamic liquid bar (probably?)
if(!added){
addLiquidBar(build -> build.liquids.current());
}
}
}
public boolean canReplace(Block other){

View File

@@ -4,7 +4,6 @@ import arc.math.*;
import arc.util.io.*;
import mindustry.graphics.*;
import mindustry.ui.*;
import mindustry.world.blocks.power.NuclearReactor.*;
import mindustry.world.blocks.production.*;
import mindustry.world.draw.*;
@@ -30,7 +29,7 @@ public class HeatProducer extends GenericCrafter{
public void setBars(){
super.setBars();
bars.add("heat", (NuclearReactorBuild entity) -> new Bar("bar.heat", Pal.lightOrange, () -> entity.heat));
bars.add("heat", (HeatProducerBuild entity) -> new Bar("bar.heat", Pal.lightOrange, () -> entity.heat));
}
public class HeatProducerBuild extends GenericCrafterBuild implements HeatBlock{

View File

@@ -5,6 +5,7 @@ import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.meta.*;
//TODO should leak!
public class LiquidJunction extends LiquidBlock{
public LiquidJunction(String name){

View File

@@ -12,9 +12,7 @@ import mindustry.entities.units.*;
import mindustry.gen.*;
import mindustry.logic.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
import mindustry.world.consumers.*;
import mindustry.world.draw.*;
import mindustry.world.meta.*;
@@ -74,41 +72,14 @@ public class GenericCrafter extends Block{
public void setBars(){
super.setBars();
//set up liquid bars for multiple liquid outputs
//TODO this will currently screw up input display if input liquids are filters - no good way to fix that yet
//set up liquid bars for liquid outputs
if(outputLiquids != null && outputLiquids.length > 0){
//no need for dynamic liquid bar
bars.remove("liquid");
Seq<Liquid> consumed = new Seq<>();
//find list of liquids consumed
if(consumes.has(ConsumeType.liquid)){
var consl = consumes.get(ConsumeType.liquid);
if(consl instanceof ConsumeLiquid liq){
consumed.add(liq.liquid);
}else if(consl instanceof ConsumeLiquids multi){
for(var stack : multi.liquids){
consumed.add(stack.liquid);
}
}
}
//display consumed first
for(var liq : consumed){
bars.add("liquid-consume-" + liq.name, entity -> new Bar(
() -> liq.localizedName,
liq::barColor,
() -> entity.liquids.get(liq) / liquidCapacity)
);
}
//then display output buffer
for(var stack : outputLiquids){
bars.add("liquid-output-" + stack.liquid.name, entity -> new Bar(
() -> stack.liquid.localizedName,
() -> stack.liquid.barColor(),
() -> entity.liquids.get(stack.liquid) / liquidCapacity)
);
addLiquidBar(stack.liquid);
}
}
}

View File

@@ -3,6 +3,7 @@ package mindustry.world.blocks.production;
import arc.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.util.*;
import mindustry.game.*;
import mindustry.graphics.*;
import mindustry.type.*;
@@ -82,6 +83,14 @@ public class Pump extends LiquidBlock{
}
}
@Override
public void setBars(){
super.setBars();
//replace dynamic output bar with own custom bar
addLiquidBar((PumpBuild build) -> build.liquidDrop);
}
protected boolean canPump(Tile tile){
return tile != null && tile.floor().liquidDrop != null;
}
@@ -89,13 +98,15 @@ public class Pump extends LiquidBlock{
public class PumpBuild extends LiquidBuild{
public float consTimer;
public float amount = 0f;
public Liquid liquidDrop = null;
public @Nullable Liquid liquidDrop = null;
@Override
public void draw(){
Draw.rect(name, x, y);
Draw.rect(region, x, y);
Drawf.liquid(liquidRegion, x, y, liquids.currentAmount() / liquidCapacity, liquids.current().color);
if(liquidDrop == null) return;
Drawf.liquid(liquidRegion, x, y, liquids.get(liquidDrop) / liquidCapacity, liquidDrop.color);
}
@Override
@@ -126,17 +137,19 @@ public class Pump extends LiquidBlock{
@Override
public void updateTile(){
if(consValid() && liquidDrop != null){
float maxPump = Math.min(liquidCapacity - liquids.total(), amount * pumpAmount * edelta());
float maxPump = Math.min(liquidCapacity - liquids.get(liquidDrop), amount * pumpAmount * edelta());
liquids.add(liquidDrop, maxPump);
//does nothing for most pumps, as those do not require items.
if((consTimer += delta()) >= consumeTime){
consume();
consumeTime = 0f;
consTimer = 0f;
}
}
dumpLiquid(liquids.current());
if(liquidDrop != null){
dumpLiquid(liquidDrop);
}
}
}

View File

@@ -30,6 +30,7 @@ public class LiquidVoid extends Block{
@Override
public void handleLiquid(Building source, Liquid liquid, float amount){
liquids.handleFlow(liquid, amount);
}
}

View File

@@ -13,8 +13,6 @@ public class BlockBars{
}
public void remove(String name){
if(!bars.containsKey(name))
throw new RuntimeException("No bar with name '" + name + "' found; current bars: " + bars.keys().toSeq());
bars.remove(name);
}

View File

@@ -90,15 +90,11 @@ public class ItemModule extends BlockModule{
/** @return a specific item's flow rate in items/s; any value < 0 means not ready.*/
public float getFlowRate(Item item){
if(flow == null) return -1f;
return displayFlow[item.id] * 60;
return flow == null ? -1f : displayFlow[item.id] * 60;
}
public boolean hasFlowItem(Item item){
if(flow == null) return false;
return cacheBits.get(item.id);
return flow != null && cacheBits.get(item.id);
}
public void each(ItemConsumer cons){

View File

@@ -1,6 +1,7 @@
package mindustry.world.modules;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.type.*;
@@ -14,18 +15,25 @@ public class LiquidModule extends BlockModule{
private static final Interval flowTimer = new Interval(2);
private static final float pollScl = 20f;
private static WindowedMean[] cacheFlow;
private static float[] cacheSums;
private static float[] displayFlow;
private static final Bits cacheBits = new Bits();
private float[] liquids = new float[content.liquids().size];
private float total;
private Liquid current = content.liquid(0);
private float smoothLiquid;
private boolean hadFlow;
private @Nullable WindowedMean flow;
private float lastAdded, currentFlowRate;
//TODO broken for multi flow
private @Nullable WindowedMean[] flow;
public void update(boolean showFlow){
smoothLiquid = Mathf.lerpDelta(smoothLiquid, currentAmount(), 0.1f);
if(showFlow){
/*
if(flowTimer.get(1, pollScl)){
if(flow == null) flow = new WindowedMean(windowSize);
@@ -36,21 +44,57 @@ public class LiquidModule extends BlockModule{
if(currentFlowRate < 0 || flowTimer.get(updateInterval)){
currentFlowRate = flow.hasEnoughData() ? flow.mean() / pollScl : -1f;
}
}*/
if(flowTimer.get(1, pollScl)){
if(flow == null){
if(cacheFlow == null || cacheFlow.length != liquids.length){
cacheFlow = new WindowedMean[liquids.length];
for(int i = 0; i < liquids.length; i++){
cacheFlow[i] = new WindowedMean(windowSize);
}
cacheSums = new float[liquids.length];
displayFlow = new float[liquids.length];
}else{
for(int i = 0; i < liquids.length; i++){
cacheFlow[i].reset();
}
Arrays.fill(cacheSums, 0);
cacheBits.clear();
}
Arrays.fill(displayFlow, -1);
flow = cacheFlow;
}
boolean updateFlow = flowTimer.get(30);
for(int i = 0; i < liquids.length; i++){
flow[i].add(cacheSums[i]);
if(cacheSums[i] > 0){
cacheBits.set(i);
}
cacheSums[i] = 0;
if(updateFlow){
displayFlow[i] = flow[i].hasEnoughData() ? flow[i].mean() / pollScl : -1;
}
}
}
}else{
currentFlowRate = -1f;
flow = null;
hadFlow = false;
}
}
/** @return current liquid's flow rate in u/s; any value < 0 means 'not ready'. */
public float getFlowRate(){
return currentFlowRate * 60;
public float getFlowRate(Liquid liquid){
return flow == null ? -1f : displayFlow[liquid.id] * 60;
}
public boolean hadFlow(){
return hadFlow;
public boolean hasFlowLiquid(Liquid liquid){
return flow != null && cacheBits.get(liquid.id);
}
public float smoothAmount(){
@@ -93,7 +137,13 @@ public class LiquidModule extends BlockModule{
current = liquid;
if(flow != null){
lastAdded += Math.max(amount, 0);
cacheSums[liquid.id] += Math.max(amount, 0);
}
}
public void handleFlow(Liquid liquid, float amount){
if(flow != null){
cacheSums[liquid.id] += Math.max(amount, 0);
}
}