Refactor crafting logic to improve turtle inventory management and enhance error handling
This commit is contained in:
@@ -1467,14 +1467,18 @@ local function getMissingIngredients(recipe)
|
||||
end
|
||||
|
||||
--- Execute a craft via the networked turtle
|
||||
-- Uses chest-side pullItems/pushItems to move items to/from the turtle,
|
||||
-- since remote turtles may not expose the inventory API (list/pushItems).
|
||||
local function craftItem(recipeIdx)
|
||||
local recipe = CRAFTABLE[recipeIdx]
|
||||
if not recipe then return false, "Invalid recipe" end
|
||||
if not craftTurtleName then return false, "No turtle" end
|
||||
if not networkModem then return false, "No modem" end
|
||||
|
||||
local turtleInv = peripheral.wrap(craftTurtleName)
|
||||
if not turtleInv then return false, "Turtle offline" end
|
||||
-- Verify the turtle is still on the network
|
||||
if not peripheral.isPresent(craftTurtleName) then
|
||||
return false, "Turtle offline"
|
||||
end
|
||||
|
||||
activity.crafting = true
|
||||
needsRedraw = true
|
||||
@@ -1482,21 +1486,29 @@ local function craftItem(recipeIdx)
|
||||
|
||||
local chests = getChests()
|
||||
|
||||
-- 1. Clear turtle inventory (pull everything out)
|
||||
local tc = turtleInv.list()
|
||||
if tc then
|
||||
for slot, item in pairs(tc) do
|
||||
-- Helper: pull all 16 turtle slots into chests (chest-side)
|
||||
local function clearTurtle(knownItems)
|
||||
for slot = 1, 16 do
|
||||
for _, ch in ipairs(chests) do
|
||||
local n = turtleInv.pushItems(ch, slot)
|
||||
if n and n > 0 then
|
||||
adjustCache(item.name, ch, n)
|
||||
break
|
||||
local chest = peripheral.wrap(ch)
|
||||
if chest then
|
||||
local n = chest.pullItems(craftTurtleName, slot)
|
||||
if n and n > 0 then
|
||||
if knownItems and knownItems[slot] then
|
||||
adjustCache(knownItems[slot], ch, n)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 2. Push ingredients into correct grid slots
|
||||
-- 1. Clear turtle inventory (safety – turtle should be empty)
|
||||
clearTurtle(nil)
|
||||
|
||||
-- 2. Push ingredients into correct grid slots, track what we placed
|
||||
local placedItems = {} -- turtleSlot -> itemName
|
||||
for gridPos = 1, 9 do
|
||||
local itemName = recipe.grid[gridPos]
|
||||
if itemName then
|
||||
@@ -1511,6 +1523,7 @@ local function craftItem(recipeIdx)
|
||||
local n = chest.pushItems(craftTurtleName, slot, 1, turtleSlot)
|
||||
if n and n > 0 then
|
||||
adjustCache(itemName, source.chest, -n)
|
||||
placedItems[turtleSlot] = itemName
|
||||
placed = true
|
||||
break
|
||||
end
|
||||
@@ -1521,20 +1534,9 @@ local function craftItem(recipeIdx)
|
||||
end
|
||||
end
|
||||
if not placed then
|
||||
-- Cleanup: pull items back from turtle
|
||||
-- Cleanup: pull placed items back using tracked names
|
||||
print("[CRAFT] Missing ingredient, aborting")
|
||||
local cleanup = turtleInv.list()
|
||||
if cleanup then
|
||||
for s, it in pairs(cleanup) do
|
||||
for _, ch in ipairs(chests) do
|
||||
local n = turtleInv.pushItems(ch, s)
|
||||
if n and n > 0 then
|
||||
adjustCache(it.name, ch, n)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
clearTurtle(placedItems)
|
||||
activity.crafting = false
|
||||
needsRedraw = true
|
||||
smelterNeedsRedraw = true
|
||||
@@ -1565,14 +1567,23 @@ local function craftItem(recipeIdx)
|
||||
end
|
||||
|
||||
-- 5. Pull all items from turtle back to chests
|
||||
tc = turtleInv.list()
|
||||
if tc then
|
||||
for s, it in pairs(tc) do
|
||||
for _, ch in ipairs(chests) do
|
||||
local n = turtleInv.pushItems(ch, s)
|
||||
-- On success: slots contain crafted output (recipe.output)
|
||||
-- On failure/timeout: slots still have placed ingredients
|
||||
local resultItems = success and {} or placedItems
|
||||
if success then
|
||||
-- After a successful craft, only the output item remains
|
||||
for slot = 1, 16 do resultItems[slot] = recipe.output end
|
||||
end
|
||||
|
||||
for slot = 1, 16 do
|
||||
for _, ch in ipairs(chests) do
|
||||
local chest = peripheral.wrap(ch)
|
||||
if chest then
|
||||
local n = chest.pullItems(craftTurtleName, slot)
|
||||
if n and n > 0 then
|
||||
adjustCache(it.name, ch, n)
|
||||
print(string.format("[CRAFT] Result %s x%d -> %s", it.name, n, ch))
|
||||
local itemName = resultItems[slot] or recipe.output
|
||||
adjustCache(itemName, ch, n)
|
||||
print(string.format("[CRAFT] Result %s x%d -> %s", itemName, n, ch))
|
||||
break
|
||||
end
|
||||
end
|
||||
@@ -2540,10 +2551,13 @@ end
|
||||
-- Order
|
||||
-------------------------------------------------
|
||||
|
||||
local function orderItem(itemName, amount)
|
||||
local function orderItem(itemName, amount, dropperOverride)
|
||||
activity.dispensing = true
|
||||
needsRedraw = true
|
||||
|
||||
-- Use client-specified dropper if provided, otherwise master's default
|
||||
local dropperTarget = (dropperOverride and dropperOverride ~= "") and dropperOverride or DROPPER_NAME
|
||||
|
||||
local catalogue = cache.catalogue
|
||||
|
||||
if not catalogue[itemName] then
|
||||
@@ -2555,9 +2569,9 @@ local function orderItem(itemName, amount)
|
||||
return false
|
||||
end
|
||||
|
||||
local dropper = peripheral.wrap(DROPPER_NAME)
|
||||
local dropper = peripheral.wrap(dropperTarget)
|
||||
if not dropper then
|
||||
statusMessage = "Dropper offline!"
|
||||
statusMessage = "Dropper offline: " .. dropperTarget
|
||||
statusColor = colors.red
|
||||
statusTimer = 5
|
||||
activity.dispensing = false
|
||||
@@ -2572,7 +2586,7 @@ local function orderItem(itemName, amount)
|
||||
for slot, slotItem in pairs(chest.list()) do
|
||||
if slotItem.name == itemName then
|
||||
local toMove = math.min(remaining, slotItem.count)
|
||||
local moved = chest.pushItems(DROPPER_NAME, slot, toMove)
|
||||
local moved = chest.pushItems(dropperTarget, slot, toMove)
|
||||
if moved and moved > 0 then
|
||||
remaining = remaining - moved
|
||||
adjustCache(itemName, entry.chest, -moved)
|
||||
@@ -3121,7 +3135,7 @@ local function main()
|
||||
if channel == ORDER_CHANNEL and type(message) == "table" then
|
||||
if message.type == "order" and message.itemName and message.amount then
|
||||
print(string.format("[NET] Order: %s x%d", message.itemName, message.amount))
|
||||
local success = orderItem(message.itemName, message.amount)
|
||||
local success = orderItem(message.itemName, message.amount, message.dropperName)
|
||||
networkModem.transmit(replyChannel, ORDER_CHANNEL, {
|
||||
type = "order_result",
|
||||
success = success,
|
||||
|
||||
Reference in New Issue
Block a user