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 de9f7b0 commit 3f5133e
Show file tree
Hide file tree
Showing 15 changed files with 954 additions and 13 deletions.
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 3f5133e

Please sign in to comment.