From cb01145787206999e96befcbfee6a13a6b1f6e5c Mon Sep 17 00:00:00 2001 From: Wesley Rogers Date: Fri, 28 Aug 2026 19:03:09 -0400 Subject: [PATCH 1/2] fix: deadlocked crafting with same slot for input and output Certain crafting stations, like the Depot from Create, will output items into the same slot that the item was inserted into. This resolves that issue by only pulling the expected item out of the inventory, rather than anything present in the expected slot. --- inv/device/Machine.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inv/device/Machine.lua b/inv/device/Machine.lua index 5b2a958..170c867 100644 --- a/inv/device/Machine.lua +++ b/inv/device/Machine.lua @@ -63,8 +63,8 @@ end -- Empties an output slot of the machine and counts any crafted items. function Machine:handleOutputSlot(item, virtSlot, realSlot) if item then - n = self.server.invManager:pullItemsFrom(item, self, realSlot) if self.recipe.output[virtSlot]:matches(item) then + local n = self.server.invManager:pullItemsFrom(item, self, realSlot) self.remaining[virtSlot] = self.remaining[virtSlot] - n if self.dest then local outItem = self.recipe.output[virtSlot]:copy() From 67d6dd901f2f1aefb08577ef1e286df22c363fa8 Mon Sep 17 00:00:00 2001 From: Wesley Rogers Date: Mon, 31 Aug 2026 23:42:01 -0400 Subject: [PATCH 2/2] fix: handle unconsumed items in output slots Certain recipes (I'm looking at you Gregtech) have tools that are not consumed as part of crafting. These get left behind in the crafting system and can cause the system to crash. This adds support for unconsumed (or transformed) items in crafting recipes. --- README.md | 5 +++++ inv/Item.lua | 5 +++++ inv/device/Machine.lua | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/README.md b/README.md index 592ca34..706ea1e 100644 --- a/README.md +++ b/README.md @@ -125,3 +125,8 @@ Custom crafting recipes must be specified in JSON files within the `config/recip } ] ``` + +Recipe inputs are consumed by default. Set `consumed` to `false` for a +reusable component. It is placed in the machine for crafting, then returned +to network storage after all outputs have been collected, before the machine +can start another recipe. diff --git a/inv/Item.lua b/inv/Item.lua index 3fdf526..e6d4f52 100644 --- a/inv/Item.lua +++ b/inv/Item.lua @@ -40,6 +40,11 @@ function Item:init(spec) if spec.count ~= nil then self.count = spec.count end + + -- bool: Whether this item is consumed by the recipe. This is meaningful + -- for recipe inputs; inputs are consumed by default for compatibility + -- with existing recipes. + self.consumed = spec.consumed ~= false end -- Returns true if the other item satisfies the criteria specified by this Item. diff --git a/inv/device/Machine.lua b/inv/device/Machine.lua index 170c867..8192554 100644 --- a/inv/device/Machine.lua +++ b/inv/device/Machine.lua @@ -77,9 +77,33 @@ function Machine:handleOutputSlot(item, virtSlot, realSlot) end end +-- Removes all input items which the recipe did not consume from the machine. +-- These are returned to network storage just like normal machine output. +function Machine:pullNonConsumedInputs() + if not self.recipe then + return true + end + for virtSlot, input in pairs(self.recipe.input) do + if not input.consumed then + local realSlot = self:mapSlot(virtSlot) + local item = self:getItemDetail(realSlot) + if item then + local moved = self.server.invManager:pullItemsFrom(item, self, realSlot) + if moved < item.count then + return false + end + end + end + end + return true +end + -- Empties all output slots of this machine, counting the crafted items -- and updating the machine state as necessary. function Machine:pullOutput() + if not self.recipe then + return + end for virtSlot, rem in pairs(self.remaining) do local realSlot = self:mapSlot(virtSlot) local item = self:getItemDetail(realSlot) @@ -90,6 +114,14 @@ function Machine:pullOutput() return end end + + -- A non-consumed input remains in the machine after crafting. Empty it + -- before making the machine available for another recipe. If storage is + -- temporarily unable to accept it, leave the machine busy and retry on + -- the next task update. + if not self:pullNonConsumedInputs() then + return + end self.recipe = nil end