Merged ItemGenerator, LiquidGenerator and ItemLiquidGenerator into a single class.
Unit tests now test the ItemsOnly, LiquidsOnly and LiquidsAndItems cases
This commit is contained in:
@@ -6,7 +6,7 @@ import io.anuke.mindustry.type.Liquid;
|
|||||||
public class BurnerGenerator extends ItemLiquidGenerator{
|
public class BurnerGenerator extends ItemLiquidGenerator{
|
||||||
|
|
||||||
public BurnerGenerator(String name){
|
public BurnerGenerator(String name){
|
||||||
super(name);
|
super(InputType.LiquidsAndItems, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package io.anuke.mindustry.world.blocks.power;
|
package io.anuke.mindustry.world.blocks.power;
|
||||||
|
|
||||||
import io.anuke.mindustry.type.Item;
|
import io.anuke.mindustry.type.Item;
|
||||||
|
import io.anuke.mindustry.type.Liquid;
|
||||||
|
|
||||||
public class DecayGenerator extends ItemGenerator{
|
public class DecayGenerator extends ItemLiquidGenerator{
|
||||||
|
|
||||||
public DecayGenerator(String name){
|
public DecayGenerator(String name){
|
||||||
super(name);
|
super(InputType.ItemsOnly, name);
|
||||||
hasItems = true;
|
hasItems = true;
|
||||||
hasLiquids = false;
|
hasLiquids = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
package io.anuke.mindustry.world.blocks.power;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
|
||||||
import io.anuke.mindustry.content.fx.BlockFx;
|
|
||||||
import io.anuke.mindustry.entities.TileEntity;
|
|
||||||
import io.anuke.mindustry.type.Item;
|
|
||||||
import io.anuke.mindustry.world.BarType;
|
|
||||||
import io.anuke.mindustry.world.Tile;
|
|
||||||
import io.anuke.mindustry.world.consumers.ConsumeItemFilter;
|
|
||||||
import io.anuke.mindustry.world.meta.BlockBar;
|
|
||||||
import io.anuke.mindustry.world.meta.BlockStat;
|
|
||||||
import io.anuke.mindustry.world.meta.StatUnit;
|
|
||||||
import io.anuke.ucore.core.Effects;
|
|
||||||
import io.anuke.ucore.core.Effects.Effect;
|
|
||||||
import io.anuke.ucore.core.Timers;
|
|
||||||
import io.anuke.ucore.graphics.Draw;
|
|
||||||
import io.anuke.ucore.util.Mathf;
|
|
||||||
|
|
||||||
import java.io.DataInput;
|
|
||||||
import java.io.DataOutput;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.tilesize;
|
|
||||||
|
|
||||||
public abstract class ItemGenerator extends PowerGenerator{
|
|
||||||
protected float minItemEfficiency = 0.2f;
|
|
||||||
protected float itemDuration = 70f;
|
|
||||||
protected Effect generateEffect = BlockFx.generatespark, explodeEffect =
|
|
||||||
BlockFx.generatespark;
|
|
||||||
protected Color heatColor = Color.valueOf("ff9b59");
|
|
||||||
protected TextureRegion topRegion;
|
|
||||||
|
|
||||||
public ItemGenerator(String name){
|
|
||||||
super(name);
|
|
||||||
itemCapacity = 20;
|
|
||||||
hasItems = true;
|
|
||||||
|
|
||||||
consumes.add(new ConsumeItemFilter(item -> getItemEfficiency(item) >= minItemEfficiency)).update(false).optional(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void load(){
|
|
||||||
super.load();
|
|
||||||
topRegion = Draw.region(name + "-top");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBars(){
|
|
||||||
super.setBars();
|
|
||||||
bars.replace(new BlockBar(BarType.inventory, true, tile -> (float) tile.entity.items.total() / itemCapacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void draw(Tile tile){
|
|
||||||
super.draw(tile);
|
|
||||||
|
|
||||||
GeneratorEntity entity = tile.entity();
|
|
||||||
|
|
||||||
if(entity.generateTime > 0){
|
|
||||||
Draw.color(heatColor);
|
|
||||||
float alpha = (entity.items.total() > 0 ? 1f : Mathf.clamp(entity.generateTime));
|
|
||||||
alpha = alpha * 0.7f + Mathf.absin(Timers.time(), 12f, 0.3f) * alpha;
|
|
||||||
Draw.alpha(alpha);
|
|
||||||
Draw.rect(topRegion, tile.drawx(), tile.drawy());
|
|
||||||
Draw.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean acceptItem(Item item, Tile tile, Tile source){
|
|
||||||
return getItemEfficiency(item) >= minItemEfficiency && tile.entity.items.total() < itemCapacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(Tile tile){
|
|
||||||
ItemGeneratorEntity entity = tile.entity();
|
|
||||||
|
|
||||||
if(!entity.cons.valid()){
|
|
||||||
entity.productionEfficiency = 0.0f;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(entity.generateTime <= 0f && entity.items.total() > 0){
|
|
||||||
Effects.effect(generateEffect, tile.worldx() + Mathf.range(3f), tile.worldy() + Mathf.range(3f));
|
|
||||||
Item item = entity.items.take();
|
|
||||||
entity.productionEfficiency = getItemEfficiency(item);
|
|
||||||
entity.explosiveness = item.explosiveness;
|
|
||||||
entity.generateTime = 1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(entity.generateTime > 0f){
|
|
||||||
entity.generateTime -= Math.min(1f / itemDuration * entity.delta(), entity.generateTime);
|
|
||||||
|
|
||||||
if(Mathf.chance(entity.delta() * 0.06 * Mathf.clamp(entity.explosiveness - 0.25f))){
|
|
||||||
//this block is run last so that in the event of a block destruction, no code relies on the block type
|
|
||||||
entity.damage(Mathf.random(8f));
|
|
||||||
Effects.effect(explodeEffect, tile.worldx() + Mathf.range(size * tilesize / 2f), tile.worldy() + Mathf.range(size * tilesize / 2f));
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
entity.productionEfficiency = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.update(tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract float getItemEfficiency(Item item);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TileEntity newEntity(){
|
|
||||||
return new ItemGeneratorEntity();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ItemGeneratorEntity extends GeneratorEntity{
|
|
||||||
public float explosiveness;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +1,86 @@
|
|||||||
package io.anuke.mindustry.world.blocks.power;
|
package io.anuke.mindustry.world.blocks.power;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
|
import io.anuke.mindustry.content.fx.BlockFx;
|
||||||
import io.anuke.mindustry.entities.TileEntity;
|
import io.anuke.mindustry.entities.TileEntity;
|
||||||
import io.anuke.mindustry.type.Item;
|
import io.anuke.mindustry.type.Item;
|
||||||
import io.anuke.mindustry.type.Liquid;
|
import io.anuke.mindustry.type.Liquid;
|
||||||
|
import io.anuke.mindustry.world.BarType;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
|
import io.anuke.mindustry.world.consumers.ConsumeItemFilter;
|
||||||
import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter;
|
import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter;
|
||||||
|
import io.anuke.mindustry.world.meta.BlockBar;
|
||||||
import io.anuke.ucore.core.Effects;
|
import io.anuke.ucore.core.Effects;
|
||||||
|
import io.anuke.ucore.core.Timers;
|
||||||
import io.anuke.ucore.graphics.Draw;
|
import io.anuke.ucore.graphics.Draw;
|
||||||
import io.anuke.ucore.util.Mathf;
|
import io.anuke.ucore.util.Mathf;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.content;
|
import static io.anuke.mindustry.Vars.content;
|
||||||
import static io.anuke.mindustry.Vars.tilesize;
|
import static io.anuke.mindustry.Vars.tilesize;
|
||||||
|
|
||||||
public abstract class ItemLiquidGenerator extends ItemGenerator{
|
/**
|
||||||
|
* Power generation block which can use items, liquids or both as input sources for power production.
|
||||||
|
* Liquids will take priority over items.
|
||||||
|
*/
|
||||||
|
public class ItemLiquidGenerator extends PowerGenerator{
|
||||||
|
|
||||||
|
protected float minItemEfficiency = 0.2f;
|
||||||
|
/** The time in number of ticks during which a single item will produce power. */
|
||||||
|
protected float itemDuration = 70f;
|
||||||
|
|
||||||
protected float minLiquidEfficiency = 0.2f;
|
protected float minLiquidEfficiency = 0.2f;
|
||||||
protected float liquidPowerMultiplier = 1.3f; // A liquid with 100% flammability will be 30% more efficient than an item with 100% flammability.
|
protected float liquidPowerMultiplier = 1.3f; // A liquid with 100% flammability will be 30% more efficient than an item with 100% flammability.
|
||||||
/**Maximum liquid used per frame.*/
|
/** Maximum liquid used per frame. */
|
||||||
protected float maxLiquidGenerate = 0.4f;
|
protected float maxLiquidGenerate = 0.4f;
|
||||||
|
|
||||||
public ItemLiquidGenerator(String name){
|
protected Effects.Effect generateEffect = BlockFx.generatespark;
|
||||||
super(name);
|
protected Effects.Effect explodeEffect = BlockFx.generatespark;
|
||||||
hasLiquids = true;
|
protected Color heatColor = Color.valueOf("ff9b59");
|
||||||
liquidCapacity = 10f;
|
protected TextureRegion topRegion;
|
||||||
|
|
||||||
consumes.add(new ConsumeLiquidFilter(liquid -> getLiquidEfficiency(liquid) >= minLiquidEfficiency, 0.001f, true)).update(false).optional(true);
|
public enum InputType{
|
||||||
|
ItemsOnly,
|
||||||
|
LiquidsOnly,
|
||||||
|
LiquidsAndItems
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemLiquidGenerator(InputType inputType, String name){
|
||||||
|
super(name);
|
||||||
|
this.hasItems = inputType != InputType.LiquidsOnly;
|
||||||
|
this.hasLiquids = inputType != InputType.ItemsOnly;
|
||||||
|
|
||||||
|
if(hasItems){
|
||||||
|
itemCapacity = 20;
|
||||||
|
consumes.add(new ConsumeItemFilter(item -> getItemEfficiency(item) >= minItemEfficiency)).update(false).optional(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hasLiquids){
|
||||||
|
liquidCapacity = 10f;
|
||||||
|
consumes.add(new ConsumeLiquidFilter(liquid -> getLiquidEfficiency(liquid) >= minLiquidEfficiency, 0.001f, true)).update(false).optional(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(){
|
public void load(){
|
||||||
super.init();
|
super.load();
|
||||||
|
if(hasItems){
|
||||||
|
topRegion = Draw.region(name + "-top");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBars(){
|
||||||
|
super.setBars();
|
||||||
|
if(hasItems){
|
||||||
|
bars.replace(new BlockBar(BarType.inventory, true, tile -> (float) tile.entity.items.total() / itemCapacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Tile tile){
|
public void update(Tile tile){
|
||||||
ItemGeneratorEntity entity = tile.entity();
|
ItemLiquidGeneratorEntity entity = tile.entity();
|
||||||
|
|
||||||
Liquid liquid = null;
|
|
||||||
for(Liquid other : content.liquids()){
|
|
||||||
if(entity.liquids.get(other) >= 0.001f && getLiquidEfficiency(other) >= minLiquidEfficiency){
|
|
||||||
liquid = other;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: Do not use this delta when calculating the amount of power or the power efficiency, but use it for resource consumption if necessary.
|
// Note: Do not use this delta when calculating the amount of power or the power efficiency, but use it for resource consumption if necessary.
|
||||||
// Power amount is delta'd by PowerGraph class already.
|
// Power amount is delta'd by PowerGraph class already.
|
||||||
@@ -51,8 +90,16 @@ public abstract class ItemLiquidGenerator extends ItemGenerator{
|
|||||||
entity.productionEfficiency = 0.0f;
|
entity.productionEfficiency = 0.0f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Liquid liquid = null;
|
||||||
|
for(Liquid other : content.liquids()){
|
||||||
|
if(hasLiquids && entity.liquids.get(other) >= 0.001f && getLiquidEfficiency(other) >= minLiquidEfficiency){
|
||||||
|
liquid = other;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
//liquid takes priority over solids
|
//liquid takes priority over solids
|
||||||
if(liquid != null && entity.liquids.get(liquid) >= 0.001f){
|
if(hasLiquids && liquid != null && entity.liquids.get(liquid) >= 0.001f){
|
||||||
float baseLiquidEfficiency = getLiquidEfficiency(liquid) * this.liquidPowerMultiplier;
|
float baseLiquidEfficiency = getLiquidEfficiency(liquid) * this.liquidPowerMultiplier;
|
||||||
float maximumPossible = maxLiquidGenerate * calculationDelta;
|
float maximumPossible = maxLiquidGenerate * calculationDelta;
|
||||||
float used = Math.min(entity.liquids.get(liquid) * calculationDelta, maximumPossible);
|
float used = Math.min(entity.liquids.get(liquid) * calculationDelta, maximumPossible);
|
||||||
@@ -65,35 +112,85 @@ public abstract class ItemLiquidGenerator extends ItemGenerator{
|
|||||||
if(used > 0.001f && Mathf.chance(0.05 * entity.delta())){
|
if(used > 0.001f && Mathf.chance(0.05 * entity.delta())){
|
||||||
Effects.effect(generateEffect, tile.drawx() + Mathf.range(3f), tile.drawy() + Mathf.range(3f));
|
Effects.effect(generateEffect, tile.drawx() + Mathf.range(3f), tile.drawy() + Mathf.range(3f));
|
||||||
}
|
}
|
||||||
|
}else if(hasItems){
|
||||||
|
// No liquids accepted or none supplied, try using items if accepted
|
||||||
|
if(entity.generateTime <= 0f && entity.items.total() > 0){
|
||||||
|
Effects.effect(generateEffect, tile.worldx() + Mathf.range(3f), tile.worldy() + Mathf.range(3f));
|
||||||
|
Item item = entity.items.take();
|
||||||
|
entity.productionEfficiency = getItemEfficiency(item);
|
||||||
|
entity.explosiveness = item.explosiveness;
|
||||||
|
entity.generateTime = 1f;
|
||||||
|
}
|
||||||
|
|
||||||
// Update the graph manually instead of letting the base class do it since that would consume items
|
if(entity.generateTime > 0f){
|
||||||
entity.power.graph.update();
|
entity.generateTime -= Math.min(1f / itemDuration * entity.delta(), entity.generateTime);
|
||||||
}else{
|
|
||||||
// No liquids accepted, act like a default ItemGenerator
|
if(Mathf.chance(entity.delta() * 0.06 * Mathf.clamp(entity.explosiveness - 0.25f))){
|
||||||
super.update(tile);
|
//this block is run last so that in the event of a block destruction, no code relies on the block type
|
||||||
|
entity.damage(Mathf.random(8f));
|
||||||
|
Effects.effect(explodeEffect, tile.worldx() + Mathf.range(size * tilesize / 2f), tile.worldy() + Mathf.range(size * tilesize / 2f));
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
entity.productionEfficiency = 0.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
super.update(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptItem(Item item, Tile tile, Tile source){
|
||||||
|
return hasItems && getItemEfficiency(item) >= minItemEfficiency && tile.entity.items.total() < itemCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){
|
||||||
|
return hasLiquids && getLiquidEfficiency(liquid) >= minLiquidEfficiency && tile.entity.liquids.get(liquid) < liquidCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(Tile tile){
|
public void draw(Tile tile){
|
||||||
super.draw(tile);
|
super.draw(tile);
|
||||||
|
|
||||||
TileEntity entity = tile.entity();
|
GeneratorEntity entity = tile.entity();
|
||||||
|
|
||||||
Draw.color(entity.liquids.current().color);
|
if(hasItems){
|
||||||
Draw.alpha(entity.liquids.currentAmount() / liquidCapacity);
|
if(entity.generateTime > 0){
|
||||||
drawLiquidCenter(tile);
|
Draw.color(heatColor);
|
||||||
Draw.color();
|
float alpha = (entity.items.total() > 0 ? 1f : Mathf.clamp(entity.generateTime));
|
||||||
}
|
alpha = alpha * 0.7f + Mathf.absin(Timers.time(), 12f, 0.3f) * alpha;
|
||||||
|
Draw.alpha(alpha);
|
||||||
|
Draw.rect(topRegion, tile.drawx(), tile.drawy());
|
||||||
|
Draw.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
if(hasLiquids){
|
||||||
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){
|
Draw.color(entity.liquids.current().color);
|
||||||
return getLiquidEfficiency(liquid) >= minLiquidEfficiency && tile.entity.liquids.get(liquid) < liquidCapacity;
|
Draw.alpha(entity.liquids.currentAmount() / liquidCapacity);
|
||||||
|
drawLiquidCenter(tile);
|
||||||
|
Draw.color();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawLiquidCenter(Tile tile){
|
public void drawLiquidCenter(Tile tile){
|
||||||
Draw.rect("blank", tile.drawx(), tile.drawy(), 2, 2);
|
Draw.rect("blank", tile.drawx(), tile.drawy(), 2, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract float getLiquidEfficiency(Liquid liquid);
|
protected float getItemEfficiency(Item item){
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float getLiquidEfficiency(Liquid liquid){
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileEntity newEntity(){
|
||||||
|
return new ItemLiquidGeneratorEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ItemLiquidGeneratorEntity extends GeneratorEntity{
|
||||||
|
public float explosiveness;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
package io.anuke.mindustry.world.blocks.power;
|
|
||||||
|
|
||||||
import io.anuke.mindustry.content.fx.BlockFx;
|
|
||||||
import io.anuke.mindustry.entities.TileEntity;
|
|
||||||
import io.anuke.mindustry.type.Liquid;
|
|
||||||
import io.anuke.mindustry.world.Tile;
|
|
||||||
import io.anuke.mindustry.world.blocks.power.ItemGenerator.ItemGeneratorEntity;
|
|
||||||
import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter;
|
|
||||||
import io.anuke.ucore.core.Effects;
|
|
||||||
import io.anuke.ucore.core.Effects.Effect;
|
|
||||||
import io.anuke.ucore.graphics.Draw;
|
|
||||||
import io.anuke.ucore.util.Mathf;
|
|
||||||
|
|
||||||
public abstract class LiquidGenerator extends PowerGenerator{
|
|
||||||
protected float minEfficiency = 0.2f;
|
|
||||||
protected float liquidPowerMultiplier;
|
|
||||||
/**Maximum liquid used per frame.*/
|
|
||||||
protected float maxLiquidGenerate;
|
|
||||||
protected Effect generateEffect = BlockFx.generatespark;
|
|
||||||
|
|
||||||
public LiquidGenerator(String name){
|
|
||||||
super(name);
|
|
||||||
liquidCapacity = 30f;
|
|
||||||
hasLiquids = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setStats(){
|
|
||||||
consumes.add(new ConsumeLiquidFilter(liquid -> getEfficiency(liquid) >= minEfficiency, maxLiquidGenerate)).update(false);
|
|
||||||
super.setStats();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void draw(Tile tile){
|
|
||||||
super.draw(tile);
|
|
||||||
|
|
||||||
TileEntity entity = tile.entity();
|
|
||||||
|
|
||||||
Draw.color(entity.liquids.current().color);
|
|
||||||
Draw.alpha(entity.liquids.total() / liquidCapacity);
|
|
||||||
drawLiquidCenter(tile);
|
|
||||||
Draw.color();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drawLiquidCenter(Tile tile){
|
|
||||||
Draw.rect("blank", tile.drawx(), tile.drawy(), 2, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(Tile tile){
|
|
||||||
ItemGeneratorEntity entity = tile.entity();
|
|
||||||
|
|
||||||
// Note: Do not use this delta when calculating the amount of power or the power efficiency, but use it for resource consumption if necessary.
|
|
||||||
// Power amount is delta'd by PowerGraph class already.
|
|
||||||
float calculationDelta = entity.delta();
|
|
||||||
|
|
||||||
if(entity.liquids.get(entity.liquids.current()) >= 0.001f){
|
|
||||||
float baseLiquidEfficiency = getEfficiency(entity.liquids.current()) * this.liquidPowerMultiplier;
|
|
||||||
float maximumPossible = maxLiquidGenerate * calculationDelta;
|
|
||||||
float used = Math.min(entity.liquids.currentAmount() * calculationDelta, maximumPossible);
|
|
||||||
|
|
||||||
entity.liquids.remove(entity.liquids.current(), used);
|
|
||||||
|
|
||||||
// Note: 1 Item with 100% Flammability = 100% efficiency. This means 100% is not max but rather a reference point for this generator.
|
|
||||||
entity.productionEfficiency = baseLiquidEfficiency * used / maximumPossible;
|
|
||||||
|
|
||||||
if(used > 0.001f && Mathf.chance(0.05 * entity.delta())){
|
|
||||||
Effects.effect(generateEffect, tile.drawx() + Mathf.range(3f), tile.drawy() + Mathf.range(3f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.update(tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){
|
|
||||||
return getEfficiency(liquid) >= minEfficiency && super.acceptLiquid(tile, source, liquid, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TileEntity newEntity(){
|
|
||||||
return new ItemGeneratorEntity();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an efficiency value for the specified liquid.
|
|
||||||
* Greater efficiency means more power generation.
|
|
||||||
* If a liquid's efficiency is below {@link #minEfficiency}, it is not accepted.
|
|
||||||
*/
|
|
||||||
protected abstract float getEfficiency(Liquid liquid);
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
package io.anuke.mindustry.world.blocks.power;
|
package io.anuke.mindustry.world.blocks.power;
|
||||||
|
|
||||||
|
import io.anuke.mindustry.type.Item;
|
||||||
import io.anuke.mindustry.type.Liquid;
|
import io.anuke.mindustry.type.Liquid;
|
||||||
import io.anuke.mindustry.world.meta.BlockStat;
|
import io.anuke.mindustry.world.meta.BlockStat;
|
||||||
import io.anuke.mindustry.world.meta.StatUnit;
|
import io.anuke.mindustry.world.meta.StatUnit;
|
||||||
|
|
||||||
public class LiquidHeatGenerator extends LiquidGenerator{
|
public class LiquidHeatGenerator extends ItemLiquidGenerator{
|
||||||
|
|
||||||
public LiquidHeatGenerator(String name){
|
public LiquidHeatGenerator(String name){
|
||||||
super(name);
|
super(InputType.LiquidsOnly, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -20,7 +21,7 @@ public class LiquidHeatGenerator extends LiquidGenerator{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected float getEfficiency(Liquid liquid){
|
protected float getLiquidEfficiency(Liquid liquid){
|
||||||
return liquid.temperature - 0.5f;
|
return liquid.temperature - 0.5f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +1,55 @@
|
|||||||
package power;
|
package power;
|
||||||
|
|
||||||
import io.anuke.mindustry.Vars;
|
|
||||||
import io.anuke.mindustry.content.Items;
|
import io.anuke.mindustry.content.Items;
|
||||||
import io.anuke.mindustry.content.Liquids;
|
import io.anuke.mindustry.content.Liquids;
|
||||||
import io.anuke.mindustry.type.Item;
|
import io.anuke.mindustry.type.Item;
|
||||||
import io.anuke.mindustry.type.Liquid;
|
import io.anuke.mindustry.type.Liquid;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.blocks.power.BurnerGenerator;
|
|
||||||
import io.anuke.mindustry.world.blocks.power.ItemGenerator;
|
|
||||||
import io.anuke.mindustry.world.blocks.power.ItemLiquidGenerator;
|
import io.anuke.mindustry.world.blocks.power.ItemLiquidGenerator;
|
||||||
import org.junit.jupiter.api.*;
|
import org.junit.jupiter.api.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class tests ItemLiquidGenerators. Currently, testing is only performed on the BurnerGenerator subclass,
|
* This class tests generators which can process items, liquids or both.
|
||||||
* which means only power calculations based on flammability are tested.
|
|
||||||
* All tests are run with a fixed delta of 0.5 so delta considerations can be tested as well.
|
* All tests are run with a fixed delta of 0.5 so delta considerations can be tested as well.
|
||||||
* Additionally, each PowerGraph::update() call will have its own thread frame, i.e. the method will never be called twice within the same frame.
|
* Additionally, each PowerGraph::update() call will have its own thread frame, i.e. the method will never be called twice within the same frame.
|
||||||
* Both of these constraints are handled by FakeThreadHandler within PowerTestFixture.
|
* Both of these constraints are handled by FakeThreadHandler within PowerTestFixture.
|
||||||
* Any power amount (produced, consumed, buffered) should be affected by FakeThreadHandler.fakeDelta but satisfaction should not!
|
* Any expected power amount (produced, consumed, buffered) should be affected by FakeThreadHandler.fakeDelta but satisfaction should not!
|
||||||
* TODO Find a way to reuse these tests for LiquidGenerator and ItemGenerator
|
|
||||||
*/
|
*/
|
||||||
public class ItemLiquidGeneratorTests extends PowerTestFixture{
|
public class ItemLiquidGeneratorTests extends PowerTestFixture{
|
||||||
|
|
||||||
private ItemLiquidGenerator generator;
|
private ItemLiquidGenerator generator;
|
||||||
private Tile tile;
|
private Tile tile;
|
||||||
private ItemGenerator.ItemGeneratorEntity entity;
|
private ItemLiquidGenerator.ItemLiquidGeneratorEntity entity;
|
||||||
private final float fakeLiquidPowerMultiplier = 2.0f;
|
private final float fakeLiquidPowerMultiplier = 2.0f;
|
||||||
private final float fakeItemDuration = 60f; // 60 ticks
|
private final float fakeItemDuration = 60f; // 60 ticks
|
||||||
private final float maximumLiquidUsage = 0.5f;
|
private final float maximumLiquidUsage = 0.5f;
|
||||||
|
|
||||||
@BeforeEach
|
public void createGenerator(ItemLiquidGenerator.InputType inputType){
|
||||||
public void createBurnerGenerator(){
|
generator = new ItemLiquidGenerator(inputType, "fakegen"){
|
||||||
// Use a burner generator instead of a custom ItemLiquidGenerator subclass since we would implement abstract methods the same way.
|
{
|
||||||
generator = new BurnerGenerator("fakegen"){{
|
powerProduction = 0.1f;
|
||||||
powerProduction = 0.1f;
|
itemDuration = 60f;
|
||||||
itemDuration = 60f;
|
liquidPowerMultiplier = fakeLiquidPowerMultiplier;
|
||||||
liquidPowerMultiplier = fakeLiquidPowerMultiplier;
|
itemDuration = fakeItemDuration;
|
||||||
itemDuration = fakeItemDuration;
|
maxLiquidGenerate = maximumLiquidUsage;
|
||||||
maxLiquidGenerate = maximumLiquidUsage;
|
}
|
||||||
}};
|
|
||||||
|
@Override
|
||||||
|
public float getItemEfficiency(Item item){
|
||||||
|
return item.flammability;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getLiquidEfficiency(Liquid liquid){
|
||||||
|
return liquid.flammability;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
tile = createFakeTile(0, 0, generator);
|
tile = createFakeTile(0, 0, generator);
|
||||||
entity = tile.entity();
|
entity = tile.entity();
|
||||||
@@ -51,27 +58,35 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
|
|||||||
/** Tests the consumption and efficiency when being supplied with liquids. */
|
/** Tests the consumption and efficiency when being supplied with liquids. */
|
||||||
@TestFactory
|
@TestFactory
|
||||||
DynamicTest[] generatorWorksProperlyWithLiquidInput(){
|
DynamicTest[] generatorWorksProperlyWithLiquidInput(){
|
||||||
return new DynamicTest[]{
|
|
||||||
dynamicTest("01", () -> simulateLiquidConsumption(Liquids.oil, 0.0f, "No liquids provided")),
|
// Execute all tests for the case where only liquids are accepted and for the case where liquids and items are accepted (but supply only liquids)
|
||||||
dynamicTest("02", () -> simulateLiquidConsumption(Liquids.oil, maximumLiquidUsage / 4.0f, "Low oil provided")),
|
ItemLiquidGenerator.InputType[] inputTypesToBeTested = new ItemLiquidGenerator.InputType[]{
|
||||||
dynamicTest("03", () -> simulateLiquidConsumption(Liquids.oil, maximumLiquidUsage * 1.0f, "Sufficient oil provided")),
|
ItemLiquidGenerator.InputType.LiquidsOnly,
|
||||||
dynamicTest("04", () -> simulateLiquidConsumption(Liquids.oil, maximumLiquidUsage * 2.0f, "Excess oil provided"))
|
ItemLiquidGenerator.InputType.LiquidsAndItems
|
||||||
// Note: The generator will decline any other liquid since it's not flammable
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ArrayList<DynamicTest> tests = new ArrayList<>();
|
||||||
|
for(ItemLiquidGenerator.InputType inputType : inputTypesToBeTested){
|
||||||
|
tests.add(dynamicTest("01", () -> simulateLiquidConsumption(inputType, Liquids.oil, 0.0f, "No liquids provided")));
|
||||||
|
tests.add(dynamicTest("02", () -> simulateLiquidConsumption(inputType, Liquids.oil, maximumLiquidUsage / 4.0f, "Low oil provided")));
|
||||||
|
tests.add(dynamicTest("03", () -> simulateLiquidConsumption(inputType, Liquids.oil, maximumLiquidUsage * 1.0f, "Sufficient oil provided")));
|
||||||
|
tests.add(dynamicTest("04", () -> simulateLiquidConsumption(inputType, Liquids.oil, maximumLiquidUsage * 2.0f, "Excess oil provided")));
|
||||||
|
// Note: The generator will decline any other liquid since it's not flammable
|
||||||
|
}
|
||||||
|
DynamicTest[] testArray = new DynamicTest[tests.size()];
|
||||||
|
testArray = tests.toArray(testArray);
|
||||||
|
return testArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
void simulateLiquidConsumption(Liquid liquid, float availableLiquidAmount, String parameterDescription){
|
void simulateLiquidConsumption(ItemLiquidGenerator.InputType inputType, Liquid liquid, float availableLiquidAmount, String parameterDescription){
|
||||||
final float baseEfficiency = fakeLiquidPowerMultiplier * liquid.flammability;
|
final float baseEfficiency = fakeLiquidPowerMultiplier * liquid.flammability;
|
||||||
final float expectedEfficiency = Math.min(1.0f, availableLiquidAmount / maximumLiquidUsage) * baseEfficiency;
|
final float expectedEfficiency = Math.min(1.0f, availableLiquidAmount / maximumLiquidUsage) * baseEfficiency;
|
||||||
final float expectedConsumptionPerTick = Math.min(maximumLiquidUsage, availableLiquidAmount);
|
final float expectedConsumptionPerTick = Math.min(maximumLiquidUsage, availableLiquidAmount);
|
||||||
final float expectedRemainingLiquidAmount = Math.max(0.0f, availableLiquidAmount - expectedConsumptionPerTick * FakeThreadHandler.fakeDelta);
|
final float expectedRemainingLiquidAmount = Math.max(0.0f, availableLiquidAmount - expectedConsumptionPerTick * FakeThreadHandler.fakeDelta);
|
||||||
|
|
||||||
assertTrue(generator.acceptLiquid(tile, null, liquid, availableLiquidAmount), parameterDescription + ": Liquids which will be declined by the generator don't need to be tested - The code won't be called for those cases.");
|
createGenerator(inputType);
|
||||||
|
assertTrue(generator.acceptLiquid(tile, null, liquid, availableLiquidAmount), inputType + " | " + parameterDescription + ": Liquids which will be declined by the generator don't need to be tested - The code won't be called for those cases.");
|
||||||
|
|
||||||
// Reset liquids since BeforeEach will not be called between dynamic tests
|
|
||||||
for(Liquid tmpLiquid : Vars.content.liquids()){
|
|
||||||
entity.liquids.reset(tmpLiquid, 0.0f);
|
|
||||||
}
|
|
||||||
entity.liquids.add(liquid, availableLiquidAmount);
|
entity.liquids.add(liquid, availableLiquidAmount);
|
||||||
entity.cons.update(tile.entity);
|
entity.cons.update(tile.entity);
|
||||||
assertTrue(entity.cons.valid());
|
assertTrue(entity.cons.valid());
|
||||||
@@ -79,34 +94,41 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
|
|||||||
// Perform an update on the generator once - This should use up any resource up to the maximum liquid usage
|
// Perform an update on the generator once - This should use up any resource up to the maximum liquid usage
|
||||||
generator.update(tile);
|
generator.update(tile);
|
||||||
|
|
||||||
assertEquals(expectedRemainingLiquidAmount, entity.liquids.get(liquid), parameterDescription + ": Remaining liquid amount mismatch.");
|
assertEquals(expectedRemainingLiquidAmount, entity.liquids.get(liquid), inputType + " | " + parameterDescription + ": Remaining liquid amount mismatch.");
|
||||||
assertEquals(expectedEfficiency, entity.productionEfficiency, parameterDescription + ": Efficiency mismatch.");
|
assertEquals(expectedEfficiency, entity.productionEfficiency, inputType + " | " + parameterDescription + ": Efficiency mismatch.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tests the consumption and efficiency when being supplied with items. */
|
/** Tests the consumption and efficiency when being supplied with items. */
|
||||||
@TestFactory
|
@TestFactory
|
||||||
DynamicTest[] generatorWorksProperlyWithItemInput(){
|
DynamicTest[] generatorWorksProperlyWithItemInput(){
|
||||||
return new DynamicTest[]{
|
|
||||||
dynamicTest("01", () -> simulateItemConsumption(Items.coal, 0, "No items provided")),
|
// Execute all tests for the case where only items are accepted and for the case where liquids and items are accepted (but supply only items)
|
||||||
dynamicTest("02", () -> simulateItemConsumption(Items.coal, 1, "Sufficient coal provided")),
|
ItemLiquidGenerator.InputType[] inputTypesToBeTested = new ItemLiquidGenerator.InputType[]{
|
||||||
dynamicTest("03", () -> simulateItemConsumption(Items.coal, 10, "Excess coal provided")),
|
ItemLiquidGenerator.InputType.ItemsOnly,
|
||||||
dynamicTest("04", () -> simulateItemConsumption(Items.blastCompound, 1, "Blast compound provided")),
|
ItemLiquidGenerator.InputType.LiquidsAndItems
|
||||||
//dynamicTest("03", () -> simulateItemConsumption(Items.plastanium, 1, "Plastanium provided")), // Not accepted by generator due to low flammability
|
|
||||||
dynamicTest("05", () -> simulateItemConsumption(Items.biomatter, 1, "Biomatter provided")),
|
|
||||||
dynamicTest("06", () -> simulateItemConsumption(Items.pyratite, 1, "Pyratite provided"))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ArrayList<DynamicTest> tests = new ArrayList<>();
|
||||||
|
for(ItemLiquidGenerator.InputType inputType : inputTypesToBeTested){
|
||||||
|
tests.add(dynamicTest("01", () -> simulateItemConsumption(inputType, Items.coal, 0, "No items provided")));
|
||||||
|
tests.add(dynamicTest("02", () -> simulateItemConsumption(inputType, Items.coal, 1, "Sufficient coal provided")));
|
||||||
|
tests.add(dynamicTest("03", () -> simulateItemConsumption(inputType, Items.coal, 10, "Excess coal provided")));
|
||||||
|
tests.add(dynamicTest("04", () -> simulateItemConsumption(inputType, Items.blastCompound, 1, "Blast compound provided")));
|
||||||
|
//dynamicTest("03", () -> simulateItemConsumption(inputType, Items.plastanium, 1, "Plastanium provided")), // Not accepted by generator due to low flammability
|
||||||
|
tests.add(dynamicTest("05", () -> simulateItemConsumption(inputType, Items.biomatter, 1, "Biomatter provided")));
|
||||||
|
tests.add(dynamicTest("06", () -> simulateItemConsumption(inputType, Items.pyratite, 1, "Pyratite provided")));
|
||||||
|
}
|
||||||
|
DynamicTest[] testArray = new DynamicTest[tests.size()];
|
||||||
|
testArray = tests.toArray(testArray);
|
||||||
|
return testArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
void simulateItemConsumption(Item item, int amount, String parameterDescription){
|
void simulateItemConsumption(ItemLiquidGenerator.InputType inputType, Item item, int amount, String parameterDescription){
|
||||||
final float expectedEfficiency = Math.min(1.0f, amount > 0 ? item.flammability : 0f);
|
final float expectedEfficiency = Math.min(1.0f, amount > 0 ? item.flammability : 0f);
|
||||||
final float expectedRemainingItemAmount = Math.max(0, amount - 1);
|
final float expectedRemainingItemAmount = Math.max(0, amount - 1);
|
||||||
assertTrue(generator.acceptItem(item, tile, null), parameterDescription + ": Items which will be declined by the generator don't need to be tested - The code won't be called for those cases.");
|
|
||||||
|
|
||||||
|
createGenerator(inputType);
|
||||||
// Clean up manually since BeforeEach will not be called between dynamic tests
|
assertTrue(generator.acceptItem(item, tile, null), inputType + " | " + parameterDescription + ": Items which will be declined by the generator don't need to be tested - The code won't be called for those cases.");
|
||||||
entity.items.clear();
|
|
||||||
entity.generateTime = 0.0f;
|
|
||||||
entity.productionEfficiency = 0.0f;
|
|
||||||
|
|
||||||
if(amount > 0){
|
if(amount > 0){
|
||||||
entity.items.add(item, amount);
|
entity.items.add(item, amount);
|
||||||
@@ -117,13 +139,24 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{
|
|||||||
// Perform an update on the generator once - This should use up one or zero items - dependent on if the item is accepted and available or not.
|
// Perform an update on the generator once - This should use up one or zero items - dependent on if the item is accepted and available or not.
|
||||||
generator.update(tile);
|
generator.update(tile);
|
||||||
|
|
||||||
assertEquals(expectedRemainingItemAmount, entity.items.get(item), parameterDescription + ": Remaining item amount mismatch.");
|
assertEquals(expectedRemainingItemAmount, entity.items.get(item), inputType + " | " + parameterDescription + ": Remaining item amount mismatch.");
|
||||||
assertEquals(expectedEfficiency, entity.productionEfficiency, parameterDescription + ": Efficiency mismatch.");
|
assertEquals(expectedEfficiency, entity.productionEfficiency, inputType + " | " + parameterDescription + ": Efficiency mismatch.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Makes sure the efficiency stays equal during the item duration. */
|
/** Makes sure the efficiency stays equal during the item duration. */
|
||||||
@Test
|
@Test
|
||||||
void efficiencyRemainsConstantWithinItemDuration(){
|
void efficiencyRemainsConstantWithinItemDuration_ItemsOnly(){
|
||||||
|
testItemDuration(ItemLiquidGenerator.InputType.ItemsOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Makes sure the efficiency stays equal during the item duration. */
|
||||||
|
@Test
|
||||||
|
void efficiencyRemainsConstantWithinItemDuration_ItemsAndLiquids(){
|
||||||
|
testItemDuration(ItemLiquidGenerator.InputType.LiquidsAndItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testItemDuration(ItemLiquidGenerator.InputType inputType){
|
||||||
|
createGenerator(inputType);
|
||||||
|
|
||||||
// Burn a single coal and test for the duration
|
// Burn a single coal and test for the duration
|
||||||
entity.items.add(Items.coal, 1);
|
entity.items.add(Items.coal, 1);
|
||||||
|
|||||||
Reference in New Issue
Block a user