Refactor crafting logic to enable auto-crafting by the turtle and improve item retrieval process
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user