From 99139dfccabece71685c943545bc4e02c19739fb Mon Sep 17 00:00:00 2001 From: Timmeey86 Date: Mon, 26 Nov 2018 08:58:16 +0100 Subject: [PATCH 1/3] Added unit tests for batteries... ...and fixed battery distribution until all tests passed --- .../world/blocks/power/PowerGraph.java | 20 ++++++++--- tests/src/test/java/PowerTests.java | 33 +++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java b/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java index b17493349a..8c07c31580 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java @@ -80,9 +80,15 @@ public class PowerGraph{ if(MathUtils.isEqual(stored, 0f)){ return 0f; } float used = Math.min(stored, needed); - float percentageRemaining = 1f - (used / stored); + float consumedPowerPercentage = Math.min(1.0f, needed / stored); for(Tile battery : batteries){ - battery.entity.power.satisfaction *= percentageRemaining; + Consumers consumes = battery.block().consumes; + if(consumes.has(ConsumePower.class)){ + ConsumePower consumePower = consumes.get(ConsumePower.class); + if(consumePower.powerCapacity > 0f){ + battery.entity.power.satisfaction = Math.max(0.0f, battery.entity.power.satisfaction - consumedPowerPercentage); + } + } } return used; } @@ -91,9 +97,15 @@ public class PowerGraph{ float capacity = getBatteryCapacity(); if(MathUtils.isEqual(capacity, 0f)){ return 0f; } - float thing = Math.min(1, excess / capacity); for(Tile battery : batteries){ - battery.entity.power.satisfaction += (1 - battery.entity.power.satisfaction) * thing; + Consumers consumes = battery.block().consumes; + if(consumes.has(ConsumePower.class)){ + ConsumePower consumePower = consumes.get(ConsumePower.class); + if(consumePower.powerCapacity > 0f){ + float additionalPowerPercentage = Math.min(1.0f, excess / consumePower.powerCapacity); + battery.entity.power.satisfaction = Math.min(1.0f, battery.entity.power.satisfaction + additionalPowerPercentage); + } + } } return Math.min(excess, capacity); } diff --git a/tests/src/test/java/PowerTests.java b/tests/src/test/java/PowerTests.java index 096e2d126a..6d6655a5b1 100644 --- a/tests/src/test/java/PowerTests.java +++ b/tests/src/test/java/PowerTests.java @@ -101,5 +101,38 @@ public class PowerTests extends PowerTestFixture{ powerGraph.update(); assertEquals(expectedSatisfaction, bufferedConsumerTile.entity.power.satisfaction, MathUtils.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of buffered consumer did not match"); } + + /** Tests the satisfaction of a single direct consumer after a single update of the power graph which contains a single producer and a single battery. + * The used battery is created with a maximum capacity of 100 and receives ten power per tick. + */ + @TestFactory + DynamicTest[] testDirectConsumptionWithBattery(){ + return new DynamicTest[]{ + dynamicTest("1", () -> test_directConsumptionWithBattery(10.0f, 0.0f, 0.0f, 10.0f, 0.0f, "Empty battery, no consumer")), + dynamicTest("2", () -> test_directConsumptionWithBattery(10.0f, 0.0f, 90.0f, 100.0f, 0.0f, "Battery full after update, no consumer")), + dynamicTest("3", () -> test_directConsumptionWithBattery(10.0f, 0.0f, 100.0f, 100.0f, 0.0f, "Full battery, no consumer")), + dynamicTest("4", () -> test_directConsumptionWithBattery(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, "No producer, no consumer, empty battery")), + dynamicTest("5", () -> test_directConsumptionWithBattery(0.0f, 0.0f, 100.0f, 100.0f, 0.0f, "No producer, no consumer, full battery")), + dynamicTest("6", () -> test_directConsumptionWithBattery(0.0f, 10.0f, 0.0f, 0.0f, 0.0f, "No producer, empty battery")), + dynamicTest("7", () -> test_directConsumptionWithBattery(0.0f, 10.0f, 100.0f, 90.0f, 1.0f, "No producer, full battery")), + dynamicTest("8", () -> test_directConsumptionWithBattery(0.0f, 10.0f, 5.0f, 0.0f, 0.5f, "No producer, low battery")) + }; + } + void test_directConsumptionWithBattery(float producedPower, float requestedPower, float initialBatteryCapacity, float expectedBatteryCapacity, float expectedSatisfaction, String parameterDescription){ + Tile producerTile = createFakeTile(0, 0, createFakeProducerBlock(producedPower)); + Tile directConsumerTile = createFakeTile(0, 1, createFakeDirectConsumer(requestedPower, 0.6f)); + float maxCapacity = 100f; + Tile batteryTile = createFakeTile(0, 2, createFakeBattery(maxCapacity, 10 )); + batteryTile.entity.power.satisfaction = initialBatteryCapacity / maxCapacity; + + PowerGraph powerGraph = new PowerGraph(); + powerGraph.add(producerTile); + powerGraph.add(directConsumerTile); + powerGraph.add(batteryTile); + + powerGraph.update(); + assertEquals(expectedBatteryCapacity, batteryTile.entity.power.satisfaction * maxCapacity, MathUtils.FLOAT_ROUNDING_ERROR, parameterDescription + ": Expected battery capacity did not match"); + assertEquals(expectedSatisfaction, directConsumerTile.entity.power.satisfaction, MathUtils.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match"); + } } } From 77b9feb76554dc3ef45559d7b40e597fae033b4f Mon Sep 17 00:00:00 2001 From: Timmeey86 Date: Mon, 26 Nov 2018 09:24:08 +0100 Subject: [PATCH 2/3] More Tests and fixes - Batteries will now get charged with no consumers - Fixed stat display of power generators --- .../world/blocks/power/PowerGenerator.java | 2 +- .../world/blocks/power/PowerGraph.java | 2 +- tests/src/test/java/PowerTests.java | 37 ++++++++++++------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java index b1ee6f73ce..b489e827da 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java @@ -22,7 +22,7 @@ public class PowerGenerator extends PowerDistributor{ @Override public void setStats(){ super.setStats(); - stats.add(generationType, powerProduction, StatUnit.powerSecond); + stats.add(generationType, powerProduction * 60.0f, StatUnit.powerSecond); } @Override diff --git a/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java b/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java index 8c07c31580..c8f5cfe846 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java @@ -132,7 +132,7 @@ public class PowerGraph{ } public void update(){ - if(threads.getFrameID() == lastFrameUpdated || consumers.size == 0 || producers.size == 0){ + if(threads.getFrameID() == lastFrameUpdated || consumers.size == 0 && producers.size == 0 && batteries.size == 0){ return; } diff --git a/tests/src/test/java/PowerTests.java b/tests/src/test/java/PowerTests.java index 6d6655a5b1..3b93652c0e 100644 --- a/tests/src/test/java/PowerTests.java +++ b/tests/src/test/java/PowerTests.java @@ -108,31 +108,40 @@ public class PowerTests extends PowerTestFixture{ @TestFactory DynamicTest[] testDirectConsumptionWithBattery(){ return new DynamicTest[]{ - dynamicTest("1", () -> test_directConsumptionWithBattery(10.0f, 0.0f, 0.0f, 10.0f, 0.0f, "Empty battery, no consumer")), - dynamicTest("2", () -> test_directConsumptionWithBattery(10.0f, 0.0f, 90.0f, 100.0f, 0.0f, "Battery full after update, no consumer")), - dynamicTest("3", () -> test_directConsumptionWithBattery(10.0f, 0.0f, 100.0f, 100.0f, 0.0f, "Full battery, no consumer")), - dynamicTest("4", () -> test_directConsumptionWithBattery(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, "No producer, no consumer, empty battery")), - dynamicTest("5", () -> test_directConsumptionWithBattery(0.0f, 0.0f, 100.0f, 100.0f, 0.0f, "No producer, no consumer, full battery")), - dynamicTest("6", () -> test_directConsumptionWithBattery(0.0f, 10.0f, 0.0f, 0.0f, 0.0f, "No producer, empty battery")), - dynamicTest("7", () -> test_directConsumptionWithBattery(0.0f, 10.0f, 100.0f, 90.0f, 1.0f, "No producer, full battery")), - dynamicTest("8", () -> test_directConsumptionWithBattery(0.0f, 10.0f, 5.0f, 0.0f, 0.5f, "No producer, low battery")) + dynamicTest("01", () -> test_directConsumptionWithBattery(10.0f, 0.0f, 0.0f, 10.0f, 0.0f, "Empty battery, no consumer")), + dynamicTest("02", () -> test_directConsumptionWithBattery(10.0f, 0.0f, 90.0f, 100.0f, 0.0f, "Battery full after update, no consumer")), + dynamicTest("03", () -> test_directConsumptionWithBattery(10.0f, 0.0f, 100.0f, 100.0f, 0.0f, "Full battery, no consumer")), + dynamicTest("04", () -> test_directConsumptionWithBattery(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, "No producer, no consumer, empty battery")), + dynamicTest("05", () -> test_directConsumptionWithBattery(0.0f, 0.0f, 100.0f, 100.0f, 0.0f, "No producer, no consumer, full battery")), + dynamicTest("06", () -> test_directConsumptionWithBattery(0.0f, 10.0f, 0.0f, 0.0f, 0.0f, "No producer, empty battery")), + dynamicTest("07", () -> test_directConsumptionWithBattery(0.0f, 10.0f, 100.0f, 90.0f, 1.0f, "No producer, full battery")), + dynamicTest("08", () -> test_directConsumptionWithBattery(0.0f, 10.0f, 5.0f, 0.0f, 0.5f, "No producer, low battery")), + dynamicTest("09", () -> test_directConsumptionWithBattery(5.0f, 10.0f, 5.0f, 0.0f, 1.0f, "Producer + Battery = Consumed")), }; } void test_directConsumptionWithBattery(float producedPower, float requestedPower, float initialBatteryCapacity, float expectedBatteryCapacity, float expectedSatisfaction, String parameterDescription){ - Tile producerTile = createFakeTile(0, 0, createFakeProducerBlock(producedPower)); - Tile directConsumerTile = createFakeTile(0, 1, createFakeDirectConsumer(requestedPower, 0.6f)); + PowerGraph powerGraph = new PowerGraph(); + + if(producedPower > 0.0f){ + Tile producerTile = createFakeTile(0, 0, createFakeProducerBlock(producedPower)); + powerGraph.add(producerTile); + } + Tile directConsumerTile = null; + if(requestedPower > 0.0f){ + directConsumerTile = createFakeTile(0, 1, createFakeDirectConsumer(requestedPower, 0.6f)); + powerGraph.add(directConsumerTile); + } float maxCapacity = 100f; Tile batteryTile = createFakeTile(0, 2, createFakeBattery(maxCapacity, 10 )); batteryTile.entity.power.satisfaction = initialBatteryCapacity / maxCapacity; - PowerGraph powerGraph = new PowerGraph(); - powerGraph.add(producerTile); - powerGraph.add(directConsumerTile); powerGraph.add(batteryTile); powerGraph.update(); assertEquals(expectedBatteryCapacity, batteryTile.entity.power.satisfaction * maxCapacity, MathUtils.FLOAT_ROUNDING_ERROR, parameterDescription + ": Expected battery capacity did not match"); - assertEquals(expectedSatisfaction, directConsumerTile.entity.power.satisfaction, MathUtils.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match"); + if(directConsumerTile != null){ + assertEquals(expectedSatisfaction, directConsumerTile.entity.power.satisfaction, MathUtils.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match"); + } } } } From f640494c1ff1680607677eff83ccf549d42e9fb5 Mon Sep 17 00:00:00 2001 From: Timmeey86 Date: Mon, 26 Nov 2018 10:26:49 +0100 Subject: [PATCH 3/3] PowerGraph now handles delta Also power bars are displayed for non-buffered consumers as well --- core/src/io/anuke/mindustry/world/Block.java | 2 +- .../mindustry/world/blocks/power/PowerGenerator.java | 2 +- .../io/anuke/mindustry/world/blocks/power/PowerGraph.java | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/src/io/anuke/mindustry/world/Block.java b/core/src/io/anuke/mindustry/world/Block.java index 8eebd822cc..e00bd316d4 100644 --- a/core/src/io/anuke/mindustry/world/Block.java +++ b/core/src/io/anuke/mindustry/world/Block.java @@ -338,7 +338,7 @@ public class Block extends BaseBlock { //TODO make this easier to config. public void setBars(){ - if(consumes.has(ConsumePower.class) && consumes.get(ConsumePower.class).isBuffered){ + if(consumes.has(ConsumePower.class)){ bars.add(new BlockBar(BarType.power, true, tile -> tile.entity.power.satisfaction)); } if(hasLiquids) diff --git a/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java index b489e827da..915ef48021 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java @@ -27,7 +27,7 @@ public class PowerGenerator extends PowerDistributor{ @Override public float getPowerProduction(Tile tile){ - return powerProduction * tile.entity().productionEfficiency * tile.entity.delta(); + return powerProduction * tile.entity().productionEfficiency; } @Override diff --git a/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java b/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java index c8f5cfe846..8439d79c11 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java @@ -37,7 +37,7 @@ public class PowerGraph{ public float getPowerProduced(){ float powerProduced = 0f; for(Tile producer : producers){ - powerProduced += producer.block().getPowerProduction(producer); + powerProduced += producer.block().getPowerProduction(producer) * producer.entity.delta(); } return powerProduced; } @@ -47,7 +47,7 @@ public class PowerGraph{ for(Tile consumer : consumers){ Consumers consumes = consumer.block().consumes; if(consumes.has(ConsumePower.class)){ - powerNeeded += consumes.get(ConsumePower.class).requestedPower(consumer.block(), consumer.entity); + powerNeeded += consumes.get(ConsumePower.class).requestedPower(consumer.block(), consumer.entity) * consumer.entity.delta(); } } return powerNeeded; @@ -69,7 +69,7 @@ public class PowerGraph{ for(Tile battery : batteries){ Consumers consumes = battery.block().consumes; if(consumes.has(ConsumePower.class)){ - totalCapacity += consumes.get(ConsumePower.class).requestedPower(battery.block(), battery.entity); + totalCapacity += consumes.get(ConsumePower.class).requestedPower(battery.block(), battery.entity) * battery.entity.delta(); } } return totalCapacity; @@ -218,6 +218,8 @@ public class PowerGraph{ } } } + // Update the graph once so direct consumers without any connected producer lose their power + graph.update(); } }