修复物品数量bug
This commit is contained in:
560
.history/Logistics/startup_20251022124027.lua
Normal file
560
.history/Logistics/startup_20251022124027.lua
Normal file
@@ -0,0 +1,560 @@
|
||||
-- Turtle Logistics System v4.2 (Fluid Support)
|
||||
-- Supports direct container-to-container transfers for items and fluids
|
||||
-- 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
|
||||
|
||||
-- Parse fluid requirements from string
|
||||
local function parseFluidRequirements(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: fluid:minAmount
|
||||
for fluid in input:gmatch("%S+") do
|
||||
local name, minAmount = fluid:match("([^:]+):(%d+)")
|
||||
if name and minAmount then
|
||||
requirements[name] = tonumber(minAmount)
|
||||
else
|
||||
requirements[fluid] = 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
|
||||
|
||||
-- Get fluid tank contents
|
||||
local function getFluidTanks(containerName)
|
||||
local container = peripheral.wrap(containerName)
|
||||
if not container then return nil end
|
||||
|
||||
if not container.tanks then
|
||||
print("Error: Container does not support fluids: "..containerName)
|
||||
return nil
|
||||
end
|
||||
|
||||
return container.tanks()
|
||||
end
|
||||
|
||||
-- Execute fluid transfer between containers
|
||||
local function executeFluidTransfer(task)
|
||||
-- Both source and destination must be containers for fluid transfers
|
||||
if isDirection(task.source) or isDirection(task.destination) then
|
||||
print("Error: Fluid transfers require container-to-container transfers")
|
||||
return false
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
if not source.tanks or not destination.tanks then
|
||||
print("Error: One or both containers do not support fluids")
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check min amount requirements
|
||||
if task.fluids then
|
||||
local sourceTanks = getFluidTanks(task.source)
|
||||
if not sourceTanks then return false end
|
||||
|
||||
local fluidAmounts = {}
|
||||
for slot, tank in pairs(sourceTanks) do
|
||||
if tank.name and task.fluids[tank.name] then
|
||||
fluidAmounts[tank.name] = (fluidAmounts[tank.name] or 0) + tank.amount
|
||||
end
|
||||
end
|
||||
|
||||
for fluidName, minAmount in pairs(task.fluids) do
|
||||
if minAmount > 0 and (fluidAmounts[fluidName] or 0) < minAmount then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Transfer fluids
|
||||
local sourceTanks = getFluidTanks(task.source)
|
||||
if not sourceTanks then return false end
|
||||
|
||||
local totalTransferred = 0
|
||||
|
||||
for slot, tank in pairs(sourceTanks) do
|
||||
local shouldTransfer = not task.fluids or (task.fluids[tank.name] ~= nil)
|
||||
|
||||
if shouldTransfer and tank.name and tank.amount > 0 then
|
||||
local amount = tank.amount
|
||||
if task.fluids and task.fluids[tank.name] then
|
||||
amount = math.min(amount, task.fluids[tank.name])
|
||||
end
|
||||
|
||||
-- Push fluid from source to destination
|
||||
local transferred = source.pushFluid(task.destination, amount, tank.name)
|
||||
totalTransferred = totalTransferred + transferred
|
||||
|
||||
-- 移除更新任务配置的代码
|
||||
-- 不要更新任务配置中的要求数量
|
||||
end
|
||||
end
|
||||
|
||||
return totalTransferred > 0
|
||||
end
|
||||
|
||||
-- Execute item transfer with min count requirements (Optimized)
|
||||
local function executeTransfer(task)
|
||||
-- Handle fluid transfers separately
|
||||
if task.type == "fluid" then
|
||||
return executeFluidTransfer(task)
|
||||
end
|
||||
|
||||
-- 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
|
||||
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
|
||||
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 = {
|
||||
type = "item",
|
||||
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("Item task added: "..newTask.source.." -> "..newTask.destination)
|
||||
|
||||
elseif command == "addfluid" and #args >= 3 then
|
||||
local newTask = {
|
||||
type = "fluid",
|
||||
source = args[2],
|
||||
destination = args[3],
|
||||
fluids = nil
|
||||
}
|
||||
|
||||
-- Parse fluid requirements
|
||||
if #args > 3 then
|
||||
local fluidsInput = table.concat(args, " ", 4)
|
||||
newTask.fluids = parseFluidRequirements(fluidsInput)
|
||||
end
|
||||
|
||||
table.insert(tasks, newTask)
|
||||
saveConfig()
|
||||
print("Fluid 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
|
||||
if task.type == "fluid" then
|
||||
local fluidInfo = ""
|
||||
if task.fluids then
|
||||
local fluidsList = {}
|
||||
for name, minAmount in pairs(task.fluids) do
|
||||
if minAmount > 0 then
|
||||
table.insert(fluidsList, name..":"..minAmount.."mB")
|
||||
else
|
||||
table.insert(fluidsList, name)
|
||||
end
|
||||
end
|
||||
fluidInfo = " ("..table.concat(fluidsList, ", ")..")"
|
||||
end
|
||||
print("[FLUID "..i.."] "..task.source.." -> "..task.destination..fluidInfo)
|
||||
else
|
||||
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("[ITEM "..i.."] "..task.source.." -> "..task.destination..itemInfo)
|
||||
end
|
||||
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 <source> <destination> [items] - Add item transfer task")
|
||||
print(" Items format:")
|
||||
print(" Simple: item1[:minCount] item2[:minCount] ...")
|
||||
print(" JSON-like: {\"item1\":minCount, \"item2\":minCount}")
|
||||
print("addfluid <source> <destination> [fluids] - Add fluid transfer task")
|
||||
print(" Fluids format:")
|
||||
print(" Simple: fluid1[:minAmount] fluid2[:minAmount] ...")
|
||||
print(" JSON-like: {\"fluid1\":minAmount, \"fluid2\":minAmount}")
|
||||
print("list - List all tasks")
|
||||
print("remove <index> - Remove task")
|
||||
print("setname <name> - 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 v4.2 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
|
||||
)
|
||||
571
.history/Logistics/startup_20251022124918.lua
Normal file
571
.history/Logistics/startup_20251022124918.lua
Normal file
@@ -0,0 +1,571 @@
|
||||
-- Turtle Logistics System v4.3 (Silent Mode & Full Transfer)
|
||||
-- Supports direct container-to-container transfers for items and fluids
|
||||
-- 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
|
||||
|
||||
-- Parse fluid requirements from string
|
||||
local function parseFluidRequirements(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: fluid:minAmount
|
||||
for fluid in input:gmatch("%S+") do
|
||||
local name, minAmount = fluid:match("([^:]+):(%d+)")
|
||||
if name and minAmount then
|
||||
requirements[name] = tonumber(minAmount)
|
||||
else
|
||||
requirements[fluid] = 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
|
||||
|
||||
-- Get fluid tank contents
|
||||
local function getFluidTanks(containerName)
|
||||
local container = peripheral.wrap(containerName)
|
||||
if not container then return nil end
|
||||
|
||||
if not container.tanks then
|
||||
print("Error: Container does not support fluids: "..containerName)
|
||||
return nil
|
||||
end
|
||||
|
||||
return container.tanks()
|
||||
end
|
||||
|
||||
-- Execute fluid transfer between containers
|
||||
local function executeFluidTransfer(task)
|
||||
-- Both source and destination must be containers for fluid transfers
|
||||
if isDirection(task.source) or isDirection(task.destination) then
|
||||
print("Error: Fluid transfers require container-to-container transfers")
|
||||
return false
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
if not source.tanks or not destination.tanks then
|
||||
print("Error: One or both containers do not support fluids")
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check min amount requirements (only if minAmount > 0)
|
||||
if task.fluids then
|
||||
local sourceTanks = getFluidTanks(task.source)
|
||||
if not sourceTanks then return false end
|
||||
|
||||
local fluidAmounts = {}
|
||||
for slot, tank in pairs(sourceTanks) do
|
||||
if tank.name and task.fluids[tank.name] then
|
||||
fluidAmounts[tank.name] = (fluidAmounts[tank.name] or 0) + tank.amount
|
||||
end
|
||||
end
|
||||
|
||||
for fluidName, minAmount in pairs(task.fluids) do
|
||||
-- Only check if minAmount > 0
|
||||
if minAmount > 0 and (fluidAmounts[fluidName] or 0) < minAmount then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Transfer fluids
|
||||
local sourceTanks = getFluidTanks(task.source)
|
||||
if not sourceTanks then return false end
|
||||
|
||||
local totalTransferred = 0
|
||||
|
||||
for slot, tank in pairs(sourceTanks) do
|
||||
local shouldTransfer = not task.fluids or (task.fluids[tank.name] ~= nil)
|
||||
|
||||
if shouldTransfer and tank.name and tank.amount > 0 then
|
||||
local amount = tank.amount
|
||||
if task.fluids and task.fluids[tank.name] then
|
||||
-- If minAmount is 0, transfer all available
|
||||
if task.fluids[tank.name] == 0 then
|
||||
amount = tank.amount
|
||||
else
|
||||
amount = math.min(amount, task.fluids[tank.name])
|
||||
end
|
||||
end
|
||||
|
||||
-- Push fluid from source to destination
|
||||
local transferred = source.pushFluid(task.destination, amount, tank.name)
|
||||
totalTransferred = totalTransferred + transferred
|
||||
end
|
||||
end
|
||||
|
||||
return totalTransferred > 0
|
||||
end
|
||||
|
||||
-- Execute item transfer with min count requirements (Optimized)
|
||||
local function executeTransfer(task)
|
||||
-- Handle fluid transfers separately
|
||||
if task.type == "fluid" then
|
||||
return executeFluidTransfer(task)
|
||||
end
|
||||
|
||||
-- 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 (only if minCount > 0)
|
||||
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
|
||||
-- Only check if minCount > 0
|
||||
if minCount > 0 and (itemCounts[itemName] or 0) < minCount then
|
||||
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
|
||||
-- If minCount is 0, transfer all available
|
||||
if task.items[item.name] == 0 then
|
||||
count = item.count
|
||||
else
|
||||
count = math.min(count, task.items[item.name])
|
||||
end
|
||||
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 (only if minCount > 0)
|
||||
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
|
||||
-- Only check if minCount > 0
|
||||
if minCount > 0 and (itemCounts[itemName] or 0) < minCount then
|
||||
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
|
||||
-- If minCount is 0, transfer all available
|
||||
if task.items[item.name] == 0 then
|
||||
count = item.count
|
||||
else
|
||||
count = math.min(count, task.items[item.name])
|
||||
end
|
||||
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 = {
|
||||
type = "item",
|
||||
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("Item task added: "..newTask.source.." -> "..newTask.destination)
|
||||
|
||||
elseif command == "addfluid" and #args >= 3 then
|
||||
local newTask = {
|
||||
type = "fluid",
|
||||
source = args[2],
|
||||
destination = args[3],
|
||||
fluids = nil
|
||||
}
|
||||
|
||||
-- Parse fluid requirements
|
||||
if #args > 3 then
|
||||
local fluidsInput = table.concat(args, " ", 4)
|
||||
newTask.fluids = parseFluidRequirements(fluidsInput)
|
||||
end
|
||||
|
||||
table.insert(tasks, newTask)
|
||||
saveConfig()
|
||||
print("Fluid 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
|
||||
if task.type == "fluid" then
|
||||
local fluidInfo = ""
|
||||
if task.fluids then
|
||||
local fluidsList = {}
|
||||
for name, minAmount in pairs(task.fluids) do
|
||||
if minAmount > 0 then
|
||||
table.insert(fluidsList, name..":"..minAmount.."mB")
|
||||
else
|
||||
table.insert(fluidsList, name)
|
||||
end
|
||||
end
|
||||
fluidInfo = " ("..table.concat(fluidsList, ", ")..")"
|
||||
end
|
||||
print("[FLUID "..i.."] "..task.source.." -> "..task.destination..fluidInfo)
|
||||
else
|
||||
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("[ITEM "..i.."] "..task.source.." -> "..task.destination..itemInfo)
|
||||
end
|
||||
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 <source> <destination> [items] - Add item transfer task")
|
||||
print(" Items format:")
|
||||
print(" Simple: item1[:minCount] item2[:minCount] ...")
|
||||
print(" JSON-like: {\"item1\":minCount, \"item2\":minCount}")
|
||||
print(" Set minCount to 0 to transfer all available items")
|
||||
print("addfluid <source> <destination> [fluids] - Add fluid transfer task")
|
||||
print(" Fluids format:")
|
||||
print(" Simple: fluid1[:minAmount] fluid2[:minAmount] ...")
|
||||
print(" JSON-like: {\"fluid1\":minAmount, \"fluid2\":minAmount}")
|
||||
print(" Set minAmount to 0 to transfer all available fluid")
|
||||
print("list - List all tasks")
|
||||
print("remove <index> - Remove task")
|
||||
print("setname <name> - 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 v4.3 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
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
-- Turtle Logistics System v4.2 (Fluid Support)
|
||||
-- Turtle Logistics System v4.3 (Silent Mode & Full Transfer)
|
||||
-- Supports direct container-to-container transfers for items and fluids
|
||||
-- Config saved in config.cfg
|
||||
|
||||
@@ -160,7 +160,7 @@ local function executeFluidTransfer(task)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check min amount requirements
|
||||
-- Check min amount requirements (only if minAmount > 0)
|
||||
if task.fluids then
|
||||
local sourceTanks = getFluidTanks(task.source)
|
||||
if not sourceTanks then return false end
|
||||
@@ -173,8 +173,8 @@ local function executeFluidTransfer(task)
|
||||
end
|
||||
|
||||
for fluidName, minAmount in pairs(task.fluids) do
|
||||
-- Only check if minAmount > 0
|
||||
if minAmount > 0 and (fluidAmounts[fluidName] or 0) < minAmount then
|
||||
print("Not enough "..fluidName.." ("..(fluidAmounts[fluidName] or 0).." < "..minAmount..")")
|
||||
return false
|
||||
end
|
||||
end
|
||||
@@ -192,17 +192,17 @@ local function executeFluidTransfer(task)
|
||||
if shouldTransfer and tank.name and tank.amount > 0 then
|
||||
local amount = tank.amount
|
||||
if task.fluids and task.fluids[tank.name] then
|
||||
amount = math.min(amount, task.fluids[tank.name])
|
||||
-- If minAmount is 0, transfer all available
|
||||
if task.fluids[tank.name] == 0 then
|
||||
amount = tank.amount
|
||||
else
|
||||
amount = math.min(amount, task.fluids[tank.name])
|
||||
end
|
||||
end
|
||||
|
||||
-- Push fluid from source to destination
|
||||
local transferred = source.pushFluid(task.destination, task.concat, task.name)
|
||||
local transferred = source.pushFluid(task.destination, amount, tank.name)
|
||||
totalTransferred = totalTransferred + transferred
|
||||
|
||||
-- Update transferred amount in requirements
|
||||
if task.fluids and task.fluids[tank.name] then
|
||||
task.fluids[tank.name] = task.fluids[tank.name] - transferred
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -230,7 +230,7 @@ local function executeTransfer(task)
|
||||
-- Get destination name for pushItems
|
||||
local destName = peripheral.getName(destination)
|
||||
|
||||
-- Check min count requirements
|
||||
-- Check min count requirements (only if minCount > 0)
|
||||
if task.items then
|
||||
local sourceItems = getContainerItems(task.source)
|
||||
local itemCounts = {}
|
||||
@@ -242,8 +242,8 @@ local function executeTransfer(task)
|
||||
end
|
||||
|
||||
for itemName, minCount in pairs(task.items) do
|
||||
-- Only check if minCount > 0
|
||||
if minCount > 0 and (itemCounts[itemName] or 0) < minCount then
|
||||
print("Not enough "..itemName.." ("..(itemCounts[itemName] or 0).." < "..minCount..")")
|
||||
return false
|
||||
end
|
||||
end
|
||||
@@ -259,16 +259,16 @@ local function executeTransfer(task)
|
||||
if shouldTransfer then
|
||||
local count = item.count
|
||||
if task.items and task.items[item.name] then
|
||||
count = math.min(count, task.items[item.name])
|
||||
-- If minCount is 0, transfer all available
|
||||
if task.items[item.name] == 0 then
|
||||
count = item.count
|
||||
else
|
||||
count = math.min(count, task.items[item.name])
|
||||
end
|
||||
end
|
||||
|
||||
local transferred = source.pushItems(destName, slot, count)
|
||||
totalTransferred = totalTransferred + transferred
|
||||
|
||||
-- Update transferred count in requirements
|
||||
if task.items and task.items[item.name] then
|
||||
task.items[item.name] = task.items[item.name] - transferred
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -318,7 +318,7 @@ local function executeTransfer(task)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check min count requirements
|
||||
-- Check min count requirements (only if minCount > 0)
|
||||
if task.items then
|
||||
local sourceItems = getContainerItems(task.source)
|
||||
local itemCounts = {}
|
||||
@@ -330,8 +330,8 @@ local function executeTransfer(task)
|
||||
end
|
||||
|
||||
for itemName, minCount in pairs(task.items) do
|
||||
-- Only check if minCount > 0
|
||||
if minCount > 0 and (itemCounts[itemName] or 0) < minCount then
|
||||
print("Not enough "..itemName.." ("..(itemCounts[itemName] or 0).." < "..minCount..")")
|
||||
return false
|
||||
end
|
||||
end
|
||||
@@ -347,7 +347,12 @@ local function executeTransfer(task)
|
||||
if shouldTransfer then
|
||||
local count = item.count
|
||||
if task.items and task.items[item.name] then
|
||||
count = math.min(count, task.items[item.name])
|
||||
-- If minCount is 0, transfer all available
|
||||
if task.items[item.name] == 0 then
|
||||
count = item.count
|
||||
else
|
||||
count = math.min(count, task.items[item.name])
|
||||
end
|
||||
end
|
||||
|
||||
if source.pushItems(turtleName, slot, count) > 0 then
|
||||
@@ -530,10 +535,12 @@ local function processCommand(cmd)
|
||||
print(" Items format:")
|
||||
print(" Simple: item1[:minCount] item2[:minCount] ...")
|
||||
print(" JSON-like: {\"item1\":minCount, \"item2\":minCount}")
|
||||
print(" Set minCount to 0 to transfer all available items")
|
||||
print("addfluid <source> <destination> [fluids] - Add fluid transfer task")
|
||||
print(" Fluids format:")
|
||||
print(" Simple: fluid1[:minAmount] fluid2[:minAmount] ...")
|
||||
print(" JSON-like: {\"fluid1\":minAmount, \"fluid2\":minAmount}")
|
||||
print(" Set minAmount to 0 to transfer all available fluid")
|
||||
print("list - List all tasks")
|
||||
print("remove <index> - Remove task")
|
||||
print("setname <name> - Set turtle peripheral name")
|
||||
@@ -548,7 +555,7 @@ end
|
||||
|
||||
-- Initialize
|
||||
loadConfig()
|
||||
print("Turtle Logistics System v4.2 started. Type 'help' for commands.")
|
||||
print("Turtle Logistics System v4.3 started. Type 'help' for commands.")
|
||||
print("Current turtle name: "..turtleName)
|
||||
|
||||
-- Main loop
|
||||
|
||||
Reference in New Issue
Block a user