From 227f477d660532f009fb6edbafd5cabfac96b4c1 Mon Sep 17 00:00:00 2001 From: Branan Riley Date: Mon, 18 May 2026 10:35:34 -0700 Subject: [PATCH] Refactor the extractor chip This is an attempt to make the extractor chip more consistent. It now extracts exactly 1 item type per update, dispatching up to 64 of that item to N destinations in the network. This fixes two bugs that I know of: * A minor exploit where sending partial stacks of many different item types could occur in one update, with no upper limit on how many individual items were sent. * An issue when the filter matches the input slot of certain machines, where the extractor would think it had successfully extracted from that input slot and no longer check the output slots for other extractable items. This leaves one strange behavior that might be intentional: * An extractor can dispatch multiple stacks of an item with a stack size less than 64, so long as each one goes to separate destinations. Fixes GTNewHorizons/GT-New-Horizons-Modpack#23624 --- .../transportation/ChipExtractor.scala | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main/scala/mrtjp/projectred/transportation/ChipExtractor.scala b/src/main/scala/mrtjp/projectred/transportation/ChipExtractor.scala index a59333062..84740e684 100644 --- a/src/main/scala/mrtjp/projectred/transportation/ChipExtractor.scala +++ b/src/main/scala/mrtjp/projectred/transportation/ChipExtractor.scala @@ -4,6 +4,7 @@ import mrtjp.core.inventory.InvWrapper import scala.collection.immutable.BitSet import scala.collection.mutable.ListBuffer +import util.control.Breaks._ class ChipExtractor extends RoutingChip with TChipFilter with TChipOrientation { private var remainingDelay = operationDelay @@ -35,20 +36,21 @@ class ChipExtractor extends RoutingChip with TChipFilter with TChipOrientation { stackSize != 0 && filt.hasItem(stackKey) != filterExclude ) { - var exclusions = BitSet.empty - var s = routeLayer.getLogisticPath(stackKey, exclusions, true) - if (s != null) { - var leftInRun = itemsToExtract + val maxRunSize = math.min(itemsToExtract, stackSize) + var leftInRun = maxRunSize + + breakable { + var exclusions = BitSet.empty + var s = routeLayer.getLogisticPath(stackKey, exclusions, true) while (s != null) { - var toExtract = math.min(leftInRun, stackSize) - toExtract = math.min(toExtract, stackKey.getMaxStackSize) + var toExtract = math.min(leftInRun, stackKey.getMaxStackSize) toExtract = math.min(toExtract, s.itemCount) - if (toExtract <= 0) return + if (toExtract <= 0) break val stack2 = stackKey.makeStack(inv.extractItem(stackKey, toExtract)) - if (stack2.stackSize <= 0) return + if (stack2.stackSize <= 0) break routeLayer.queueStackToSend( stack2, @@ -57,12 +59,15 @@ class ChipExtractor extends RoutingChip with TChipFilter with TChipOrientation { ) leftInRun -= stack2.stackSize - if (leftInRun <= 0) return + if (leftInRun <= 0) break exclusions += s.responder s = routeLayer.getLogisticPath(stackKey, exclusions, true) } } + + // Confirm that we actually extracted something. If not, we can still try the next item type + if (leftInRun < maxRunSize) return } } }