From ac9755cc9ccc513363b97ef831f0fdd8d6920b7e Mon Sep 17 00:00:00 2001 From: raoulvdberge Date: Sun, 19 May 2024 16:39:14 +0200 Subject: [PATCH 1/3] refactor: unify storage block and disk drive network nodes --- .../network/test/NetworkTest.java | 5 +- .../MultiStorageNetworkNodeFactory.java | 23 - .../StorageNetworkNodeFactory.java | 11 +- .../network/test/NetworkNodeFactoryTest.java | 9 +- .../test/NetworkTestExtensionTest.java | 6 +- .../multistorage/ExposedMultiStorage.java | 63 -- .../multistorage/MultiStorageNetworkNode.java | 157 ---- .../multistorage/MultiStorageProvider.java | 10 - .../impl/node/multistorage/package-info.java | 7 - .../impl/node/storage/ExposedStorage.java | 72 +- .../impl/node/storage/StorageNetworkNode.java | 130 +++- .../impl/PriorityNetworkBuilderImplTest.java | 5 +- .../MultiStorageNetworkNodeTest.java | 698 ------------------ .../PriorityStorageNetworkNodeTest.java} | 22 +- .../StorageNetworkNodeProviderImpl.java} | 4 +- .../node/storage/StorageNetworkNodeTest.java | 624 +++++++++++----- .../StorageNetworkComponentImplTest.java | 11 +- .../AbstractStorageContainerBlockItem.java | 2 +- ...ockEntity.java => StorageBlockEntity.java} | 4 +- .../storage/StorageContainerItemHelper.java | 4 +- .../common/storage/DiskInventory.java | 4 +- .../StorageContainerItemHelperImpl.java | 8 +- .../AbstractDiskDriveBlockEntity.java | 6 +- .../diskdrive/DiskDriveBlockEntityTicker.java | 4 +- .../AbstractStorageBlockBlockEntity.java | 90 +-- .../FluidStorageBlockBlockEntity.java | 2 +- .../ItemStorageBlockBlockEntity.java | 2 +- .../StorageBlockLootItemFunction.java | 4 +- .../api/storage/StateTrackedStorage.java | 9 +- .../api/storage/StateTrackedStorageTest.java | 4 +- 30 files changed, 700 insertions(+), 1300 deletions(-) delete mode 100644 refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/nodefactory/MultiStorageNetworkNodeFactory.java delete mode 100644 refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/ExposedMultiStorage.java delete mode 100644 refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageNetworkNode.java delete mode 100644 refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageProvider.java delete mode 100644 refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/package-info.java delete mode 100644 refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageNetworkNodeTest.java rename refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/{multistorage/PriorityMultiStorageNetworkNodeTest.java => storage/PriorityStorageNetworkNodeTest.java} (78%) rename refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/{multistorage/MultiStorageProviderImpl.java => storage/StorageNetworkNodeProviderImpl.java} (78%) rename refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/{ItemTransferableStorageBlockEntity.java => StorageBlockEntity.java} (79%) diff --git a/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/NetworkTest.java b/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/NetworkTest.java index 15b6880bb..5bc29c45c 100644 --- a/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/NetworkTest.java +++ b/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/NetworkTest.java @@ -8,7 +8,6 @@ import com.refinedmods.refinedstorage2.api.network.impl.node.grid.GridNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.iface.InterfaceNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.importer.ImporterNetworkNode; -import com.refinedmods.refinedstorage2.api.network.impl.node.multistorage.MultiStorageNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.relay.RelayInputNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.relay.RelayOutputNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.storage.StorageNetworkNode; @@ -19,7 +18,6 @@ import com.refinedmods.refinedstorage2.network.test.nodefactory.GridNetworkNodeFactory; import com.refinedmods.refinedstorage2.network.test.nodefactory.ImporterNetworkNodeFactory; import com.refinedmods.refinedstorage2.network.test.nodefactory.InterfaceNetworkNodeFactory; -import com.refinedmods.refinedstorage2.network.test.nodefactory.MultiStorageNetworkNodeFactory; import com.refinedmods.refinedstorage2.network.test.nodefactory.RelayInputNetworkNodeFactory; import com.refinedmods.refinedstorage2.network.test.nodefactory.RelayOutputNetworkNodeFactory; import com.refinedmods.refinedstorage2.network.test.nodefactory.SimpleNetworkNodeFactory; @@ -36,12 +34,11 @@ @Target(ElementType.TYPE) @ExtendWith(NetworkTestExtension.class) @RegisterNetworkNode(value = ControllerNetworkNodeFactory.class, clazz = ControllerNetworkNode.class) -@RegisterNetworkNode(value = MultiStorageNetworkNodeFactory.class, clazz = MultiStorageNetworkNode.class) +@RegisterNetworkNode(value = StorageNetworkNodeFactory.class, clazz = StorageNetworkNode.class) @RegisterNetworkNode(value = ExporterNetworkNodeFactory.class, clazz = ExporterNetworkNode.class) @RegisterNetworkNode(value = GridNetworkNodeFactory.class, clazz = GridNetworkNode.class) @RegisterNetworkNode(value = ImporterNetworkNodeFactory.class, clazz = ImporterNetworkNode.class) @RegisterNetworkNode(value = SimpleNetworkNodeFactory.class, clazz = SimpleNetworkNode.class) -@RegisterNetworkNode(value = StorageNetworkNodeFactory.class, clazz = StorageNetworkNode.class) @RegisterNetworkNode(value = InterfaceNetworkNodeFactory.class, clazz = InterfaceNetworkNode.class) @RegisterNetworkNode(value = ExternalStorageNetworkNodeFactory.class, clazz = ExternalStorageNetworkNode.class) @RegisterNetworkNode(value = DetectorNetworkNodeFactory.class, clazz = DetectorNetworkNode.class) diff --git a/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/nodefactory/MultiStorageNetworkNodeFactory.java b/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/nodefactory/MultiStorageNetworkNodeFactory.java deleted file mode 100644 index 0e56caffe..000000000 --- a/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/nodefactory/MultiStorageNetworkNodeFactory.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.refinedmods.refinedstorage2.network.test.nodefactory; - -import com.refinedmods.refinedstorage2.api.network.impl.node.AbstractNetworkNode; -import com.refinedmods.refinedstorage2.api.network.impl.node.multistorage.MultiStorageNetworkNode; -import com.refinedmods.refinedstorage2.network.test.AddNetworkNode; - -import java.util.Map; - -public class MultiStorageNetworkNodeFactory extends AbstractNetworkNodeFactory { - public static final String PROPERTY_ENERGY_USAGE_PER_STORAGE = "energy_usage_per_storage"; - public static final String PROPERTY_SIZE = "size"; - - @Override - protected AbstractNetworkNode innerCreate(final AddNetworkNode ctx, final Map properties) { - final long energyUsagePerStorage = (long) properties.getOrDefault(PROPERTY_ENERGY_USAGE_PER_STORAGE, 0L); - final int size = (int) properties.getOrDefault(PROPERTY_SIZE, 9); - return new MultiStorageNetworkNode( - getEnergyUsage(properties), - energyUsagePerStorage, - size - ); - } -} diff --git a/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/nodefactory/StorageNetworkNodeFactory.java b/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/nodefactory/StorageNetworkNodeFactory.java index 9600b77f0..df47e8da8 100644 --- a/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/nodefactory/StorageNetworkNodeFactory.java +++ b/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/nodefactory/StorageNetworkNodeFactory.java @@ -7,8 +7,17 @@ import java.util.Map; public class StorageNetworkNodeFactory extends AbstractNetworkNodeFactory { + public static final String PROPERTY_ENERGY_USAGE_PER_STORAGE = "energy_usage_per_storage"; + public static final String PROPERTY_SIZE = "size"; + @Override protected AbstractNetworkNode innerCreate(final AddNetworkNode ctx, final Map properties) { - return new StorageNetworkNode(getEnergyUsage(properties)); + final long energyUsagePerStorage = (long) properties.getOrDefault(PROPERTY_ENERGY_USAGE_PER_STORAGE, 0L); + final int size = (int) properties.getOrDefault(PROPERTY_SIZE, 9); + return new StorageNetworkNode( + getEnergyUsage(properties), + energyUsagePerStorage, + size + ); } } diff --git a/refinedstorage2-network-test/src/test/java/com/refinedmods/refinedstorage2/network/test/NetworkNodeFactoryTest.java b/refinedstorage2-network-test/src/test/java/com/refinedmods/refinedstorage2/network/test/NetworkNodeFactoryTest.java index baf5f2079..bfe41ac4f 100644 --- a/refinedstorage2-network-test/src/test/java/com/refinedmods/refinedstorage2/network/test/NetworkNodeFactoryTest.java +++ b/refinedstorage2-network-test/src/test/java/com/refinedmods/refinedstorage2/network/test/NetworkNodeFactoryTest.java @@ -8,7 +8,8 @@ import com.refinedmods.refinedstorage2.api.network.impl.node.grid.GridNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.iface.InterfaceNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.importer.ImporterNetworkNode; -import com.refinedmods.refinedstorage2.api.network.impl.node.multistorage.MultiStorageNetworkNode; +import com.refinedmods.refinedstorage2.api.network.impl.node.relay.RelayInputNetworkNode; +import com.refinedmods.refinedstorage2.api.network.impl.node.relay.RelayOutputNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.storage.StorageNetworkNode; import org.junit.jupiter.api.Test; @@ -21,8 +22,6 @@ class NetworkNodeFactoryTest { @AddNetworkNode ControllerNetworkNode controller; @AddNetworkNode - MultiStorageNetworkNode multiStorage; - @AddNetworkNode ExporterNetworkNode exporter; @AddNetworkNode GridNetworkNode grid; @@ -38,6 +37,10 @@ class NetworkNodeFactoryTest { ExternalStorageNetworkNode externalStorage; @AddNetworkNode DetectorNetworkNode detector; + @AddNetworkNode + RelayInputNetworkNode relayInput; + @AddNetworkNode + RelayOutputNetworkNode relayOutput; @Test void testInitialization() { diff --git a/refinedstorage2-network-test/src/test/java/com/refinedmods/refinedstorage2/network/test/NetworkTestExtensionTest.java b/refinedstorage2-network-test/src/test/java/com/refinedmods/refinedstorage2/network/test/NetworkTestExtensionTest.java index f842ed7c8..7f75d9e2d 100644 --- a/refinedstorage2-network-test/src/test/java/com/refinedmods/refinedstorage2/network/test/NetworkTestExtensionTest.java +++ b/refinedstorage2-network-test/src/test/java/com/refinedmods/refinedstorage2/network/test/NetworkTestExtensionTest.java @@ -3,14 +3,12 @@ import com.refinedmods.refinedstorage2.api.network.Network; import com.refinedmods.refinedstorage2.api.network.energy.EnergyNetworkComponent; import com.refinedmods.refinedstorage2.api.network.impl.node.SimpleNetworkNode; -import com.refinedmods.refinedstorage2.api.network.impl.node.multistorage.MultiStorageNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.storage.StorageNetworkNode; import com.refinedmods.refinedstorage2.api.network.node.GraphNetworkComponent; import com.refinedmods.refinedstorage2.api.network.node.container.NetworkNodeContainer; import com.refinedmods.refinedstorage2.api.network.security.SecurityNetworkComponent; import com.refinedmods.refinedstorage2.api.network.storage.StorageNetworkComponent; import com.refinedmods.refinedstorage2.network.test.nodefactory.AbstractNetworkNodeFactory; -import com.refinedmods.refinedstorage2.network.test.nodefactory.MultiStorageNetworkNodeFactory; import com.refinedmods.refinedstorage2.network.test.nodefactory.SimpleNetworkNodeFactory; import com.refinedmods.refinedstorage2.network.test.nodefactory.StorageNetworkNodeFactory; @@ -23,7 +21,7 @@ @ExtendWith({NetworkTestExtension.class}) @SetupNetwork(id = "a", energyCapacity = 100, energyStored = 50) @SetupNetwork(id = "b") -@RegisterNetworkNode(value = MultiStorageNetworkNodeFactory.class, clazz = MultiStorageNetworkNode.class) +@RegisterNetworkNode(value = StorageNetworkNodeFactory.class, clazz = StorageNetworkNode.class) @RegisterNetworkNode(value = StorageNetworkNodeFactory.class, clazz = StorageNetworkNode.class) @RegisterNetworkNode(value = SimpleNetworkNodeFactory.class, clazz = SimpleNetworkNode.class) class NetworkTestExtensionTest { @@ -41,7 +39,7 @@ class NetworkTestExtensionTest { @AddNetworkNode(networkId = "b", properties = { @AddNetworkNode.Property(key = AbstractNetworkNodeFactory.PROPERTY_ACTIVE, boolValue = false) }) - MultiStorageNetworkNode storageInB; + StorageNetworkNode storageInB; @AddNetworkNode(networkId = "nonexistent") SimpleNetworkNode nonexistentNetworkNode; diff --git a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/ExposedMultiStorage.java b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/ExposedMultiStorage.java deleted file mode 100644 index 7823b4dc5..000000000 --- a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/ExposedMultiStorage.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.refinedmods.refinedstorage2.api.network.impl.node.multistorage; - -import com.refinedmods.refinedstorage2.api.network.impl.storage.AbstractImmutableConfiguredProxyStorage; -import com.refinedmods.refinedstorage2.api.network.impl.storage.StorageConfiguration; -import com.refinedmods.refinedstorage2.api.resource.ResourceKey; -import com.refinedmods.refinedstorage2.api.resource.list.ResourceListImpl; -import com.refinedmods.refinedstorage2.api.storage.Actor; -import com.refinedmods.refinedstorage2.api.storage.Storage; -import com.refinedmods.refinedstorage2.api.storage.composite.CompositeStorage; -import com.refinedmods.refinedstorage2.api.storage.composite.CompositeStorageImpl; -import com.refinedmods.refinedstorage2.api.storage.composite.ParentComposite; -import com.refinedmods.refinedstorage2.api.storage.tracked.TrackedResource; - -import java.util.List; -import java.util.Optional; - -class ExposedMultiStorage extends AbstractImmutableConfiguredProxyStorage - implements CompositeStorage { - protected ExposedMultiStorage(final StorageConfiguration config) { - super(config, new CompositeStorageImpl(new ResourceListImpl())); - } - - @Override - public void sortSources() { - // no-op: cannot sort individual storages. - } - - @Override - public void addSource(final Storage source) { - getDelegate().addSource(source); - } - - @Override - public void removeSource(final Storage source) { - getDelegate().removeSource(source); - } - - @Override - public List getSources() { - return getDelegate().getSources(); - } - - @Override - public void clearSources() { - getDelegate().clearSources(); - } - - @Override - public Optional findTrackedResourceByActorType(final ResourceKey resource, - final Class actorType) { - return getDelegate().findTrackedResourceByActorType(resource, actorType); - } - - @Override - public void onAddedIntoComposite(final ParentComposite parentComposite) { - getDelegate().onAddedIntoComposite(parentComposite); - } - - @Override - public void onRemovedFromComposite(final ParentComposite parentComposite) { - getDelegate().onRemovedFromComposite(parentComposite); - } -} diff --git a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageNetworkNode.java b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageNetworkNode.java deleted file mode 100644 index 463778f84..000000000 --- a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageNetworkNode.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.refinedmods.refinedstorage2.api.network.impl.node.multistorage; - -import com.refinedmods.refinedstorage2.api.network.impl.storage.AbstractStorageNetworkNode; -import com.refinedmods.refinedstorage2.api.network.storage.StorageProvider; -import com.refinedmods.refinedstorage2.api.storage.StateTrackedStorage; -import com.refinedmods.refinedstorage2.api.storage.Storage; -import com.refinedmods.refinedstorage2.api.storage.StorageState; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import javax.annotation.Nullable; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MultiStorageNetworkNode extends AbstractStorageNetworkNode implements StorageProvider { - private static final Logger LOGGER = LoggerFactory.getLogger(MultiStorageNetworkNode.class); - - @Nullable - private MultiStorageProvider provider; - @Nullable - private StateTrackedStorage.Listener listener; - - private final long energyUsage; - private final long energyUsagePerStorage; - - private final StateTrackedStorage[] cache; - private final ExposedMultiStorage storage; - private int activeStorages; - - public MultiStorageNetworkNode(final long energyUsage, - final long energyUsagePerStorage, - final int size) { - this.energyUsage = energyUsage; - this.energyUsagePerStorage = energyUsagePerStorage; - this.storage = new ExposedMultiStorage(this); - this.cache = new StateTrackedStorage[size]; - } - - public void setProvider(final MultiStorageProvider provider) { - this.provider = provider; - final List changes = new ArrayList<>(); - for (int i = 0; i < cache.length; ++i) { - changes.addAll(initializeStorage(i)); - } - // If we are already initialized, update all the storages to keep the exposed storages in sync. - // If we are not initialized, update nothing as we have to wait for an activeness update. - if (activeStorages > 0) { - changes.forEach(this::processStorageChange); - } - updateActiveStorageCount(); - } - - public void onStorageChanged(final int index) { - if (index < 0 || index >= cache.length) { - LOGGER.warn("Invalid index {}", index); - return; - } - initializeStorage(index).forEach(this::processStorageChange); - updateActiveStorageCount(); - } - - private Set initializeStorage(final int index) { - final Set results = new HashSet<>(); - - if (cache[index] != null) { - results.add(new StorageChange(true, cache[index])); - } - - if (provider != null) { - provider.resolve(index).ifPresentOrElse(resolved -> { - final StateTrackedStorage newStorage = new StateTrackedStorage(resolved, listener); - cache[index] = newStorage; - results.add(new StorageChange(false, newStorage)); - }, () -> cache[index] = null); - } - - return results; - } - - private void processStorageChange(final StorageChange change) { - if (!isActive()) { - return; - } - if (change.removed) { - storage.removeSource(change.storage); - } else { - storage.addSource(change.storage); - } - } - - private void updateActiveStorageCount() { - this.activeStorages = (int) Arrays.stream(cache).filter(Objects::nonNull).count(); - } - - @Override - protected void onActiveChanged(final boolean newActive) { - super.onActiveChanged(newActive); - if (network == null) { - return; - } - LOGGER.debug("Activeness got changed to {}, updating underlying internal storages", newActive); - if (newActive) { - enableAllStorages(); - } else { - disableAllStorages(); - } - } - - private void enableAllStorages() { - for (final StateTrackedStorage internalStorage : cache) { - if (internalStorage != null) { - storage.addSource(internalStorage); - } - } - } - - private void disableAllStorages() { - storage.clearSources(); - } - - public void setListener(final StateTrackedStorage.Listener listener) { - this.listener = listener; - } - - @Override - public long getEnergyUsage() { - return energyUsage + (energyUsagePerStorage * activeStorages); - } - - public int getSize() { - return cache.length; - } - - public StorageState getState(final int index) { - final var cached = cache[index]; - if (cached == null) { - return StorageState.NONE; - } - if (!isActive()) { - return StorageState.INACTIVE; - } - return cached.getState(); - } - - @Override - public Storage getStorage() { - return storage; - } - - private record StorageChange(boolean removed, StateTrackedStorage storage) { - } -} diff --git a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageProvider.java b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageProvider.java deleted file mode 100644 index 8dd420fa1..000000000 --- a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageProvider.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.refinedmods.refinedstorage2.api.network.impl.node.multistorage; - -import com.refinedmods.refinedstorage2.api.storage.Storage; - -import java.util.Optional; - -@FunctionalInterface -public interface MultiStorageProvider { - Optional resolve(int index); -} diff --git a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/package-info.java b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/package-info.java deleted file mode 100644 index 3e84146e5..000000000 --- a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -@ParametersAreNonnullByDefault -@FieldsAndMethodsAreNonnullByDefault -package com.refinedmods.refinedstorage2.api.network.impl.node.multistorage; - -import com.refinedmods.refinedstorage2.api.core.FieldsAndMethodsAreNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/ExposedStorage.java b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/ExposedStorage.java index c4e7b035b..48a2104f7 100644 --- a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/ExposedStorage.java +++ b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/ExposedStorage.java @@ -1,60 +1,76 @@ package com.refinedmods.refinedstorage2.api.network.impl.node.storage; -import com.refinedmods.refinedstorage2.api.network.impl.storage.AbstractConfiguredProxyStorage; +import com.refinedmods.refinedstorage2.api.network.impl.storage.AbstractImmutableConfiguredProxyStorage; import com.refinedmods.refinedstorage2.api.network.impl.storage.StorageConfiguration; import com.refinedmods.refinedstorage2.api.resource.ResourceKey; +import com.refinedmods.refinedstorage2.api.resource.list.ResourceListImpl; import com.refinedmods.refinedstorage2.api.storage.Actor; import com.refinedmods.refinedstorage2.api.storage.Storage; +import com.refinedmods.refinedstorage2.api.storage.composite.CompositeStorage; +import com.refinedmods.refinedstorage2.api.storage.composite.CompositeStorageImpl; import com.refinedmods.refinedstorage2.api.storage.composite.ParentComposite; import com.refinedmods.refinedstorage2.api.storage.limited.LimitedStorage; import com.refinedmods.refinedstorage2.api.storage.tracked.TrackedResource; -import com.refinedmods.refinedstorage2.api.storage.tracked.TrackedStorage; -import java.util.HashSet; +import java.util.List; import java.util.Optional; -import java.util.Set; -class ExposedStorage extends AbstractConfiguredProxyStorage implements TrackedStorage { - private final Set parents = new HashSet<>(); +class ExposedStorage extends AbstractImmutableConfiguredProxyStorage implements CompositeStorage { + protected ExposedStorage(final StorageConfiguration config) { + super(config, new CompositeStorageImpl(new ResourceListImpl())); + } - ExposedStorage(final StorageConfiguration config) { - super(config); + long getCapacity() { + final CompositeStorageImpl delegate = getUnsafeDelegate(); + if (delegate == null) { + return 0; + } + return delegate.getSources() + .stream() + .filter(LimitedStorage.class::isInstance) + .map(LimitedStorage.class::cast) + .mapToLong(LimitedStorage::getCapacity) + .sum(); } @Override - public Optional findTrackedResourceByActorType(final ResourceKey resource, - final Class actorType) { - return getUnsafeDelegate() instanceof TrackedStorage trackedStorage - ? trackedStorage.findTrackedResourceByActorType(resource, actorType) - : Optional.empty(); + public void sortSources() { + // no-op: cannot sort individual storages. } @Override - public void onAddedIntoComposite(final ParentComposite parentComposite) { - parents.add(parentComposite); + public void addSource(final Storage source) { + getDelegate().addSource(source); } @Override - public void onRemovedFromComposite(final ParentComposite parentComposite) { - parents.remove(parentComposite); + public void removeSource(final Storage source) { + getDelegate().removeSource(source); + } + + @Override + public List getSources() { + return getDelegate().getSources(); } - public long getCapacity() { - return getUnsafeDelegate() instanceof LimitedStorage limitedStorage - ? limitedStorage.getCapacity() - : 0L; + @Override + public void clearSources() { + getDelegate().clearSources(); + } + + @Override + public Optional findTrackedResourceByActorType(final ResourceKey resource, + final Class actorType) { + return getDelegate().findTrackedResourceByActorType(resource, actorType); } @Override - public void setDelegate(final Storage newDelegate) { - super.setDelegate(newDelegate); - parents.forEach(parent -> parent.onSourceAddedToChild(newDelegate)); + public void onAddedIntoComposite(final ParentComposite parentComposite) { + getDelegate().onAddedIntoComposite(parentComposite); } @Override - public void clearDelegate() { - final Storage delegate = getDelegate(); - parents.forEach(parent -> parent.onSourceRemovedFromChild(delegate)); - super.clearDelegate(); + public void onRemovedFromComposite(final ParentComposite parentComposite) { + getDelegate().onRemovedFromComposite(parentComposite); } } diff --git a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNode.java b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNode.java index ca7e2773f..76d71f3b4 100644 --- a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNode.java +++ b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNode.java @@ -2,8 +2,17 @@ import com.refinedmods.refinedstorage2.api.network.impl.storage.AbstractStorageNetworkNode; import com.refinedmods.refinedstorage2.api.network.storage.StorageProvider; +import com.refinedmods.refinedstorage2.api.storage.StateTrackedStorage; import com.refinedmods.refinedstorage2.api.storage.Storage; +import com.refinedmods.refinedstorage2.api.storage.StorageState; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import javax.annotation.Nullable; import org.slf4j.Logger; @@ -12,37 +21,126 @@ public class StorageNetworkNode extends AbstractStorageNetworkNode implements StorageProvider { private static final Logger LOGGER = LoggerFactory.getLogger(StorageNetworkNode.class); - private final long energyUsage; - private final ExposedStorage storage = new ExposedStorage(this); @Nullable - private Storage internalStorage; + private Provider provider; + @Nullable + private StateTrackedStorage.Listener listener; + + private final long energyUsage; + private final long energyUsagePerStorage; + + private final StateTrackedStorage[] cache; + private final ExposedStorage storage; + private int activeStorages; - public StorageNetworkNode(final long energyUsage) { + public StorageNetworkNode(final long energyUsage, final long energyUsagePerStorage, final int size) { this.energyUsage = energyUsage; + this.energyUsagePerStorage = energyUsagePerStorage; + this.storage = new ExposedStorage(this); + this.cache = new StateTrackedStorage[size]; + } + + public void setProvider(final Provider provider) { + this.provider = provider; + final List changes = new ArrayList<>(); + for (int i = 0; i < cache.length; ++i) { + changes.addAll(initializeStorage(i)); + } + // If we are already initialized, update all the storages to keep the exposed storages in sync. + // If we are not initialized, update nothing as we have to wait for an activeness update. + if (activeStorages > 0) { + changes.forEach(this::processStorageChange); + } + updateActiveStorageCount(); + } + + public void onStorageChanged(final int index) { + if (index < 0 || index >= cache.length) { + LOGGER.warn("Invalid index {}", index); + return; + } + initializeStorage(index).forEach(this::processStorageChange); + updateActiveStorageCount(); + } + + private Set initializeStorage(final int index) { + final Set results = new HashSet<>(); + if (cache[index] != null) { + results.add(new StorageChange(true, cache[index])); + } + if (provider != null) { + provider.resolve(index).ifPresentOrElse(resolved -> { + final StateTrackedStorage newStorage = new StateTrackedStorage(resolved, listener); + cache[index] = newStorage; + results.add(new StorageChange(false, newStorage)); + }, () -> cache[index] = null); + } + return results; + } + + private void processStorageChange(final StorageChange change) { + if (!isActive()) { + return; + } + if (change.removed) { + storage.removeSource(change.storage); + } else { + storage.addSource(change.storage); + } } - public void setStorage(final Storage storage) { - LOGGER.debug("Loading storage {}", storage); - this.internalStorage = storage; + private void updateActiveStorageCount() { + this.activeStorages = (int) Arrays.stream(cache).filter(Objects::nonNull).count(); } @Override protected void onActiveChanged(final boolean newActive) { super.onActiveChanged(newActive); - if (network == null || internalStorage == null) { + if (network == null) { return; } - LOGGER.debug("Storage activeness got changed to '{}', updating underlying storage", newActive); + LOGGER.debug("Activeness got changed to {}, updating underlying internal storages", newActive); if (newActive) { - storage.setDelegate(internalStorage); + enableAllStorages(); } else { - storage.clearDelegate(); + disableAllStorages(); + } + } + + private void enableAllStorages() { + for (final StateTrackedStorage internalStorage : cache) { + if (internalStorage != null) { + storage.addSource(internalStorage); + } } } + private void disableAllStorages() { + storage.clearSources(); + } + + public void setListener(final StateTrackedStorage.Listener listener) { + this.listener = listener; + } + @Override public long getEnergyUsage() { - return energyUsage; + return energyUsage + (energyUsagePerStorage * activeStorages); + } + + public int getSize() { + return cache.length; + } + + public StorageState getState(final int index) { + final var cached = cache[index]; + if (cached == null) { + return StorageState.NONE; + } + if (!isActive()) { + return StorageState.INACTIVE; + } + return cached.getState(); } public long getStored() { @@ -57,4 +155,12 @@ public long getCapacity() { public Storage getStorage() { return storage; } + + private record StorageChange(boolean removed, StateTrackedStorage storage) { + } + + @FunctionalInterface + public interface Provider { + Optional resolve(int index); + } } diff --git a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/PriorityNetworkBuilderImplTest.java b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/PriorityNetworkBuilderImplTest.java index b5b5bea44..625e32e7c 100644 --- a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/PriorityNetworkBuilderImplTest.java +++ b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/PriorityNetworkBuilderImplTest.java @@ -13,6 +13,7 @@ import com.refinedmods.refinedstorage2.api.storage.InMemoryStorageImpl; import com.refinedmods.refinedstorage2.network.test.fake.FakeActor; +import java.util.Optional; import java.util.function.Supplier; import org.junit.jupiter.api.Test; @@ -115,10 +116,10 @@ void shouldRespectPriorityWhenMerging() { private NetworkSide createNetworkSide(final MasterSlave side, final Supplier networkFactory) { - final StorageNetworkNode nodeA = new StorageNetworkNode(0); + final StorageNetworkNode nodeA = new StorageNetworkNode(0, 0, 1); final InMemoryStorageImpl storage = new InMemoryStorageImpl(); storage.insert(side, 10, Action.EXECUTE, FakeActor.INSTANCE); - nodeA.setStorage(storage); + nodeA.setProvider(index -> Optional.of(storage)); final NetworkNodeContainer a = createContainerWithNetwork( nodeA, container -> networkFactory.get(), diff --git a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageNetworkNodeTest.java b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageNetworkNodeTest.java deleted file mode 100644 index 3c696ab91..000000000 --- a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageNetworkNodeTest.java +++ /dev/null @@ -1,698 +0,0 @@ -package com.refinedmods.refinedstorage2.api.network.impl.node.multistorage; - -import com.refinedmods.refinedstorage2.api.core.Action; -import com.refinedmods.refinedstorage2.api.network.Network; -import com.refinedmods.refinedstorage2.api.network.storage.StorageNetworkComponent; -import com.refinedmods.refinedstorage2.api.resource.ResourceAmount; -import com.refinedmods.refinedstorage2.api.resource.filter.FilterMode; -import com.refinedmods.refinedstorage2.api.storage.AccessMode; -import com.refinedmods.refinedstorage2.api.storage.EmptyActor; -import com.refinedmods.refinedstorage2.api.storage.InMemoryStorageImpl; -import com.refinedmods.refinedstorage2.api.storage.StateTrackedStorage; -import com.refinedmods.refinedstorage2.api.storage.Storage; -import com.refinedmods.refinedstorage2.api.storage.StorageState; -import com.refinedmods.refinedstorage2.api.storage.limited.LimitedStorageImpl; -import com.refinedmods.refinedstorage2.api.storage.tracked.TrackedStorageImpl; -import com.refinedmods.refinedstorage2.network.test.AddNetworkNode; -import com.refinedmods.refinedstorage2.network.test.InjectNetwork; -import com.refinedmods.refinedstorage2.network.test.InjectNetworkStorageComponent; -import com.refinedmods.refinedstorage2.network.test.NetworkTest; -import com.refinedmods.refinedstorage2.network.test.SetupNetwork; -import com.refinedmods.refinedstorage2.network.test.fake.FakeActor; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.EnumSource; -import org.junit.jupiter.params.provider.ValueSource; - -import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.A; -import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.A_ALTERNATIVE; -import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.A_ALTERNATIVE2; -import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.B; -import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.B_ALTERNATIVE; -import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.C; -import static com.refinedmods.refinedstorage2.network.test.nodefactory.AbstractNetworkNodeFactory.PROPERTY_ENERGY_USAGE; -import static com.refinedmods.refinedstorage2.network.test.nodefactory.MultiStorageNetworkNodeFactory.PROPERTY_ENERGY_USAGE_PER_STORAGE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -@NetworkTest -@SetupNetwork -class MultiStorageNetworkNodeTest { - private static final long BASE_USAGE = 10; - private static final long USAGE_PER_STORAGE = 3; - - @AddNetworkNode(properties = { - @AddNetworkNode.Property(key = PROPERTY_ENERGY_USAGE, longValue = BASE_USAGE), - @AddNetworkNode.Property(key = PROPERTY_ENERGY_USAGE_PER_STORAGE, longValue = USAGE_PER_STORAGE) - }) - MultiStorageNetworkNode sut; - - MultiStorageProviderImpl provider; - - @BeforeEach - void setUp() { - provider = new MultiStorageProviderImpl(); - } - - @Test - void shouldInitializeButNotShowResourcesYet( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - final Storage storage = new LimitedStorageImpl(10); - storage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(1, storage); - - // Act - sut.setProvider(provider); - - // Assert - assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE + USAGE_PER_STORAGE); - assertThat(networkStorage.getAll()).isEmpty(); - assertThat(networkStorage.getStored()).isZero(); - } - - @Test - void shouldInitializeAndShowResourcesAfterEnabling( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - final Storage storage = new LimitedStorageImpl(100); - storage.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); - storage.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(1, storage); - - // Act - sut.setProvider(provider); - sut.setActive(true); - - // Assert - assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( - new ResourceAmount(A, 50), - new ResourceAmount(B, 50) - ); - } - - @Test - void shouldInitializeMultipleTimes( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - final Storage storage1 = new LimitedStorageImpl(10); - storage1.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(8, storage1); - sut.setProvider(provider); - sut.setActive(true); - - final Storage storage2 = new LimitedStorageImpl(10); - storage2.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(8, storage2); - - // Act - sut.setProvider(provider); - - // Assert - assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE + USAGE_PER_STORAGE); - assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(B, 5) - ); - } - - @Test - void testInitialState(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { - // Assert - assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE); - assertThat(sut.getFilterMode()).isEqualTo(FilterMode.BLOCK); - assertThat(networkStorage.getAll()).isEmpty(); - assertThat(networkStorage.getStored()).isZero(); - assertThat(sut.getSize()).isEqualTo(9); - for (int i = 0; i < 9; ++i) { - assertThat(sut.getState(i)).isEqualTo(StorageState.NONE); - } - } - - @ParameterizedTest - @ValueSource(booleans = {true, false}) - void testState(final boolean active) { - // Arrange - final Storage normalStorage = new LimitedStorageImpl(100); - normalStorage.insert(A, 74, Action.EXECUTE, EmptyActor.INSTANCE); - - final Storage nearCapacityStorage = new LimitedStorageImpl(100); - nearCapacityStorage.insert(A, 75, Action.EXECUTE, EmptyActor.INSTANCE); - - final Storage fullStorage = new LimitedStorageImpl(100); - fullStorage.insert(A, 100, Action.EXECUTE, EmptyActor.INSTANCE); - - final Storage unlimitedStorage = new InMemoryStorageImpl(); - - provider.set(2, unlimitedStorage); - provider.set(3, normalStorage); - provider.set(5, nearCapacityStorage); - provider.set(7, fullStorage); - - // Act - sut.setProvider(provider); - sut.setActive(active); - - // Assert - assertThat(sut.getState(0)).isEqualTo(StorageState.NONE); - assertThat(sut.getState(1)).isEqualTo(StorageState.NONE); - assertThat(sut.getState(2)).isEqualTo(active ? StorageState.NORMAL : StorageState.INACTIVE); - assertThat(sut.getState(3)).isEqualTo(active ? StorageState.NORMAL : StorageState.INACTIVE); - assertThat(sut.getState(4)).isEqualTo(StorageState.NONE); - assertThat(sut.getState(5)).isEqualTo(active ? StorageState.NEAR_CAPACITY : StorageState.INACTIVE); - assertThat(sut.getState(6)).isEqualTo(StorageState.NONE); - assertThat(sut.getState(7)).isEqualTo(active ? StorageState.FULL : StorageState.INACTIVE); - assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE + (USAGE_PER_STORAGE * 4)); - } - - @Test - void shouldDetectNewStorage(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { - // Arrange - initializeAndActivate(); - - final Storage storage = new LimitedStorageImpl(10); - storage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(8, storage); - - // Act - sut.onStorageChanged(8); - - // Assert - assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE + USAGE_PER_STORAGE); - assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(A, 5) - ); - } - - @Test - void shouldDetectChangedStorage(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { - // Arrange - final Storage originalStorage = new LimitedStorageImpl(10); - originalStorage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(0, originalStorage); - initializeAndActivate(); - - final Storage replacedStorage = new LimitedStorageImpl(10); - replacedStorage.insert(B, 2, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(0, replacedStorage); - - // Act - final Collection preChanging = new HashSet<>(networkStorage.getAll()); - sut.onStorageChanged(0); - final Collection postChanging = networkStorage.getAll(); - - // Assert - assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE + USAGE_PER_STORAGE); - assertThat(preChanging).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(A, 5) - ); - assertThat(postChanging).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(B, 2) - ); - assertThat(networkStorage.getStored()).isEqualTo(2L); - } - - @Test - void shouldDetectRemovedStorage(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { - // Arrange - final Storage storage = new LimitedStorageImpl(10); - storage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(7, storage); - initializeAndActivate(); - - provider.remove(7); - - // Act - final Collection preRemoval = new HashSet<>(networkStorage.getAll()); - sut.onStorageChanged(7); - final Collection postRemoval = networkStorage.getAll(); - - // Assert - assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE); - assertThat(preRemoval).isNotEmpty(); - assertThat(postRemoval).isEmpty(); - assertThat(networkStorage.getStored()).isZero(); - } - - @Test - void shouldNotDetectStorageChangeInInvalidIndex() { - // Act - sut.onStorageChanged(-1); - sut.onStorageChanged(9); - - // Assert - assertThat(sut.getSize()).isEqualTo(9); - for (int i = 0; i < 9; ++i) { - assertThat(sut.getState(i)).isEqualTo(StorageState.NONE); - } - } - - @Test - void shouldNotUpdateNetworkStorageWhenChangingStorageWhenInactive( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - final Storage storage = new LimitedStorageImpl(100); - storage.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); - storage.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(1, storage); - initializeAndActivate(); - - // Act - final Collection preInactiveness = new HashSet<>(networkStorage.getAll()); - sut.setActive(false); - sut.onStorageChanged(1); - final Collection postInactiveness = networkStorage.getAll(); - - // Assert - assertThat(preInactiveness).isNotEmpty(); - assertThat(postInactiveness).isEmpty(); - assertThat(networkStorage.getStored()).isZero(); - } - - @Test - void shouldHaveResourcesFromStoragePresentInNetwork( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - final Storage storage = new LimitedStorageImpl(100); - storage.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); - storage.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(1, storage); - - initializeAndActivate(); - - // Act - final Collection resources = networkStorage.getAll(); - final long stored = networkStorage.getStored(); - - // Assert - assertThat(resources).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( - new ResourceAmount(A, 50), - new ResourceAmount(B, 50) - ); - assertThat(stored).isEqualTo(100); - } - - @Test - void shouldInsert(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { - // Arrange - final Storage storage1 = new LimitedStorageImpl(100); - provider.set(1, storage1); - - final Storage storage2 = new LimitedStorageImpl(100); - provider.set(2, storage2); - - final Storage storage3 = new LimitedStorageImpl(100); - provider.set(3, storage3); - - initializeAndActivate(); - - // Act - final long inserted1 = networkStorage.insert(A, 150, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted2 = networkStorage.insert(A, 10, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted3 = networkStorage.insert(B, 300, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - assertThat(inserted1).isEqualTo(150); - assertThat(inserted2).isEqualTo(10); - assertThat(inserted3).isEqualTo(140); - - assertThat(storage1.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(A, 100) - ); - assertThat(storage2.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( - new ResourceAmount(A, 60), - new ResourceAmount(B, 40) - ); - assertThat(storage3.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(B, 100) - ); - - assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( - new ResourceAmount(B, 140), - new ResourceAmount(A, 160) - ); - assertThat(networkStorage.getStored()).isEqualTo(inserted1 + inserted2 + inserted3); - } - - @Test - void shouldExtract(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { - // Arrange - final Storage storage1 = new LimitedStorageImpl(100); - storage1.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); - storage1.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(1, storage1); - - final Storage storage2 = new LimitedStorageImpl(100); - storage2.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); - storage2.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(2, storage2); - - final Storage storage3 = new LimitedStorageImpl(100); - storage3.insert(C, 10, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(3, storage3); - - initializeAndActivate(); - - // Act - final long extracted = networkStorage.extract(A, 85, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - assertThat(extracted).isEqualTo(85); - - assertThat(storage1.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(B, 50) - ); - assertThat(storage2.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( - new ResourceAmount(B, 50), - new ResourceAmount(A, 15) - ); - assertThat(storage3.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(C, 10) - ); - - assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( - new ResourceAmount(B, 100), - new ResourceAmount(A, 15), - new ResourceAmount(C, 10) - ); - assertThat(networkStorage.getStored()).isEqualTo(125); - } - - @Test - void shouldRespectAllowlistWhenInserting( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - sut.setFilterMode(FilterMode.ALLOW); - sut.setFilters(Set.of(A, B)); - - final Storage storage = new LimitedStorageImpl(100); - provider.set(1, storage); - initializeAndActivate(); - - // Act - final long inserted1 = networkStorage.insert(A, 12, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted2 = networkStorage.insert(B, 12, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted3 = networkStorage.insert(C, 10, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - assertThat(inserted1).isEqualTo(12); - assertThat(inserted2).isEqualTo(12); - assertThat(inserted3).isZero(); - } - - @Test - void shouldRespectAllowlistWithNormalizerWhenInserting( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - sut.setFilterMode(FilterMode.ALLOW); - sut.setFilters(Set.of(A)); - sut.setNormalizer(resource -> { - if (resource == A_ALTERNATIVE || resource == A_ALTERNATIVE2) { - return A; - } - if (resource == B_ALTERNATIVE) { - return B; - } - return resource; - }); - - final Storage storage = new LimitedStorageImpl(100); - provider.set(1, storage); - initializeAndActivate(); - - // Act - final long inserted1 = networkStorage.insert(A, 1, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted2 = networkStorage.insert(A_ALTERNATIVE, 1, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted3 = networkStorage.insert(A_ALTERNATIVE2, 1, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted4 = networkStorage.insert(B, 1, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted5 = networkStorage.insert(B_ALTERNATIVE, 1, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - assertThat(inserted1).isEqualTo(1); - assertThat(inserted2).isEqualTo(1); - assertThat(inserted3).isEqualTo(1); - assertThat(inserted4).isZero(); - assertThat(inserted5).isZero(); - } - - @Test - void shouldRespectEmptyAllowlistWhenInserting( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - sut.setFilterMode(FilterMode.ALLOW); - sut.setFilters(Set.of()); - - final Storage storage = new LimitedStorageImpl(100); - provider.set(1, storage); - initializeAndActivate(); - - // Act - final long inserted1 = networkStorage.insert(A, 12, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted2 = networkStorage.insert(B, 12, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted3 = networkStorage.insert(C, 10, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - assertThat(inserted1).isZero(); - assertThat(inserted2).isZero(); - assertThat(inserted3).isZero(); - } - - @Test - void shouldRespectBlocklistWhenInserting( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - sut.setFilterMode(FilterMode.BLOCK); - sut.setFilters(Set.of(A, B)); - - final Storage storage = new LimitedStorageImpl(100); - provider.set(1, storage); - initializeAndActivate(); - - // Act - final long inserted1 = networkStorage.insert(A, 12, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted2 = networkStorage.insert(B, 12, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted3 = networkStorage.insert(C, 10, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - assertThat(inserted1).isZero(); - assertThat(inserted2).isZero(); - assertThat(inserted3).isEqualTo(10); - } - - @Test - void shouldRespectEmptyBlocklistWhenInserting( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - sut.setFilterMode(FilterMode.BLOCK); - sut.setFilters(Set.of()); - - final Storage storage = new LimitedStorageImpl(100); - provider.set(1, storage); - initializeAndActivate(); - - // Act - final long inserted1 = networkStorage.insert(A, 12, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted2 = networkStorage.insert(B, 12, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted3 = networkStorage.insert(C, 10, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - assertThat(inserted1).isEqualTo(12); - assertThat(inserted2).isEqualTo(12); - assertThat(inserted3).isEqualTo(10); - } - - @ParameterizedTest - @EnumSource(AccessMode.class) - void shouldRespectAccessModeWhenInserting( - final AccessMode accessMode, - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - sut.setAccessMode(accessMode); - - final Storage storage = new LimitedStorageImpl(100); - provider.set(1, storage); - initializeAndActivate(); - - // Act - final long inserted = networkStorage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - switch (accessMode) { - case INSERT_EXTRACT, INSERT -> assertThat(inserted).isEqualTo(5); - case EXTRACT -> assertThat(inserted).isZero(); - } - } - - @ParameterizedTest - @EnumSource(AccessMode.class) - void shouldRespectAccessModeWhenExtracting( - final AccessMode accessMode, - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - sut.setAccessMode(accessMode); - - final Storage storage = new LimitedStorageImpl(100); - provider.set(1, storage); - initializeAndActivate(); - - storage.insert(A, 20, Action.EXECUTE, EmptyActor.INSTANCE); - - // Act - final long extracted = networkStorage.extract(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - switch (accessMode) { - case INSERT_EXTRACT, EXTRACT -> assertThat(extracted).isEqualTo(5); - case INSERT -> assertThat(extracted).isZero(); - } - } - - @Test - void shouldNotAllowInsertsWhenInactive( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - final Storage storage = new LimitedStorageImpl(100); - provider.set(1, storage); - initializeAndActivate(); - - sut.setActive(false); - - // Act - final long inserted = networkStorage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - assertThat(inserted).isZero(); - } - - @Test - void shouldNotAllowExtractsWhenInactive( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - final Storage storage = new LimitedStorageImpl(100); - storage.insert(A, 20, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(1, storage); - initializeAndActivate(); - - sut.setActive(false); - - // Act - final long extracted = networkStorage.extract(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - assertThat(extracted).isZero(); - } - - @Test - void shouldHideFromNetworkWhenInactive( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - final Storage storage = new LimitedStorageImpl(100); - storage.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); - storage.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(1, storage); - initializeAndActivate(); - - // Act - final Collection preInactiveness = new HashSet<>(networkStorage.getAll()); - sut.setActive(false); - final Collection postInactiveness = networkStorage.getAll(); - - // Assert - assertThat(preInactiveness).isNotEmpty(); - assertThat(postInactiveness).isEmpty(); - } - - @Test - void shouldNoLongerShowOnNetworkWhenRemoved( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage, - @InjectNetwork final Network network - ) { - // Arrange - final Storage storage1 = new LimitedStorageImpl(100); - storage1.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(1, storage1); - initializeAndActivate(); - - // Act & assert - final Storage storage2 = new LimitedStorageImpl(100); - storage2.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(2, storage2); - sut.onStorageChanged(2); - - assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( - new ResourceAmount(A, 50), - new ResourceAmount(B, 50) - ); - - network.removeContainer(() -> sut); - assertThat(networkStorage.getAll()).isEmpty(); - - final Storage storage3 = new LimitedStorageImpl(100); - storage3.insert(C, 50, Action.EXECUTE, EmptyActor.INSTANCE); - provider.set(3, storage3); - sut.onStorageChanged(3); - - assertThat(networkStorage.getAll()).isEmpty(); - } - - @Test - void shouldTrackChanges(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { - // Arrange - final Storage storage = new TrackedStorageImpl(new LimitedStorageImpl(100), () -> 0L); - provider.set(1, storage); - initializeAndActivate(); - - // Act - final long inserted = networkStorage.insert(A, 10, Action.EXECUTE, FakeActor.INSTANCE); - - // Assert - assertThat(inserted).isEqualTo(10); - assertThat(networkStorage.findTrackedResourceByActorType(A, FakeActor.class)).isNotEmpty(); - } - - @Test - void shouldNotifyListenerWhenStateChanges( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - final StateTrackedStorage.Listener listener = mock(StateTrackedStorage.Listener.class); - sut.setListener(listener); - - final Storage storage = new LimitedStorageImpl(100); - provider.set(1, storage); - initializeAndActivate(); - - // Act - networkStorage.insert(A, 75, Action.EXECUTE, FakeActor.INSTANCE); - - // Assert - verify(listener, times(1)).onStorageStateChanged(); - } - - private void initializeAndActivate() { - sut.setProvider(provider); - sut.setActive(true); - } -} diff --git a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/PriorityMultiStorageNetworkNodeTest.java b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/PriorityStorageNetworkNodeTest.java similarity index 78% rename from refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/PriorityMultiStorageNetworkNodeTest.java rename to refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/PriorityStorageNetworkNodeTest.java index baf6d15f1..b5b7fa837 100644 --- a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/PriorityMultiStorageNetworkNodeTest.java +++ b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/PriorityStorageNetworkNodeTest.java @@ -1,4 +1,4 @@ -package com.refinedmods.refinedstorage2.api.network.impl.node.multistorage; +package com.refinedmods.refinedstorage2.api.network.impl.node.storage; import com.refinedmods.refinedstorage2.api.core.Action; import com.refinedmods.refinedstorage2.api.network.storage.StorageNetworkComponent; @@ -19,40 +19,40 @@ @NetworkTest @SetupNetwork -class PriorityMultiStorageNetworkNodeTest { +class PriorityStorageNetworkNodeTest { @AddNetworkNode - MultiStorageNetworkNode a; + StorageNetworkNode a; @AddNetworkNode - MultiStorageNetworkNode b; + StorageNetworkNode b; - MultiStorageProviderImpl provider; + StorageNetworkNodeProviderImpl provider; @BeforeEach void setUp() { - provider = new MultiStorageProviderImpl(); + provider = new StorageNetworkNodeProviderImpl(); } @ParameterizedTest @ValueSource(booleans = {true, false}) void shouldRespectPriority( - final boolean multiStorageAHasPriority, + final boolean storageAHasPriority, @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage ) { // Arrange final Storage storage1 = new LimitedStorageImpl(100); - final MultiStorageProviderImpl provider1 = new MultiStorageProviderImpl(); + final StorageNetworkNodeProviderImpl provider1 = new StorageNetworkNodeProviderImpl(); provider1.set(1, storage1); a.setProvider(provider1); a.setActive(true); final Storage storage2 = new LimitedStorageImpl(100); - final MultiStorageProviderImpl provider2 = new MultiStorageProviderImpl(); + final StorageNetworkNodeProviderImpl provider2 = new StorageNetworkNodeProviderImpl(); provider2.set(1, storage2); b.setProvider(provider2); b.setActive(true); - if (multiStorageAHasPriority) { + if (storageAHasPriority) { a.setPriority(5); b.setPriority(2); } else { @@ -64,7 +64,7 @@ void shouldRespectPriority( networkStorage.insert(A, 1, Action.EXECUTE, EmptyActor.INSTANCE); // Assert - if (multiStorageAHasPriority) { + if (storageAHasPriority) { assertThat(storage1.getAll()).isNotEmpty(); assertThat(storage2.getAll()).isEmpty(); } else { diff --git a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageProviderImpl.java b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeProviderImpl.java similarity index 78% rename from refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageProviderImpl.java rename to refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeProviderImpl.java index 09df89765..8034a5f5b 100644 --- a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/multistorage/MultiStorageProviderImpl.java +++ b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeProviderImpl.java @@ -1,4 +1,4 @@ -package com.refinedmods.refinedstorage2.api.network.impl.node.multistorage; +package com.refinedmods.refinedstorage2.api.network.impl.node.storage; import com.refinedmods.refinedstorage2.api.storage.Storage; @@ -6,7 +6,7 @@ import java.util.Map; import java.util.Optional; -class MultiStorageProviderImpl implements MultiStorageProvider { +class StorageNetworkNodeProviderImpl implements StorageNetworkNode.Provider { private final Map storages = new HashMap<>(); @Override diff --git a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeTest.java b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeTest.java index bb04a9e36..74241524f 100644 --- a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeTest.java +++ b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeTest.java @@ -1,133 +1,406 @@ package com.refinedmods.refinedstorage2.api.network.impl.node.storage; import com.refinedmods.refinedstorage2.api.core.Action; +import com.refinedmods.refinedstorage2.api.network.Network; import com.refinedmods.refinedstorage2.api.network.storage.StorageNetworkComponent; import com.refinedmods.refinedstorage2.api.resource.ResourceAmount; import com.refinedmods.refinedstorage2.api.resource.filter.FilterMode; import com.refinedmods.refinedstorage2.api.storage.AccessMode; import com.refinedmods.refinedstorage2.api.storage.EmptyActor; +import com.refinedmods.refinedstorage2.api.storage.InMemoryStorageImpl; +import com.refinedmods.refinedstorage2.api.storage.StateTrackedStorage; import com.refinedmods.refinedstorage2.api.storage.Storage; -import com.refinedmods.refinedstorage2.api.storage.limited.LimitedStorage; +import com.refinedmods.refinedstorage2.api.storage.StorageState; import com.refinedmods.refinedstorage2.api.storage.limited.LimitedStorageImpl; import com.refinedmods.refinedstorage2.api.storage.tracked.TrackedStorageImpl; import com.refinedmods.refinedstorage2.network.test.AddNetworkNode; +import com.refinedmods.refinedstorage2.network.test.InjectNetwork; import com.refinedmods.refinedstorage2.network.test.InjectNetworkStorageComponent; import com.refinedmods.refinedstorage2.network.test.NetworkTest; import com.refinedmods.refinedstorage2.network.test.SetupNetwork; import com.refinedmods.refinedstorage2.network.test.fake.FakeActor; import java.util.Collection; +import java.util.HashSet; import java.util.Set; -import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.ValueSource; import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.A; +import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.A_ALTERNATIVE; +import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.A_ALTERNATIVE2; import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.B; +import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.B_ALTERNATIVE; import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.C; import static com.refinedmods.refinedstorage2.network.test.nodefactory.AbstractNetworkNodeFactory.PROPERTY_ENERGY_USAGE; +import static com.refinedmods.refinedstorage2.network.test.nodefactory.StorageNetworkNodeFactory.PROPERTY_ENERGY_USAGE_PER_STORAGE; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; @NetworkTest @SetupNetwork class StorageNetworkNodeTest { - private static final int ENERGY_USAGE = 5; + private static final long BASE_USAGE = 10; + private static final long USAGE_PER_STORAGE = 3; @AddNetworkNode(properties = { - @AddNetworkNode.Property(key = PROPERTY_ENERGY_USAGE, longValue = ENERGY_USAGE) + @AddNetworkNode.Property(key = PROPERTY_ENERGY_USAGE, longValue = BASE_USAGE), + @AddNetworkNode.Property(key = PROPERTY_ENERGY_USAGE_PER_STORAGE, longValue = USAGE_PER_STORAGE) }) StorageNetworkNode sut; + StorageNetworkNodeProviderImpl provider; + + @BeforeEach + void setUp() { + provider = new StorageNetworkNodeProviderImpl(); + } + @Test - void testInitialState(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + void shouldInitializeButNotShowResourcesYet( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + final Storage storage = new LimitedStorageImpl(10); + storage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(1, storage); + // Act - final long inserted = networkStorage.insert(A, 10, Action.EXECUTE, EmptyActor.INSTANCE); - final long extracted = networkStorage.extract(A, 10, Action.EXECUTE, EmptyActor.INSTANCE); + sut.setProvider(provider); // Assert - assertThat(inserted).isZero(); - assertThat(extracted).isZero(); - assertThat(sut.getEnergyUsage()).isEqualTo(ENERGY_USAGE); - assertThat(sut.getAccessMode()).isEqualTo(AccessMode.INSERT_EXTRACT); + assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE + USAGE_PER_STORAGE); + assertThat(networkStorage.getAll()).isEmpty(); + assertThat(networkStorage.getStored()).isZero(); + } + + @Test + void shouldInitializeAndShowResourcesAfterEnabling( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + final Storage storage = new LimitedStorageImpl(100); + storage.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); + storage.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(1, storage); + + // Act + sut.setProvider(provider); + sut.setActive(true); + + // Assert + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 50), + new ResourceAmount(B, 50) + ); + } + + @Test + void shouldInitializeMultipleTimes( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + final Storage storage1 = new LimitedStorageImpl(10); + storage1.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(8, storage1); + sut.setProvider(provider); + sut.setActive(true); + + final Storage storage2 = new LimitedStorageImpl(10); + storage2.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(8, storage2); + + // Act + sut.setProvider(provider); + + // Assert + assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE + USAGE_PER_STORAGE); + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(B, 5) + ); + } + + @Test + void testInitialState(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + // Assert + assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE); assertThat(sut.getFilterMode()).isEqualTo(FilterMode.BLOCK); - assertThat(sut.getStored()).isZero(); - assertThat(sut.getCapacity()).isZero(); - assertThat(sut.getPriority()).isZero(); assertThat(networkStorage.getAll()).isEmpty(); assertThat(networkStorage.getStored()).isZero(); + assertThat(sut.getSize()).isEqualTo(9); + for (int i = 0; i < 9; ++i) { + assertThat(sut.getState(i)).isEqualTo(StorageState.NONE); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testState(final boolean active) { + // Arrange + final Storage normalStorage = new LimitedStorageImpl(100); + normalStorage.insert(A, 74, Action.EXECUTE, EmptyActor.INSTANCE); + + final Storage nearCapacityStorage = new LimitedStorageImpl(100); + nearCapacityStorage.insert(A, 75, Action.EXECUTE, EmptyActor.INSTANCE); + + final Storage fullStorage = new LimitedStorageImpl(100); + fullStorage.insert(A, 100, Action.EXECUTE, EmptyActor.INSTANCE); + + final Storage unlimitedStorage = new InMemoryStorageImpl(); + + provider.set(2, unlimitedStorage); + provider.set(3, normalStorage); + provider.set(5, nearCapacityStorage); + provider.set(7, fullStorage); + + // Act + sut.setProvider(provider); + sut.setActive(active); + + // Assert + assertThat(sut.getState(0)).isEqualTo(StorageState.NONE); + assertThat(sut.getState(1)).isEqualTo(StorageState.NONE); + assertThat(sut.getState(2)).isEqualTo(active ? StorageState.NORMAL : StorageState.INACTIVE); + assertThat(sut.getState(3)).isEqualTo(active ? StorageState.NORMAL : StorageState.INACTIVE); + assertThat(sut.getState(4)).isEqualTo(StorageState.NONE); + assertThat(sut.getState(5)).isEqualTo(active ? StorageState.NEAR_CAPACITY : StorageState.INACTIVE); + assertThat(sut.getState(6)).isEqualTo(StorageState.NONE); + assertThat(sut.getState(7)).isEqualTo(active ? StorageState.FULL : StorageState.INACTIVE); + assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE + (USAGE_PER_STORAGE * 4)); } @Test - void shouldInitialize(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + void shouldDetectNewStorage(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { // Arrange - final LimitedStorage limitedStorage = new LimitedStorageImpl(100); - limitedStorage.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); + initializeAndActivate(); + + final Storage storage = new LimitedStorageImpl(10); + storage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(8, storage); // Act - activateStorage(limitedStorage); + sut.onStorageChanged(8); // Assert - assertThat(sut.getStored()).isEqualTo(50L); - assertThat(sut.getCapacity()).isEqualTo(100L); + assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE + USAGE_PER_STORAGE); assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(A, 50L) + new ResourceAmount(A, 5) ); } @Test - void shouldInsert(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + void shouldDetectChangedStorage(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + // Arrange + final Storage originalStorage = new LimitedStorageImpl(10); + originalStorage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(0, originalStorage); + initializeAndActivate(); + + final Storage replacedStorage = new LimitedStorageImpl(10); + replacedStorage.insert(B, 2, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(0, replacedStorage); + + // Act + final Collection preChanging = new HashSet<>(networkStorage.getAll()); + sut.onStorageChanged(0); + final Collection postChanging = networkStorage.getAll(); + + // Assert + assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE + USAGE_PER_STORAGE); + assertThat(preChanging).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(A, 5) + ); + assertThat(postChanging).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(B, 2) + ); + assertThat(networkStorage.getStored()).isEqualTo(2L); + } + + @Test + void shouldDetectRemovedStorage(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + // Arrange + final Storage storage = new LimitedStorageImpl(10); + storage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(7, storage); + initializeAndActivate(); + + provider.remove(7); + + // Act + final Collection preRemoval = new HashSet<>(networkStorage.getAll()); + sut.onStorageChanged(7); + final Collection postRemoval = networkStorage.getAll(); + + // Assert + assertThat(sut.getEnergyUsage()).isEqualTo(BASE_USAGE); + assertThat(preRemoval).isNotEmpty(); + assertThat(postRemoval).isEmpty(); + assertThat(networkStorage.getStored()).isZero(); + } + + @Test + void shouldNotDetectStorageChangeInInvalidIndex() { + // Act + sut.onStorageChanged(-1); + sut.onStorageChanged(9); + + // Assert + assertThat(sut.getSize()).isEqualTo(9); + for (int i = 0; i < 9; ++i) { + assertThat(sut.getState(i)).isEqualTo(StorageState.NONE); + } + } + + @Test + void shouldNotUpdateNetworkStorageWhenChangingStorageWhenInactive( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { // Arrange final Storage storage = new LimitedStorageImpl(100); - activateStorage(storage); + storage.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); + storage.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(1, storage); + initializeAndActivate(); // Act - final long inserted = networkStorage.insert(A, 100, Action.EXECUTE, EmptyActor.INSTANCE); + final Collection preInactiveness = new HashSet<>(networkStorage.getAll()); + sut.setActive(false); + sut.onStorageChanged(1); + final Collection postInactiveness = networkStorage.getAll(); // Assert - assertThat(inserted).isEqualTo(100); - assertThat(storage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(A, 100) + assertThat(preInactiveness).isNotEmpty(); + assertThat(postInactiveness).isEmpty(); + assertThat(networkStorage.getStored()).isZero(); + } + + @Test + void shouldHaveResourcesFromStoragePresentInNetwork( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + final Storage storage = new LimitedStorageImpl(100); + storage.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); + storage.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(1, storage); + + initializeAndActivate(); + + // Act + final Collection resources = networkStorage.getAll(); + final long stored = networkStorage.getStored(); + + // Assert + assertThat(resources).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 50), + new ResourceAmount(B, 50) ); - assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + assertThat(stored).isEqualTo(100); + } + + @Test + void shouldInsert(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + // Arrange + final Storage storage1 = new LimitedStorageImpl(100); + provider.set(1, storage1); + + final Storage storage2 = new LimitedStorageImpl(100); + provider.set(2, storage2); + + final Storage storage3 = new LimitedStorageImpl(100); + provider.set(3, storage3); + + initializeAndActivate(); + + // Act + final long inserted1 = networkStorage.insert(A, 150, Action.EXECUTE, EmptyActor.INSTANCE); + final long inserted2 = networkStorage.insert(A, 10, Action.EXECUTE, EmptyActor.INSTANCE); + final long inserted3 = networkStorage.insert(B, 300, Action.EXECUTE, EmptyActor.INSTANCE); + + // Assert + assertThat(inserted1).isEqualTo(150); + assertThat(inserted2).isEqualTo(10); + assertThat(inserted3).isEqualTo(140); + + assertThat(storage1.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( new ResourceAmount(A, 100) ); + assertThat(storage2.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 60), + new ResourceAmount(B, 40) + ); + assertThat(storage3.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(B, 100) + ); + + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(B, 140), + new ResourceAmount(A, 160) + ); + assertThat(networkStorage.getStored()).isEqualTo(inserted1 + inserted2 + inserted3); } @Test void shouldExtract(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { // Arrange - final Storage storage = new LimitedStorageImpl(200); - storage.insert(A, 100, Action.EXECUTE, EmptyActor.INSTANCE); - storage.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); - activateStorage(storage); + final Storage storage1 = new LimitedStorageImpl(100); + storage1.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); + storage1.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(1, storage1); + + final Storage storage2 = new LimitedStorageImpl(100); + storage2.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); + storage2.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(2, storage2); + + final Storage storage3 = new LimitedStorageImpl(100); + storage3.insert(C, 10, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(3, storage3); + + initializeAndActivate(); // Act - final long extracted = networkStorage.extract(A, 30, Action.EXECUTE, EmptyActor.INSTANCE); + final long extracted = networkStorage.extract(A, 85, Action.EXECUTE, EmptyActor.INSTANCE); // Assert - assertThat(extracted).isEqualTo(30); - assertThat(storage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( - new ResourceAmount(A, 70), + assertThat(extracted).isEqualTo(85); + + assertThat(storage1.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( new ResourceAmount(B, 50) ); + assertThat(storage2.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(B, 50), + new ResourceAmount(A, 15) + ); + assertThat(storage3.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(C, 10) + ); + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( - new ResourceAmount(A, 70), - new ResourceAmount(B, 50) + new ResourceAmount(B, 100), + new ResourceAmount(A, 15), + new ResourceAmount(C, 10) ); + assertThat(networkStorage.getStored()).isEqualTo(125); } @Test void shouldRespectAllowlistWhenInserting( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { // Arrange sut.setFilterMode(FilterMode.ALLOW); sut.setFilters(Set.of(A, B)); final Storage storage = new LimitedStorageImpl(100); - activateStorage(storage); + provider.set(1, storage); + initializeAndActivate(); // Act final long inserted1 = networkStorage.insert(A, 12, Action.EXECUTE, EmptyActor.INSTANCE); @@ -140,15 +413,53 @@ void shouldRespectAllowlistWhenInserting( assertThat(inserted3).isZero(); } + @Test + void shouldRespectAllowlistWithNormalizerWhenInserting( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + sut.setFilterMode(FilterMode.ALLOW); + sut.setFilters(Set.of(A)); + sut.setNormalizer(resource -> { + if (resource == A_ALTERNATIVE || resource == A_ALTERNATIVE2) { + return A; + } + if (resource == B_ALTERNATIVE) { + return B; + } + return resource; + }); + + final Storage storage = new LimitedStorageImpl(100); + provider.set(1, storage); + initializeAndActivate(); + + // Act + final long inserted1 = networkStorage.insert(A, 1, Action.EXECUTE, EmptyActor.INSTANCE); + final long inserted2 = networkStorage.insert(A_ALTERNATIVE, 1, Action.EXECUTE, EmptyActor.INSTANCE); + final long inserted3 = networkStorage.insert(A_ALTERNATIVE2, 1, Action.EXECUTE, EmptyActor.INSTANCE); + final long inserted4 = networkStorage.insert(B, 1, Action.EXECUTE, EmptyActor.INSTANCE); + final long inserted5 = networkStorage.insert(B_ALTERNATIVE, 1, Action.EXECUTE, EmptyActor.INSTANCE); + + // Assert + assertThat(inserted1).isEqualTo(1); + assertThat(inserted2).isEqualTo(1); + assertThat(inserted3).isEqualTo(1); + assertThat(inserted4).isZero(); + assertThat(inserted5).isZero(); + } + @Test void shouldRespectEmptyAllowlistWhenInserting( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { // Arrange sut.setFilterMode(FilterMode.ALLOW); sut.setFilters(Set.of()); final Storage storage = new LimitedStorageImpl(100); - activateStorage(storage); + provider.set(1, storage); + initializeAndActivate(); // Act final long inserted1 = networkStorage.insert(A, 12, Action.EXECUTE, EmptyActor.INSTANCE); @@ -163,13 +474,15 @@ void shouldRespectEmptyAllowlistWhenInserting( @Test void shouldRespectBlocklistWhenInserting( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { // Arrange sut.setFilterMode(FilterMode.BLOCK); sut.setFilters(Set.of(A, B)); final Storage storage = new LimitedStorageImpl(100); - activateStorage(storage); + provider.set(1, storage); + initializeAndActivate(); // Act final long inserted1 = networkStorage.insert(A, 12, Action.EXECUTE, EmptyActor.INSTANCE); @@ -184,13 +497,15 @@ void shouldRespectBlocklistWhenInserting( @Test void shouldRespectEmptyBlocklistWhenInserting( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { // Arrange sut.setFilterMode(FilterMode.BLOCK); sut.setFilters(Set.of()); final Storage storage = new LimitedStorageImpl(100); - activateStorage(storage); + provider.set(1, storage); + initializeAndActivate(); // Act final long inserted1 = networkStorage.insert(A, 12, Action.EXECUTE, EmptyActor.INSTANCE); @@ -205,15 +520,16 @@ void shouldRespectEmptyBlocklistWhenInserting( @ParameterizedTest @EnumSource(AccessMode.class) - void shouldRespectAccessModeWhenInserting(final AccessMode accessMode, - @InjectNetworkStorageComponent - final StorageNetworkComponent networkStorage + void shouldRespectAccessModeWhenInserting( + final AccessMode accessMode, + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage ) { // Arrange sut.setAccessMode(accessMode); final Storage storage = new LimitedStorageImpl(100); - activateStorage(storage); + provider.set(1, storage); + initializeAndActivate(); // Act final long inserted = networkStorage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); @@ -227,16 +543,18 @@ void shouldRespectAccessModeWhenInserting(final AccessMode accessMode, @ParameterizedTest @EnumSource(AccessMode.class) - void shouldRespectAccessModeWhenExtracting(final AccessMode accessMode, - @InjectNetworkStorageComponent - final StorageNetworkComponent networkStorage + void shouldRespectAccessModeWhenExtracting( + final AccessMode accessMode, + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage ) { // Arrange sut.setAccessMode(accessMode); final Storage storage = new LimitedStorageImpl(100); + provider.set(1, storage); + initializeAndActivate(); + storage.insert(A, 20, Action.EXECUTE, EmptyActor.INSTANCE); - activateStorage(storage); // Act final long extracted = networkStorage.extract(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); @@ -249,10 +567,14 @@ void shouldRespectAccessModeWhenExtracting(final AccessMode accessMode, } @Test - void shouldNotInsertWhenInactive(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + void shouldNotAllowInsertsWhenInactive( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { // Arrange final Storage storage = new LimitedStorageImpl(100); - activateStorage(storage); + provider.set(1, storage); + initializeAndActivate(); + sut.setActive(false); // Act @@ -263,10 +585,14 @@ void shouldNotInsertWhenInactive(@InjectNetworkStorageComponent final StorageNet } @Test - void shouldNotExtractWhenInactive(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + void shouldNotAllowExtractsWhenInactive( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { // Arrange final Storage storage = new LimitedStorageImpl(100); - activateStorage(storage); + storage.insert(A, 20, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(1, storage); + initializeAndActivate(); sut.setActive(false); @@ -278,189 +604,95 @@ void shouldNotExtractWhenInactive(@InjectNetworkStorageComponent final StorageNe } @Test - void shouldHideStorageContentsWhenInactive( + void shouldHideFromNetworkWhenInactive( @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage ) { // Arrange final Storage storage = new LimitedStorageImpl(100); storage.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); storage.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); - activateStorage(storage); + provider.set(1, storage); + initializeAndActivate(); // Act + final Collection preInactiveness = new HashSet<>(networkStorage.getAll()); sut.setActive(false); + final Collection postInactiveness = networkStorage.getAll(); // Assert - assertThat(networkStorage.getAll()).isEmpty(); + assertThat(preInactiveness).isNotEmpty(); + assertThat(postInactiveness).isEmpty(); } @Test - void shouldShowStorageContentsWhenActive( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + void shouldNoLongerShowOnNetworkWhenRemoved( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage, + @InjectNetwork final Network network + ) { // Arrange - final Storage storage = new LimitedStorageImpl(100); - storage.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); - storage.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); + final Storage storage1 = new LimitedStorageImpl(100); + storage1.insert(A, 50, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(1, storage1); + initializeAndActivate(); - // Act - activateStorage(storage); + // Act & assert + final Storage storage2 = new LimitedStorageImpl(100); + storage2.insert(B, 50, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(2, storage2); + sut.onStorageChanged(2); - // Assert assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( new ResourceAmount(A, 50), new ResourceAmount(B, 50) ); - } - - @Test - void shouldNotInsertWhenFull(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { - // Arrange - final Storage storage = new LimitedStorageImpl(100); - storage.insert(A, 95, Action.EXECUTE, EmptyActor.INSTANCE); - activateStorage(storage); - - // Act - final long inserted1 = networkStorage.insert(A, 7, Action.EXECUTE, EmptyActor.INSTANCE); - final Collection stored1 = networkStorage.getAll(); - final long inserted2 = networkStorage.insert(A, 7, Action.EXECUTE, EmptyActor.INSTANCE); - final Collection stored2 = networkStorage.getAll(); - - // Assert - assertThat(inserted1).isEqualTo(5); - assertThat(stored1).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(A, 100) - ); - - assertThat(inserted2).isZero(); - assertThat(stored2).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(A, 100) - ); - } - - @Test - void shouldNotInsertWhenFullWhenStorageVoidsExcessButIsNotInAllowlistMode( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - final LimitedStorageImpl storage = new LimitedStorageImpl(100); - storage.insert(A, 95, Action.EXECUTE, EmptyActor.INSTANCE); - activateStorage(storage); - sut.setVoidExcess(true); + network.removeContainer(() -> sut); + assertThat(networkStorage.getAll()).isEmpty(); - // Act - final long inserted = networkStorage.insert(A, 7, Action.EXECUTE, EmptyActor.INSTANCE); + final Storage storage3 = new LimitedStorageImpl(100); + storage3.insert(C, 50, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(3, storage3); + sut.onStorageChanged(3); - // Assert - assertThat(inserted).isEqualTo(5); - assertThat(storage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(A, 100) - ); + assertThat(networkStorage.getAll()).isEmpty(); } @Test - void shouldNotInsertWhenStorageVoidsExcessAndInAllowlistModeWithoutConfiguredFilter( - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { + void shouldTrackChanges(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { // Arrange - final LimitedStorageImpl storage = new LimitedStorageImpl(100); - activateStorage(storage); - - sut.setVoidExcess(true); - sut.setFilterMode(FilterMode.ALLOW); + final Storage storage = new TrackedStorageImpl(new LimitedStorageImpl(100), () -> 0L); + provider.set(1, storage); + initializeAndActivate(); // Act - final long inserted = networkStorage.insert(A, 7, Action.EXECUTE, EmptyActor.INSTANCE); + final long inserted = networkStorage.insert(A, 10, Action.EXECUTE, FakeActor.INSTANCE); // Assert - assertThat(inserted).isZero(); - assertThat(storage.getAll()).isEmpty(); + assertThat(inserted).isEqualTo(10); + assertThat(networkStorage.findTrackedResourceByActorType(A, FakeActor.class)).isNotEmpty(); } @Test - void shouldInsertWhenFullWhenStorageVoidsExcessAndIsInAllowlistMode( + void shouldNotifyListenerWhenStateChanges( @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage ) { // Arrange - final LimitedStorageImpl storage = new LimitedStorageImpl(100); - storage.insert(A, 95, Action.EXECUTE, EmptyActor.INSTANCE); - activateStorage(storage); - - sut.setVoidExcess(true); - sut.setFilterMode(FilterMode.ALLOW); - sut.setFilters(Set.of(A)); - - // Act - final long inserted1 = networkStorage.insert(A, 3, Action.EXECUTE, EmptyActor.INSTANCE); - final long inserted2 = networkStorage.insert(A, 7, Action.EXECUTE, EmptyActor.INSTANCE); - final long insertedOther = networkStorage.insert(B, 1, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - assertThat(inserted1).isEqualTo(3); - assertThat(inserted2).isEqualTo(7); - assertThat(insertedOther).isZero(); - assertThat(storage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new ResourceAmount(A, 100) - ); - } + final StateTrackedStorage.Listener listener = mock(StateTrackedStorage.Listener.class); + sut.setListener(listener); - @Test - void shouldTrackChanges(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { - // Arrange - activateStorage(new TrackedStorageImpl(new LimitedStorageImpl(100), () -> 0L)); + final Storage storage = new LimitedStorageImpl(100); + provider.set(1, storage); + initializeAndActivate(); // Act - final long inserted = networkStorage.insert(A, 10, Action.EXECUTE, FakeActor.INSTANCE); + networkStorage.insert(A, 75, Action.EXECUTE, FakeActor.INSTANCE); // Assert - assertThat(inserted).isEqualTo(10); - assertThat(networkStorage.findTrackedResourceByActorType(A, FakeActor.class)).isNotEmpty(); + verify(listener, times(1)).onStorageStateChanged(); } - private void activateStorage(final Storage storage) { - sut.setStorage(storage); + private void initializeAndActivate() { + sut.setProvider(provider); sut.setActive(true); } - - @Nested - class PriorityTest { - @AddNetworkNode - StorageNetworkNode otherStorage; - - @ParameterizedTest - @ValueSource(booleans = {true, false}) - void shouldRespectPriority( - final boolean oneHasPriority, - @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage - ) { - // Arrange - final LimitedStorageImpl storage1 = new LimitedStorageImpl(100); - sut.setStorage(storage1); - sut.setActive(true); - - final LimitedStorageImpl storage2 = new LimitedStorageImpl(100); - otherStorage.setStorage(storage2); - otherStorage.setActive(true); - - if (oneHasPriority) { - sut.setPriority(5); - otherStorage.setPriority(2); - } else { - sut.setPriority(2); - otherStorage.setPriority(5); - } - - // Act - networkStorage.insert(A, 1, Action.EXECUTE, EmptyActor.INSTANCE); - - // Assert - if (oneHasPriority) { - assertThat(storage1.getAll()).isNotEmpty(); - assertThat(storage2.getAll()).isEmpty(); - } else { - assertThat(storage1.getAll()).isEmpty(); - assertThat(storage2.getAll()).isNotEmpty(); - } - } - } } diff --git a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/storage/StorageNetworkComponentImplTest.java b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/storage/StorageNetworkComponentImplTest.java index eb99af6f1..f1f4757ab 100644 --- a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/storage/StorageNetworkComponentImplTest.java +++ b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/storage/StorageNetworkComponentImplTest.java @@ -17,6 +17,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -38,15 +39,17 @@ class StorageNetworkComponentImplTest { void setUp() { sut = new StorageNetworkComponentImpl(new ResourceListImpl()); - storage1 = new StorageNetworkNode(0); + storage1 = new StorageNetworkNode(0, 0, 1); storage1.setNetwork(new NetworkImpl(NetworkTestFixtures.NETWORK_COMPONENT_MAP_FACTORY)); - storage1.setStorage(new LimitedStorageImpl(100)); + final var storage1S = new LimitedStorageImpl(100); + storage1.setProvider(index -> Optional.of(storage1S)); storage1.setActive(true); storage1Container = () -> storage1; - storage2 = new StorageNetworkNode(0); + storage2 = new StorageNetworkNode(0, 0, 1); storage2.setNetwork(new NetworkImpl(NetworkTestFixtures.NETWORK_COMPONENT_MAP_FACTORY)); - storage2.setStorage(new LimitedStorageImpl(100)); + final var storage2S = new LimitedStorageImpl(100); + storage2.setProvider(index -> Optional.of(storage2S)); storage2.setActive(true); storage2Container = () -> storage2; } diff --git a/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/AbstractStorageContainerBlockItem.java b/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/AbstractStorageContainerBlockItem.java index c874ae24f..f4c499eae 100644 --- a/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/AbstractStorageContainerBlockItem.java +++ b/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/AbstractStorageContainerBlockItem.java @@ -62,7 +62,7 @@ protected boolean updateCustomBlockEntityTag(final BlockPos pos, private void updateBlockEntityTag(final BlockPos pos, final Level level, final ItemStack stack) { - if (level.getBlockEntity(pos) instanceof ItemTransferableStorageBlockEntity blockEntity) { + if (level.getBlockEntity(pos) instanceof StorageBlockEntity blockEntity) { helper.transferToBlockEntity(stack, blockEntity); } else { LOGGER.warn("Storage could not be set, block entity does not exist yet at {}", pos); diff --git a/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/ItemTransferableStorageBlockEntity.java b/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/StorageBlockEntity.java similarity index 79% rename from refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/ItemTransferableStorageBlockEntity.java rename to refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/StorageBlockEntity.java index ffa22ac93..be88e8a16 100644 --- a/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/ItemTransferableStorageBlockEntity.java +++ b/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/StorageBlockEntity.java @@ -10,9 +10,9 @@ * The "storage block" is an example of such an item. */ @API(status = API.Status.STABLE, since = "2.0.0-milestone.3.3") -public interface ItemTransferableStorageBlockEntity { +public interface StorageBlockEntity { @Nullable UUID getStorageId(); - void modifyStorageIdAfterAlreadyInitialized(UUID id); + void setStorageId(UUID storageId); } diff --git a/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/StorageContainerItemHelper.java b/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/StorageContainerItemHelper.java index b2577334b..c2428eac2 100644 --- a/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/StorageContainerItemHelper.java +++ b/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/storage/StorageContainerItemHelper.java @@ -40,9 +40,9 @@ void appendToTooltip(ItemStack stack, LongFunction amountFormatter, boolean hasCapacity); - void transferToBlockEntity(ItemStack stack, ItemTransferableStorageBlockEntity blockEntity); + void transferToBlockEntity(ItemStack stack, StorageBlockEntity blockEntity); - void transferFromBlockEntity(ItemStack stack, ItemTransferableStorageBlockEntity blockEntity); + void transferFromBlockEntity(ItemStack stack, StorageBlockEntity blockEntity); void registerDiskModel(Item item, ResourceLocation model); diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/DiskInventory.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/DiskInventory.java index 5db389b00..d20e42241 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/DiskInventory.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/DiskInventory.java @@ -1,6 +1,6 @@ package com.refinedmods.refinedstorage2.platform.common.storage; -import com.refinedmods.refinedstorage2.api.network.impl.node.multistorage.MultiStorageProvider; +import com.refinedmods.refinedstorage2.api.network.impl.node.storage.StorageNetworkNode; import com.refinedmods.refinedstorage2.api.storage.Storage; import com.refinedmods.refinedstorage2.api.storage.StorageState; import com.refinedmods.refinedstorage2.platform.api.storage.StorageContainerItem; @@ -16,7 +16,7 @@ import net.minecraft.world.SimpleContainer; import net.minecraft.world.item.ItemStack; -public class DiskInventory extends SimpleContainer implements MultiStorageProvider { +public class DiskInventory extends SimpleContainer implements StorageNetworkNode.Provider { private static final String TAG_DISK_STATE = "s"; private static final String TAG_DISK_ITEM_ID = "i"; diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/StorageContainerItemHelperImpl.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/StorageContainerItemHelperImpl.java index 84c88cc6b..ee061f0e6 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/StorageContainerItemHelperImpl.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/StorageContainerItemHelperImpl.java @@ -2,7 +2,7 @@ import com.refinedmods.refinedstorage2.api.storage.Storage; import com.refinedmods.refinedstorage2.platform.api.PlatformApi; -import com.refinedmods.refinedstorage2.platform.api.storage.ItemTransferableStorageBlockEntity; +import com.refinedmods.refinedstorage2.platform.api.storage.StorageBlockEntity; import com.refinedmods.refinedstorage2.platform.api.storage.StorageContainerItemHelper; import com.refinedmods.refinedstorage2.platform.api.storage.StorageInfo; import com.refinedmods.refinedstorage2.platform.api.storage.StorageRepository; @@ -127,15 +127,15 @@ public void appendToTooltip(final ItemStack stack, } @Override - public void transferToBlockEntity(final ItemStack stack, final ItemTransferableStorageBlockEntity blockEntity) { + public void transferToBlockEntity(final ItemStack stack, final StorageBlockEntity blockEntity) { getId(stack).ifPresent(id -> { - blockEntity.modifyStorageIdAfterAlreadyInitialized(id); + blockEntity.setStorageId(id); LOGGER.debug("Transferred storage {} to block entity {}", id, blockEntity); }); } @Override - public void transferFromBlockEntity(final ItemStack stack, final ItemTransferableStorageBlockEntity blockEntity) { + public void transferFromBlockEntity(final ItemStack stack, final StorageBlockEntity blockEntity) { final UUID storageId = blockEntity.getStorageId(); if (storageId != null) { LOGGER.debug("Transferred storage {} from block entity {} to stack", storageId, blockEntity); diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/diskdrive/AbstractDiskDriveBlockEntity.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/diskdrive/AbstractDiskDriveBlockEntity.java index ca814bdb5..b8189de59 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/diskdrive/AbstractDiskDriveBlockEntity.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/diskdrive/AbstractDiskDriveBlockEntity.java @@ -1,6 +1,6 @@ package com.refinedmods.refinedstorage2.platform.common.storage.diskdrive; -import com.refinedmods.refinedstorage2.api.network.impl.node.multistorage.MultiStorageNetworkNode; +import com.refinedmods.refinedstorage2.api.network.impl.node.storage.StorageNetworkNode; import com.refinedmods.refinedstorage2.platform.api.PlatformApi; import com.refinedmods.refinedstorage2.platform.common.Platform; import com.refinedmods.refinedstorage2.platform.common.content.BlockEntities; @@ -39,7 +39,7 @@ import net.minecraft.world.level.block.state.BlockState; public abstract class AbstractDiskDriveBlockEntity - extends AbstractRedstoneModeNetworkNodeContainerBlockEntity + extends AbstractRedstoneModeNetworkNodeContainerBlockEntity implements BlockEntityWithDrops, NetworkNodeMenuProvider { public static final int AMOUNT_OF_DISKS = 8; @@ -55,7 +55,7 @@ public abstract class AbstractDiskDriveBlockEntity private final DiskStateChangeListener diskStateListener = new DiskStateChangeListener(this); protected AbstractDiskDriveBlockEntity(final BlockPos pos, final BlockState state) { - super(BlockEntities.INSTANCE.getDiskDrive(), pos, state, new MultiStorageNetworkNode( + super(BlockEntities.INSTANCE.getDiskDrive(), pos, state, new StorageNetworkNode( Platform.INSTANCE.getConfig().getDiskDrive().getEnergyUsage(), Platform.INSTANCE.getConfig().getDiskDrive().getEnergyUsagePerDisk(), AMOUNT_OF_DISKS diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/diskdrive/DiskDriveBlockEntityTicker.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/diskdrive/DiskDriveBlockEntityTicker.java index 9b77b4538..ea731571e 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/diskdrive/DiskDriveBlockEntityTicker.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/diskdrive/DiskDriveBlockEntityTicker.java @@ -1,6 +1,6 @@ package com.refinedmods.refinedstorage2.platform.common.storage.diskdrive; -import com.refinedmods.refinedstorage2.api.network.impl.node.multistorage.MultiStorageNetworkNode; +import com.refinedmods.refinedstorage2.api.network.impl.node.storage.StorageNetworkNode; import com.refinedmods.refinedstorage2.platform.common.content.BlockEntities; import com.refinedmods.refinedstorage2.platform.common.support.network.NetworkNodeBlockEntityTicker; @@ -9,7 +9,7 @@ import net.minecraft.world.level.block.state.BlockState; class DiskDriveBlockEntityTicker - extends NetworkNodeBlockEntityTicker { + extends NetworkNodeBlockEntityTicker { DiskDriveBlockEntityTicker() { super(BlockEntities.INSTANCE::getDiskDrive); diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/AbstractStorageBlockBlockEntity.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/AbstractStorageBlockBlockEntity.java index c0d533097..bb092f234 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/AbstractStorageBlockBlockEntity.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/AbstractStorageBlockBlockEntity.java @@ -3,7 +3,7 @@ import com.refinedmods.refinedstorage2.api.network.impl.node.storage.StorageNetworkNode; import com.refinedmods.refinedstorage2.api.storage.Storage; import com.refinedmods.refinedstorage2.platform.api.PlatformApi; -import com.refinedmods.refinedstorage2.platform.api.storage.ItemTransferableStorageBlockEntity; +import com.refinedmods.refinedstorage2.platform.api.storage.StorageBlockEntity; import com.refinedmods.refinedstorage2.platform.api.storage.StorageRepository; import com.refinedmods.refinedstorage2.platform.api.support.resource.ResourceContainer; import com.refinedmods.refinedstorage2.platform.api.support.resource.ResourceFactory; @@ -13,7 +13,7 @@ import com.refinedmods.refinedstorage2.platform.common.support.network.AbstractRedstoneModeNetworkNodeContainerBlockEntity; import com.refinedmods.refinedstorage2.platform.common.support.resource.ResourceContainerImpl; -import java.util.Objects; +import java.util.Optional; import java.util.UUID; import javax.annotation.Nullable; @@ -29,7 +29,7 @@ abstract class AbstractStorageBlockBlockEntity extends AbstractRedstoneModeNetworkNodeContainerBlockEntity - implements NetworkNodeMenuProvider, ItemTransferableStorageBlockEntity { + implements NetworkNodeMenuProvider, StorageBlockEntity, StorageNetworkNode.Provider { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractStorageBlockBlockEntity.class); private static final String TAG_STORAGE_ID = "sid"; @@ -69,7 +69,6 @@ public void setLevel(final Level level) { if (level.isClientSide()) { return; } - final StorageRepository storageRepository = PlatformApi.INSTANCE.getStorageRepository(level); if (storageId == null) { // We are a new block entity, or: // - We are placed through NBT @@ -78,42 +77,17 @@ public void setLevel(final Level level) { // (#setLevel(Level) -> #modifyStorageAfterAlreadyInitialized(UUID)). // In both cases listed above we need to clean up the storage we create here. storageId = UUID.randomUUID(); + final StorageRepository storageRepository = PlatformApi.INSTANCE.getStorageRepository(level); final Storage storage = createStorage(storageRepository::markAsChanged); storageRepository.set(storageId, storage); - mainNode.setStorage(storage); - } else { - // The existing block entity got loaded in the level (#load(CompoundTag) -> #setLevel(Level)). - storageRepository.get(storageId).ifPresentOrElse( - mainNode::setStorage, - () -> LOGGER.warn("Storage {} could not be resolved", storageId) - ); } - } - - @Override - public void modifyStorageIdAfterAlreadyInitialized(final UUID actualStorageId) { - LOGGER.debug( - "Storage {} got placed through NBT, replacing with actual storage {}", - storageId, - actualStorageId - ); - cleanupUnneededInitialStorageAndReinitialize(actualStorageId); - this.storageId = actualStorageId; + mainNode.setProvider(this); } @Override public void load(final CompoundTag tag) { if (tag.contains(TAG_STORAGE_ID)) { - final UUID actualStorageId = tag.getUUID(TAG_STORAGE_ID); - if (isPlacedThroughNbtPlacement(actualStorageId)) { - LOGGER.debug( - "Storage {} got placed through nbt, replacing with actual storage {}", - storageId, - actualStorageId - ); - cleanupUnneededInitialStorageAndReinitialize(actualStorageId); - } - storageId = actualStorageId; + setStorageId(tag.getUUID(TAG_STORAGE_ID)); } super.load(tag); } @@ -125,27 +99,6 @@ public void readConfiguration(final CompoundTag tag) { filter.load(tag); } - private void cleanupUnneededInitialStorageAndReinitialize(final UUID actualStorageId) { - // We got placed through NBT (#setLevel(Level) -> #load(CompoundTag)), or, - // we got placed with an existing storage ID (#setLevel(Level) -> modifyStorageAfterAlreadyInitialized(UUID)). - // Clean up the storage created earlier in #setLevel(Level). - final StorageRepository storageRepository = PlatformApi.INSTANCE - .getStorageRepository(Objects.requireNonNull(level)); - storageRepository.removeIfEmpty(Objects.requireNonNull(storageId)).ifPresentOrElse( - storage -> LOGGER.debug("Unneeded storage {} successfully removed", storageId), - () -> LOGGER.warn("Unneeded storage {} could not be removed", storageId) - ); - storageRepository.get(actualStorageId).ifPresentOrElse( - mainNode::setStorage, - () -> LOGGER.warn("Actual storage ID {} could not be resolved!", actualStorageId) - ); - } - - private boolean isPlacedThroughNbtPlacement(final UUID otherStorageId) { - // When placed through nbt, the level is already set and a default new storage was created. - return level != null && storageId != null && !storageId.equals(otherStorageId); - } - @Override public void saveAdditional(final CompoundTag tag) { super.saveAdditional(tag); @@ -161,6 +114,28 @@ public void writeConfiguration(final CompoundTag tag) { filter.save(tag); } + @Override + public void setStorageId(final UUID storageId) { + tryRemoveCurrentStorage(storageId); + this.storageId = storageId; + mainNode.onStorageChanged(0); + } + + private void tryRemoveCurrentStorage(final UUID newStorageId) { + if (level == null || storageId == null || storageId.equals(newStorageId)) { + return; + } + // We got placed through NBT (#setLevel(Level) -> #load(CompoundTag)), or, + // we got placed with an existing storage ID (#setLevel(Level) -> #setStorageId(UUID)). + // Clean up the storage created earlier in #setLevel(Level). + LOGGER.info("Updating storage ID from {} to {}. Removing old storage", storageId, newStorageId); + final StorageRepository storageRepository = PlatformApi.INSTANCE.getStorageRepository(level); + storageRepository.removeIfEmpty(storageId).ifPresentOrElse( + storage -> LOGGER.info("Storage {} successfully removed", storageId), + () -> LOGGER.warn("Storage {} could not be removed", storageId) + ); + } + @Override @Nullable public UUID getStorageId() { @@ -177,4 +152,13 @@ public void writeScreenOpeningData(final ServerPlayer player, final FriendlyByte buf.writeLong(mainNode.getCapacity()); filter.getFilterContainer().writeToUpdatePacket(buf); } + + @Override + public Optional resolve(final int index) { + if (level == null || storageId == null) { + return Optional.empty(); + } + final StorageRepository storageRepository = PlatformApi.INSTANCE.getStorageRepository(level); + return storageRepository.get(storageId); + } } diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/FluidStorageBlockBlockEntity.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/FluidStorageBlockBlockEntity.java index 412d4d87a..6b34e6fa1 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/FluidStorageBlockBlockEntity.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/FluidStorageBlockBlockEntity.java @@ -28,7 +28,7 @@ public FluidStorageBlockBlockEntity(final BlockPos pos, BlockEntities.INSTANCE.getFluidStorageBlock(variant), pos, state, - new StorageNetworkNode(getEnergyUsage(variant)), + new StorageNetworkNode(getEnergyUsage(variant), 0, 1), PlatformApi.INSTANCE.getFluidResourceFactory() ); this.variant = variant; diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/ItemStorageBlockBlockEntity.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/ItemStorageBlockBlockEntity.java index 397d572ba..0efc11d89 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/ItemStorageBlockBlockEntity.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/ItemStorageBlockBlockEntity.java @@ -28,7 +28,7 @@ public ItemStorageBlockBlockEntity(final BlockPos pos, BlockEntities.INSTANCE.getItemStorageBlock(variant), pos, state, - new StorageNetworkNode(getEnergyUsage(variant)), + new StorageNetworkNode(getEnergyUsage(variant), 0, 1), PlatformApi.INSTANCE.getItemResourceFactory() ); this.variant = variant; diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/StorageBlockLootItemFunction.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/StorageBlockLootItemFunction.java index 126792210..6f064375d 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/StorageBlockLootItemFunction.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/StorageBlockLootItemFunction.java @@ -1,7 +1,7 @@ package com.refinedmods.refinedstorage2.platform.common.storage.storageblock; import com.refinedmods.refinedstorage2.platform.api.PlatformApi; -import com.refinedmods.refinedstorage2.platform.api.storage.ItemTransferableStorageBlockEntity; +import com.refinedmods.refinedstorage2.platform.api.storage.StorageBlockEntity; import com.refinedmods.refinedstorage2.platform.common.content.LootFunctions; import net.minecraft.world.item.ItemStack; @@ -20,7 +20,7 @@ public LootItemFunctionType getType() { @Override public ItemStack apply(final ItemStack stack, final LootContext lootContext) { final BlockEntity blockEntity = lootContext.getParam(LootContextParams.BLOCK_ENTITY); - if (blockEntity instanceof ItemTransferableStorageBlockEntity transferable) { + if (blockEntity instanceof StorageBlockEntity transferable) { PlatformApi.INSTANCE.getStorageContainerItemHelper().transferFromBlockEntity(stack, transferable); } return stack; diff --git a/refinedstorage2-storage-api/src/main/java/com/refinedmods/refinedstorage2/api/storage/StateTrackedStorage.java b/refinedstorage2-storage-api/src/main/java/com/refinedmods/refinedstorage2/api/storage/StateTrackedStorage.java index 7b4fd4401..6e2da1903 100644 --- a/refinedstorage2-storage-api/src/main/java/com/refinedmods/refinedstorage2/api/storage/StateTrackedStorage.java +++ b/refinedstorage2-storage-api/src/main/java/com/refinedmods/refinedstorage2/api/storage/StateTrackedStorage.java @@ -11,7 +11,7 @@ import java.util.Optional; import javax.annotation.Nullable; -public class StateTrackedStorage implements TrackedStorage { +public class StateTrackedStorage implements TrackedStorage, LimitedStorage { private static final double NEAR_CAPACITY_THRESHOLD = .75; private final Storage delegate; @@ -96,6 +96,13 @@ public Optional findTrackedResourceByActorType(final ResourceKe : Optional.empty(); } + @Override + public long getCapacity() { + return delegate instanceof LimitedStorage limitedStorage + ? limitedStorage.getCapacity() + : 0; + } + @FunctionalInterface public interface Listener { void onStorageStateChanged(); diff --git a/refinedstorage2-storage-api/src/test/java/com/refinedmods/refinedstorage2/api/storage/StateTrackedStorageTest.java b/refinedstorage2-storage-api/src/test/java/com/refinedmods/refinedstorage2/api/storage/StateTrackedStorageTest.java index 594b42135..bfdc6df44 100644 --- a/refinedstorage2-storage-api/src/test/java/com/refinedmods/refinedstorage2/api/storage/StateTrackedStorageTest.java +++ b/refinedstorage2-storage-api/src/test/java/com/refinedmods/refinedstorage2/api/storage/StateTrackedStorageTest.java @@ -65,9 +65,9 @@ void shouldSetInitialState() { new ResourceAmount(TestResource.A, 75) ); assertThat(sut.getStored()).isEqualTo(75); + assertThat(sut.getCapacity()).isZero(); } - @Test void shouldSetInitialStateForLimitedStorage() { // Arrange @@ -82,6 +82,8 @@ void shouldSetInitialStateForLimitedStorage() { // Assert verify(listener, never()).onStorageStateChanged(); assertThat(state).isEqualTo(StorageState.NEAR_CAPACITY); + assertThat(sut.getStored()).isEqualTo(75); + assertThat(sut.getCapacity()).isEqualTo(100); } @Test From 96841ecb122afa5c2ba3e03f638fb3f24602abf6 Mon Sep 17 00:00:00 2001 From: raoulvdberge Date: Sun, 19 May 2024 18:18:37 +0200 Subject: [PATCH 2/3] refactor: introduce common storage container network node --- .../AbstractStorageContainerNetworkNode.java | 119 ++++++++++++++++++ .../impl/node/storage/StorageNetworkNode.java | 113 ++--------------- .../StorageNetworkNodeProviderImpl.java | 3 +- .../common/storage/DiskInventory.java | 4 +- .../AbstractStorageBlockBlockEntity.java | 3 +- 5 files changed, 134 insertions(+), 108 deletions(-) create mode 100644 refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/AbstractStorageContainerNetworkNode.java diff --git a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/AbstractStorageContainerNetworkNode.java b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/AbstractStorageContainerNetworkNode.java new file mode 100644 index 000000000..5258c2dfc --- /dev/null +++ b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/AbstractStorageContainerNetworkNode.java @@ -0,0 +1,119 @@ +package com.refinedmods.refinedstorage2.api.network.impl.node; + +import com.refinedmods.refinedstorage2.api.network.impl.storage.AbstractStorageNetworkNode; +import com.refinedmods.refinedstorage2.api.storage.StateTrackedStorage; +import com.refinedmods.refinedstorage2.api.storage.Storage; +import com.refinedmods.refinedstorage2.api.storage.StorageState; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import javax.annotation.Nullable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractStorageContainerNetworkNode extends AbstractStorageNetworkNode { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractStorageContainerNetworkNode.class); + + protected final StateTrackedStorage[] storages; + + private final long energyUsage; + private final long energyUsagePerStorage; + + @Nullable + private Provider provider; + @Nullable + private StateTrackedStorage.Listener listener; + private int activeStorages; + + protected AbstractStorageContainerNetworkNode(final long energyUsage, + final long energyUsagePerStorage, + final int size) { + this.energyUsage = energyUsage; + this.energyUsagePerStorage = energyUsagePerStorage; + this.storages = new StateTrackedStorage[size]; + } + + public void setListener(final StateTrackedStorage.Listener listener) { + this.listener = listener; + } + + public void setProvider(final Provider provider) { + this.provider = provider; + final List changes = new ArrayList<>(); + for (int i = 0; i < storages.length; ++i) { + changes.addAll(initializeStorage(i)); + } + // If we are already initialized, update all the storages to keep the exposed storages in sync. + // If we are not initialized, update nothing as we have to wait for an activeness update. + if (activeStorages > 0) { + changes.forEach(this::onStorageChange); + } + updateActiveStorageCount(); + } + + public void onStorageChanged(final int index) { + if (index < 0 || index >= storages.length) { + LOGGER.warn("Invalid index {}", index); + return; + } + initializeStorage(index).forEach(this::onStorageChange); + updateActiveStorageCount(); + } + + protected void onStorageChange(final StorageChange change) { + // no op + } + + private Set initializeStorage(final int index) { + final Set results = new HashSet<>(); + if (storages[index] != null) { + results.add(new StorageChange(true, storages[index])); + } + if (provider != null) { + provider.resolve(index).ifPresentOrElse(resolved -> { + final StateTrackedStorage newStorage = new StateTrackedStorage(resolved, listener); + storages[index] = newStorage; + results.add(new StorageChange(false, newStorage)); + }, () -> storages[index] = null); + } + return results; + } + + private void updateActiveStorageCount() { + this.activeStorages = (int) Arrays.stream(storages).filter(Objects::nonNull).count(); + } + + @Override + public long getEnergyUsage() { + return energyUsage + (energyUsagePerStorage * activeStorages); + } + + public int getSize() { + return storages.length; + } + + public StorageState getState(final int index) { + final var storage = storages[index]; + if (storage == null) { + return StorageState.NONE; + } + if (!isActive()) { + return StorageState.INACTIVE; + } + return storage.getState(); + } + + protected record StorageChange(boolean removed, StateTrackedStorage storage) { + } + + @FunctionalInterface + public interface Provider { + Optional resolve(int index); + } +} diff --git a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNode.java b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNode.java index 76d71f3b4..b58b3cbb8 100644 --- a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNode.java +++ b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNode.java @@ -1,98 +1,35 @@ package com.refinedmods.refinedstorage2.api.network.impl.node.storage; -import com.refinedmods.refinedstorage2.api.network.impl.storage.AbstractStorageNetworkNode; +import com.refinedmods.refinedstorage2.api.network.impl.node.AbstractStorageContainerNetworkNode; import com.refinedmods.refinedstorage2.api.network.storage.StorageProvider; import com.refinedmods.refinedstorage2.api.storage.StateTrackedStorage; import com.refinedmods.refinedstorage2.api.storage.Storage; -import com.refinedmods.refinedstorage2.api.storage.StorageState; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class StorageNetworkNode extends AbstractStorageNetworkNode implements StorageProvider { +public class StorageNetworkNode extends AbstractStorageContainerNetworkNode implements StorageProvider { private static final Logger LOGGER = LoggerFactory.getLogger(StorageNetworkNode.class); - @Nullable - private Provider provider; - @Nullable - private StateTrackedStorage.Listener listener; - - private final long energyUsage; - private final long energyUsagePerStorage; - - private final StateTrackedStorage[] cache; private final ExposedStorage storage; - private int activeStorages; public StorageNetworkNode(final long energyUsage, final long energyUsagePerStorage, final int size) { - this.energyUsage = energyUsage; - this.energyUsagePerStorage = energyUsagePerStorage; + super(energyUsage, energyUsagePerStorage, size); this.storage = new ExposedStorage(this); - this.cache = new StateTrackedStorage[size]; } - public void setProvider(final Provider provider) { - this.provider = provider; - final List changes = new ArrayList<>(); - for (int i = 0; i < cache.length; ++i) { - changes.addAll(initializeStorage(i)); - } - // If we are already initialized, update all the storages to keep the exposed storages in sync. - // If we are not initialized, update nothing as we have to wait for an activeness update. - if (activeStorages > 0) { - changes.forEach(this::processStorageChange); - } - updateActiveStorageCount(); - } - - public void onStorageChanged(final int index) { - if (index < 0 || index >= cache.length) { - LOGGER.warn("Invalid index {}", index); - return; - } - initializeStorage(index).forEach(this::processStorageChange); - updateActiveStorageCount(); - } - - private Set initializeStorage(final int index) { - final Set results = new HashSet<>(); - if (cache[index] != null) { - results.add(new StorageChange(true, cache[index])); - } - if (provider != null) { - provider.resolve(index).ifPresentOrElse(resolved -> { - final StateTrackedStorage newStorage = new StateTrackedStorage(resolved, listener); - cache[index] = newStorage; - results.add(new StorageChange(false, newStorage)); - }, () -> cache[index] = null); - } - return results; - } - - private void processStorageChange(final StorageChange change) { + @Override + protected void onStorageChange(final AbstractStorageContainerNetworkNode.StorageChange change) { if (!isActive()) { return; } - if (change.removed) { - storage.removeSource(change.storage); + if (change.removed()) { + storage.removeSource(change.storage()); } else { - storage.addSource(change.storage); + storage.addSource(change.storage()); } } - private void updateActiveStorageCount() { - this.activeStorages = (int) Arrays.stream(cache).filter(Objects::nonNull).count(); - } - @Override protected void onActiveChanged(final boolean newActive) { super.onActiveChanged(newActive); @@ -108,7 +45,7 @@ protected void onActiveChanged(final boolean newActive) { } private void enableAllStorages() { - for (final StateTrackedStorage internalStorage : cache) { + for (final StateTrackedStorage internalStorage : storages) { if (internalStorage != null) { storage.addSource(internalStorage); } @@ -119,30 +56,6 @@ private void disableAllStorages() { storage.clearSources(); } - public void setListener(final StateTrackedStorage.Listener listener) { - this.listener = listener; - } - - @Override - public long getEnergyUsage() { - return energyUsage + (energyUsagePerStorage * activeStorages); - } - - public int getSize() { - return cache.length; - } - - public StorageState getState(final int index) { - final var cached = cache[index]; - if (cached == null) { - return StorageState.NONE; - } - if (!isActive()) { - return StorageState.INACTIVE; - } - return cached.getState(); - } - public long getStored() { return storage.getStored(); } @@ -155,12 +68,4 @@ public long getCapacity() { public Storage getStorage() { return storage; } - - private record StorageChange(boolean removed, StateTrackedStorage storage) { - } - - @FunctionalInterface - public interface Provider { - Optional resolve(int index); - } } diff --git a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeProviderImpl.java b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeProviderImpl.java index 8034a5f5b..5181ab680 100644 --- a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeProviderImpl.java +++ b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeProviderImpl.java @@ -1,12 +1,13 @@ package com.refinedmods.refinedstorage2.api.network.impl.node.storage; +import com.refinedmods.refinedstorage2.api.network.impl.node.AbstractStorageContainerNetworkNode; import com.refinedmods.refinedstorage2.api.storage.Storage; import java.util.HashMap; import java.util.Map; import java.util.Optional; -class StorageNetworkNodeProviderImpl implements StorageNetworkNode.Provider { +class StorageNetworkNodeProviderImpl implements AbstractStorageContainerNetworkNode.Provider { private final Map storages = new HashMap<>(); @Override diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/DiskInventory.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/DiskInventory.java index d20e42241..d5a8871bc 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/DiskInventory.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/DiskInventory.java @@ -1,6 +1,6 @@ package com.refinedmods.refinedstorage2.platform.common.storage; -import com.refinedmods.refinedstorage2.api.network.impl.node.storage.StorageNetworkNode; +import com.refinedmods.refinedstorage2.api.network.impl.node.AbstractStorageContainerNetworkNode; import com.refinedmods.refinedstorage2.api.storage.Storage; import com.refinedmods.refinedstorage2.api.storage.StorageState; import com.refinedmods.refinedstorage2.platform.api.storage.StorageContainerItem; @@ -16,7 +16,7 @@ import net.minecraft.world.SimpleContainer; import net.minecraft.world.item.ItemStack; -public class DiskInventory extends SimpleContainer implements StorageNetworkNode.Provider { +public class DiskInventory extends SimpleContainer implements AbstractStorageContainerNetworkNode.Provider { private static final String TAG_DISK_STATE = "s"; private static final String TAG_DISK_ITEM_ID = "i"; diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/AbstractStorageBlockBlockEntity.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/AbstractStorageBlockBlockEntity.java index bb092f234..c658ea8b5 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/AbstractStorageBlockBlockEntity.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/storage/storageblock/AbstractStorageBlockBlockEntity.java @@ -1,5 +1,6 @@ package com.refinedmods.refinedstorage2.platform.common.storage.storageblock; +import com.refinedmods.refinedstorage2.api.network.impl.node.AbstractStorageContainerNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.storage.StorageNetworkNode; import com.refinedmods.refinedstorage2.api.storage.Storage; import com.refinedmods.refinedstorage2.platform.api.PlatformApi; @@ -29,7 +30,7 @@ abstract class AbstractStorageBlockBlockEntity extends AbstractRedstoneModeNetworkNodeContainerBlockEntity - implements NetworkNodeMenuProvider, StorageBlockEntity, StorageNetworkNode.Provider { + implements NetworkNodeMenuProvider, StorageBlockEntity, AbstractStorageContainerNetworkNode.Provider { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractStorageBlockBlockEntity.class); private static final String TAG_STORAGE_ID = "sid"; From 8aeaa1d81509cba8d4521aea216120d40ee0446a Mon Sep 17 00:00:00 2001 From: raoulvdberge Date: Sat, 25 May 2024 11:34:00 +0200 Subject: [PATCH 3/3] feat: storage transfer network node --- config/checkstyle/checkstyle.xml | 2 +- .../network/test/NetworkTest.java | 3 + .../network/test/NetworkTestFixtures.java | 4 +- .../StorageTransferNetworkNodeFactory.java | 23 + .../network/test/NetworkNodeFactoryTest.java | 3 + .../StorageTransferListener.java | 6 + .../storagetransfer/StorageTransferMode.java | 6 + .../StorageTransferNetworkNode.java | 141 ++++ .../node/storagetransfer/package-info.java | 7 + ...odeProviderImpl.java => ProviderImpl.java} | 5 +- .../PriorityStorageNetworkNodeTest.java | 9 +- .../node/storage/StorageNetworkNodeTest.java | 5 +- .../StorageTransferNetworkNodeTest.java | 718 ++++++++++++++++++ .../api/resource/list/ResourceListImpl.java | 12 +- .../api/storage/InMemoryStorageImpl.java | 10 +- .../api/storage/StateTrackedStorage.java | 1 + 16 files changed, 941 insertions(+), 14 deletions(-) create mode 100644 refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/nodefactory/StorageTransferNetworkNodeFactory.java create mode 100644 refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferListener.java create mode 100644 refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferMode.java create mode 100644 refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferNetworkNode.java create mode 100644 refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/package-info.java rename refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/{storage/StorageNetworkNodeProviderImpl.java => ProviderImpl.java} (66%) create mode 100644 refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferNetworkNodeTest.java diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 87191bb2b..0f886cd2a 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -21,7 +21,7 @@ - + diff --git a/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/NetworkTest.java b/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/NetworkTest.java index 5bc29c45c..d7cc58db4 100644 --- a/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/NetworkTest.java +++ b/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/NetworkTest.java @@ -11,6 +11,7 @@ import com.refinedmods.refinedstorage2.api.network.impl.node.relay.RelayInputNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.relay.RelayOutputNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.storage.StorageNetworkNode; +import com.refinedmods.refinedstorage2.api.network.impl.node.storagetransfer.StorageTransferNetworkNode; import com.refinedmods.refinedstorage2.network.test.nodefactory.ControllerNetworkNodeFactory; import com.refinedmods.refinedstorage2.network.test.nodefactory.DetectorNetworkNodeFactory; import com.refinedmods.refinedstorage2.network.test.nodefactory.ExporterNetworkNodeFactory; @@ -22,6 +23,7 @@ import com.refinedmods.refinedstorage2.network.test.nodefactory.RelayOutputNetworkNodeFactory; import com.refinedmods.refinedstorage2.network.test.nodefactory.SimpleNetworkNodeFactory; import com.refinedmods.refinedstorage2.network.test.nodefactory.StorageNetworkNodeFactory; +import com.refinedmods.refinedstorage2.network.test.nodefactory.StorageTransferNetworkNodeFactory; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -44,5 +46,6 @@ @RegisterNetworkNode(value = DetectorNetworkNodeFactory.class, clazz = DetectorNetworkNode.class) @RegisterNetworkNode(value = RelayInputNetworkNodeFactory.class, clazz = RelayInputNetworkNode.class) @RegisterNetworkNode(value = RelayOutputNetworkNodeFactory.class, clazz = RelayOutputNetworkNode.class) +@RegisterNetworkNode(value = StorageTransferNetworkNodeFactory.class, clazz = StorageTransferNetworkNode.class) public @interface NetworkTest { } diff --git a/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/NetworkTestFixtures.java b/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/NetworkTestFixtures.java index 4cbfc678c..aa4a5a1c5 100644 --- a/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/NetworkTestFixtures.java +++ b/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/NetworkTestFixtures.java @@ -15,6 +15,8 @@ import com.refinedmods.refinedstorage2.api.resource.list.ResourceListImpl; import com.refinedmods.refinedstorage2.network.test.fake.FakePermissions; +import java.util.LinkedHashMap; + public final class NetworkTestFixtures { public static final ComponentMapFactory NETWORK_COMPONENT_MAP_FACTORY = new ComponentMapFactory<>(); @@ -30,7 +32,7 @@ public final class NetworkTestFixtures { ); NETWORK_COMPONENT_MAP_FACTORY.addFactory( StorageNetworkComponent.class, - network -> new StorageNetworkComponentImpl(new ResourceListImpl()) + network -> new StorageNetworkComponentImpl(new ResourceListImpl(new LinkedHashMap<>())) ); NETWORK_COMPONENT_MAP_FACTORY.addFactory( SecurityNetworkComponent.class, diff --git a/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/nodefactory/StorageTransferNetworkNodeFactory.java b/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/nodefactory/StorageTransferNetworkNodeFactory.java new file mode 100644 index 000000000..3dc766bd3 --- /dev/null +++ b/refinedstorage2-network-test/src/main/java/com/refinedmods/refinedstorage2/network/test/nodefactory/StorageTransferNetworkNodeFactory.java @@ -0,0 +1,23 @@ +package com.refinedmods.refinedstorage2.network.test.nodefactory; + +import com.refinedmods.refinedstorage2.api.network.impl.node.AbstractNetworkNode; +import com.refinedmods.refinedstorage2.api.network.impl.node.storagetransfer.StorageTransferNetworkNode; +import com.refinedmods.refinedstorage2.network.test.AddNetworkNode; + +import java.util.Map; + +public class StorageTransferNetworkNodeFactory extends AbstractNetworkNodeFactory { + public static final String PROPERTY_ENERGY_USAGE_PER_STORAGE = "energy_usage_per_storage"; + public static final String PROPERTY_SIZE = "size"; + + @Override + protected AbstractNetworkNode innerCreate(final AddNetworkNode ctx, final Map properties) { + final long energyUsagePerStorage = (long) properties.getOrDefault(PROPERTY_ENERGY_USAGE_PER_STORAGE, 0L); + final int size = (int) properties.getOrDefault(PROPERTY_SIZE, 6); + return new StorageTransferNetworkNode( + getEnergyUsage(properties), + energyUsagePerStorage, + size + ); + } +} diff --git a/refinedstorage2-network-test/src/test/java/com/refinedmods/refinedstorage2/network/test/NetworkNodeFactoryTest.java b/refinedstorage2-network-test/src/test/java/com/refinedmods/refinedstorage2/network/test/NetworkNodeFactoryTest.java index bfe41ac4f..cff8bdbf9 100644 --- a/refinedstorage2-network-test/src/test/java/com/refinedmods/refinedstorage2/network/test/NetworkNodeFactoryTest.java +++ b/refinedstorage2-network-test/src/test/java/com/refinedmods/refinedstorage2/network/test/NetworkNodeFactoryTest.java @@ -11,6 +11,7 @@ import com.refinedmods.refinedstorage2.api.network.impl.node.relay.RelayInputNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.relay.RelayOutputNetworkNode; import com.refinedmods.refinedstorage2.api.network.impl.node.storage.StorageNetworkNode; +import com.refinedmods.refinedstorage2.api.network.impl.node.storagetransfer.StorageTransferNetworkNode; import org.junit.jupiter.api.Test; @@ -41,6 +42,8 @@ class NetworkNodeFactoryTest { RelayInputNetworkNode relayInput; @AddNetworkNode RelayOutputNetworkNode relayOutput; + @AddNetworkNode + StorageTransferNetworkNode storageTransfer; @Test void testInitialization() { diff --git a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferListener.java b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferListener.java new file mode 100644 index 000000000..b4e34ced4 --- /dev/null +++ b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferListener.java @@ -0,0 +1,6 @@ +package com.refinedmods.refinedstorage2.api.network.impl.node.storagetransfer; + +@FunctionalInterface +public interface StorageTransferListener { + void onTransferSuccess(int index); +} diff --git a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferMode.java b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferMode.java new file mode 100644 index 000000000..58e8eed37 --- /dev/null +++ b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferMode.java @@ -0,0 +1,6 @@ +package com.refinedmods.refinedstorage2.api.network.impl.node.storagetransfer; + +public enum StorageTransferMode { + INSERT, + EXTRACT +} diff --git a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferNetworkNode.java b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferNetworkNode.java new file mode 100644 index 000000000..0680ffccd --- /dev/null +++ b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferNetworkNode.java @@ -0,0 +1,141 @@ +package com.refinedmods.refinedstorage2.api.network.impl.node.storagetransfer; + +import com.refinedmods.refinedstorage2.api.network.impl.node.AbstractStorageContainerNetworkNode; +import com.refinedmods.refinedstorage2.api.network.node.NetworkNodeActor; +import com.refinedmods.refinedstorage2.api.network.storage.StorageNetworkComponent; +import com.refinedmods.refinedstorage2.api.resource.ResourceAmount; +import com.refinedmods.refinedstorage2.api.resource.ResourceKey; +import com.refinedmods.refinedstorage2.api.storage.Actor; +import com.refinedmods.refinedstorage2.api.storage.Storage; +import com.refinedmods.refinedstorage2.api.storage.TransferHelper; +import com.refinedmods.refinedstorage2.api.storage.limited.LimitedStorage; + +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.function.Predicate; +import java.util.function.ToLongFunction; +import javax.annotation.Nullable; + +public class StorageTransferNetworkNode extends AbstractStorageContainerNetworkNode { + private final Actor actor = new NetworkNodeActor(this); + + private StorageTransferMode mode = StorageTransferMode.INSERT; + @Nullable + private ToLongFunction transferQuotaProvider; + @Nullable + private StorageTransferListener listener; + + public StorageTransferNetworkNode(final long energyUsage, final long energyUsagePerStorage, final int size) { + super(energyUsage, energyUsagePerStorage, size); + } + + public void setMode(final StorageTransferMode mode) { + this.mode = mode; + } + + public void setTransferQuotaProvider(final ToLongFunction transferQuotaProvider) { + this.transferQuotaProvider = transferQuotaProvider; + } + + public void setListener(@Nullable final StorageTransferListener listener) { + this.listener = listener; + } + + @Override + public void doWork() { + super.doWork(); + if (!isActive() || network == null) { + return; + } + final StorageNetworkComponent networkStorage = network.getComponent(StorageNetworkComponent.class); + for (int i = 0; i < storages.length / 2; ++i) { + final Storage storage = storages[i]; + if (storage == null) { + continue; + } + final Result result = transfer(storage, networkStorage); + if (processResult(result, i)) { + return; + } + } + } + + private Result transfer(final Storage storage, final StorageNetworkComponent networkStorage) { + if (transferQuotaProvider == null) { + return Result.FAILURE; + } + final long transferQuota = transferQuotaProvider.applyAsLong(storage); + if (mode == StorageTransferMode.INSERT) { + return transfer(storage, networkStorage, transferQuota, this::hasNoExtractableResources); + } + return transfer( + networkStorage, + storage, + transferQuota, + source -> hasNoExtractableResources(source) || storageIsFull(storage) + ); + } + + private Result transfer(final Storage source, + final Storage destination, + final long transferQuota, + final Predicate readyPredicate) { + if (readyPredicate.test(source)) { + return Result.SUCCESS; + } + if (transfer(source, destination, transferQuota)) { + return readyPredicate.test(source) + ? Result.SUCCESS + : Result.PARTIAL; + } + return Result.FAILURE; + } + + private boolean transfer(final Storage source, final Storage destination, final long transferQuota) { + long remainder = transferQuota; + final Collection sourceContents = new LinkedHashSet<>(source.getAll()); + for (final ResourceAmount resourceAmount : sourceContents) { + final ResourceKey resource = resourceAmount.getResource(); + if (!isAllowed(resource)) { + continue; + } + final long amount = Math.min(remainder, resourceAmount.getAmount()); + final long transferred = TransferHelper.transfer(resource, amount, actor, source, destination, source); + remainder -= transferred; + if (remainder == 0) { + return true; + } + } + return remainder != transferQuota; + } + + private boolean hasNoExtractableResources(final Storage source) { + return source.getAll().stream().noneMatch(resourceAmount -> isAllowed(resourceAmount.getResource())); + } + + private boolean storageIsFull(final Storage storage) { + return storage instanceof LimitedStorage limitedStorage + && limitedStorage.getCapacity() > 0 + && limitedStorage.getCapacity() == limitedStorage.getStored(); + } + + private boolean processResult(final Result result, final int index) { + if (result.isSuccess()) { + if (result == Result.SUCCESS && listener != null) { + listener.onTransferSuccess(index); + } + return true; + } + return false; + } + + private enum Result { + SUCCESS, + PARTIAL, + FAILURE; + + private boolean isSuccess() { + return this == PARTIAL || this == SUCCESS; + } + } +} diff --git a/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/package-info.java b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/package-info.java new file mode 100644 index 000000000..6f817bc33 --- /dev/null +++ b/refinedstorage2-network/src/main/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@FieldsAndMethodsAreNonnullByDefault +package com.refinedmods.refinedstorage2.api.network.impl.node.storagetransfer; + +import com.refinedmods.refinedstorage2.api.core.FieldsAndMethodsAreNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeProviderImpl.java b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/ProviderImpl.java similarity index 66% rename from refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeProviderImpl.java rename to refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/ProviderImpl.java index 5181ab680..a55d74eda 100644 --- a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeProviderImpl.java +++ b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/ProviderImpl.java @@ -1,13 +1,12 @@ -package com.refinedmods.refinedstorage2.api.network.impl.node.storage; +package com.refinedmods.refinedstorage2.api.network.impl.node; -import com.refinedmods.refinedstorage2.api.network.impl.node.AbstractStorageContainerNetworkNode; import com.refinedmods.refinedstorage2.api.storage.Storage; import java.util.HashMap; import java.util.Map; import java.util.Optional; -class StorageNetworkNodeProviderImpl implements AbstractStorageContainerNetworkNode.Provider { +public class ProviderImpl implements AbstractStorageContainerNetworkNode.Provider { private final Map storages = new HashMap<>(); @Override diff --git a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/PriorityStorageNetworkNodeTest.java b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/PriorityStorageNetworkNodeTest.java index b5b7fa837..f1761eac5 100644 --- a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/PriorityStorageNetworkNodeTest.java +++ b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/PriorityStorageNetworkNodeTest.java @@ -1,6 +1,7 @@ package com.refinedmods.refinedstorage2.api.network.impl.node.storage; import com.refinedmods.refinedstorage2.api.core.Action; +import com.refinedmods.refinedstorage2.api.network.impl.node.ProviderImpl; import com.refinedmods.refinedstorage2.api.network.storage.StorageNetworkComponent; import com.refinedmods.refinedstorage2.api.storage.EmptyActor; import com.refinedmods.refinedstorage2.api.storage.Storage; @@ -26,11 +27,11 @@ class PriorityStorageNetworkNodeTest { @AddNetworkNode StorageNetworkNode b; - StorageNetworkNodeProviderImpl provider; + ProviderImpl provider; @BeforeEach void setUp() { - provider = new StorageNetworkNodeProviderImpl(); + provider = new ProviderImpl(); } @ParameterizedTest @@ -41,13 +42,13 @@ void shouldRespectPriority( ) { // Arrange final Storage storage1 = new LimitedStorageImpl(100); - final StorageNetworkNodeProviderImpl provider1 = new StorageNetworkNodeProviderImpl(); + final ProviderImpl provider1 = new ProviderImpl(); provider1.set(1, storage1); a.setProvider(provider1); a.setActive(true); final Storage storage2 = new LimitedStorageImpl(100); - final StorageNetworkNodeProviderImpl provider2 = new StorageNetworkNodeProviderImpl(); + final ProviderImpl provider2 = new ProviderImpl(); provider2.set(1, storage2); b.setProvider(provider2); b.setActive(true); diff --git a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeTest.java b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeTest.java index 74241524f..441da0459 100644 --- a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeTest.java +++ b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storage/StorageNetworkNodeTest.java @@ -2,6 +2,7 @@ import com.refinedmods.refinedstorage2.api.core.Action; import com.refinedmods.refinedstorage2.api.network.Network; +import com.refinedmods.refinedstorage2.api.network.impl.node.ProviderImpl; import com.refinedmods.refinedstorage2.api.network.storage.StorageNetworkComponent; import com.refinedmods.refinedstorage2.api.resource.ResourceAmount; import com.refinedmods.refinedstorage2.api.resource.filter.FilterMode; @@ -55,11 +56,11 @@ class StorageNetworkNodeTest { }) StorageNetworkNode sut; - StorageNetworkNodeProviderImpl provider; + ProviderImpl provider; @BeforeEach void setUp() { - provider = new StorageNetworkNodeProviderImpl(); + provider = new ProviderImpl(); } @Test diff --git a/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferNetworkNodeTest.java b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferNetworkNodeTest.java new file mode 100644 index 000000000..0249b8f3e --- /dev/null +++ b/refinedstorage2-network/src/test/java/com/refinedmods/refinedstorage2/api/network/impl/node/storagetransfer/StorageTransferNetworkNodeTest.java @@ -0,0 +1,718 @@ +package com.refinedmods.refinedstorage2.api.network.impl.node.storagetransfer; + +import com.refinedmods.refinedstorage2.api.core.Action; +import com.refinedmods.refinedstorage2.api.network.impl.node.ProviderImpl; +import com.refinedmods.refinedstorage2.api.network.storage.StorageNetworkComponent; +import com.refinedmods.refinedstorage2.api.resource.ResourceAmount; +import com.refinedmods.refinedstorage2.api.resource.ResourceKey; +import com.refinedmods.refinedstorage2.api.resource.filter.FilterMode; +import com.refinedmods.refinedstorage2.api.resource.list.ResourceListImpl; +import com.refinedmods.refinedstorage2.api.storage.Actor; +import com.refinedmods.refinedstorage2.api.storage.EmptyActor; +import com.refinedmods.refinedstorage2.api.storage.InMemoryStorageImpl; +import com.refinedmods.refinedstorage2.api.storage.Storage; +import com.refinedmods.refinedstorage2.api.storage.limited.LimitedStorageImpl; +import com.refinedmods.refinedstorage2.network.test.AddNetworkNode; +import com.refinedmods.refinedstorage2.network.test.InjectNetworkStorageComponent; +import com.refinedmods.refinedstorage2.network.test.NetworkTest; +import com.refinedmods.refinedstorage2.network.test.SetupNetwork; + +import java.util.LinkedHashMap; +import java.util.Set; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.A; +import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.A_ALTERNATIVE; +import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.B; +import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.C; +import static com.refinedmods.refinedstorage2.network.test.fake.FakeResources.D; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@NetworkTest +@SetupNetwork +class StorageTransferNetworkNodeTest { + @AddNetworkNode + StorageTransferNetworkNode sut; + StorageTransferListener listener; + ProviderImpl provider; + + @BeforeEach + void setUp() { + provider = new ProviderImpl(); + listener = mock(StorageTransferListener.class); + sut.setListener(listener); + } + + @Test + void shouldNotTransferWithoutNetwork(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + + final Storage source = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(0, source); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 20L); + + // Act + sut.setNetwork(null); + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).isEmpty(); + assertThat(source.getAll()).isNotEmpty(); + } + + @Test + void shouldNotTransferWhenInactive(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + + final Storage source = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(0, source); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 20L); + + // Act + sut.setActive(false); + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).isEmpty(); + assertThat(source.getAll()).isNotEmpty(); + } + + @ParameterizedTest + @EnumSource(StorageTransferMode.class) + void shouldNotTransferWithoutTransferQuotaProvider( + final StorageTransferMode mode, + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + networkStorage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + + final Storage source = new InMemoryStorageImpl(); + source.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(0, source); + + sut.setProvider(provider); + sut.setMode(mode); + + // Act + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(A, 5) + ); + assertThat(source.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(B, 5) + ); + } + + @Test + void shouldInsert(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + + final Storage source0 = new LimitedStorageImpl(1) { + @Override + public long extract(final ResourceKey resource, + final long amount, + final Action action, + final Actor actor) { + return 0; + } + }; + source0.insert(A, 1, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(0, source0); + + final Storage source1 = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source1.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(C, 35, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(1, source1); + + final Storage source2 = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source2.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(2, source2); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 20L); + + // Act + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 5), + new ResourceAmount(B, 5), + new ResourceAmount(C, 10) + ); + assertThat(source0.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(A, 1) + ); + assertThat(source1.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(C, 25), + new ResourceAmount(D, 5) + ); + assertThat(source2.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(D, 5) + ); + verify(listener, never()).onTransferSuccess(anyInt()); + } + + @Test + void shouldInsertAllowlist(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + + final Storage source1 = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source1.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(C, 35, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set((sut.getSize() / 2) - 2, source1); + + final Storage source2 = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source2.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set((sut.getSize() / 2) - 1, source2); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 20L); + sut.setFilterMode(FilterMode.ALLOW); + sut.setFilters(Set.of(A, B)); + + // Act + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 5), + new ResourceAmount(B, 5) + ); + assertThat(source1.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(C, 35), + new ResourceAmount(D, 5) + ); + assertThat(source2.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(D, 5) + ); + verify(listener, times(1)).onTransferSuccess((sut.getSize() / 2) - 2); + } + + @Test + void shouldInsertBlocklist(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + + final Storage source1 = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source1.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(C, 35, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(0, source1); + + final Storage source2 = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source2.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(1, source2); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 20L); + sut.setFilterMode(FilterMode.BLOCK); + sut.setFilters(Set.of(A, B)); + + // Act + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(C, 20) + ); + assertThat(source1.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 5), + new ResourceAmount(B, 5), + new ResourceAmount(C, 15), + new ResourceAmount(D, 5) + ); + assertThat(source2.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(D, 5) + ); + verify(listener, never()).onTransferSuccess(anyInt()); + } + + @Test + void shouldNotifyListenerWhenReadyInsertingBecauseStorageWasAlreadyEmpty() { + // Arrange + final Storage source = new InMemoryStorageImpl(); + provider.set(0, source); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 15L); + + // Act + sut.doWork(); + + // Assert + verify(listener, times(1)).onTransferSuccess(0); + } + + @Test + void shouldNotifyListenerWhenReadyInsertingAllResources( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + + final Storage source = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source.insert(C, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(0, source); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 15L); + + // Act + sut.doWork(); + + // Assert + assertThat(source.getAll()).isEmpty(); + verify(listener, times(1)).onTransferSuccess(0); + } + + @Test + void shouldNotifyListenerWhenReadyInsertingAllResourcesAndUsingFilterButInsertedNothing() { + // Arrange + final Storage source1 = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source1.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(C, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(0, source1); + + final Storage source2 = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source2.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(1, source2); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 15L); + sut.setFilterMode(FilterMode.ALLOW); + sut.setFilters(Set.of(A)); + + // Act + sut.doWork(); + + // Assert + assertThat(source1.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(B, 5), + new ResourceAmount(C, 5) + ); + assertThat(source2.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(D, 5) + ); + verify(listener, times(1)).onTransferSuccess(0); + } + + @Test + void shouldNotifyListenerWhenReadyInsertingAllResourcesAndUsingFilterButStillInsertedSomething( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + + final Storage source1 = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source1.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(C, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(0, source1); + + final Storage source2 = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source2.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(1, source2); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 15L); + sut.setFilterMode(FilterMode.ALLOW); + sut.setFilters(Set.of(A)); + + // Act + sut.doWork(); + + // Assert + assertThat(source1.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(B, 5), + new ResourceAmount(C, 5) + ); + assertThat(source2.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(D, 5) + ); + verify(listener, times(1)).onTransferSuccess(0); + } + + @Test + void shouldNotNotifyListenerWhenReadyInsertingAllResourcesAndNetworkIsFull( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + networkStorage.addSource(new LimitedStorageImpl(15)); + + final Storage source1 = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source1.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(C, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source1.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(0, source1); + + final Storage source2 = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source2.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(1, source2); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 100L); + + // Act + sut.doWork(); + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 5), + new ResourceAmount(B, 5), + new ResourceAmount(C, 5) + ); + assertThat(source1.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(D, 5) + ); + assertThat(source2.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(A, 5) + ); + verify(listener, never()).onTransferSuccess(anyInt()); + } + + @Test + void shouldExtract(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + networkStorage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(C, 35, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + + final Storage source1 = new LimitedStorageImpl(0); + provider.set(0, source1); + + final Storage source2 = new InMemoryStorageImpl(); + provider.set(1, source2); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 20L); + sut.setMode(StorageTransferMode.EXTRACT); + + // Act + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(C, 25), + new ResourceAmount(D, 5) + ); + assertThat(source2.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 5), + new ResourceAmount(B, 5), + new ResourceAmount(C, 10) + ); + assertThat(source1.getAll()).isEmpty(); + verify(listener, never()).onTransferSuccess(anyInt()); + } + + @Test + void shouldExtractAllowlist(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + networkStorage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(C, 35, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + + final Storage source1 = new InMemoryStorageImpl(); + provider.set(0, source1); + + final Storage source2 = new InMemoryStorageImpl(); + provider.set(1, source2); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 20L); + sut.setMode(StorageTransferMode.EXTRACT); + sut.setFilterMode(FilterMode.ALLOW); + sut.setFilters(Set.of(A, B)); + + // Act + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(C, 35), + new ResourceAmount(D, 5) + ); + assertThat(source1.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 5), + new ResourceAmount(B, 5) + ); + assertThat(source2.getAll()).isEmpty(); + verify(listener, times(1)).onTransferSuccess(0); + } + + @Test + void shouldExtractBlocklist(@InjectNetworkStorageComponent final StorageNetworkComponent networkStorage) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + networkStorage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(C, 35, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + + final Storage source1 = new InMemoryStorageImpl(); + provider.set(0, source1); + + final Storage source2 = new InMemoryStorageImpl(); + provider.set(1, source2); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 20L); + sut.setMode(StorageTransferMode.EXTRACT); + sut.setFilterMode(FilterMode.BLOCK); + sut.setFilters(Set.of(A, B)); + + // Act + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 5), + new ResourceAmount(B, 5), + new ResourceAmount(C, 15), + new ResourceAmount(D, 5) + ); + assertThat(source1.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(C, 20) + ); + assertThat(source2.getAll()).isEmpty(); + verify(listener, never()).onTransferSuccess(anyInt()); + } + + @Test + void shouldNotifyListenerWhenReadyExtractingBecauseStorageWasAlreadyEmpty() { + // Arrange + final Storage source = new InMemoryStorageImpl(); + provider.set(0, source); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 15L); + sut.setMode(StorageTransferMode.EXTRACT); + + // Act + sut.doWork(); + + // Assert + verify(listener, times(1)).onTransferSuccess(0); + } + + @Test + void shouldNotifyListenerWhenReadyExtractingAllResources( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + networkStorage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(C, 5, Action.EXECUTE, EmptyActor.INSTANCE); + + final Storage source = new InMemoryStorageImpl(); + provider.set(0, source); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 15L); + sut.setMode(StorageTransferMode.EXTRACT); + + // Act + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).isEmpty(); + assertThat(source.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 5), + new ResourceAmount(B, 5), + new ResourceAmount(C, 5) + ); + verify(listener, times(1)).onTransferSuccess(0); + } + + @Test + void shouldNotifyListenerWhenReadyExtractingAllResourcesAndUsingFilterButInsertedNothing( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + networkStorage.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(C, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + + final Storage source = new InMemoryStorageImpl(); + provider.set(0, source); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 15L); + sut.setFilterMode(FilterMode.ALLOW); + sut.setFilters(Set.of(A)); + sut.setMode(StorageTransferMode.EXTRACT); + + // Act + sut.doWork(); + + // Assert + assertThat(source.getAll()).isEmpty(); + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(B, 5), + new ResourceAmount(C, 5), + new ResourceAmount(D, 5) + ); + verify(listener, times(1)).onTransferSuccess(0); + } + + @Test + void shouldNotifyListenerWhenReadyExtractingAllResourcesAndUsingFilterButStillExtractedSomething( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>()))); + networkStorage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(C, 5, Action.EXECUTE, EmptyActor.INSTANCE); + + final Storage source = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + provider.set(0, source); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 15L); + sut.setFilterMode(FilterMode.ALLOW); + sut.setFilters(Set.of(A)); + sut.setMode(StorageTransferMode.EXTRACT); + + // Act + sut.doWork(); + + // Assert + assertThat(source.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(A, 5) + ); + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(B, 5), + new ResourceAmount(C, 5) + ); + verify(listener, times(1)).onTransferSuccess(0); + } + + @Test + void shouldNotifyListenerWhenExtractingAllResourcesAndReachingCapacity( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + networkStorage.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + networkStorage.insert(C, 5, Action.EXECUTE, EmptyActor.INSTANCE); + + final Storage source = new LimitedStorageImpl(10); + provider.set(0, source); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 100L); + sut.setMode(StorageTransferMode.EXTRACT); + + // Act + sut.doWork(); + + // Assert + assertThat(source.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 5), + new ResourceAmount(B, 5) + ); + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(C, 5) + ); + verify(listener, times(1)).onTransferSuccess(0); + } + + @Test + void shouldRespectNormalizer( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + + final Storage source = new InMemoryStorageImpl(new ResourceListImpl(new LinkedHashMap<>())); + source.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source.insert(A_ALTERNATIVE, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source.insert(B, 5, Action.EXECUTE, EmptyActor.INSTANCE); + source.insert(D, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(0, source); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 20L); + sut.setFilterMode(FilterMode.ALLOW); + sut.setFilters(Set.of(A)); + sut.setNormalizer(resource -> resource == A || resource == A_ALTERNATIVE ? A : resource); + + // Act + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(A, 5), + new ResourceAmount(A_ALTERNATIVE, 5) + ); + assertThat(source.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( + new ResourceAmount(B, 5), + new ResourceAmount(D, 5) + ); + verify(listener, times(1)).onTransferSuccess(0); + } + + @Test + void shouldNotTransferAtIndexHigherThanHalf( + @InjectNetworkStorageComponent final StorageNetworkComponent networkStorage + ) { + // Arrange + networkStorage.addSource(new InMemoryStorageImpl()); + + final Storage source = new InMemoryStorageImpl(); + source.insert(A, 5, Action.EXECUTE, EmptyActor.INSTANCE); + provider.set(sut.getSize() / 2, source); + + sut.setProvider(provider); + sut.setTransferQuotaProvider(storage -> 20L); + + // Act + sut.doWork(); + + // Assert + assertThat(networkStorage.getAll()).isEmpty(); + assertThat(source.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( + new ResourceAmount(A, 5) + ); + verify(listener, never()).onTransferSuccess(1); + } +} diff --git a/refinedstorage2-resource-api/src/main/java/com/refinedmods/refinedstorage2/api/resource/list/ResourceListImpl.java b/refinedstorage2-resource-api/src/main/java/com/refinedmods/refinedstorage2/api/resource/list/ResourceListImpl.java index d9a2c42b1..3ba666d75 100644 --- a/refinedstorage2-resource-api/src/main/java/com/refinedmods/refinedstorage2/api/resource/list/ResourceListImpl.java +++ b/refinedstorage2-resource-api/src/main/java/com/refinedmods/refinedstorage2/api/resource/list/ResourceListImpl.java @@ -11,11 +11,19 @@ import org.apiguardian.api.API; /** - * An implementation of a {@link ResourceList} that stores the resource entries in a {@link HashMap}. + * An implementation of a {@link ResourceList} that stores the resource entries in memory. */ @API(status = API.Status.STABLE, since = "2.0.0-milestone.1.2") public class ResourceListImpl implements ResourceList { - private final Map entries = new HashMap<>(); + private final Map entries; + + public ResourceListImpl(final Map entries) { + this.entries = entries; + } + + public ResourceListImpl() { + this(new HashMap<>()); + } @Override public OperationResult add(final ResourceKey resource, final long amount) { diff --git a/refinedstorage2-storage-api/src/main/java/com/refinedmods/refinedstorage2/api/storage/InMemoryStorageImpl.java b/refinedstorage2-storage-api/src/main/java/com/refinedmods/refinedstorage2/api/storage/InMemoryStorageImpl.java index d03e7aa85..dbdf0cb0b 100644 --- a/refinedstorage2-storage-api/src/main/java/com/refinedmods/refinedstorage2/api/storage/InMemoryStorageImpl.java +++ b/refinedstorage2-storage-api/src/main/java/com/refinedmods/refinedstorage2/api/storage/InMemoryStorageImpl.java @@ -15,9 +15,17 @@ */ @API(status = API.Status.STABLE, since = "2.0.0-milestone.1.0") public class InMemoryStorageImpl implements Storage { - private final ResourceList list = new ResourceListImpl(); + private final ResourceList list; private long stored; + public InMemoryStorageImpl(final ResourceList list) { + this.list = list; + } + + public InMemoryStorageImpl() { + this(new ResourceListImpl()); + } + @Override public long extract(final ResourceKey resource, final long amount, final Action action, final Actor actor) { ResourceAmount.validate(resource, amount); diff --git a/refinedstorage2-storage-api/src/main/java/com/refinedmods/refinedstorage2/api/storage/StateTrackedStorage.java b/refinedstorage2-storage-api/src/main/java/com/refinedmods/refinedstorage2/api/storage/StateTrackedStorage.java index 6e2da1903..70da6d0ce 100644 --- a/refinedstorage2-storage-api/src/main/java/com/refinedmods/refinedstorage2/api/storage/StateTrackedStorage.java +++ b/refinedstorage2-storage-api/src/main/java/com/refinedmods/refinedstorage2/api/storage/StateTrackedStorage.java @@ -17,6 +17,7 @@ public class StateTrackedStorage implements TrackedStorage, LimitedStorage { private final Storage delegate; @Nullable private final Listener listener; + private StorageState state; public StateTrackedStorage(final Storage delegate, @Nullable final Listener listener) {