-- Turtle Logistics System v4.1 (Optimized) -- Supports direct container-to-container transfers -- Config saved in config.cfg local configFile = "config.cfg" local tasks = {} local turtleName = "turtle_" .. os.getComputerID() -- Default name local directions = { up = "up", down = "down", forward = "forward" } -- Load configuration local function loadConfig() if fs.exists(configFile) then local file = fs.open(configFile, "r") local data = file.readAll() file.close() tasks = textutils.unserialize(data) or {} end -- Load turtle name if set if fs.exists("turtle_name.cfg") then local nameFile = fs.open("turtle_name.cfg", "r") turtleName = nameFile.readAll() nameFile.close() end end -- Save configuration local function saveConfig() local file = fs.open(configFile, "w") file.write(textutils.serialize(tasks)) file.close() end -- Save turtle name local function saveTurtleName() local nameFile = fs.open("turtle_name.cfg", "w") nameFile.write(turtleName) nameFile.close() end -- Check if value is a direction local function isDirection(value) return directions[value] ~= nil end -- Parse item requirements from string local function parseItemRequirements(input) local requirements = {} -- Check if input is a JSON-like table if input:sub(1,1) == "{" and input:sub(-1) == "}" then -- Remove curly braces local content = input:sub(2, -2) -- Split key-value pairs for pair in content:gmatch("[^,]+") do local key, value = pair:match("[\"']?(.-)[\"']?%s*:%s*(%d+)") if key and value then requirements[key] = tonumber(value) end end else -- Simple format: item:minCount for item in input:gmatch("%S+") do local name, minCount = item:match("([^:]+):(%d+)") if name and minCount then requirements[name] = tonumber(minCount) else requirements[item] = 0 -- No minimum requirement end end end return requirements end -- Get container item list using container.list() local function getContainerItems(containerName) local container = peripheral.wrap(containerName) if not container then return nil end local items = {} local containerList = container.list() for slot, item in pairs(containerList) do items[slot] = { count = item.count, name = item.name } end return items end -- Execute item transfer with min count requirements (Optimized) local function executeTransfer(task) -- Case 1: Both source and destination are containers if not isDirection(task.source) and not isDirection(task.destination) then local source = peripheral.wrap(task.source) local destination = peripheral.wrap(task.destination) if not source or not destination then if not source then print("Error: Source container not found: "..task.source) end if not destination then print("Error: Destination container not found: "..task.destination) end return false end -- Get destination name for pushItems local destName = peripheral.getName(destination) -- Check min count requirements if task.items then local sourceItems = getContainerItems(task.source) local itemCounts = {} for slot, item in pairs(sourceItems) do if task.items[item.name] then itemCounts[item.name] = (itemCounts[item.name] or 0) + item.count end end for itemName, minCount in pairs(task.items) do if minCount > 0 and (itemCounts[itemName] or 0) < minCount then print("Not enough "..itemName.." ("..(itemCounts[itemName] or 0).." < "..minCount..")") return false end end end -- Transfer items directly local sourceItems = getContainerItems(task.source) local totalTransferred = 0 for slot, item in pairs(sourceItems) do local shouldTransfer = not task.items or (task.items[item.name] ~= nil) if shouldTransfer then local count = item.count if task.items and task.items[item.name] then count = math.min(count, task.items[item.name]) end local transferred = source.pushItems(destName, slot, count) totalTransferred = totalTransferred + transferred end end return totalTransferred > 0 -- Case 2: Source is direction, destination is container elseif isDirection(task.source) and not isDirection(task.destination) then local destination = peripheral.wrap(task.destination) if not destination then print("Error: Destination container not found: "..task.destination) return false end -- Suck items from direction (limited to 16 slots) local sucked = false local suckFunc = turtle.suck if task.source == "up" then suckFunc = turtle.suckUp elseif task.source == "down" then suckFunc = turtle.suckDown end for i = 1, 16 do if suckFunc() then sucked = true else break end end if not sucked then return false end -- Push items to destination container local pushed = false for slot = 1, 16 do if turtle.getItemCount(slot) > 0 then if destination.pullItems(turtleName, slot) > 0 then pushed = true end end end return pushed -- Case 3: Source is container, destination is direction elseif not isDirection(task.source) and isDirection(task.destination) then local source = peripheral.wrap(task.source) if not source then print("Error: Source container not found: "..task.source) return false end -- Check min count requirements if task.items then local sourceItems = getContainerItems(task.source) local itemCounts = {} for slot, item in pairs(sourceItems) do if task.items[item.name] then itemCounts[item.name] = (itemCounts[item.name] or 0) + item.count end end for itemName, minCount in pairs(task.items) do if minCount > 0 and (itemCounts[itemName] or 0) < minCount then print("Not enough "..itemName.." ("..(itemCounts[itemName] or 0).." < "..minCount..")") return false end end end -- Pull items to turtle local sourceItems = getContainerItems(task.source) local pulled = false for slot, item in pairs(sourceItems) do local shouldTransfer = not task.items or (task.items[item.name] ~= nil) if shouldTransfer then local count = item.count if task.items and task.items[item.name] then count = math.min(count, task.items[item.name]) end if source.pushItems(turtleName, slot, count) > 0 then pulled = true end end end if not pulled then return false end -- Drop items to direction local dropFunc = turtle.drop if task.destination == "up" then dropFunc = turtle.dropUp elseif task.destination == "down" then dropFunc = turtle.dropDown end local dropped = false for slot = 1, 16 do if turtle.getItemCount(slot) > 0 then turtle.select(slot) if dropFunc() then dropped = true end end end return dropped -- Case 4: Both source and destination are directions else -- Suck items from source direction (limited to 16 slots) local suckFunc = turtle.suck if task.source == "up" then suckFunc = turtle.suckUp elseif task.source == "down" then suckFunc = turtle.suckDown end local sucked = false for i = 1, 16 do if suckFunc() then sucked = true else break end end if not sucked then return false end -- Drop items to destination direction local dropFunc = turtle.drop if task.destination == "up" then dropFunc = turtle.dropUp elseif task.destination == "down" then dropFunc = turtle.dropDown end local dropped = false for slot = 1, 16 do if turtle.getItemCount(slot) > 0 then turtle.select(slot) if dropFunc() then dropped = true end end end return dropped end end -- Main task loop (optimized) local function taskLoop() while true do for i, task in ipairs(tasks) do local success, err = pcall(executeTransfer, task) if not success then print("Task "..i.." error: "..err) end end os.sleep(0.5) -- Slightly longer sleep to reduce CPU usage end end -- Command processing local function processCommand(cmd) local args = {} for word in cmd:gmatch("%S+") do table.insert(args, word) end if #args == 0 then return end local command = args[1]:lower() if command == "add" and #args >= 3 then local newTask = { source = args[2], destination = args[3], items = nil } -- Parse item requirements if #args > 3 then local itemsInput = table.concat(args, " ", 4) newTask.items = parseItemRequirements(itemsInput) end table.insert(tasks, newTask) saveConfig() print("Task added: "..newTask.source.." -> "..newTask.destination) elseif command == "list" then if #tasks == 0 then print("No tasks configured") else for i, task in ipairs(tasks) do local itemInfo = "" if task.items then local itemsList = {} for name, minCount in pairs(task.items) do if minCount > 0 then table.insert(itemsList, name..":"..minCount) else table.insert(itemsList, name) end end itemInfo = " ("..table.concat(itemsList, ", ")..")" end print("["..i.."] "..task.source.." -> "..task.destination..itemInfo) end end elseif command == "remove" and #args >= 2 then local index = tonumber(args[2]) if index and tasks[index] then table.remove(tasks, index) saveConfig() print("Task "..index.." removed") else print("Invalid task index") end elseif command == "setname" and #args >= 2 then turtleName = args[2] saveTurtleName() print("Turtle name set to: "..turtleName) elseif command == "help" then print("Available commands:") print("add [items] - Add transfer task") print(" Items format:") print(" Simple: item1[:minCount] item2[:minCount] ...") print(" JSON-like: {\"item1\":minCount, \"item2\":minCount}") print("list - List all tasks") print("remove - Remove task") print("setname - Set turtle peripheral name") print("exit - Exit program") elseif command == "exit" then print("Exiting program") os.sleep(0.5) error("Program terminated", 0) end end -- Initialize loadConfig() print("Turtle Logistics System started. Type 'help' for commands.") print("Current turtle name: "..turtleName) -- Main loop parallel.waitForAll( function() while true do write("> ") local command = read() processCommand(command) end end, taskLoop )