Skip to content

Commit

Permalink
feat: storage transfer network node
Browse files Browse the repository at this point in the history
  • Loading branch information
raoulvdberge committed Jun 22, 2024
1 parent 96841ec commit 6130bae
Show file tree
Hide file tree
Showing 16 changed files with 958 additions and 14 deletions.
2 changes: 1 addition & 1 deletion config/checkstyle/checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
</module>
<module name="FileLength">
<property name="max" value="700"/>
<property name="max" value="750"/>
</module>
<module name="NewlineAtEndOfFile"/>
<module name="JavadocPackage"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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 {
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<NetworkComponent, Network> NETWORK_COMPONENT_MAP_FACTORY =
new ComponentMapFactory<>();
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String, Object> 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
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -41,6 +42,8 @@ class NetworkNodeFactoryTest {
RelayInputNetworkNode relayInput;
@AddNetworkNode
RelayOutputNetworkNode relayOutput;
@AddNetworkNode
StorageTransferNetworkNode storageTransfer;

@Test
void testInitialization() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.refinedmods.refinedstorage2.api.network.impl.node.storagetransfer;

@FunctionalInterface
public interface StorageTransferListener {
void onTransferReady(int index);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.refinedmods.refinedstorage2.api.network.impl.node.storagetransfer;

public enum StorageTransferMode {
INSERT,
EXTRACT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
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.resource.filter.Filter;
import com.refinedmods.refinedstorage2.api.resource.filter.FilterMode;
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.Set;
import java.util.function.Predicate;
import java.util.function.ToLongFunction;
import java.util.function.UnaryOperator;
import javax.annotation.Nullable;

public class StorageTransferNetworkNode extends AbstractStorageContainerNetworkNode {
private final Filter filter = new Filter();
private final Actor actor = new NetworkNodeActor(this);

private StorageTransferMode mode = StorageTransferMode.INSERT;
@Nullable
private ToLongFunction<Storage> 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 setFilters(final Set<ResourceKey> filters) {
filter.setFilters(filters);
}

public void setFilterMode(final FilterMode filterMode) {
filter.setMode(filterMode);
}

public void setNormalizer(final UnaryOperator<ResourceKey> normalizer) {
filter.setNormalizer(normalizer);
}

public void setTransferQuotaProvider(final ToLongFunction<Storage> 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<Storage> 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<ResourceAmount> all = new LinkedHashSet<>(source.getAll());
for (final ResourceAmount resourceAmount : all) {
final ResourceKey resource = resourceAmount.getResource();
if (!filter.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) {
break;
}
}
return remainder != transferQuota;
}

private boolean hasNoExtractableResources(final Storage source) {
return source.getAll().stream().noneMatch(resourceAmount -> filter.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.onTransferReady(index);
}
return true;
}
return false;
}

private enum Result {
SUCCESS,
PARTIAL,
FAILURE;

private boolean isSuccess() {
return this == PARTIAL || this == SUCCESS;
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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<Integer, Storage> storages = new HashMap<>();

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -26,11 +27,11 @@ class PriorityStorageNetworkNodeTest {
@AddNetworkNode
StorageNetworkNode b;

StorageNetworkNodeProviderImpl provider;
ProviderImpl provider;

@BeforeEach
void setUp() {
provider = new StorageNetworkNodeProviderImpl();
provider = new ProviderImpl();
}

@ParameterizedTest
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -55,11 +56,11 @@ class StorageNetworkNodeTest {
})
StorageNetworkNode sut;

StorageNetworkNodeProviderImpl provider;
ProviderImpl provider;

@BeforeEach
void setUp() {
provider = new StorageNetworkNodeProviderImpl();
provider = new ProviderImpl();
}

@Test
Expand Down
Loading

0 comments on commit 6130bae

Please sign in to comment.