prevent over-sending

This commit is contained in:
Ellpeck 2020-04-17 22:29:02 +02:00
parent 16dae95d50
commit a7bdd85139
9 changed files with 83 additions and 26 deletions

View file

@ -11,9 +11,9 @@ public interface IModule {
void tick(ItemStack module, PipeTileEntity tile); 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); int getPriority(ItemStack module, PipeTileEntity tile);

View file

@ -15,7 +15,6 @@ import net.minecraft.util.text.*;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.items.IItemHandler;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List; import java.util.List;
@ -48,12 +47,12 @@ public abstract class ModuleItem extends Item implements IModule {
} }
@Override @Override
public boolean canAcceptItem(ItemStack module, PipeTileEntity tile, ItemStack stack) { public boolean canNetworkSee(ItemStack module, PipeTileEntity tile) {
return true; return true;
} }
@Override @Override
public boolean isAvailableDestination(ItemStack module, PipeTileEntity tile, ItemStack stack, IItemHandler destination) { public boolean canAcceptItem(ItemStack module, PipeTileEntity tile, ItemStack stack) {
return true; return true;
} }

View file

@ -14,18 +14,29 @@ import java.util.Map;
public class NetworkLocation { public class NetworkLocation {
public final BlockPos pipePos; public final BlockPos pipePos;
public final ListMultimap<Direction, Pair<Integer, ItemStack>> items; private ListMultimap<Direction, Pair<Integer, ItemStack>> items;
public NetworkLocation(BlockPos pipePos, ListMultimap<Direction, Pair<Integer, ItemStack>> items) { public NetworkLocation(BlockPos pipePos) {
this.pipePos = 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<Direction, Integer> getStackLocation(ItemStack stack) { public Pair<Direction, Integer> getStackLocation(ItemStack stack) {
if (this.isEmpty())
return null;
for (Map.Entry<Direction, Pair<Integer, ItemStack>> entry : this.items.entries()) { for (Map.Entry<Direction, Pair<Integer, ItemStack>> entry : this.items.entries()) {
if (entry.getValue().getRight().isItemEqual(stack)) if (entry.getValue().getRight().isItemEqual(stack))
return Pair.of(entry.getKey(), entry.getValue().getLeft()); return Pair.of(entry.getKey(), entry.getValue().getLeft());
} }
return null; return null;
} }
public boolean isEmpty() {
return this.items == null || this.items.isEmpty();
}
} }

View file

@ -191,7 +191,7 @@ public class PipeItem implements INBTSerializable<CompoundNBT> {
return this.path.get(0); return this.path.get(0);
} }
private BlockPos getDestPipe() { public BlockPos getDestPipe() {
return this.path.get(this.path.size() - 1); return this.path.get(this.path.size() - 1);
} }

View file

@ -40,6 +40,7 @@ import javax.annotation.Nullable;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphListener<BlockPos, NetworkEdge> { public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphListener<BlockPos, NetworkEdge> {
@ -118,11 +119,11 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphL
this.refreshNode(edge.endPipe, this.world.getBlockState(edge.endPipe)); this.refreshNode(edge.endPipe, this.world.getBlockState(edge.endPipe));
} }
public boolean tryInsertItem(BlockPos startPipePos, BlockPos startInventory, ItemStack stack) { public boolean tryInsertItem(BlockPos startPipePos, BlockPos startInventory, ItemStack stack, boolean preventOversending) {
return this.routeItem(startPipePos, startInventory, stack, speed -> new PipeItem(stack, speed)); return this.routeItem(startPipePos, startInventory, stack, speed -> new PipeItem(stack, speed), preventOversending);
} }
public boolean routeItem(BlockPos startPipePos, BlockPos startInventory, ItemStack stack, Function<Float, PipeItem> itemSupplier) { public boolean routeItem(BlockPos startPipePos, BlockPos startInventory, ItemStack stack, Function<Float, PipeItem> itemSupplier, boolean preventOversending) {
if (!this.isNode(startPipePos)) if (!this.isNode(startPipePos))
return false; return false;
if (!this.world.isBlockLoaded(startPipePos)) if (!this.world.isBlockLoaded(startPipePos))
@ -133,7 +134,7 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphL
this.startProfile("find_destination"); this.startProfile("find_destination");
for (BlockPos pipePos : this.getOrderedDestinations(startPipePos)) { for (BlockPos pipePos : this.getOrderedDestinations(startPipePos)) {
PipeTileEntity pipe = this.getPipe(pipePos); PipeTileEntity pipe = this.getPipe(pipePos);
BlockPos dest = pipe.getAvailableDestination(stack, false); BlockPos dest = pipe.getAvailableDestination(stack, false, preventOversending);
if (dest != null) { if (dest != null) {
this.endProfile(); this.endProfile();
return this.routeItemToLocation(startPipePos, startInventory, pipe.getPos(), dest, itemSupplier); return this.routeItemToLocation(startPipePos, startInventory, pipe.getPos(), dest, itemSupplier);
@ -179,23 +180,23 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphL
this.startProfile("get_network_items"); this.startProfile("get_network_items");
List<NetworkLocation> info = new ArrayList<>(); List<NetworkLocation> info = new ArrayList<>();
for (BlockPos dest : this.getOrderedDestinations(node)) { for (BlockPos dest : this.getOrderedDestinations(node)) {
NetworkLocation location = new NetworkLocation(dest);
PipeTileEntity pipe = this.getPipe(dest); PipeTileEntity pipe = this.getPipe(dest);
if (!pipe.canNetworkSee())
continue;
for (Direction dir : Direction.values()) { for (Direction dir : Direction.values()) {
IItemHandler handler = pipe.getItemHandler(dir); IItemHandler handler = pipe.getItemHandler(dir);
if (handler == null) if (handler == null)
continue; continue;
ListMultimap<Direction, Pair<Integer, ItemStack>> items = null;
for (int i = 0; i < handler.getSlots(); i++) { for (int i = 0; i < handler.getSlots(); i++) {
ItemStack found = handler.extractItem(i, Integer.MAX_VALUE, true); ItemStack found = handler.extractItem(i, Integer.MAX_VALUE, true);
if (found.isEmpty()) if (found.isEmpty())
continue; continue;
if (items == null) location.addItem(dir, i, found);
items = ArrayListMultimap.create();
items.put(dir, Pair.of(i, found));
} }
if (items != null)
info.add(new NetworkLocation(dest, items));
} }
if (!location.isEmpty())
info.add(location);
} }
this.endProfile(); this.endProfile();
return info; return info;
@ -299,6 +300,19 @@ public class PipeNetwork implements ICapabilitySerializable<CompoundNBT>, GraphL
return this.pipeItems.get(pos); return this.pipeItems.get(pos);
} }
public Stream<PipeItem> getPipeItemsOnTheWay(BlockPos goalPipe) {
this.startProfile("get_pipe_items_on_the_way");
Stream<PipeItem> 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 @Override
public void edgeAdded(GraphEdgeChangeEvent<BlockPos, NetworkEdge> e) { public void edgeAdded(GraphEdgeChangeEvent<BlockPos, NetworkEdge> e) {
this.clearDestinationCache(e.getEdgeSource(), e.getEdgeTarget()); this.clearDestinationCache(e.getEdgeSource(), e.getEdgeTarget());

View file

@ -124,7 +124,7 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
return this.getBlockState().get(PipeBlock.DIRECTIONS.get(dir)).isConnected(); 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))) if (!internal && this.streamModules().anyMatch(m -> !m.getRight().canAcceptItem(m.getLeft(), this, stack)))
return null; return null;
for (Direction dir : Direction.values()) { for (Direction dir : Direction.values()) {
@ -133,8 +133,23 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
continue; continue;
if (!ItemHandlerHelper.insertItem(handler, stack, true).isEmpty()) if (!ItemHandlerHelper.insertItem(handler, stack, true).isEmpty())
continue; continue;
if (this.streamModules().anyMatch(m -> !m.getRight().isAvailableDestination(m.getLeft(), this, stack, handler))) if (preventOversending) {
continue; // 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 this.pos.offset(dir);
} }
return null; return null;
@ -166,6 +181,10 @@ public class PipeTileEntity extends TileEntity implements INamedContainerProvide
return Arrays.stream(Direction.values()).anyMatch(this::isConnectedInventory); return Arrays.stream(Direction.values()).anyMatch(this::isConnectedInventory);
} }
public boolean canNetworkSee() {
return this.streamModules().allMatch(m -> m.getRight().canNetworkSee(m.getLeft(), this));
}
private Stream<Pair<ItemStack, IModule>> streamModules() { private Stream<Pair<ItemStack, IModule>> streamModules() {
Stream.Builder<Pair<ItemStack, IModule>> builder = Stream.builder(); Stream.Builder<Pair<ItemStack, IModule>> builder = Stream.builder();
for (int i = 0; i < this.modules.getSlots(); i++) { for (int i = 0; i < this.modules.getSlots(); i++) {

View file

@ -18,6 +18,7 @@ public class ExtractionModuleItem extends ModuleItem {
private final int maxExtraction; private final int maxExtraction;
private final int speed; private final int speed;
private final boolean preventOversending;
public final int filterSlots; public final int filterSlots;
public ExtractionModuleItem(String name, ModuleTier tier) { public ExtractionModuleItem(String name, ModuleTier tier) {
@ -25,6 +26,7 @@ public class ExtractionModuleItem extends ModuleItem {
this.maxExtraction = tier.forTier(1, 8, 64); this.maxExtraction = tier.forTier(1, 8, 64);
this.speed = tier.forTier(20, 15, 10); this.speed = tier.forTier(20, 15, 10);
this.filterSlots = tier.forTier(3, 6, 9); this.filterSlots = tier.forTier(3, 6, 9);
this.preventOversending = tier.forTier(false, false, true);
} }
@Override @Override
@ -44,7 +46,7 @@ public class ExtractionModuleItem extends ModuleItem {
continue; continue;
if (!filter.isAllowed(stack)) if (!filter.isAllowed(stack))
continue; 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); handler.extractItem(j, this.maxExtraction, false);
return; return;
} }
@ -52,6 +54,11 @@ public class ExtractionModuleItem extends ModuleItem {
} }
} }
@Override
public boolean canNetworkSee(ItemStack module, PipeTileEntity tile) {
return false;
}
@Override @Override
public boolean canAcceptItem(ItemStack module, PipeTileEntity tile, ItemStack stack) { public boolean canAcceptItem(ItemStack module, PipeTileEntity tile, ItemStack stack) {
return false; return false;

View file

@ -23,6 +23,7 @@ import java.util.List;
public class RetrievalModuleItem extends ModuleItem { public class RetrievalModuleItem extends ModuleItem {
private final int maxExtraction; private final int maxExtraction;
private final int speed; private final int speed;
private final boolean preventOversending;
public final int filterSlots; public final int filterSlots;
public RetrievalModuleItem(String name, ModuleTier tier) { public RetrievalModuleItem(String name, ModuleTier tier) {
@ -30,6 +31,7 @@ public class RetrievalModuleItem extends ModuleItem {
this.maxExtraction = tier.forTier(1, 8, 16); this.maxExtraction = tier.forTier(1, 8, 16);
this.speed = tier.forTier(40, 20, 10); this.speed = tier.forTier(40, 20, 10);
this.filterSlots = tier.forTier(3, 6, 9); this.filterSlots = tier.forTier(3, 6, 9);
this.preventOversending = tier.forTier(false, true, true);
} }
@Override @Override
@ -48,7 +50,7 @@ public class RetrievalModuleItem extends ModuleItem {
continue; continue;
ItemStack copy = filtered.copy(); ItemStack copy = filtered.copy();
copy.setCount(this.maxExtraction); copy.setCount(this.maxExtraction);
BlockPos dest = tile.getAvailableDestination(copy, true); BlockPos dest = tile.getAvailableDestination(copy, true, this.preventOversending);
if (dest == null) if (dest == null)
continue; continue;
// loop through locations to find a location that has the item // 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 @Override
public boolean canAcceptItem(ItemStack module, PipeTileEntity tile, ItemStack stack) { public boolean canAcceptItem(ItemStack module, PipeTileEntity tile, ItemStack stack) {
return false; return false;

View file

@ -15,11 +15,11 @@
"item.prettypipes.low_retrieval_module": "Low Retrieval Module", "item.prettypipes.low_retrieval_module": "Low Retrieval Module",
"item.prettypipes.medium_retrieval_module": "Medium Retrieval Module", "item.prettypipes.medium_retrieval_module": "Medium Retrieval Module",
"item.prettypipes.high_retrieval_module": "High 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.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.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.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", "block.prettypipes.pipe": "Pipe",
"itemGroup.prettypipes": "Pretty Pipes", "itemGroup.prettypipes": "Pretty Pipes",
"container.prettypipes.pipe": "Pipe", "container.prettypipes.pipe": "Pipe",