-- Crafting Turtle Script -- Run this on the crafting turtle (turtle with crafting table). -- Listens for craft commands from the master via wired modem. -- Pulls ingredients from chests, crafts, and pushes results back. -- Requires a wired modem attached to the turtle. ------------------------------------------------- -- Default configuration (overridden by .turtle_config) ------------------------------------------------- -- Modem channels (must match inventoryManager.lua) local CRAFT_CHANNEL = 4203 -- master -> turtle (craft requests) local CRAFT_REPLY_CHANNEL = 4204 -- turtle -> master (craft results) -- Crafting grid slots in a turtle's 4x4 inventory local CRAFT_SLOTS = {1, 2, 3, 5, 6, 7, 9, 10, 11} ------------------------------------------------- -- Load config from file if present ------------------------------------------------- local TURTLE_CONFIG_FILE = ".turtle_config" local function loadConfig() if not fs.exists(TURTLE_CONFIG_FILE) then return end local f = fs.open(TURTLE_CONFIG_FILE, "r") local data = f.readAll() f.close() local ok, cfg = pcall(textutils.unserialiseJSON, data) if not ok or not cfg then print("[WARN] Failed to parse " .. TURTLE_CONFIG_FILE) return end if cfg.craftChannel then CRAFT_CHANNEL = cfg.craftChannel end if cfg.craftReplyChannel then CRAFT_REPLY_CHANNEL = cfg.craftReplyChannel end print("[CONFIG] Loaded from " .. TURTLE_CONFIG_FILE) end loadConfig() ------------------------------------------------- -- Setup ------------------------------------------------- print("=================================") print(" Crafting Turtle (Modem-Based)") 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 -- Find wired modem and get our network name local modem = nil local modemSide = nil local selfName = nil for _, side in ipairs({"top", "bottom", "left", "right", "front", "back"}) do if peripheral.getType(side) == "modem" then local m = peripheral.wrap(side) if m.getNameLocal then local name = m.getNameLocal() if name then modem = m modemSide = side selfName = name break end end end end if not modem or not selfName then print("[ERR] No wired modem found!") print(" Attach a wired modem to the turtle") print(" and connect it to the network.") return end print("[OK] Modem: " .. modemSide) print("[OK] Network name: " .. selfName) -- Open channel for receiving craft commands modem.open(CRAFT_CHANNEL) print("[OK] Listening on channel " .. CRAFT_CHANNEL) -- Wrap our own inventory peripheral for pullItems/pushItems local selfInv = peripheral.wrap(selfName) if not selfInv then print("[ERR] Cannot wrap own peripheral: " .. selfName) print(" Make sure the wired modem is connected.") return end print("[OK] Self-inventory peripheral ready") print("") print("Waiting for craft commands from master...") print("") ------------------------------------------------- -- Helpers ------------------------------------------------- local function clearInventory(chests) -- Push all items from all 16 turtle slots back to chests local cleared = 0 for slot = 1, 16 do if turtle.getItemCount(slot) > 0 then for _, chestName in ipairs(chests) do local ok, n = pcall(selfInv.pushItems, chestName, slot) if ok and n and n > 0 then cleared = cleared + n break end end end end return cleared 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 ------------------------------------------------- -- Craft command handler ------------------------------------------------- local function handleCraftCommand(message) -- message format from master: -- { -- type = "craft_request", -- recipeIdx = , -- output = , -- expected output item name -- slots = { [turtleSlot] = { chestName=..., chestSlot=..., itemName=..., count=... }, ... }, -- returnChests = { "chest_0", "chest_1", ... }, -- } local slots = message.slots local returnChests = message.returnChests local output = message.output or "unknown" if not slots or not returnChests then print("[CRAFT] Invalid command: missing slots or returnChests") return { type = "craft_result", success = false, error = "Invalid command" } end print(string.format("[CRAFT] Received craft request: %s", output)) -- 1. Clear turtle inventory (safety — should be empty) clearInventory(returnChests) -- 2. Pull ingredients from chests into crafting grid slots local placedItems = {} -- turtleSlot -> itemName local allPlaced = true for turtleSlotStr, info in pairs(slots) do local turtleSlot = tonumber(turtleSlotStr) local chestName = info.chestName local chestSlot = info.chestSlot local itemName = info.itemName local count = info.count or 1 print(string.format("[CRAFT] Pulling %s from %s slot %d -> turtle slot %d", itemName, chestName, chestSlot, turtleSlot)) local ok, n = pcall(selfInv.pullItems, chestName, chestSlot, count, turtleSlot) if ok and n and n > 0 then placedItems[turtleSlot] = itemName print(string.format("[CRAFT] Placed %s x%d in slot %d", itemName, n, turtleSlot)) else if not ok then print(string.format("[CRAFT] pullItems error: %s", tostring(n))) else print(string.format("[CRAFT] pullItems returned %s (expected %d)", tostring(n), count)) end allPlaced = false break end end if not allPlaced then -- Abort: push everything back print("[CRAFT] Failed to place all ingredients, aborting") local returnedItems = {} for slot, itemName in pairs(placedItems) do returnedItems[tostring(slot)] = itemName end clearInventory(returnChests) return { type = "craft_result", success = false, error = "Failed to pull ingredients", returnedItems = returnedItems, } end -- 3. Craft print("[CRAFT] Grid contents:") print(describeGrid()) print("[CRAFT] Attempting craft...") local craftOk, craftErr = turtle.craft() if not craftOk then print("[CRAFT] Failed: " .. tostring(craftErr)) -- Collect what's still in the grid for the master to track local returnedItems = {} for slot, itemName in pairs(placedItems) do returnedItems[tostring(slot)] = itemName end -- Push ingredients back clearInventory(returnChests) return { type = "craft_result", success = false, error = "Craft failed: " .. tostring(craftErr), returnedItems = returnedItems, } end -- 4. Collect results info local results = {} local totalOutput = 0 for slot = 1, 16 do local detail = turtle.getItemDetail(slot) if detail then table.insert(results, { name = detail.name, count = detail.count, slot = slot }) totalOutput = totalOutput + detail.count end end print("[CRAFT] Success! Output:") for _, r in ipairs(results) do print(string.format(" %s x%d", r.name, r.count)) end -- 5. Push results back to chests local pushed = clearInventory(returnChests) print(string.format("[CRAFT] Pushed %d items back to storage", pushed)) return { type = "craft_result", success = true, output = output, totalOutput = totalOutput, results = results, } end ------------------------------------------------- -- Main loop: listen for modem commands ------------------------------------------------- while true do local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message") if channel == CRAFT_CHANNEL and type(message) == "table" then if message.type == "craft_request" then local result = handleCraftCommand(message) -- Send result back to master modem.transmit(CRAFT_REPLY_CHANNEL, CRAFT_CHANNEL, result) elseif message.type == "ping" then -- Health check from master modem.transmit(CRAFT_REPLY_CHANNEL, CRAFT_CHANNEL, { type = "pong", name = selfName, }) end end end