diff --git a/src/main/java/de/ellpeck/prettypipes/misc/DirectionSelector.java b/src/main/java/de/ellpeck/prettypipes/misc/DirectionSelector.java index 82e3dcd..cebaadc 100644 --- a/src/main/java/de/ellpeck/prettypipes/misc/DirectionSelector.java +++ b/src/main/java/de/ellpeck/prettypipes/misc/DirectionSelector.java @@ -16,7 +16,7 @@ import net.minecraftforge.client.gui.widget.ExtendedButton; public class DirectionSelector { - public Direction direction; + private Direction direction; private boolean modified; private final ItemStack stack; @@ -35,7 +35,7 @@ public class DirectionSelector { @Override public Component getMessage() { var pipe = DirectionSelector.this.pipe; - var dir = DirectionSelector.this.direction; + var dir = DirectionSelector.this.getDirection(); MutableComponent msg = new TranslatableComponent("dir." + PrettyPipes.ID + "." + (dir != null ? dir.getName() : "none")); if (dir != null) { var blockName = pipe.getItemHandler(dir) != null ? pipe.getLevel().getBlockState(pipe.getBlockPos().relative(dir)).getBlock().getName() : null; @@ -48,7 +48,7 @@ public class DirectionSelector { } public void onButtonPacket() { - var dir = this.getValidDirection(this.direction != null ? this.direction : Direction.UP); + var dir = this.getValidDirection(this.getDirection()); if (this.direction != dir) { this.direction = dir; this.modified = true; @@ -61,8 +61,9 @@ public class DirectionSelector { this.modified = false; var tag = new CompoundTag(); - if (this.direction != null) - tag.putString("direction", this.direction.getName()); + var dir = this.getDirection(); + if (dir != null) + tag.putString("direction", dir.getName()); this.stack.getOrCreateTag().put("direction_selector", tag); } @@ -71,11 +72,13 @@ public class DirectionSelector { var tag = this.stack.getTag().getCompound("direction_selector"); this.direction = Direction.byName(tag.getString("direction")); } + } - // default to the first direction with a container - // don't mark as modified here because we don't want to save this automatic direction + public Direction getDirection() { + // default to the first direction with a container if ours is invalid or unset if (this.direction == null || !this.isDirectionValid(this.direction)) - this.direction = this.getValidDirection(Direction.UP); + return this.getValidDirection(this.direction); + return this.direction; } private boolean isDirectionValid(Direction dir) { @@ -84,10 +87,13 @@ public class DirectionSelector { return this.pipe.streamModules() .filter(p -> p.getLeft() != this.stack) .map(p -> p.getRight().getDirectionSelector(p.getLeft(), this.pipe)) + // don't use getDirection here because we don't want a stack overflow .noneMatch(p -> p != null && p.direction == dir); } private Direction getValidDirection(Direction dir) { + if (dir == null) + dir = Direction.UP; for (var i = 0; i < 6; i++) { dir = Direction.from3DDataValue(dir.get3DDataValue() + 1); if (this.isDirectionValid(dir)) diff --git a/src/main/java/de/ellpeck/prettypipes/misc/ItemFilter.java b/src/main/java/de/ellpeck/prettypipes/misc/ItemFilter.java index fb80392..ff90ac7 100644 --- a/src/main/java/de/ellpeck/prettypipes/misc/ItemFilter.java +++ b/src/main/java/de/ellpeck/prettypipes/misc/ItemFilter.java @@ -52,7 +52,7 @@ public class ItemFilter extends ItemStackHandler { List buttons = new ArrayList<>(); if (this.canModifyWhitelist) { var whitelistText = (Supplier) () -> "info." + PrettyPipes.ID + "." + (this.isWhitelist ? "whitelist" : "blacklist"); - buttons.add(new Button(x - 20 * (rightAligned ? 1 : 0), y, 20, 20, new TranslatableComponent(whitelistText.get()), button -> { + buttons.add(new Button(x - 20, y, 20, 20, new TranslatableComponent(whitelistText.get()), button -> { PacketButton.sendAndExecute(this.pipe.getBlockPos(), PacketButton.ButtonResult.FILTER_CHANGE, 0); button.setMessage(new TranslatableComponent(whitelistText.get())); }) { @@ -63,7 +63,7 @@ public class ItemFilter extends ItemStackHandler { }); } if (this.canPopulateFromInventories) { - buttons.add(new Button(x + 22 * (rightAligned ? -1 : 1), y, 20, 20, new TranslatableComponent("info." + PrettyPipes.ID + ".populate"), button -> PacketButton.sendAndExecute(this.pipe.getBlockPos(), PacketButton.ButtonResult.FILTER_CHANGE, 1)) { + buttons.add(new Button(x - 42, y, 20, 20, new TranslatableComponent("info." + PrettyPipes.ID + ".populate"), button -> PacketButton.sendAndExecute(this.pipe.getBlockPos(), PacketButton.ButtonResult.FILTER_CHANGE, 1)) { @Override public void renderToolTip(PoseStack matrix, int x, int y) { gui.renderTooltip(matrix, new TranslatableComponent("info." + PrettyPipes.ID + ".populate.description").withStyle(ChatFormatting.GRAY), x, y); diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlockEntity.java b/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlockEntity.java index 5ffe857..0316b62 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlockEntity.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/PipeBlockEntity.java @@ -186,63 +186,68 @@ public class PipeBlockEntity extends BlockEntity implements MenuProvider, IPipeC } public Pair getAvailableDestination(ItemStack stack, boolean force, boolean preventOversending) { - if (!this.canWork()) - return null; for (var dir : Direction.values()) { - var handler = this.getItemHandler(dir); - if (handler == null || !force && this.streamModules().anyMatch(m -> !m.getRight().canAcceptItem(m.getLeft(), this, stack, dir, handler))) - continue; - var remain = ItemHandlerHelper.insertItem(handler, stack, true); - // did we insert anything? - if (remain.getCount() == stack.getCount()) - continue; - var toInsert = stack.copy(); - toInsert.shrink(remain.getCount()); - // limit to the max amount that modules allow us to insert - var maxAmount = this.streamModules().mapToInt(m -> m.getRight().getMaxInsertionAmount(m.getLeft(), this, stack, handler)).min().orElse(Integer.MAX_VALUE); - if (maxAmount < toInsert.getCount()) - toInsert.setCount(maxAmount); - var offset = this.worldPosition.relative(dir); - if (preventOversending || maxAmount < Integer.MAX_VALUE) { - var network = PipeNetwork.get(this.level); - // these are the items that are currently in the pipes, going to this inventory - var onTheWay = network.getItemsOnTheWay(offset, null); - if (onTheWay > 0) { - if (maxAmount < Integer.MAX_VALUE) { - // these are the items on the way, limited to items of the same type as stack - var onTheWaySame = network.getItemsOnTheWay(offset, stack); - // check if any modules are limiting us - if (toInsert.getCount() + onTheWaySame > maxAmount) - toInsert.setCount(maxAmount - onTheWaySame); - } - // totalSpace will be the amount of items that fit into the attached container - var totalSpace = 0; - for (var i = 0; i < handler.getSlots(); i++) { - var copy = stack.copy(); - var maxStackSize = copy.getMaxStackSize(); - // if the container can store more than 64 items in this slot, then it's likely - // a barrel or similar, meaning that the slot limit matters more than the max stack size - var limit = handler.getSlotLimit(i); - if (limit > 64) - maxStackSize = limit; - copy.setCount(maxStackSize); - // this is an inaccurate check since it ignores the fact that some slots might - // have space for items of other types, but it'll be good enough for us - var left = handler.insertItem(i, copy, true); - totalSpace += maxStackSize - left.getCount(); - } - // if the items on the way plus the items we're trying to move are too much, reduce - if (onTheWay + toInsert.getCount() > totalSpace) - toInsert.setCount(totalSpace - onTheWay); - } - } - // we return the item that can actually be inserted, NOT the remainder! - if (!toInsert.isEmpty()) - return Pair.of(offset, toInsert); + var dest = this.getAvailableDestination(dir, stack, force, preventOversending); + if (!dest.isEmpty()) + return Pair.of(this.worldPosition.relative(dir), dest); } return null; } + public ItemStack getAvailableDestination(Direction direction, ItemStack stack, boolean force, boolean preventOversending) { + if (!this.canWork()) + return ItemStack.EMPTY; + var handler = this.getItemHandler(direction); + if (handler == null || !force && this.streamModules().anyMatch(m -> !m.getRight().canAcceptItem(m.getLeft(), this, stack, direction, handler))) + return ItemStack.EMPTY; + var remain = ItemHandlerHelper.insertItem(handler, stack, true); + // did we insert anything? + if (remain.getCount() == stack.getCount()) + return ItemStack.EMPTY; + var toInsert = stack.copy(); + toInsert.shrink(remain.getCount()); + // limit to the max amount that modules allow us to insert + var maxAmount = this.streamModules().mapToInt(m -> m.getRight().getMaxInsertionAmount(m.getLeft(), this, stack, handler)).min().orElse(Integer.MAX_VALUE); + if (maxAmount < toInsert.getCount()) + toInsert.setCount(maxAmount); + var offset = this.worldPosition.relative(direction); + if (preventOversending || maxAmount < Integer.MAX_VALUE) { + var network = PipeNetwork.get(this.level); + // these are the items that are currently in the pipes, going to this inventory + var onTheWay = network.getItemsOnTheWay(offset, null); + if (onTheWay > 0) { + if (maxAmount < Integer.MAX_VALUE) { + // these are the items on the way, limited to items of the same type as stack + var onTheWaySame = network.getItemsOnTheWay(offset, stack); + // check if any modules are limiting us + if (toInsert.getCount() + onTheWaySame > maxAmount) + toInsert.setCount(maxAmount - onTheWaySame); + } + // totalSpace will be the amount of items that fit into the attached container + var totalSpace = 0; + for (var i = 0; i < handler.getSlots(); i++) { + var copy = stack.copy(); + var maxStackSize = copy.getMaxStackSize(); + // if the container can store more than 64 items in this slot, then it's likely + // a barrel or similar, meaning that the slot limit matters more than the max stack size + var limit = handler.getSlotLimit(i); + if (limit > 64) + maxStackSize = limit; + copy.setCount(maxStackSize); + // this is an inaccurate check since it ignores the fact that some slots might + // have space for items of other types, but it'll be good enough for us + var left = handler.insertItem(i, copy, true); + totalSpace += maxStackSize - left.getCount(); + } + // if the items on the way plus the items we're trying to move are too much, reduce + if (onTheWay + toInsert.getCount() > totalSpace) + toInsert.setCount(totalSpace - onTheWay); + } + } + // we return the item that can actually be inserted, NOT the remainder! + return toInsert; + } + public int getPriority() { return this.priority; } 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 316fe47..26fa807 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 @@ -35,10 +35,10 @@ public class ExtractionModuleItem extends ModuleItem { if (!tile.shouldWorkNow(this.speed) || !tile.canWork()) return; var filter = this.getItemFilter(module, tile); - var dirSelector = this.getDirectionSelector(module, tile); - if (dirSelector.direction == null) + var dir = this.getDirectionSelector(module, tile).getDirection(); + if (dir == null) return; - var handler = tile.getItemHandler(dirSelector.direction); + var handler = tile.getItemHandler(dir); if (handler == null) return; @@ -49,7 +49,7 @@ public class ExtractionModuleItem extends ModuleItem { continue; if (!filter.isAllowed(stack)) continue; - var remain = network.routeItem(tile.getBlockPos(), tile.getBlockPos().relative(dirSelector.direction), stack, this.preventOversending); + var remain = network.routeItem(tile.getBlockPos(), tile.getBlockPos().relative(dir), stack, this.preventOversending); if (remain.getCount() != stack.getCount()) { handler.extractItem(j, stack.getCount() - remain.getCount(), false); return; @@ -59,12 +59,12 @@ public class ExtractionModuleItem extends ModuleItem { @Override public boolean canNetworkSee(ItemStack module, PipeBlockEntity tile, Direction direction, IItemHandler handler) { - return direction != this.getDirectionSelector(module, tile).direction; + return direction != this.getDirectionSelector(module, tile).getDirection(); } @Override public boolean canAcceptItem(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction, IItemHandler destination) { - return direction != this.getDirectionSelector(module, tile).direction; + return direction != this.getDirectionSelector(module, tile).getDirection(); } @Override diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/modules/insertion/FilterModuleContainer.java b/src/main/java/de/ellpeck/prettypipes/pipe/modules/insertion/FilterModuleContainer.java index 2b7d194..d512e02 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/modules/insertion/FilterModuleContainer.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/modules/insertion/FilterModuleContainer.java @@ -1,5 +1,7 @@ package de.ellpeck.prettypipes.pipe.modules.insertion; +import de.ellpeck.prettypipes.misc.DirectionSelector; +import de.ellpeck.prettypipes.misc.DirectionSelector.IDirectionContainer; import de.ellpeck.prettypipes.misc.ItemFilter; import de.ellpeck.prettypipes.misc.ItemFilter.IFilteredContainer; import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; @@ -9,9 +11,10 @@ import net.minecraft.world.inventory.MenuType; import javax.annotation.Nullable; -public class FilterModuleContainer extends AbstractPipeContainer implements IFilteredContainer { +public class FilterModuleContainer extends AbstractPipeContainer implements IFilteredContainer, IDirectionContainer { public ItemFilter filter; + public DirectionSelector directionSelector; public FilterModuleContainer(@Nullable MenuType type, int id, Player player, BlockPos pos, int moduleIndex) { super(type, id, player, pos, moduleIndex); @@ -26,6 +29,8 @@ public class FilterModuleContainer extends AbstractPipeContainer { @Override protected void init() { super.init(); - for (var widget : this.menu.filter.getButtons(this, this.leftPos + 7, this.topPos + 17 + 32 + 18 * Mth.ceil(this.menu.filter.getSlots() / 9F) + 2, false)) + var buttonsY = this.topPos + 17 + 32 + 18 * Mth.ceil(this.menu.filter.getSlots() / 9F) + 2; + for (var widget : this.menu.filter.getButtons(this, this.leftPos + this.imageWidth - 7, buttonsY, true)) this.addRenderableWidget(widget); + this.addRenderableWidget(this.menu.directionSelector.getButton(this.leftPos + 7, buttonsY)); } } diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/modules/insertion/FilterModuleItem.java b/src/main/java/de/ellpeck/prettypipes/pipe/modules/insertion/FilterModuleItem.java index 768fdf0..bd4eb12 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/modules/insertion/FilterModuleItem.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/modules/insertion/FilterModuleItem.java @@ -4,6 +4,7 @@ import de.ellpeck.prettypipes.Registry; import de.ellpeck.prettypipes.items.IModule; import de.ellpeck.prettypipes.items.ModuleItem; import de.ellpeck.prettypipes.items.ModuleTier; +import de.ellpeck.prettypipes.misc.DirectionSelector; import de.ellpeck.prettypipes.misc.ItemFilter; import de.ellpeck.prettypipes.pipe.PipeBlockEntity; import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; @@ -26,8 +27,7 @@ public class FilterModuleItem extends ModuleItem { @Override public boolean canAcceptItem(ItemStack module, PipeBlockEntity tile, ItemStack stack, Direction direction, IItemHandler destination) { - var filter = this.getItemFilter(module, tile); - return filter.isAllowed(stack); + return this.getDirectionSelector(module, tile).getDirection() != direction || this.getItemFilter(module, tile).isAllowed(stack); } @Override @@ -51,4 +51,9 @@ public class FilterModuleItem extends ModuleItem { filter.canPopulateFromInventories = this.canPopulateFromInventories; return filter; } + + @Override + public DirectionSelector getDirectionSelector(ItemStack module, PipeBlockEntity tile) { + return new DirectionSelector(module, tile); + } } diff --git a/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleContainer.java b/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleContainer.java index 0b04e1f..78d2022 100644 --- a/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleContainer.java +++ b/src/main/java/de/ellpeck/prettypipes/pipe/modules/retrieval/RetrievalModuleContainer.java @@ -1,18 +1,20 @@ package de.ellpeck.prettypipes.pipe.modules.retrieval; +import de.ellpeck.prettypipes.misc.DirectionSelector; +import de.ellpeck.prettypipes.misc.DirectionSelector.IDirectionContainer; import de.ellpeck.prettypipes.misc.ItemFilter; import de.ellpeck.prettypipes.misc.ItemFilter.IFilteredContainer; import de.ellpeck.prettypipes.pipe.containers.AbstractPipeContainer; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.Slot; import javax.annotation.Nullable; -public class RetrievalModuleContainer extends AbstractPipeContainer implements IFilteredContainer { +public class RetrievalModuleContainer extends AbstractPipeContainer implements IFilteredContainer, IDirectionContainer { public ItemFilter filter; + public DirectionSelector directionSelector; public RetrievalModuleContainer(@Nullable MenuType type, int id, Player player, BlockPos pos, int moduleIndex) { super(type, id, player, pos, moduleIndex); @@ -21,6 +23,8 @@ public class RetrievalModuleContainer extends AbstractPipeContainer