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 5b2a958..8192554 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() @@ -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