Refactor crafting logic to enable auto-crafting by the turtle and improve item retrieval process

This commit is contained in:
MayaTheShy
2026-03-16 00:37:32 -04:00
parent efa79e56cb
commit 473570f398
2 changed files with 111 additions and 59 deletions

View File

@@ -1,45 +1,88 @@
-- Crafting Turtle Script
-- Run this on the crafting turtle (turtle with crafting table).
-- Listens for craft commands from the master computer via wired modem.
-- Polls its own crafting grid slots and auto-crafts when items appear.
-- No modem required — works via the wired network inventory access.
local CRAFT_CHANNEL = 4203
local CRAFT_REPLY_CHANNEL = 4204
-- Crafting grid slots in a turtle's 4x4 inventory
local CRAFT_SLOTS = {1, 2, 3, 5, 6, 7, 9, 10, 11}
-- Find modem (wired or wireless)
local modem = peripheral.find("modem")
if not modem then
print("[ERR] No modem found! Attach a wired modem.")
-- How long to wait after detecting items before crafting,
-- giving the master time to finish placing all ingredients.
local SETTLE_DELAY = 1.0
-- Polling interval (seconds)
local POLL_INTERVAL = 0.5
print("=================================")
print(" Crafting Turtle (Auto-Craft)")
print("=================================")
print("")
-- Verify this is a crafting turtle
if not turtle or not turtle.craft then
print("[ERR] No turtle.craft() available!")
print(" This must be a Crafting Turtle.")
return
end
modem.open(CRAFT_CHANNEL)
print("Polling crafting slots for items...")
print("Ready. Items placed in grid will be auto-crafted.")
print("")
print("=================================")
print(" Crafting Turtle (Listener)")
print("=================================")
print("")
print("Listening on channel " .. CRAFT_CHANNEL)
print("Ready for craft commands from master.")
print("")
local function hasCraftingItems()
for _, slot in ipairs(CRAFT_SLOTS) do
if turtle.getItemCount(slot) > 0 then
return true
end
end
return false
end
local function describeGrid()
local parts = {}
for _, slot in ipairs(CRAFT_SLOTS) do
local detail = turtle.getItemDetail(slot)
if detail then
table.insert(parts, string.format(" slot %d: %s x%d", slot, detail.name, detail.count))
end
end
return table.concat(parts, "\n")
end
while true do
local event, side, channel, replyChannel, message = os.pullEvent("modem_message")
if channel == CRAFT_CHANNEL and type(message) == "table" and message.type == "craft" then
local count = message.count or 1
print(string.format("[CRAFT] Received craft request (count=%d)", count))
if hasCraftingItems() then
-- Wait for the master to finish placing all ingredients
print("[CRAFT] Items detected in grid, waiting " .. SETTLE_DELAY .. "s...")
sleep(SETTLE_DELAY)
local ok, err = turtle.craft(count)
-- Check again — items might have been pulled back (abort)
if hasCraftingItems() then
print("[CRAFT] Grid contents:")
print(describeGrid())
print("[CRAFT] Attempting craft...")
if ok then
print("[CRAFT] Success!")
local ok, err = turtle.craft()
if ok then
-- Show what was crafted
local results = {}
for slot = 1, 16 do
local detail = turtle.getItemDetail(slot)
if detail then
table.insert(results, string.format("%s x%d", detail.name, detail.count))
end
end
print("[CRAFT] Success! Result: " .. table.concat(results, ", "))
else
print("[CRAFT] Failed: " .. tostring(err))
end
-- Wait for master to pull results before polling again
sleep(2)
else
print("[CRAFT] Failed: " .. tostring(err))
print("[CRAFT] Items removed before crafting (aborted by master)")
end
modem.transmit(replyChannel, CRAFT_CHANNEL, {
type = "craft_result",
success = ok,
error = not ok and tostring(err) or nil,
})
end
sleep(POLL_INTERVAL)
end

View File

@@ -1545,45 +1545,54 @@ local function craftItem(recipeIdx)
end
end
-- 3. Signal turtle to craft
networkModem.transmit(CRAFT_CHANNEL, CRAFT_REPLY_CHANNEL, { type = "craft", count = 1 })
print(string.format("[CRAFT] Sent craft request: %s", recipe.output))
-- 3. Wait for turtle to auto-craft
-- The turtle polls its crafting slots and crafts automatically.
-- Give it time: SETTLE_DELAY (1s) + craft time + margin.
print(string.format("[CRAFT] Ingredients placed for %s, waiting for turtle...", recipe.output))
sleep(3)
-- 4. Wait for reply with timeout
local timer = os.startTimer(5)
local success = false
local errMsg = "Turtle timeout"
while true do
local event = {os.pullEvent()}
if event[1] == "modem_message" and event[3] == CRAFT_REPLY_CHANNEL
and type(event[5]) == "table" and event[5].type == "craft_result" then
os.cancelTimer(timer)
success = event[5].success
errMsg = event[5].error
break
elseif event[1] == "timer" and event[2] == timer then
break
-- 4. Pull all items from turtle back to chests
-- Strategy: first check crafting grid slots. If they're empty,
-- the turtle consumed the ingredients = craft succeeded.
-- Then pull everything remaining (output items or leftover ingredients).
local ingredientsRemain = false
-- Check crafting grid slots first
for gridPos = 1, 9 do
if placedItems[GRID_TO_SLOT[gridPos]] then
for _, ch in ipairs(chests) do
local chest = peripheral.wrap(ch)
if chest then
local n = chest.pullItems(craftTurtleName, GRID_TO_SLOT[gridPos])
if n and n > 0 then
-- Ingredient still there = craft failed for this slot
ingredientsRemain = true
local itemName = placedItems[GRID_TO_SLOT[gridPos]]
adjustCache(itemName, ch, n)
print(string.format("[CRAFT] Ingredient returned: %s x%d from slot %d", itemName, n, GRID_TO_SLOT[gridPos]))
break
end
end
end
end
end
-- 5. Pull all items from turtle back to chests
-- 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
local success = not ingredientsRemain
local pulledOutput = 0
-- Pull everything remaining (output on success, or stray items)
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
local itemName = resultItems[slot] or recipe.output
-- On success these are crafted output; on failure, leftovers
local itemName = success and recipe.output or (placedItems[slot] or recipe.output)
adjustCache(itemName, ch, n)
print(string.format("[CRAFT] Result %s x%d -> %s", itemName, n, ch))
if success then pulledOutput = pulledOutput + n end
print(string.format("[CRAFT] Pulled %s x%d from slot %d -> %s", itemName, n, slot, ch))
break
end
end
@@ -1596,11 +1605,11 @@ local function craftItem(recipeIdx)
if success then
local short = recipe.output:gsub("^minecraft:", ""):gsub("_", " ")
print(string.format("[CRAFT] OK: %s x%d", short, recipe.count))
print(string.format("[CRAFT] OK: %s x%d", short, pulledOutput))
return true
else
print(string.format("[CRAFT] Failed: %s", errMsg or "unknown"))
return false, errMsg or "Craft failed"
print("[CRAFT] Failed: ingredients were not consumed by turtle")
return false, "Craft failed"
end
end