Compare commits
6 Commits
v151
...
new-liquid
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c89d7d273 | ||
|
|
3ea742b06d | ||
|
|
9bedadac79 | ||
|
|
5ccadcf38f | ||
|
|
a32462971b | ||
|
|
3faf8ca07f |
@@ -15,6 +15,7 @@ manifold=36
|
|||||||
mega=5
|
mega=5
|
||||||
mindustry.entities.comp.BuildingComp=6
|
mindustry.entities.comp.BuildingComp=6
|
||||||
mindustry.entities.comp.BulletComp=7
|
mindustry.entities.comp.BulletComp=7
|
||||||
|
mindustry.entities.comp.ConduitGraphUpdaterComp=48
|
||||||
mindustry.entities.comp.DecalComp=8
|
mindustry.entities.comp.DecalComp=8
|
||||||
mindustry.entities.comp.EffectStateComp=9
|
mindustry.entities.comp.EffectStateComp=9
|
||||||
mindustry.entities.comp.FireComp=10
|
mindustry.entities.comp.FireComp=10
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
{fields:[]}
|
||||||
@@ -99,7 +99,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
|
|
||||||
private transient boolean sleeping;
|
private transient boolean sleeping;
|
||||||
private transient float sleepTime;
|
private transient float sleepTime;
|
||||||
private transient boolean initialized;
|
private transient boolean initialized, wasAdded;
|
||||||
|
|
||||||
/** Sets this tile entity data to this and adds it if necessary. */
|
/** Sets this tile entity data to this and adds it if necessary. */
|
||||||
public Building init(Tile tile, Team team, boolean shouldAdd, int rotation){
|
public Building init(Tile tile, Team team, boolean shouldAdd, int rotation){
|
||||||
@@ -174,6 +174,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
//endregion
|
//endregion
|
||||||
//region io
|
//region io
|
||||||
|
|
||||||
|
/** certain blocks merge liquid graphs, so it is necessary to provide a fake one at write-time */
|
||||||
|
public LiquidModule writeLiquids(){
|
||||||
|
return liquids;
|
||||||
|
}
|
||||||
|
|
||||||
public final void writeBase(Writes write){
|
public final void writeBase(Writes write){
|
||||||
boolean writeVisibility = state.rules.fog && visibleFlags != 0;
|
boolean writeVisibility = state.rules.fog && visibleFlags != 0;
|
||||||
|
|
||||||
@@ -186,7 +191,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
write.b(moduleBitmask());
|
write.b(moduleBitmask());
|
||||||
if(items != null) items.write(write);
|
if(items != null) items.write(write);
|
||||||
if(power != null) power.write(write);
|
if(power != null) power.write(write);
|
||||||
if(liquids != null) liquids.write(write);
|
if(liquids != null) writeLiquids().write(write);
|
||||||
|
|
||||||
//efficiency is written as two bytes to save space
|
//efficiency is written as two bytes to save space
|
||||||
write.b((byte)(Mathf.clamp(efficiency) * 255f));
|
write.b((byte)(Mathf.clamp(efficiency) * 255f));
|
||||||
@@ -820,6 +825,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
|
|
||||||
if(!net.client() && state.isCampaign() && team == state.rules.defaultTeam) liquid.unlock();
|
if(!net.client() && state.isCampaign() && team == state.rules.defaultTeam) liquid.unlock();
|
||||||
|
|
||||||
|
float selfCapacity = liquidCapacity();
|
||||||
|
|
||||||
for(int i = 0; i < proximity.size; i++){
|
for(int i = 0; i < proximity.size; i++){
|
||||||
incrementDump(proximity.size);
|
incrementDump(proximity.size);
|
||||||
|
|
||||||
@@ -829,10 +836,10 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
other = other.getLiquidDestination(self(), liquid);
|
other = other.getLiquidDestination(self(), liquid);
|
||||||
|
|
||||||
if(other != null && other.team == team && other.block.hasLiquids && canDumpLiquid(other, liquid) && other.liquids != null){
|
if(other != null && other.team == team && other.block.hasLiquids && canDumpLiquid(other, liquid) && other.liquids != null){
|
||||||
float ofract = other.liquids.get(liquid) / other.block.liquidCapacity;
|
float ofract = other.liquids.get(liquid) / other.liquidCapacity();
|
||||||
float fract = liquids.get(liquid) / block.liquidCapacity;
|
float fract = liquids.get(liquid) / selfCapacity;
|
||||||
|
|
||||||
if(ofract < fract) transferLiquid(other, (fract - ofract) * block.liquidCapacity / scaling, liquid);
|
if(ofract < fract) transferLiquid(other, (fract - ofract) * selfCapacity / scaling, liquid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -842,7 +849,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void transferLiquid(Building next, float amount, Liquid liquid){
|
public void transferLiquid(Building next, float amount, Liquid liquid){
|
||||||
float flow = Math.min(next.block.liquidCapacity - next.liquids.get(liquid), amount);
|
float flow = Math.min(next.liquidCapacity() - next.liquids.get(liquid), amount);
|
||||||
|
|
||||||
if(next.acceptLiquid(self(), liquid)){
|
if(next.acceptLiquid(self(), liquid)){
|
||||||
next.handleLiquid(self(), liquid, flow);
|
next.handleLiquid(self(), liquid, flow);
|
||||||
@@ -869,19 +876,20 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
if(next == null) return 0;
|
if(next == null) return 0;
|
||||||
|
|
||||||
next = next.getLiquidDestination(self(), liquid);
|
next = next.getLiquidDestination(self(), liquid);
|
||||||
|
float selfCapacity = liquidCapacity(), nextCapacity = next.liquidCapacity();
|
||||||
|
|
||||||
if(next.team == team && next.block.hasLiquids && liquids.get(liquid) > 0f){
|
if(next.team == team && next.block.hasLiquids && liquids.get(liquid) > 0f){
|
||||||
float ofract = next.liquids.get(liquid) / next.block.liquidCapacity;
|
float ofract = next.liquids.get(liquid) / nextCapacity;
|
||||||
float fract = liquids.get(liquid) / block.liquidCapacity * block.liquidPressure;
|
float fract = liquids.get(liquid) / selfCapacity * block.liquidPressure;
|
||||||
float flow = Math.min(Mathf.clamp((fract - ofract)) * (block.liquidCapacity), liquids.get(liquid));
|
float flow = Math.min(Mathf.clamp((fract - ofract)) * selfCapacity, liquids.get(liquid));
|
||||||
flow = Math.min(flow, next.block.liquidCapacity - next.liquids.get(liquid));
|
flow = Math.min(flow, nextCapacity - next.liquids.get(liquid));
|
||||||
|
|
||||||
if(flow > 0f && ofract <= fract && next.acceptLiquid(self(), liquid)){
|
if(flow > 0f && ofract <= fract && next.acceptLiquid(self(), liquid)){
|
||||||
next.handleLiquid(self(), liquid, flow);
|
next.handleLiquid(self(), liquid, flow);
|
||||||
liquids.remove(liquid, flow);
|
liquids.remove(liquid, flow);
|
||||||
return flow;
|
return flow;
|
||||||
//handle reactions between different liquid types ▼
|
//handle reactions between different liquid types ▼
|
||||||
}else if(!next.block.consumesLiquid(liquid) && next.liquids.currentAmount() / next.block.liquidCapacity > 0.1f && fract > 0.1f){
|
}else if(!next.block.consumesLiquid(liquid) && next.liquids.currentAmount() / nextCapacity > 0.1f && fract > 0.1f){
|
||||||
//TODO !IMPORTANT! uses current(), which is 1) wrong for multi-liquid blocks and 2) causes unwanted reactions, e.g. hydrogen + slag in pump
|
//TODO !IMPORTANT! uses current(), which is 1) wrong for multi-liquid blocks and 2) causes unwanted reactions, e.g. hydrogen + slag in pump
|
||||||
//TODO these are incorrect effect positions
|
//TODO these are incorrect effect positions
|
||||||
float fx = (x + next.x) / 2f, fy = (y + next.y) / 2f;
|
float fx = (x + next.x) / 2f, fy = (y + next.y) / 2f;
|
||||||
@@ -907,6 +915,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Override to set a custom liquid capacity, e.g. for blocks with shared inventories. */
|
||||||
|
public float liquidCapacity(){
|
||||||
|
return block.liquidCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
public Building getLiquidDestination(Building from, Liquid liquid){
|
public Building getLiquidDestination(Building from, Liquid liquid){
|
||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
@@ -1074,6 +1087,9 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
noSleep();
|
noSleep();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Like onProximityAdded, but only called once. Essentially does what onProximityAdded was supposed to. */
|
||||||
|
public void onAdded(){}
|
||||||
|
|
||||||
public void updatePowerGraph(){
|
public void updatePowerGraph(){
|
||||||
for(Building other : getPowerConnections(tempBuilds)){
|
for(Building other : getPowerConnections(tempBuilds)){
|
||||||
if(other.power != null){
|
if(other.power != null){
|
||||||
@@ -1679,6 +1695,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
other.onProximityUpdate();
|
other.onProximityUpdate();
|
||||||
}
|
}
|
||||||
proximity.clear();
|
proximity.clear();
|
||||||
|
wasAdded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rotated(int prevRotation, int newRotation){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateProximity(){
|
public void updateProximity(){
|
||||||
@@ -1701,6 +1722,10 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
proximity.add(tile);
|
proximity.add(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!wasAdded){
|
||||||
|
onAdded();
|
||||||
|
wasAdded = true;
|
||||||
|
}
|
||||||
onProximityAdded();
|
onProximityAdded();
|
||||||
onProximityUpdate();
|
onProximityUpdate();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package mindustry.entities.comp;
|
||||||
|
|
||||||
|
import mindustry.annotations.Annotations.*;
|
||||||
|
import mindustry.gen.*;
|
||||||
|
import mindustry.world.blocks.liquid.Conduit.*;
|
||||||
|
|
||||||
|
@EntityDef(value = ConduitGraphUpdaterc.class, serialize = false, genio = false)
|
||||||
|
@Component
|
||||||
|
abstract class ConduitGraphUpdaterComp implements Entityc{
|
||||||
|
public transient ConduitGraph graph;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(){
|
||||||
|
graph.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -464,8 +464,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(player != null) build.lastAccessed = player.name;
|
if(player != null) build.lastAccessed = player.name;
|
||||||
build.rotation = Mathf.mod(build.rotation + Mathf.sign(direction), 4);
|
int newRotation = Mathf.mod(build.rotation + Mathf.sign(direction), 4), prev = build.rotation;
|
||||||
|
build.rotation = newRotation;
|
||||||
build.updateProximity();
|
build.updateProximity();
|
||||||
|
build.rotated(prev, newRotation);
|
||||||
build.noSleep();
|
build.noSleep();
|
||||||
Fx.rotateBlock.at(build.x, build.y, build.block.size);
|
Fx.rotateBlock.at(build.x, build.y, build.block.size);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,7 +558,7 @@ public class Block extends UnlockableContent implements Senseable{
|
|||||||
addBar("liquid-" + liq.name, entity -> !liq.unlockedNow() ? null : new Bar(
|
addBar("liquid-" + liq.name, entity -> !liq.unlockedNow() ? null : new Bar(
|
||||||
() -> liq.localizedName,
|
() -> liq.localizedName,
|
||||||
liq::barColor,
|
liq::barColor,
|
||||||
() -> entity.liquids.get(liq) / liquidCapacity
|
() -> entity.liquids.get(liq) / entity.liquidCapacity()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,7 +567,7 @@ public class Block extends UnlockableContent implements Senseable{
|
|||||||
addBar("liquid", entity -> new Bar(
|
addBar("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 || 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 ? Color.clear : current.get((T)entity).barColor(),
|
||||||
() -> current.get((T)entity) == null ? 0f : entity.liquids.get(current.get((T)entity)) / liquidCapacity)
|
() -> current.get((T)entity) == null ? 0f : entity.liquids.get(current.get((T)entity)) / entity.liquidCapacity())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import arc.math.*;
|
|||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
|
import arc.util.io.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
import mindustry.content.*;
|
import mindustry.content.*;
|
||||||
import mindustry.entities.*;
|
import mindustry.entities.*;
|
||||||
@@ -15,17 +16,22 @@ import mindustry.entities.units.*;
|
|||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.graphics.*;
|
import mindustry.graphics.*;
|
||||||
import mindustry.input.*;
|
import mindustry.input.*;
|
||||||
|
import mindustry.logic.*;
|
||||||
import mindustry.type.*;
|
import mindustry.type.*;
|
||||||
import mindustry.world.*;
|
import mindustry.world.*;
|
||||||
import mindustry.world.blocks.*;
|
import mindustry.world.blocks.*;
|
||||||
import mindustry.world.blocks.distribution.*;
|
import mindustry.world.blocks.distribution.*;
|
||||||
|
import mindustry.world.modules.*;
|
||||||
|
|
||||||
import static mindustry.Vars.*;
|
import static mindustry.Vars.*;
|
||||||
import static mindustry.type.Liquid.*;
|
import static mindustry.type.Liquid.*;
|
||||||
|
|
||||||
public class Conduit extends LiquidBlock implements Autotiler{
|
public class Conduit extends LiquidBlock implements Autotiler{
|
||||||
|
static final boolean debugGraphs = false;
|
||||||
|
static final float mergeThreshold = 0.2f;
|
||||||
static final float rotatePad = 6, hpad = rotatePad / 2f / 4f;
|
static final float rotatePad = 6, hpad = rotatePad / 2f / 4f;
|
||||||
static final float[][] rotateOffsets = {{hpad, hpad}, {-hpad, hpad}, {-hpad, -hpad}, {hpad, -hpad}};
|
static final float[][] rotateOffsets = {{hpad, hpad}, {-hpad, hpad}, {-hpad, -hpad}, {hpad, -hpad}};
|
||||||
|
static final LiquidModule tempLiquids = new LiquidModule();
|
||||||
|
|
||||||
public final int timerFlow = timers++;
|
public final int timerFlow = timers++;
|
||||||
|
|
||||||
@@ -51,6 +57,10 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
|||||||
noUpdateDisabled = true;
|
noUpdateDisabled = true;
|
||||||
canOverdrive = false;
|
canOverdrive = false;
|
||||||
priority = TargetPriority.transport;
|
priority = TargetPriority.transport;
|
||||||
|
|
||||||
|
//conduits don't need to update
|
||||||
|
update = false;
|
||||||
|
destructible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -148,10 +158,78 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class ConduitBuild extends LiquidBuild implements ChainedBuilding{
|
public class ConduitBuild extends LiquidBuild implements ChainedBuilding{
|
||||||
|
public @Nullable ConduitGraph graph;
|
||||||
|
|
||||||
public float smoothLiquid;
|
public float smoothLiquid;
|
||||||
public int blendbits, xscl = 1, yscl = 1, blending;
|
public int blendbits, xscl = 1, yscl = 1, blending;
|
||||||
public boolean capped, backCapped = false;
|
public boolean capped, backCapped = false;
|
||||||
|
|
||||||
|
protected void addGraphs(){
|
||||||
|
//connect self to every nearby graph
|
||||||
|
getConnections(other -> {
|
||||||
|
if(other.graph != null){
|
||||||
|
other.graph.merge(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//nothing to connect to
|
||||||
|
if(graph == null){
|
||||||
|
new ConduitGraph().merge(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeGraphs(){
|
||||||
|
//graph is getting recalculated, no longer valid
|
||||||
|
if(graph != null){
|
||||||
|
graph.checkRemove();
|
||||||
|
graph.remove(this);
|
||||||
|
graph = null; //TODO ?????
|
||||||
|
}
|
||||||
|
|
||||||
|
getConnections(other -> new ConduitGraph().reflow(this, other));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void control(LAccess type, double p1, double p2, double p3, double p4){
|
||||||
|
if(type == LAccess.enabled){
|
||||||
|
boolean shouldEnable = !Mathf.zero((float)p1);
|
||||||
|
if(enabled != shouldEnable){
|
||||||
|
|
||||||
|
if(graph != null){
|
||||||
|
//keep track of how many conduits are disabled, so the graph can stop working
|
||||||
|
if(shouldEnable){
|
||||||
|
graph.disabledConduits --;
|
||||||
|
}else{
|
||||||
|
graph.disabledConduits ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enabled = shouldEnable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAdded(){
|
||||||
|
addGraphs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProximityRemoved(){
|
||||||
|
super.onProximityRemoved();
|
||||||
|
|
||||||
|
removeGraphs();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rotated(int prevRot, int newRot){
|
||||||
|
//essentially simulates the conduit being removed and re-placed - hacky, but it works
|
||||||
|
rotation = prevRot;
|
||||||
|
removeGraphs();
|
||||||
|
rotation = newRot;
|
||||||
|
addGraphs();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(){
|
public void draw(){
|
||||||
int r = this.rotation;
|
int r = this.rotation;
|
||||||
@@ -173,6 +251,21 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
|||||||
|
|
||||||
if(capped && capRegion.found()) Draw.rect(capRegion, x, y, rotdeg());
|
if(capped && capRegion.found()) Draw.rect(capRegion, x, y, rotdeg());
|
||||||
if(backCapped && capRegion.found()) Draw.rect(capRegion, x, y, rotdeg() + 180);
|
if(backCapped && capRegion.found()) Draw.rect(capRegion, x, y, rotdeg() + 180);
|
||||||
|
|
||||||
|
if(debugGraphs){
|
||||||
|
//simple visualization that assigns random color to each graph
|
||||||
|
Mathf.rand.setSeed(graph == null ? -1 : graph.id);
|
||||||
|
Draw.color(Tmp.c1.rand());
|
||||||
|
|
||||||
|
Drawf.selected(tileX(), tileY(), block, Tmp.c1);
|
||||||
|
Draw.color(Pal.accent);
|
||||||
|
|
||||||
|
if(this == graph.head){
|
||||||
|
Fill.poly(x, y, 3, 2f, rotdeg());
|
||||||
|
}
|
||||||
|
|
||||||
|
Draw.color();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void drawAt(float x, float y, int bits, int rotation, SliceMode slice){
|
protected void drawAt(float x, float y, int bits, int rotation, SliceMode slice){
|
||||||
@@ -196,7 +289,7 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
|||||||
//the drawing state machine sure was a great design choice with no downsides or hidden behavior!!!
|
//the drawing state machine sure was a great design choice with no downsides or hidden behavior!!!
|
||||||
float xscl = Draw.xscl, yscl = Draw.yscl;
|
float xscl = Draw.xscl, yscl = Draw.yscl;
|
||||||
Draw.scl(1f, 1f);
|
Draw.scl(1f, 1f);
|
||||||
Drawf.liquid(sliced(liquidr, slice), x + ox, y + oy, smoothLiquid, liquids.current().color.write(Tmp.c1).a(1f));
|
Drawf.liquid(sliced(liquidr, slice), x + ox, y + oy, graph == null ? smoothLiquid : graph.smoothLiquid, liquids.current().color.write(Tmp.c1).a(1f));
|
||||||
Draw.scl(xscl, yscl);
|
Draw.scl(xscl, yscl);
|
||||||
|
|
||||||
Draw.rect(sliced(topRegions[bits], slice), x, y, angle);
|
Draw.rect(sliced(topRegions[bits], slice), x, y, angle);
|
||||||
@@ -225,15 +318,15 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateTile(){
|
public LiquidModule writeLiquids(){
|
||||||
smoothLiquid = Mathf.lerpDelta(smoothLiquid, liquids.currentAmount() / liquidCapacity, 0.05f);
|
//"saved" liquids are based on a fraction, essentially splitting apart and re-joining
|
||||||
|
tempLiquids.set(liquids, graph == null ? 1f : block.liquidCapacity / graph.totalCapacity);
|
||||||
if(liquids.currentAmount() > 0.0001f && timer(timerFlow, 1)){
|
return tempLiquids;
|
||||||
moveLiquidForward(leaks, liquids.current());
|
|
||||||
noSleep();
|
|
||||||
}else{
|
|
||||||
sleep();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float liquidCapacity(){
|
||||||
|
return graph == null ? block.liquidCapacity : graph.totalCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -245,5 +338,195 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeAll(Writes write){
|
||||||
|
super.writeAll(write);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calls callback with every conduit that transfers fluids to this one. */
|
||||||
|
public void getConnections(Cons<ConduitBuild> cons){
|
||||||
|
for(var other : proximity){
|
||||||
|
if(canMerge(other)){
|
||||||
|
cons.get((ConduitBuild)other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canMerge(Building other){
|
||||||
|
return
|
||||||
|
other instanceof ConduitBuild conduit && other.team == team &&
|
||||||
|
(front() == conduit || other.front() == this) &&
|
||||||
|
(other.liquids.current() == liquids.current() || other.liquids.currentAmount() <= mergeThreshold || liquids.currentAmount() <= mergeThreshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO:
|
||||||
|
- [X] liquids shared as one inventory
|
||||||
|
- [X] liquids merged when placing
|
||||||
|
- [X] liquids split when breaking
|
||||||
|
- [X] liquids saved
|
||||||
|
- [X] liquids accept input
|
||||||
|
- [X] liquids transfer forward
|
||||||
|
- [X] liquids leak
|
||||||
|
- [X] liquids display properly (including flow rate)
|
||||||
|
- [X] liquids merge different types correctly
|
||||||
|
- [X] conduits can (or can't) be disabled
|
||||||
|
*/
|
||||||
|
public static class ConduitGraph{
|
||||||
|
private static final IntSet closedSet = new IntSet(), headSet = new IntSet();
|
||||||
|
private static final Queue<ConduitBuild> queue = new Queue<>();
|
||||||
|
|
||||||
|
static int lastId = 0;
|
||||||
|
|
||||||
|
public final int id = lastId ++;
|
||||||
|
public float smoothLiquid;
|
||||||
|
|
||||||
|
/** if any are disabled, does not update */
|
||||||
|
private int disabledConduits;
|
||||||
|
private Seq<ConduitBuild> conduits = new Seq<>();
|
||||||
|
private final @Nullable ConduitGraphUpdater entity;
|
||||||
|
private LiquidModule liquids = new LiquidModule();
|
||||||
|
private float totalCapacity;
|
||||||
|
|
||||||
|
public @Nullable ConduitBuild head;
|
||||||
|
|
||||||
|
public ConduitGraph(){
|
||||||
|
entity = ConduitGraphUpdater.create();
|
||||||
|
entity.graph = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(){
|
||||||
|
smoothLiquid = Mathf.lerpDelta(smoothLiquid, liquids.currentAmount() / totalCapacity, 0.05f);
|
||||||
|
|
||||||
|
if(disabledConduits > 0) return;
|
||||||
|
|
||||||
|
if(head != null){
|
||||||
|
|
||||||
|
//move forward as the head
|
||||||
|
if(liquids.currentAmount() > 0.0001f && head.timer(((Conduit)head.block).timerFlow, 1)){
|
||||||
|
head.moveLiquidForward(((Conduit)head.block).leaks, liquids.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
//merge with front if one of the conduits becomes empty
|
||||||
|
if(head.front() instanceof ConduitBuild build && build.graph != this && head.canMerge(build)){
|
||||||
|
merge(build);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkAdd(){
|
||||||
|
if(entity != null) entity.add();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkRemove(){
|
||||||
|
if(entity != null) entity.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(ConduitBuild build){
|
||||||
|
float fraction = build.block.liquidCapacity / totalCapacity;
|
||||||
|
//remove fraction of liquids based on what part this conduit constituted
|
||||||
|
//e.g. 70% of capacity was made up by this conduit = multiply liquids by 0.3 (remove 70%)
|
||||||
|
liquids.mul(1f - fraction);
|
||||||
|
|
||||||
|
totalCapacity -= build.block.liquidCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reflow(@Nullable ConduitBuild ignore, ConduitBuild conduit){
|
||||||
|
closedSet.clear();
|
||||||
|
queue.clear();
|
||||||
|
|
||||||
|
//ignore the starting point and don't add it, as it is being removed
|
||||||
|
if(ignore != null) closedSet.add(ignore.id);
|
||||||
|
|
||||||
|
closedSet.add(conduit.id);
|
||||||
|
queue.add(conduit);
|
||||||
|
|
||||||
|
|
||||||
|
while(queue.size > 0){
|
||||||
|
var parent = queue.removeFirst();
|
||||||
|
assign(parent, ignore);
|
||||||
|
|
||||||
|
parent.getConnections(child -> {
|
||||||
|
if(closedSet.add(child.id)){
|
||||||
|
queue.addLast(child);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
closedSet.clear();
|
||||||
|
queue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void merge(ConduitBuild other){
|
||||||
|
if(other.graph == this) return;
|
||||||
|
|
||||||
|
if(other.graph != null){
|
||||||
|
|
||||||
|
//merge graphs - TODO - flip if it is larger, like power graphs?
|
||||||
|
for(var cond : other.graph.conduits){
|
||||||
|
assign(cond);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
assign(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assign(ConduitBuild build){
|
||||||
|
assign(build, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assign(ConduitBuild build, @Nullable Building ignore){
|
||||||
|
if(build.graph != this){
|
||||||
|
|
||||||
|
//merge graph liquids - TODO - how does this react to different types
|
||||||
|
if(build.graph != null){
|
||||||
|
build.graph.checkRemove();
|
||||||
|
|
||||||
|
//add liquids based on what fraction it made up
|
||||||
|
liquids.add(build.liquids, build.block.liquidCapacity / build.graph.totalCapacity);
|
||||||
|
}else{
|
||||||
|
//simple direct liquid merge
|
||||||
|
liquids.add(build.liquids);
|
||||||
|
}
|
||||||
|
|
||||||
|
totalCapacity += build.block.liquidCapacity;
|
||||||
|
build.graph = this;
|
||||||
|
build.liquids = liquids;
|
||||||
|
conduits.add(build);
|
||||||
|
checkAdd();
|
||||||
|
|
||||||
|
//re-validate head
|
||||||
|
if(head == null){
|
||||||
|
head = build;
|
||||||
|
}
|
||||||
|
|
||||||
|
//find the best head block
|
||||||
|
headSet.clear();
|
||||||
|
headSet.add(head.id);
|
||||||
|
|
||||||
|
while(true){
|
||||||
|
var next = head.front();
|
||||||
|
|
||||||
|
if(next instanceof ConduitBuild cond && cond.team == head.team && next != ignore && cond.graph == this){
|
||||||
|
if(!headSet.add(next.id)){
|
||||||
|
//there's a loop, which means a head does not exist
|
||||||
|
head = null;
|
||||||
|
break;
|
||||||
|
}else{
|
||||||
|
head = cond;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//found the end
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//snap smoothLiquid so it doesn't start at 0
|
||||||
|
smoothLiquid = liquids.currentAmount() / totalCapacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class DrawLiquidRegion extends DrawBlock{
|
|||||||
public void draw(Building build){
|
public void draw(Building build){
|
||||||
Liquid drawn = drawLiquid != null ? drawLiquid : build.liquids.current();
|
Liquid drawn = drawLiquid != null ? drawLiquid : build.liquids.current();
|
||||||
Drawf.liquid(liquid, build.x, build.y,
|
Drawf.liquid(liquid, build.x, build.y,
|
||||||
build.liquids.get(drawn) / build.block.liquidCapacity * alpha,
|
build.liquids.get(drawn) / build.liquidCapacity() * alpha,
|
||||||
drawn.color
|
drawn.color
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,12 @@ public class LiquidModule extends BlockModule{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void mul(float amount){
|
||||||
|
for(int i = 0; i < liquids.length; i ++){
|
||||||
|
liquids[i] *= amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void stopFlow(){
|
public void stopFlow(){
|
||||||
flow = null;
|
flow = null;
|
||||||
}
|
}
|
||||||
@@ -107,6 +113,27 @@ public class LiquidModule extends BlockModule{
|
|||||||
Arrays.fill(liquids, 0);
|
Arrays.fill(liquids, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void add(LiquidModule other){
|
||||||
|
add(other, 1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(LiquidModule other, float mul){
|
||||||
|
for(int i = 0; i < liquids.length; i ++){
|
||||||
|
liquids[i] += other.liquids[i] * mul;
|
||||||
|
|
||||||
|
if(liquids[i] > liquids[current.id]){
|
||||||
|
current = content.liquid(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(LiquidModule other, float mul){
|
||||||
|
current = other.current;
|
||||||
|
for(int i = 0; i < liquids.length; i ++){
|
||||||
|
liquids[i] = other.liquids[i] * mul;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void add(Liquid liquid, float amount){
|
public void add(Liquid liquid, float amount){
|
||||||
liquids[liquid.id] += amount;
|
liquids[liquid.id] += amount;
|
||||||
current = liquid;
|
current = liquid;
|
||||||
@@ -180,6 +207,20 @@ public class LiquidModule extends BlockModule{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
var res = new StringBuilder();
|
||||||
|
res.append("LiquidModule{ current=").append(current).append(", ");
|
||||||
|
for(int i = 0; i < liquids.length; i++){
|
||||||
|
if(liquids[i] > 0){
|
||||||
|
res.append(content.liquid(i).name).append(":").append(liquids[i]).append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.setLength(res.length() - 2);
|
||||||
|
res.append("}");
|
||||||
|
return res.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public interface LiquidConsumer{
|
public interface LiquidConsumer{
|
||||||
void accept(Liquid liquid, float amount);
|
void accept(Liquid liquid, float amount);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,4 +25,4 @@ org.gradle.caching=true
|
|||||||
#used for slow jitpack builds; TODO see if this actually works
|
#used for slow jitpack builds; TODO see if this actually works
|
||||||
org.gradle.internal.http.socketTimeout=100000
|
org.gradle.internal.http.socketTimeout=100000
|
||||||
org.gradle.internal.http.connectionTimeout=100000
|
org.gradle.internal.http.connectionTimeout=100000
|
||||||
archash=77461f1c82
|
archash=eb3b8bdd10
|
||||||
|
|||||||
Reference in New Issue
Block a user