移除历史文件
This commit is contained in:
@@ -1,560 +0,0 @@
|
|||||||
-- 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
|
|
||||||
)
|
|
||||||
@@ -1,571 +0,0 @@
|
|||||||
-- 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
|
|
||||||
)
|
|
||||||
Reference in New Issue
Block a user