diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/detector/DetectorBlockEntity.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/detector/DetectorBlockEntity.java index 2ec523324..574e8e7e1 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/detector/DetectorBlockEntity.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/detector/DetectorBlockEntity.java @@ -4,6 +4,7 @@ import com.refinedmods.refinedstorage.api.network.impl.node.detector.DetectorAmountStrategyImpl; import com.refinedmods.refinedstorage.api.network.impl.node.detector.DetectorMode; import com.refinedmods.refinedstorage.api.network.impl.node.detector.DetectorNetworkNode; +import com.refinedmods.refinedstorage.api.resource.ResourceKey; import com.refinedmods.refinedstorage.common.Platform; import com.refinedmods.refinedstorage.common.api.RefinedStorageApi; import com.refinedmods.refinedstorage.common.api.support.network.InWorldNetworkNodeContainer; @@ -22,7 +23,6 @@ import java.util.Optional; import javax.annotation.Nullable; -import com.google.common.util.concurrent.RateLimiter; import net.minecraft.core.BlockPos; import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; @@ -40,12 +40,13 @@ public class DetectorBlockEntity extends AbstractBaseNetworkNodeContainerBlockEntity implements NetworkNodeExtendedMenuProvider { private static final Logger LOGGER = LoggerFactory.getLogger(DetectorBlockEntity.class); + private static final int POWERED_CHANGE_TICK_RATE = 20; private static final String TAG_AMOUNT = "amount"; private static final String TAG_MODE = "mode"; private final FilterWithFuzzyMode filter; - private final RateLimiter poweredChangeRateLimiter = RateLimiter.create(1); + private int poweredChangeTicks; private double amount; @@ -109,6 +110,10 @@ private void propagateAmount() { mainNetworkNode.setAmount(normalizedAmount); } + void setConfiguredResource(final ResourceKey configuredResource) { + mainNetworkNode.setConfiguredResource(configuredResource); + } + boolean isFuzzyMode() { return filter.isFuzzyMode(); } @@ -165,7 +170,7 @@ public void updateActiveness(final BlockState state, @Nullable final BooleanProp super.updateActiveness(state, activenessProperty); final boolean powered = mainNetworkNode.isActive() && mainNetworkNode.isActivated(); final boolean needToUpdatePowered = state.getValue(DetectorBlock.POWERED) != powered; - if (level != null && needToUpdatePowered && poweredChangeRateLimiter.tryAcquire()) { + if (level != null && needToUpdatePowered && poweredChangeTicks++ % POWERED_CHANGE_TICK_RATE == 0) { level.setBlockAndUpdate(getBlockPos(), state.setValue(DetectorBlock.POWERED, powered)); } } diff --git a/refinedstorage-neoforge/src/test/java/com/refinedmods/refinedstorage/common/detector/DetectorTest.java b/refinedstorage-neoforge/src/test/java/com/refinedmods/refinedstorage/common/detector/DetectorTest.java new file mode 100644 index 000000000..20c10f21c --- /dev/null +++ b/refinedstorage-neoforge/src/test/java/com/refinedmods/refinedstorage/common/detector/DetectorTest.java @@ -0,0 +1,162 @@ +package com.refinedmods.refinedstorage.common.detector; + +import com.refinedmods.refinedstorage.api.network.impl.node.detector.DetectorMode; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; +import com.refinedmods.refinedstorage.common.util.IdentifierUtil; + +import net.minecraft.core.Direction; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.RedStoneWireBlock; +import net.neoforged.neoforge.gametest.GameTestHolder; +import net.neoforged.neoforge.gametest.PrefixGameTestTemplate; + +import static com.refinedmods.refinedstorage.common.GameTestUtil.asResource; +import static com.refinedmods.refinedstorage.common.GameTestUtil.getItemAsDamaged; +import static com.refinedmods.refinedstorage.common.GameTestUtil.insert; +import static com.refinedmods.refinedstorage.common.GameTestUtil.networkIsAvailable; +import static com.refinedmods.refinedstorage.common.GameTestUtil.storageContainsExactly; +import static com.refinedmods.refinedstorage.common.detector.DetectorTestPlots.preparePlot; +import static net.minecraft.world.item.Items.DIAMOND_CHESTPLATE; +import static net.minecraft.world.item.Items.DIRT; +import static net.minecraft.world.item.Items.STONE; + +@GameTestHolder(IdentifierUtil.MOD_ID) +@PrefixGameTestTemplate(false) +public final class DetectorTest { + private DetectorTest() { + } + + @GameTest(template = "empty_15x15") + public static void shouldEmitRedstoneUnder(final GameTestHelper helper) { + preparePlot(helper, Direction.DOWN, (detector, pos, sequence) -> { + // Arrange + sequence.thenWaitUntil(networkIsAvailable(helper, pos, network -> { + insert(helper, network, DIRT, 10); + insert(helper, network, STONE, 15); + })); + + // Act + detector.setConfiguredResource(asResource(DIRT)); + detector.setMode(DetectorMode.UNDER); + detector.setAmount(5); + + // Assert + sequence + .thenWaitUntil(storageContainsExactly( + helper, + pos, + new ResourceAmount(asResource(DIRT), 10), + new ResourceAmount(asResource(STONE), 15) + )) + .thenWaitUntil(() -> helper.assertBlockProperty(pos.north(), RedStoneWireBlock.POWER, 0)) + .thenExecute(() -> detector.setAmount(10)) + .thenWaitUntil(() -> helper.assertBlockProperty(pos.north(), RedStoneWireBlock.POWER, 0)) + .thenExecute(() -> detector.setAmount(15)) + .thenWaitUntil(() -> helper.assertBlockProperty(pos.north(), RedStoneWireBlock.POWER, 15)) + .thenSucceed(); + }); + } + + @GameTest(template = "empty_15x15") + public static void shouldEmitRedstoneEquals(final GameTestHelper helper) { + preparePlot(helper, Direction.DOWN, (detector, pos, sequence) -> { + // Arrange + sequence.thenWaitUntil(networkIsAvailable(helper, pos, network -> { + insert(helper, network, DIRT, 10); + insert(helper, network, STONE, 15); + })); + + // Act + final ItemStack damagedDiamondChestplate = getItemAsDamaged(DIAMOND_CHESTPLATE.getDefaultInstance(), 500); + detector.setConfiguredResource(asResource(DIRT)); + detector.setAmount(9); + + // Assert + sequence + .thenWaitUntil(storageContainsExactly( + helper, + pos, + new ResourceAmount(asResource(DIRT), 10), + new ResourceAmount(asResource(STONE), 15) + )) + .thenWaitUntil(() -> helper.assertBlockProperty(pos.north(), RedStoneWireBlock.POWER, 0)) + .thenExecute(() -> detector.setAmount(10)) + .thenWaitUntil(() -> helper.assertBlockProperty(pos.north(), RedStoneWireBlock.POWER, 15)) + .thenExecute(() -> { + detector.setConfiguredResource(asResource(damagedDiamondChestplate)); + detector.setAmount(1); + }) + .thenWaitUntil(() -> helper.assertBlockProperty(pos.north(), RedStoneWireBlock.POWER, 0)) + .thenExecute(networkIsAvailable(helper, pos, network -> + insert(helper, network, asResource(damagedDiamondChestplate), 1))) + .thenWaitUntil(() -> helper.assertBlockProperty(pos.north(), RedStoneWireBlock.POWER, 15)) + .thenSucceed(); + }); + } + + @GameTest(template = "empty_15x15") + public static void shouldEmitRedstoneAbove(final GameTestHelper helper) { + preparePlot(helper, Direction.DOWN, (detector, pos, sequence) -> { + // Arrange + sequence.thenWaitUntil(networkIsAvailable(helper, pos, network -> { + insert(helper, network, DIRT, 10); + insert(helper, network, STONE, 15); + })); + + // Act + detector.setConfiguredResource(asResource(DIRT)); + detector.setMode(DetectorMode.ABOVE); + detector.setAmount(15); + + // Assert + sequence + .thenWaitUntil(storageContainsExactly( + helper, + pos, + new ResourceAmount(asResource(DIRT), 10), + new ResourceAmount(asResource(STONE), 15) + )) + .thenWaitUntil(() -> helper.assertBlockProperty(pos.north(), RedStoneWireBlock.POWER, 0)) + .thenExecute(() -> detector.setAmount(10)) + .thenWaitUntil(() -> helper.assertBlockProperty(pos.north(), RedStoneWireBlock.POWER, 0)) + .thenExecute(() -> detector.setAmount(5)) + .thenWaitUntil(() -> helper.assertBlockProperty(pos.north(), RedStoneWireBlock.POWER, 15)) + .thenSucceed(); + }); + } + + @GameTest(template = "empty_15x15") + public static void shouldEmitRedstoneFuzzy(final GameTestHelper helper) { + preparePlot(helper, Direction.DOWN, (detector, pos, sequence) -> { + // Arrange + final ItemStack damagedDiamondChestplate = getItemAsDamaged(DIAMOND_CHESTPLATE.getDefaultInstance(), 500); + + sequence.thenWaitUntil(networkIsAvailable(helper, pos, network -> { + insert(helper, network, DIRT, 10); + insert(helper, network, asResource(DIAMOND_CHESTPLATE.getDefaultInstance()), 1); + insert(helper, network, asResource(damagedDiamondChestplate), 1); + })); + + // Act + detector.setFuzzyMode(true); + detector.setConfiguredResource(asResource(DIAMOND_CHESTPLATE.getDefaultInstance())); + detector.setAmount(1); + + // Assert + sequence + .thenWaitUntil(storageContainsExactly( + helper, + pos, + new ResourceAmount(asResource(DIRT), 10), + new ResourceAmount(asResource(DIAMOND_CHESTPLATE.getDefaultInstance()), 1), + new ResourceAmount(asResource(damagedDiamondChestplate), 1) + )) + .thenWaitUntil(() -> helper.assertBlockProperty(pos.north(), RedStoneWireBlock.POWER, 0)) + .thenExecute(() -> detector.setAmount(2)) + .thenWaitUntil(() -> helper.assertBlockProperty(pos.north(), RedStoneWireBlock.POWER, 15)) + .thenSucceed(); + }); + } +} diff --git a/refinedstorage-neoforge/src/test/java/com/refinedmods/refinedstorage/common/detector/DetectorTestPlots.java b/refinedstorage-neoforge/src/test/java/com/refinedmods/refinedstorage/common/detector/DetectorTestPlots.java new file mode 100644 index 000000000..84aa4c0da --- /dev/null +++ b/refinedstorage-neoforge/src/test/java/com/refinedmods/refinedstorage/common/detector/DetectorTestPlots.java @@ -0,0 +1,39 @@ +package com.refinedmods.refinedstorage.common.detector; + +import com.refinedmods.refinedstorage.common.storage.FluidStorageVariant; +import com.refinedmods.refinedstorage.common.storage.ItemStorageVariant; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.gametest.framework.GameTestSequence; +import net.minecraft.world.level.block.Blocks; +import org.apache.commons.lang3.function.TriConsumer; + +import static com.refinedmods.refinedstorage.common.GameTestUtil.RSBLOCKS; +import static com.refinedmods.refinedstorage.common.GameTestUtil.requireBlockEntity; +import static net.minecraft.core.BlockPos.ZERO; + +final class DetectorTestPlots { + private DetectorTestPlots() { + } + + static void preparePlot(final GameTestHelper helper, + final Direction direction, + final TriConsumer consumer) { + helper.setBlock(ZERO.above(), RSBLOCKS.getCreativeController().getDefault()); + helper.setBlock(ZERO.above().above(), RSBLOCKS.getItemStorageBlock(ItemStorageVariant.ONE_K)); + helper.setBlock( + ZERO.above().above().north(), + RSBLOCKS.getFluidStorageBlock(FluidStorageVariant.SIXTY_FOUR_B) + ); + helper.setBlock(ZERO.above().above().above().north(), Blocks.REDSTONE_WIRE); + final BlockPos detectorPos = ZERO.above().above().above(); + helper.setBlock(detectorPos, RSBLOCKS.getDetector().getDefault().rotated(direction)); + consumer.accept( + requireBlockEntity(helper, detectorPos, DetectorBlockEntity.class), + detectorPos, + helper.startSequence() + ); + } +}