diff --git a/src/main/java/com/sk89q/craftbook/mechanics/pipe/Pipes.java b/src/main/java/com/sk89q/craftbook/mechanics/pipe/Pipes.java index 3b6c9f4aa..c64d1d0ab 100644 --- a/src/main/java/com/sk89q/craftbook/mechanics/pipe/Pipes.java +++ b/src/main/java/com/sk89q/craftbook/mechanics/pipe/Pipes.java @@ -47,6 +47,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Set; public class Pipes extends AbstractCraftBookMechanic { @@ -130,7 +131,17 @@ else if (SignUtil.isStandingSign(block.getRelative(face)) && face != BlockFace.U return null; } - private void searchNearbyPipes(Block block, Set visitedPipes, List items) { + /** True when the sign's first line marks the pull pass-through: 'pass', 'bypass' or 'b'. */ + private static boolean isPassThroughSign(ChangedSign sign) { + if (sign == null) + return false; + return switch (sign.getLine(0).trim().toLowerCase(Locale.ROOT)) { + case "pass", "bypass", "b" -> true; + default -> false; + }; + } + + private void searchNearbyPipes(Block block, Set visitedPipes, List items, boolean passThrough) { Deque searchQueue = new ArrayDeque<>(); searchQueue.addFirst(block); @@ -165,44 +176,48 @@ private void searchNearbyPipes(Block block, Set visitedPipes, List newItems = new ArrayList<>(); - - Block fac = bl.getRelative(p.getFacing()); - - PipePutEvent event = new PipePutEvent(bl, new ArrayList<>(filteredItems), fac); - Bukkit.getPluginManager().callEvent(event); - - if (!event.isCancelled()) { - if (InventoryUtil.doesBlockHaveInventory(fac)) { - InventoryHolder holder = (InventoryHolder) fac.getState(); - newItems.addAll(InventoryUtil.addItemsToInventory(holder, event.getItems().toArray(new ItemStack[event.getItems().size()]))); - } else if (fac.getType() == Material.JUKEBOX) { - Jukebox juke = (Jukebox) fac.getState(); - List its = new ArrayList<>(event.getItems()); - if (juke.getPlaying() == Material.AIR) { - Iterator iter = its.iterator(); - while (iter.hasNext()) { - ItemStack st = iter.next(); - if (!st.getType().isRecord()) continue; - juke.setPlaying(st.getType()); - juke.update(); - if (st.getAmount() > 1) - st.setAmount(st.getAmount() - 1); - else - iter.remove(); - break; + if(filteredItems.isEmpty()) { + // Unmatched items stop at a filtered output, unless this pull runs + // pass-through; then they continue searching for their own output. + if (!passThrough) + continue; + } else { + List newItems = new ArrayList<>(); + + Block fac = bl.getRelative(p.getFacing()); + + PipePutEvent event = new PipePutEvent(bl, new ArrayList<>(filteredItems), fac); + Bukkit.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + if (InventoryUtil.doesBlockHaveInventory(fac)) { + InventoryHolder holder = (InventoryHolder) fac.getState(); + newItems.addAll(InventoryUtil.addItemsToInventory(holder, event.getItems().toArray(new ItemStack[event.getItems().size()]))); + } else if (fac.getType() == Material.JUKEBOX) { + Jukebox juke = (Jukebox) fac.getState(); + List its = new ArrayList<>(event.getItems()); + if (juke.getPlaying() == Material.AIR) { + Iterator iter = its.iterator(); + while (iter.hasNext()) { + ItemStack st = iter.next(); + if (!st.getType().isRecord()) continue; + juke.setPlaying(st.getType()); + juke.update(); + if (st.getAmount() > 1) + st.setAmount(st.getAmount() - 1); + else + iter.remove(); + break; + } } + newItems.addAll(its); + } else { + newItems.addAll(event.getItems()); } - newItems.addAll(its); - } else { - newItems.addAll(event.getItems()); - } - items.removeAll(filteredItems); - items.addAll(newItems); + items.removeAll(filteredItems); + items.addAll(newItems); + } } } else if (blType == Material.DROPPER) { ChangedSign sign = getSignOnPiston(bl); @@ -224,20 +239,22 @@ private void searchNearbyPipes(Block block, Set visitedPipes, List filteredItems = new ArrayList<>(VerifyUtil.withoutNulls(ItemUtil.filterItems(items, pFilters, pExceptions))); - if(filteredItems.isEmpty()) - continue; - - Dropper dropper = (Dropper) bl.getState(); - List newItems = - new ArrayList<>(dropper.getInventory().addItem(filteredItems.toArray(new ItemStack[filteredItems.size()])).values()); + if(filteredItems.isEmpty()) { + if (!passThrough) + continue; + } else { + Dropper dropper = (Dropper) bl.getState(); + List newItems = + new ArrayList<>(dropper.getInventory().addItem(filteredItems.toArray(new ItemStack[filteredItems.size()])).values()); - for(ItemStack stack : dropper.getInventory().getContents()) - if(ItemUtil.isStackValid(stack)) - for(int i = 0; i < stack.getAmount(); i++) - dropper.drop(); + for(ItemStack stack : dropper.getInventory().getContents()) + if(ItemUtil.isStackValid(stack)) + for(int i = 0; i < stack.getAmount(); i++) + dropper.drop(); - items.removeAll(filteredItems); - items.addAll(newItems); + items.removeAll(filteredItems); + items.addAll(newItems); + } } if (!items.isEmpty()) { @@ -348,6 +365,10 @@ private void startPipe(Block block, List items, boolean request) { if (block.getType() == Material.STICKY_PISTON) { + // The pulling piston's own sign can mark the whole pull as pass-through, + // so its items flow past filtered outputs they don't match. + boolean passThrough = isPassThroughSign(sign); + List leftovers = new ArrayList<>(); Piston p = (Piston) block.getBlockData(); @@ -384,7 +405,7 @@ private void startPipe(Block block, List items, boolean request) { items.addAll(event.getItems()); if(!event.isCancelled()) { visitedPipes.add(fac.getLocation().toVector()); - searchNearbyPipes(block, visitedPipes, items); + searchNearbyPipes(block, visitedPipes, items, passThrough); } if (!items.isEmpty()) { @@ -415,7 +436,7 @@ private void startPipe(Block block, List items, boolean request) { items.addAll(event.getItems()); if(!event.isCancelled()) { visitedPipes.add(fac.getLocation().toVector()); - searchNearbyPipes(block, visitedPipes, items); + searchNearbyPipes(block, visitedPipes, items, passThrough); } if (!items.isEmpty()) { @@ -444,7 +465,7 @@ private void startPipe(Block block, List items, boolean request) { if (!event.isCancelled() && !items.isEmpty()) { visitedPipes.add(fac.getLocation().toVector()); - searchNearbyPipes(block, visitedPipes, items); + searchNearbyPipes(block, visitedPipes, items, passThrough); } leftovers.addAll(items); @@ -455,7 +476,7 @@ private void startPipe(Block block, List items, boolean request) { items.addAll(event.getItems()); if(!event.isCancelled() && !items.isEmpty()) { visitedPipes.add(fac.getLocation().toVector()); - searchNearbyPipes(block, visitedPipes, items); + searchNearbyPipes(block, visitedPipes, items, passThrough); } leftovers.addAll(items); }