From a7bdd851393d29426b2ee3dabb630f6dd6c47cb8 Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Fri, 17 Apr 2020 22:29:02 +0200 Subject: [PATCH] prevent over-sending --- .../de/ellpeck/prettypipes/items/IModule.java | 4 +-- .../ellpeck/prettypipes/items/ModuleItem.java | 5 ++- .../prettypipes/network/NetworkLocation.java | 17 ++++++++-- .../ellpeck/prettypipes/network/PipeItem.java | 2 +- .../prettypipes/network/PipeNetwork.java | 34 +++++++++++++------ .../prettypipes/pipe/PipeTileEntity.java | 25 ++++++++++++-- .../extraction/ExtractionModuleItem.java | 9 ++++- .../retrieval/RetrievalModuleItem.java | 9 ++++- .../assets/prettypipes/lang/en_us.json | 4 +-- 9 files changed, 83 insertions(+), 26 deletions(-) diff --git a/src/main/java/de/ellpeck/prettypipes/items/IModule.java b/src/main/java/de/ellpeck/prettypipes/items/IModule.java index 8b7e43f..fddb3b7 100644 --- a/src/main/java/de/ellpeck/prettypipes/items/IModule.java +++ b/src/main/java/de/ellpeck/prettypipes/items/IModule.java @@ -11,9 +11,9 @@ public interface IModule { void tick(ItemStack module, PipeTileEntity tile); - boolean canAcceptItem(ItemStack module, PipeTileEntity tile, ItemStack stack); + boolean canNetworkSee(ItemStack module, PipeTileEntity tile); - boolean isAvailableDestination(ItemStack module, PipeTileEntity tile, ItemStack stack, IItemHandler destination); + boolean canAcceptItem(ItemStack module, PipeTileEntity tile, ItemStack stack); int getPriority(ItemStack module, PipeTileEntity tile); diff --git a/src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java b/src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java index aa6c4ad..6f099b5 100644 --- a/src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java +++ b/src/main/java/de/ellpeck/prettypipes/items/ModuleItem.java @@ -15,7 +15,6 @@ import net.minecraft.util.text.*; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.items.IItemHandler; import javax.annotation.Nullable; import java.util.List; @@ -48,12 +47,12 @@ public abstract class ModuleItem extends Item implements IModule { } @Override - public boolean canAcceptItem(ItemStack module, PipeTileEntity tile, ItemStack stack) { + public boolean canNetworkSee(ItemStack module, PipeTileEntity tile) { return true; } @Override - public boolean isAvailableDestination(ItemStack module, PipeTileEntity tile, ItemStack stack, IItemHandler destination) { + public boolean canAcceptItem(ItemStack module, PipeTileEntity tile, ItemStack stack) { return true; } diff --git a/src/main/java/de/ellpeck/prettypipes/network/NetworkLocation.java b/src/main/java/de/ellpeck/prettypipes/network/NetworkLocation.java index 0d42f8e..7dc3ba9 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/NetworkLocation.java +++ b/src/main/java/de/ellpeck/prettypipes/network/NetworkLocation.java @@ -14,18 +14,29 @@ import java.util.Map; public class NetworkLocation { public final BlockPos pipePos; - public final ListMultimap> items; + private ListMultimap> items; - public NetworkLocation(BlockPos pipePos, ListMultimap> items) { + public NetworkLocation(BlockPos pipePos) { this.pipePos = pipePos; - this.items = items; + } + + public void addItem(Direction direction, int slot, ItemStack stack) { + if (this.items == null) + this.items = ArrayListMultimap.create(); + this.items.put(direction, Pair.of(slot, stack)); } public Pair getStackLocation(ItemStack stack) { + if (this.isEmpty()) + return null; for (Map.Entry> entry : this.items.entries()) { if (entry.getValue().getRight().isItemEqual(stack)) return Pair.of(entry.getKey(), entry.getValue().getLeft()); } return null; } + + public boolean isEmpty() { + return this.items == null || this.items.isEmpty(); + } } diff --git a/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java b/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java index 4ee17c7..ee8ae4c 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java +++ b/src/main/java/de/ellpeck/prettypipes/network/PipeItem.java @@ -191,7 +191,7 @@ public class PipeItem implements INBTSerializable { return this.path.get(0); } - private BlockPos getDestPipe() { + public BlockPos getDestPipe() { return this.path.get(this.path.size() - 1); } diff --git a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java index a16376f..12b6721 100644 --- a/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java +++ b/src/main/java/de/ellpeck/prettypipes/network/PipeNetwork.java @@ -40,6 +40,7 @@ import javax.annotation.Nullable; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; public class PipeNetwork implements ICapabilitySerializable, GraphListener { @@ -118,11 +119,11 @@ public class PipeNetwork implements ICapabilitySerializable, GraphL this.refreshNode(edge.endPipe, this.world.getBlockState(edge.endPipe)); } - public boolean tryInsertItem(BlockPos startPipePos, BlockPos startInventory, ItemStack stack) { - return this.routeItem(startPipePos, startInventory, stack, speed -> new PipeItem(stack, speed)); + public boolean tryInsertItem(BlockPos startPipePos, BlockPos startInventory, ItemStack stack, boolean preventOversending) { + return this.routeItem(startPipePos, startInventory, stack, speed -> new PipeItem(stack, speed), preventOversending); } - public boolean routeItem(BlockPos startPipePos, BlockPos startInventory, ItemStack stack, Function itemSupplier) { + public boolean routeItem(BlockPos startPipePos, BlockPos startInventory, ItemStack stack, Function itemSupplier, boolean preventOversending) { if (!this.isNode(startPipePos)) return false; if (!this.world.isBlockLoaded(startPipePos)) @@ -133,7 +134,7 @@ public class PipeNetwork implements ICapabilitySerializable, GraphL this.startProfile("find_destination"); for (BlockPos pipePos : this.getOrderedDestinations(startPipePos)) { PipeTileEntity pipe = this.getPipe(pipePos); - BlockPos dest = pipe.getAvailableDestination(stack, false); + BlockPos dest = pipe.getAvailableDestination(stack, false, preventOversending); if (dest != null) { this.endProfile(); return this.routeItemToLocation(startPipePos, startInventory, pipe.getPos(), dest, itemSupplier); @@ -179,23 +180,23 @@ public class PipeNetwork implements ICapabilitySerializable, GraphL this.startProfile("get_network_items"); List info = new ArrayList<>(); for (BlockPos dest : this.getOrderedDestinations(node)) { + NetworkLocation location = new NetworkLocation(dest); PipeTileEntity pipe = this.getPipe(dest); + if (!pipe.canNetworkSee()) + continue; for (Direction dir : Direction.values()) { IItemHandler handler = pipe.getItemHandler(dir); if (handler == null) continue; - ListMultimap> items = null; for (int i = 0; i < handler.getSlots(); i++) { ItemStack found = handler.extractItem(i, Integer.MAX_VALUE, true); if (found.isEmpty()) continue; - if (items == null) - items = ArrayListMultimap.create(); - items.put(dir, Pair.of(i, found)); + location.addItem(dir, i, found); } - if (items != null) - info.add(new NetworkLocation(dest, items)); } + if (!location.isEmpty()) + info.add(location); } this.endProfile(); return info; @@ -299,6 +300,19 @@ public class PipeNetwork implements ICapabilitySerializable, GraphL return this.pipeItems.get(pos); } + public Stream getPipeItemsOnTheWay(BlockPos goalPipe) { + this.startProfile("get_pipe_items_on_the_way"); + Stream ret = this.pipeItems.values().stream().filter(i -> i.getDestPipe().equals(goalPipe)); + this.endProfile(); + return ret; + } + + public int getItemsOnTheWay(BlockPos goalPipe, ItemStack type) { + return this.getPipeItemsOnTheWay(goalPipe) + .filter(i -> i.stack.isItemEqual(type)) + .mapToInt(i -> i.stack.getCount()).sum(); + } + @Override public void edgeAdded(GraphEdgeChangeEvent e) { this.clearDestinationCache(e.getEdgeSource(), e.getEdgeTarget()); diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java b/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java index 5b9786a..2e6695d 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/PipeTileEntity.java @@ -124,7 +124,7 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide return this.getBlockState().get(PipeBlock.DIRECTIONS.get(dir)).isConnected(); } - public BlockPos getAvailableDestination(ItemStack stack, boolean internal) { + public BlockPos getAvailableDestination(ItemStack stack, boolean internal, boolean preventOversending) { if (!internal && this.streamModules().anyMatch(m -> !m.getRight().canAcceptItem(m.getLeft(), this, stack))) return null; for (Direction dir : Direction.values()) { @@ -133,8 +133,23 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide continue; if (!ItemHandlerHelper.insertItem(handler, stack, true).isEmpty()) continue; - if (this.streamModules().anyMatch(m -> !m.getRight().isAvailableDestination(m.getLeft(), this, stack, handler))) - continue; + if (preventOversending) { + // these are the items that are currently in the pipes, going to this pipe + int onTheWay = PipeNetwork.get(this.world).getItemsOnTheWay(this.pos, stack); + if (onTheWay > 0) { + ItemStack copy = stack.copy(); + copy.setCount(copy.getMaxStackSize()); + // totalSpace will be the amount of items that fit into the attached container + int totalSpace = 0; + for (int i = 0; i < handler.getSlots(); i++) { + ItemStack remain = handler.insertItem(i, copy, true); + totalSpace += copy.getMaxStackSize() - remain.getCount(); + } + // if the items on the way plus the items we're trying to move are too much, abort + if (onTheWay + stack.getCount() > totalSpace) + continue; + } + } return this.pos.offset(dir); } return null; @@ -166,6 +181,10 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide return Arrays.stream(Direction.values()).anyMatch(this::isConnectedInventory); } + public boolean canNetworkSee() { + return this.streamModules().allMatch(m -> m.getRight().canNetworkSee(m.getLeft(), this)); + } + private Stream> streamModules() { Stream.Builder> builder = Stream.builder(); for (int i = 0; i < this.modules.getSlots(); i++) { diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/modules/extraction/ExtractionModuleItem.java b/src/main/java/de/ellpeck/prettypipes/pipe/modules/extraction/ExtractionModuleItem.java index 797b72c..b8afe4d 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/modules/extraction/ExtractionModuleItem.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/modules/extraction/ExtractionModuleItem.java @@ -18,6 +18,7 @@ public class ExtractionModuleItem extends ModuleItem { private final int maxExtraction; private final int speed; + private final boolean preventOversending; public final int filterSlots; public ExtractionModuleItem(String name, ModuleTier tier) { @@ -25,6 +26,7 @@ public class ExtractionModuleItem extends ModuleItem { this.maxExtraction = tier.forTier(1, 8, 64); this.speed = tier.forTier(20, 15, 10); this.filterSlots = tier.forTier(3, 6, 9); + this.preventOversending = tier.forTier(false, false, true); } @Override @@ -44,7 +46,7 @@ public class ExtractionModuleItem extends ModuleItem { continue; if (!filter.isAllowed(stack)) continue; - if (network.tryInsertItem(tile.getPos(), tile.getPos().offset(dir), stack)) { + if (network.tryInsertItem(tile.getPos(), tile.getPos().offset(dir), stack, this.preventOversending)) { handler.extractItem(j, this.maxExtraction, false); return; } @@ -52,6 +54,11 @@ public class ExtractionModuleItem extends ModuleItem { } } + @Override + public boolean canNetworkSee(ItemStack module, PipeTileEntity tile) { + return false; + } + @Override public boolean canAcceptItem(ItemStack module, PipeTileEntity tile, ItemStack stack) { return false; diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java b/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java index 2c7fe62..94af0bd 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleItem.java @@ -23,6 +23,7 @@ import java.util.List; public class RetrievalModuleItem extends ModuleItem { private final int maxExtraction; private final int speed; + private final boolean preventOversending; public final int filterSlots; public RetrievalModuleItem(String name, ModuleTier tier) { @@ -30,6 +31,7 @@ public class RetrievalModuleItem extends ModuleItem { this.maxExtraction = tier.forTier(1, 8, 16); this.speed = tier.forTier(40, 20, 10); this.filterSlots = tier.forTier(3, 6, 9); + this.preventOversending = tier.forTier(false, true, true); } @Override @@ -48,7 +50,7 @@ public class RetrievalModuleItem extends ModuleItem { continue; ItemStack copy = filtered.copy(); copy.setCount(this.maxExtraction); - BlockPos dest = tile.getAvailableDestination(copy, true); + BlockPos dest = tile.getAvailableDestination(copy, true, this.preventOversending); if (dest == null) continue; // loop through locations to find a location that has the item @@ -71,6 +73,11 @@ public class RetrievalModuleItem extends ModuleItem { } } + @Override + public boolean canNetworkSee(ItemStack module, PipeTileEntity tile) { + return false; + } + @Override public boolean canAcceptItem(ItemStack module, PipeTileEntity tile, ItemStack stack) { return false; diff --git a/src/main/resources/assets/prettypipes/lang/en_us.json b/src/main/resources/assets/prettypipes/lang/en_us.json index baa21dc..ad5f2b5 100644 --- a/src/main/resources/assets/prettypipes/lang/en_us.json +++ b/src/main/resources/assets/prettypipes/lang/en_us.json @@ -15,11 +15,11 @@ "item.prettypipes.low_retrieval_module": "Low Retrieval Module", "item.prettypipes.medium_retrieval_module": "Medium Retrieval Module", "item.prettypipes.high_retrieval_module": "High Retrieval Module", - "info.prettypipes.extraction_module": "Pulls items from adjacent inventories\nFilters and pull rates vary by tier", + "info.prettypipes.extraction_module": "Pulls items from adjacent inventories\nFilters and pull rates vary by tier\nHigh tiers prevent over-sending", "info.prettypipes.filter_module": "Restricts flow from pipes into adjacent inventories\nFilter amount varies by tier", "info.prettypipes.speed_module": "Increases speed of items exiting adjacent inventories\nSpeed varies by tier", "info.prettypipes.low_priority_module": "Decreases the reception priority of adjacent inventories\nLower priority means items will prefer other inventories", - "info.prettypipes.retrieval_module": "Pulls items from other inventories in the network\nFilters and pull rates vary by tier", + "info.prettypipes.retrieval_module": "Pulls items from other inventories in the network\nFilters and pull rates vary by tier\nHigh tiers prevent over-sending", "block.prettypipes.pipe": "Pipe", "itemGroup.prettypipes": "Pretty Pipes", "container.prettypipes.pipe": "Pipe",