947 lines
42 KiB
Lua
947 lines
42 KiB
Lua
-- Logistics System v5.0 (Multi-Container & Cache Mode)
|
||
-- 支持带缓存的复杂容器间传输
|
||
-- 配置保存在 config.cfg
|
||
local configFile = "config.cfg"
|
||
local tasks = {}
|
||
local settings = {
|
||
logEnabled = false, -- 日志开关,默认关闭
|
||
zhlog = false, -- 中文日志开关,默认关闭
|
||
delay = 0.01 -- 轮询延迟,默认0.01秒
|
||
}
|
||
local Tlist = {} -- 缓存传输列表
|
||
local lastOutput = {} -- 记录每个任务每个优先级组上次使用的输出容器
|
||
|
||
-- 加载配置
|
||
local function loadConfig()
|
||
if fs.exists(configFile) then
|
||
local file = fs.open(configFile, "r")
|
||
local data = file.readAll()
|
||
file.close()
|
||
local config = textutils.unserialize(data) or {}
|
||
|
||
-- 加载设置
|
||
if config.settings then
|
||
settings.logEnabled = config.settings.logEnabled or settings.logEnabled
|
||
settings.zhlog = config.settings.zhlog or settings.zhlog
|
||
settings.delay = config.settings.delay or settings.delay
|
||
end
|
||
|
||
-- 加载任务
|
||
tasks = config.tasks or {}
|
||
|
||
-- 加载传输列表
|
||
Tlist = config.Tlist or {}
|
||
|
||
end
|
||
end
|
||
loadConfig()
|
||
|
||
-- 保存配置
|
||
local function saveConfig()
|
||
local config = {
|
||
settings = {
|
||
logEnabled = settings.logEnabled,
|
||
zhlog = settings.zhlog,
|
||
delay = settings.delay
|
||
},
|
||
tasks = tasks,
|
||
Tlist = Tlist
|
||
}
|
||
|
||
local file = fs.open(configFile, "w")
|
||
file.write(textutils.serialize(config))
|
||
file.close()
|
||
end
|
||
|
||
if settings.zhlog then
|
||
printUtf8 = load(http.get("https://alist.liulikeji.cn/d/HFS/utf8ptrint.lua").readAll())()
|
||
term.clear()
|
||
term.setCursorPos(1,1)
|
||
else
|
||
function printUtf8(logMessage,color,bcolor)
|
||
term.setTextColour(color)
|
||
term.setBackgroundColour(bcolor)
|
||
print(logMessage)
|
||
term.setTextColour(colors.white)
|
||
term.setBackgroundColour(colors.black)
|
||
end
|
||
end
|
||
|
||
-- 日志级别定义
|
||
local LOG_LEVEL = {
|
||
SUCCESS = {name = "SUCCESS", color = colors.green},
|
||
SKIPPED = {name = "SKIPPED", color = colors.orange},
|
||
INFO = {name = "INFO", color = colors.white},
|
||
WARNING = {name = "WARNING", color = colors.yellow},
|
||
ERROR = {name = "ERROR", color = colors.red},
|
||
DEBUG = {name = "DEBUG", color = colors.lightGray}
|
||
}
|
||
|
||
-- 日志记录函数
|
||
local function log(level, zhMessage, enMessage)
|
||
if level ~= LOG_LEVEL.ERROR then
|
||
if not settings.logEnabled then return end
|
||
end
|
||
|
||
local message = settings.zhlog and zhMessage or enMessage
|
||
local timeStr = os.date("%H:%M:%S")
|
||
local levelName = level.name
|
||
local color = level.color
|
||
|
||
-- 格式化日志消息
|
||
local logMessage = string.format("[%s] %s: %s", timeStr, levelName, message)
|
||
|
||
-- 打印日志
|
||
printUtf8(logMessage, color, colors.black)
|
||
end
|
||
|
||
-- 命令输出函数(双语支持)
|
||
local function echo(zhMessage, enMessage)
|
||
local message = settings.zhlog and zhMessage or enMessage
|
||
printUtf8(message, colors.lightBlue, colors.black)
|
||
end
|
||
|
||
-- 初始化日志
|
||
log(LOG_LEVEL.INFO, "程序开始 - 物流系统 v5.0", "Program started - Turtle Logistics System v5.0")
|
||
|
||
-- 获取容器物品列表
|
||
local function getContainerItems(containerName)
|
||
local container = peripheral.wrap(containerName)
|
||
if not container then
|
||
log(LOG_LEVEL.ERROR, "错误: 容器不存在: "..containerName, "Error: Container not found: "..containerName)
|
||
return nil
|
||
end
|
||
|
||
local items = {}
|
||
local containerList = container.list()
|
||
|
||
for slot, item in pairs(containerList) do
|
||
items[tostring(slot)] = {
|
||
count = item.count,
|
||
name = item.name
|
||
}
|
||
end
|
||
|
||
return items
|
||
end
|
||
|
||
-- 比较两个物品列表是否相同
|
||
local function compareItems(items1, items2)
|
||
if not items1 or not items2 then return false end
|
||
|
||
-- 检查槽位数量
|
||
local count1 = 0
|
||
for _ in pairs(items1) do count1 = count1 + 1 end
|
||
local count2 = 0
|
||
for _ in pairs(items2) do count2 = count2 + 1 end
|
||
if count1 ~= count2 then return false end
|
||
|
||
-- 检查每个槽位
|
||
for slot, item1 in pairs(items1) do
|
||
local item2 = items2[slot]
|
||
if not item2 then return false end
|
||
if item1.name ~= item2.name or item1.count ~= item2.count then
|
||
return false
|
||
end
|
||
end
|
||
|
||
return true
|
||
end
|
||
|
||
-- 获取容器中不在Tlist中的物品
|
||
local function getNewItems(containerName)
|
||
local currentItems = getContainerItems(containerName)
|
||
if not currentItems then return nil end
|
||
|
||
local tlistItems = Tlist[containerName] or {}
|
||
local newItems = {}
|
||
|
||
for slot, item in pairs(currentItems) do
|
||
local tlistItem = tlistItems[slot]
|
||
if not tlistItem or tlistItem.name ~= item.name or tlistItem.count ~= item.count then
|
||
newItems[slot] = item
|
||
end
|
||
end
|
||
|
||
return newItems
|
||
end
|
||
|
||
-- 更新Tlist中的容器记录
|
||
local function updateTlist(containerName, items)
|
||
if not Tlist[containerName] then
|
||
Tlist[containerName] = {}
|
||
end
|
||
|
||
-- 只更新传入的物品槽位
|
||
for slot, item in pairs(items) do
|
||
Tlist[containerName][slot] = {
|
||
name = item.name,
|
||
count = item.count
|
||
}
|
||
end
|
||
end
|
||
|
||
-- 清理Tlist中缺失的物品
|
||
local function cleanTlist(containerName)
|
||
if not Tlist[containerName] then return end
|
||
|
||
local currentItems = getContainerItems(containerName)
|
||
if not currentItems then return end
|
||
|
||
local toRemove = {}
|
||
|
||
-- 找出Tlist中存在但容器中不存在的物品
|
||
for slot, tlistItem in pairs(Tlist[containerName]) do
|
||
local currentItem = currentItems[slot]
|
||
if not currentItem or currentItem.name ~= tlistItem.name or currentItem.count ~= tlistItem.count then
|
||
table.insert(toRemove, slot)
|
||
end
|
||
end
|
||
|
||
-- 移除这些物品
|
||
for _, slot in ipairs(toRemove) do
|
||
Tlist[containerName][slot] = nil
|
||
end
|
||
end
|
||
|
||
-- 辅助函数:检查物品是否通过过滤规则
|
||
local function isItemAllowed(itemName, containerConfig)
|
||
-- 如果有白名单,只允许白名单中的物品
|
||
if containerConfig.whitelist then
|
||
return containerConfig.whitelist[itemName] ~= nil
|
||
end
|
||
|
||
-- 如果有黑名单,排除黑名单中的物品
|
||
if containerConfig.blacklist then
|
||
return containerConfig.blacklist[itemName] == nil
|
||
end
|
||
|
||
-- 没有过滤规则时允许所有物品
|
||
return true
|
||
end
|
||
|
||
-- 获取物品的传输数量限制
|
||
local function getTransferLimit(itemName, containerConfig)
|
||
-- 检查白名单中是否有该物品的数量限制
|
||
if containerConfig.whitelist and containerConfig.whitelist[itemName] then
|
||
local countSetting = containerConfig.whitelist[itemName].count
|
||
if countSetting and countSetting > 0 then
|
||
return countSetting
|
||
end
|
||
end
|
||
-- 如果没有限制或限制为0,则返回nil表示传输全部
|
||
return nil
|
||
end
|
||
|
||
-- 在 executeItemTask 函数中添加更多调试日志
|
||
local function executeItemTask(task, taskIndex)
|
||
log(LOG_LEVEL.INFO, "开始执行物品任务 #"..taskIndex, "Starting item transfer task #"..taskIndex)
|
||
|
||
-- 收集所有输入容器的物品
|
||
local allItemsToTransfer = {}
|
||
|
||
-- 处理输入容器
|
||
for inputName, inputConfig in pairs(task.input) do
|
||
log(LOG_LEVEL.DEBUG, "开始处理输入容器: "..inputName, "Starting processing input container: "..inputName)
|
||
|
||
local container = peripheral.wrap(inputName)
|
||
if not container then
|
||
log(LOG_LEVEL.ERROR, "错误: 输入容器不存在: "..inputName, "Error: Input container not found: "..inputName)
|
||
goto continue
|
||
end
|
||
|
||
-- 缓存容器处理
|
||
if inputConfig.cache then
|
||
log(LOG_LEVEL.DEBUG, "容器 "..inputName.." 是缓存容器", "Container "..inputName.." is a cache container")
|
||
|
||
-- 清理Tlist中缺失的物品
|
||
cleanTlist(inputName)
|
||
|
||
-- 获取当前物品状态
|
||
local currentItems = getContainerItems(inputName)
|
||
if not currentItems then
|
||
log(LOG_LEVEL.DEBUG, "无法获取容器物品: "..inputName, "Failed to get container items: "..inputName)
|
||
goto continue
|
||
end
|
||
|
||
-- 检查是否与Tlist完全相同
|
||
if compareItems(currentItems, Tlist[inputName] or {}) then
|
||
log(LOG_LEVEL.DEBUG, "容器内容与Tlist相同,跳过: "..inputName, "Container contents match Tlist, skipping: "..inputName)
|
||
goto continue
|
||
end
|
||
|
||
-- 获取新物品(不在Tlist中的)
|
||
local newItems = getNewItems(inputName)
|
||
if not newItems or not next(newItems) then
|
||
log(LOG_LEVEL.DEBUG, "没有新物品,跳过: "..inputName, "No new items, skipping: "..inputName)
|
||
goto continue
|
||
end
|
||
|
||
-- 添加到传输列表(应用输入容器过滤)
|
||
for slot, item in pairs(newItems) do
|
||
if isItemAllowed(item.name, inputConfig) then
|
||
-- 不再在输入容器限制流量
|
||
-- -- 获取传输数量限制
|
||
-- local transferLimit = getTransferLimit(item.name, inputConfig)
|
||
|
||
-- -- 检查是否满足传输条件
|
||
-- if transferLimit and item.count < transferLimit then
|
||
-- log(LOG_LEVEL.DEBUG, "物品 "..item.name.." 数量不足("..item.count.."<"..transferLimit.."),跳过传输",
|
||
-- "Item "..item.name.." insufficient quantity ("..item.count.."<"..transferLimit.."), skipping transfer")
|
||
-- goto continue_item
|
||
-- end
|
||
|
||
-- local transferCount = transferLimit or item.count
|
||
local transferCount = item.count
|
||
|
||
-- 如果数量大于0才添加
|
||
if transferCount > 0 then
|
||
log(LOG_LEVEL.DEBUG, "添加物品到传输列表: "..item.name.." x"..transferCount.." (槽位 "..slot..")",
|
||
"Adding item to transfer list: "..item.name.." x"..transferCount.." (slot "..slot..")")
|
||
table.insert(allItemsToTransfer, {
|
||
container = inputName,
|
||
slot = tonumber(slot),
|
||
name = item.name,
|
||
count = transferCount
|
||
})
|
||
else
|
||
log(LOG_LEVEL.DEBUG, "物品 "..item.name.." 数量不足,跳过传输",
|
||
"Item "..item.name.." insufficient quantity, skipping transfer")
|
||
end
|
||
else
|
||
log(LOG_LEVEL.DEBUG, "物品 "..item.name.." 被输入容器 "..inputName.." 过滤",
|
||
"Item "..item.name.." filtered by input container "..inputName)
|
||
end
|
||
|
||
::continue_item::
|
||
end
|
||
else
|
||
log(LOG_LEVEL.DEBUG, "容器 "..inputName.." 不是缓存容器", "Container "..inputName.." is not a cache container")
|
||
local items = getContainerItems(inputName)
|
||
if not items then
|
||
log(LOG_LEVEL.DEBUG, "无法获取容器物品: "..inputName, "Failed to get container items: "..inputName)
|
||
goto continue
|
||
end
|
||
|
||
for slot, item in pairs(items) do
|
||
-- 应用输入容器过滤
|
||
if isItemAllowed(item.name, inputConfig) then
|
||
-- 不再在输入容器限制流量
|
||
-- 获取传输数量限制
|
||
-- local transferLimit = getTransferLimit(item.name, inputConfig)
|
||
|
||
-- -- 检查是否满足传输条件
|
||
-- if transferLimit and item.count < transferLimit then
|
||
-- log(LOG_LEVEL.DEBUG, "物品 "..item.name.." 数量不足("..item.count.."<"..transferLimit.."),跳过传输",
|
||
-- "Item "..item.name.." insufficient quantity ("..item.count.."<"..transferLimit.."), skipping transfer")
|
||
-- goto continue_item_non_cache
|
||
-- end
|
||
|
||
-- local transferCount = transferLimit or item.count
|
||
local transferCount = item.count
|
||
|
||
-- 如果数量大于0才添加
|
||
if transferCount > 0 then
|
||
log(LOG_LEVEL.DEBUG, "添加物品到传输列表: "..item.name.." x"..transferCount.." (槽位 "..slot..")",
|
||
"Adding item to transfer list: "..item.name.." x"..transferCount.." (slot "..slot..")")
|
||
table.insert(allItemsToTransfer, {
|
||
container = inputName,
|
||
slot = tonumber(slot),
|
||
name = item.name,
|
||
count = transferCount
|
||
})
|
||
else
|
||
log(LOG_LEVEL.DEBUG, "物品 "..item.name.." 数量不足,跳过传输",
|
||
"Item "..item.name.." insufficient quantity, skipping transfer")
|
||
end
|
||
else
|
||
log(LOG_LEVEL.DEBUG, "物品 "..item.name.." 被输入容器 "..inputName.." 过滤",
|
||
"Item "..item.name.." filtered by input container "..inputName)
|
||
end
|
||
|
||
::continue_item_non_cache::
|
||
end
|
||
end
|
||
|
||
::continue::
|
||
end
|
||
|
||
if #allItemsToTransfer == 0 then
|
||
log(LOG_LEVEL.SKIPPED, "没有物品需要传输", "No items to transfer")
|
||
return false
|
||
end
|
||
|
||
log(LOG_LEVEL.INFO, "找到 "..#allItemsToTransfer.." 个物品需要传输", "Found "..#allItemsToTransfer.." items to transfer")
|
||
|
||
-- 按优先级分组输出容器
|
||
local outputGroups = {}
|
||
for outputName, outputConfig in pairs(task.output) do
|
||
local priority = outputConfig.priority or 1
|
||
if not outputGroups[priority] then
|
||
outputGroups[priority] = {}
|
||
end
|
||
table.insert(outputGroups[priority], {
|
||
name = outputName,
|
||
config = outputConfig
|
||
})
|
||
end
|
||
|
||
-- 按优先级排序(从高到低)
|
||
local sortedPriorities = {}
|
||
for priority in pairs(outputGroups) do
|
||
table.insert(sortedPriorities, priority)
|
||
end
|
||
table.sort(sortedPriorities, function(a, b) return a > b end)
|
||
|
||
-- 传输物品
|
||
local transferred = false
|
||
|
||
for _, itemData in ipairs(allItemsToTransfer) do
|
||
log(LOG_LEVEL.DEBUG, "尝试传输物品: "..itemData.name.." x"..itemData.count.." (源容器: "..itemData.container..", 槽位: "..itemData.slot..")",
|
||
"Attempting to transfer item: "..itemData.name.." x"..itemData.count.." (source: "..itemData.container..", slot: "..itemData.slot..")")
|
||
|
||
local sourceContainer = peripheral.wrap(itemData.container)
|
||
if not sourceContainer then
|
||
log(LOG_LEVEL.ERROR, "错误: 源容器不存在: "..itemData.container, "Error: Source container not found: "..itemData.container)
|
||
goto next_item
|
||
end
|
||
|
||
-- 尝试推送到输出容器
|
||
local pushed = false
|
||
|
||
-- 按优先级尝试输出
|
||
for _, priority in ipairs(sortedPriorities) do
|
||
local group = outputGroups[priority]
|
||
|
||
-- 轮询输出
|
||
local key = taskIndex.."_"..priority -- 使用任务索引和优先级作为唯一键
|
||
log(LOG_LEVEL.DEBUG, "输出容器键: "..key, "Output container key: "..key)
|
||
|
||
local startIdx = lastOutput[key] or 1
|
||
local idx = startIdx
|
||
local attempts = 0
|
||
|
||
repeat
|
||
log(LOG_LEVEL.DEBUG, "输出容器索引: "..tostring(idx).." 容器组大小: "..tostring(#group),"Output container index: "..tostring(idx).." group size: "..tostring(#group))
|
||
local output = group[idx]
|
||
log(LOG_LEVEL.DEBUG, "尝试输出容器: "..output.name.." (优先级 "..priority..", 尝试 "..attempts.."/"..#group..")",
|
||
"Attempting output container: "..output.name.." (priority "..priority..", attempt "..attempts.."/"..#group..")")
|
||
|
||
local outputContainer = peripheral.wrap(output.name)
|
||
|
||
if outputContainer then
|
||
-- 应用输出容器过滤
|
||
if not isItemAllowed(itemData.name, output.config) then
|
||
log(LOG_LEVEL.DEBUG, "物品 "..itemData.name.." 被输出容器 "..output.name.." 过滤",
|
||
"Item "..itemData.name.." filtered by output container "..output.name)
|
||
goto next_output
|
||
end
|
||
|
||
local transferLimit = getTransferLimit(itemData.name, output.config)
|
||
|
||
-- 检查是否满足传输条件
|
||
if transferLimit and itemData.count < transferLimit then
|
||
log(LOG_LEVEL.DEBUG, "物品 "..itemData.name.." 数量不足("..itemData.count.."<"..transferLimit.."),跳过传输",
|
||
"Item "..itemData.name.." insufficient quantity ("..itemData.count.."<"..transferLimit.."), skipping transfer")
|
||
goto next_output
|
||
end
|
||
|
||
local transferCount = transferLimit or itemData.count
|
||
|
||
log(LOG_LEVEL.DEBUG, "尝试推送到 "..output.name.." (优先级 "..priority..")", "Attempting push to "..output.name.." (priority "..priority..")")
|
||
|
||
-- 推送物品
|
||
local pushedCount = sourceContainer.pushItems(
|
||
output.name,
|
||
itemData.slot,
|
||
transferCount
|
||
)
|
||
|
||
if pushedCount > 0 then
|
||
log(LOG_LEVEL.SUCCESS, "成功推送 "..pushedCount.." 个 "..itemData.name.." 到 "..output.name, "Successfully pushed "..pushedCount.." "..itemData.name.." to "..output.name)
|
||
pushed = true
|
||
transferred = true
|
||
|
||
-- 更新输出容器的Tlist(如果是缓存容器)
|
||
if output.config.cache then
|
||
log(LOG_LEVEL.DEBUG, "更新输出容器Tlist: "..output.name, "Updating output container Tlist: "..output.name)
|
||
if not Tlist[output.name] then
|
||
Tlist[output.name] = {}
|
||
end
|
||
|
||
-- 获取输出容器当前物品
|
||
local outputItems = getContainerItems(output.name)
|
||
if outputItems then
|
||
-- 只更新传输的物品槽位
|
||
for slot, item in pairs(outputItems) do
|
||
if item.name == itemData.name then
|
||
Tlist[output.name][slot] = {
|
||
name = item.name,
|
||
count = item.count
|
||
}
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
-- 更新输入容器的Tlist(如果是缓存容器)
|
||
if task.input[itemData.container] and task.input[itemData.container].cache then
|
||
log(LOG_LEVEL.DEBUG, "更新输入容器Tlist: "..itemData.container, "Updating input container Tlist: "..itemData.container)
|
||
updateTlist(itemData.container, {
|
||
[tostring(itemData.slot)] = {
|
||
name = itemData.name,
|
||
count = itemData.count - pushedCount
|
||
}
|
||
})
|
||
end
|
||
|
||
-- 更新轮询索引
|
||
log(LOG_LEVEL.DEBUG, "轮询: idx:" .. tostring(idx) .. " #group:" .. tostring(#group))
|
||
lastOutput[key] = idx % #group + 1
|
||
break
|
||
else
|
||
log(LOG_LEVEL.WARNING, "推送失败到 "..output.name.." (可能容器已满或无法接收)",
|
||
"Push failed to "..output.name.." (container may be full or unable to receive)")
|
||
end
|
||
else
|
||
log(LOG_LEVEL.ERROR, "输出容器不存在或无法访问: "..output.name, "Output container not found or inaccessible: "..output.name)
|
||
end
|
||
|
||
::next_output::
|
||
idx = idx % #group + 1
|
||
attempts = attempts + 1
|
||
until attempts >= #group
|
||
|
||
if pushed then break end
|
||
end
|
||
|
||
if not pushed then
|
||
log(LOG_LEVEL.WARNING, "警告: 无法传输物品 "..itemData.name.." x"..itemData.count.." (所有输出容器尝试失败)",
|
||
"Warning: Failed to transfer item "..itemData.name.." x"..itemData.count.." (all output containers failed)")
|
||
end
|
||
|
||
::next_item::
|
||
end
|
||
|
||
if not transferred then
|
||
log(LOG_LEVEL.DEBUG, "所有物品传输尝试失败", "All item transfer attempts failed")
|
||
end
|
||
|
||
return transferred
|
||
end
|
||
|
||
-- 执行流体传输任务
|
||
local function executeFluidTask(task, taskIndex)
|
||
log(LOG_LEVEL.INFO, "开始执行流体任务 #"..taskIndex, "Starting fluid transfer task #"..taskIndex)
|
||
|
||
local transferred = false
|
||
|
||
-- 处理输入容器
|
||
for inputName, inputConfig in pairs(task.input) do
|
||
log(LOG_LEVEL.INFO, "处理输入容器: "..inputName, "Processing input container: "..inputName)
|
||
|
||
local source = peripheral.wrap(inputName)
|
||
if not source then
|
||
log(LOG_LEVEL.ERROR, "错误: 源容器不存在: "..inputName, "Error: Source container not found: "..inputName)
|
||
goto continue
|
||
end
|
||
|
||
if not source.tanks then
|
||
log(LOG_LEVEL.WARNING, "警告: 容器不支持流体: "..inputName.." - 跳过", "Warning: Container does not support fluids: "..inputName.." - skipping")
|
||
goto continue
|
||
end
|
||
|
||
-- 获取流体槽 - 使用 pairs 而不是 # 来计算数量
|
||
local tanks = source.tanks()
|
||
if not tanks then
|
||
log(LOG_LEVEL.INFO, "容器中没有流体槽: "..inputName, "No fluid tanks in container: "..inputName)
|
||
goto continue
|
||
end
|
||
|
||
-- 正确计算流体槽数量
|
||
local tankCount = 0
|
||
for _ in pairs(tanks) do tankCount = tankCount + 1 end
|
||
|
||
if tankCount == 0 then
|
||
log(LOG_LEVEL.INFO, "容器中没有流体槽: "..inputName, "No fluid tanks in container: "..inputName)
|
||
goto continue
|
||
end
|
||
|
||
-- 使用 pairs 遍历所有流体槽
|
||
for tankIndex, tank in pairs(tanks) do
|
||
-- 确保 tank 是有效的表
|
||
if type(tank) == "table" and tank.name and tank.amount then
|
||
-- 应用输入容器过滤
|
||
if tank.amount > 0 and isItemAllowed(tank.name, inputConfig) then
|
||
log(LOG_LEVEL.INFO, "找到可传输流体: "..tank.name.." ("..tank.amount.."mB)", "Found transferable fluid: "..tank.name.." ("..tank.amount.."mB)")
|
||
|
||
-- 按优先级分组输出容器
|
||
local outputGroups = {}
|
||
for outputName, outputConfig in pairs(task.output) do
|
||
local priority = outputConfig.priority or 1
|
||
if not outputGroups[priority] then
|
||
outputGroups[priority] = {}
|
||
end
|
||
table.insert(outputGroups[priority], {
|
||
name = outputName,
|
||
config = outputConfig
|
||
})
|
||
end
|
||
|
||
-- 按优先级排序(从高到低)
|
||
local sortedPriorities = {}
|
||
for priority in pairs(outputGroups) do
|
||
table.insert(sortedPriorities, priority)
|
||
end
|
||
table.sort(sortedPriorities, function(a, b) return a > b end)
|
||
|
||
-- 尝试传输流体
|
||
local pushed = false
|
||
local amountToTransfer = tank.amount
|
||
|
||
for _, priority in ipairs(sortedPriorities) do
|
||
local group = outputGroups[priority]
|
||
|
||
-- 轮询输出
|
||
local key = taskIndex.."_"..priority -- 使用任务索引和优先级作为唯一键
|
||
local startIdx = lastOutput[key] or 1
|
||
local idx = startIdx
|
||
local attempts = 0
|
||
|
||
repeat
|
||
local output = group[idx]
|
||
local destination = peripheral.wrap(output.name)
|
||
|
||
if destination and destination.tanks then
|
||
-- 应用输出容器过滤
|
||
if not isItemAllowed(tank.name, output.config) then
|
||
log(LOG_LEVEL.INFO, "流体 "..tank.name.." 被输出容器 "..output.name.." 过滤",
|
||
"Fluid "..tank.name.." filtered by output container "..output.name)
|
||
goto next_output
|
||
end
|
||
|
||
log(LOG_LEVEL.INFO, "尝试推送到 "..output.name.." (优先级 "..priority..")", "Attempting push to "..output.name.." (priority "..priority..")")
|
||
|
||
-- 推送流体
|
||
local pushedAmount = source.pushFluid(
|
||
output.name,
|
||
amountToTransfer,
|
||
tank.name,
|
||
tankIndex
|
||
)
|
||
|
||
if pushedAmount > 0 then
|
||
log(LOG_LEVEL.SUCCESS, "成功推送 "..pushedAmount.."mB "..tank.name.." 到 "..output.name, "Successfully pushed "..pushedAmount.."mB "..tank.name.." to "..output.name)
|
||
pushed = true
|
||
transferred = true
|
||
amountToTransfer = amountToTransfer - pushedAmount
|
||
|
||
-- 更新输出容器的Tlist(如果是缓存容器)
|
||
if output.config.cache then
|
||
log(LOG_LEVEL.DEBUG, "更新输出容器Tlist: "..output.name, "Updating output container Tlist: "..output.name)
|
||
if not Tlist[output.name] then
|
||
Tlist[output.name] = {}
|
||
end
|
||
|
||
-- 获取输出容器当前流体
|
||
local destTanks = destination.tanks()
|
||
if destTanks then
|
||
for _, destTank in pairs(destTanks) do
|
||
if destTank.name == tank.name then
|
||
Tlist[output.name][tank.name] = {
|
||
amount = destTank.amount
|
||
}
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
-- 更新轮询索引
|
||
lastOutput[key] = idx % #group + 1
|
||
else
|
||
log(LOG_LEVEL.WARNING, "推送失败到 "..output.name, "Push failed to "..output.name)
|
||
end
|
||
else
|
||
if not destination then
|
||
log(LOG_LEVEL.ERROR, "错误: 输出容器不存在: "..output.name, "Error: Output container not found: "..output.name)
|
||
else
|
||
log(LOG_LEVEL.WARNING, "错误: 输出容器不支持流体: "..output.name, "Error: Output container does not support fluids: "..output.name)
|
||
end
|
||
end
|
||
|
||
::next_output::
|
||
idx = idx % #group + 1
|
||
attempts = attempts + 1
|
||
until attempts >= #group or amountToTransfer <= 0
|
||
|
||
if amountToTransfer <= 0 then break end
|
||
end
|
||
|
||
if amountToTransfer > 0 then
|
||
log(LOG_LEVEL.WARNING, string.format("警告: 仍有 %dmB %s 未传输", amountToTransfer, tank.name),
|
||
string.format("Warning: Still %dmB %s not transferred", amountToTransfer, tank.name))
|
||
end
|
||
else
|
||
if tank.amount == 0 then
|
||
log(LOG_LEVEL.INFO, "槽位 "..tankIndex.." 无流体", "Tank "..tankIndex.." has no fluid")
|
||
else
|
||
log(LOG_LEVEL.INFO, "流体 "..tank.name.." 被输入容器 "..inputName.." 过滤",
|
||
"Fluid "..tank.name.." filtered by input container "..inputName)
|
||
end
|
||
end
|
||
else
|
||
log(LOG_LEVEL.WARNING, "警告: 槽位 "..tankIndex.." 的数据无效", "Warning: Invalid data for tank "..tankIndex)
|
||
end
|
||
end
|
||
|
||
::continue::
|
||
end
|
||
|
||
return transferred
|
||
end
|
||
|
||
-- 执行任务
|
||
local function executeTask(task, taskIndex)
|
||
if task.type == "item" then
|
||
return executeItemTask(task, taskIndex)
|
||
elseif task.type == "fluid" then
|
||
return executeFluidTask(task, taskIndex)
|
||
else
|
||
log(LOG_LEVEL.ERROR, "错误: 未知任务类型: "..(task.type or "nil"), "Error: Unknown task type: "..(task.type or "nil"))
|
||
return false
|
||
end
|
||
end
|
||
|
||
-- 主任务循环
|
||
local function taskLoop()
|
||
log(LOG_LEVEL.INFO, "任务循环开始", "Task loop started")
|
||
while true do
|
||
for i, task in ipairs(tasks) do
|
||
log(LOG_LEVEL.INFO, "开始任务 #"..i, "Starting task #"..i)
|
||
local success, result = pcall(executeTask, task, i)
|
||
if not success then
|
||
log(LOG_LEVEL.ERROR, "任务 #"..i.." 错误: "..tostring(result), "Task #"..i.." error: "..tostring(result))
|
||
elseif result then
|
||
log(LOG_LEVEL.SUCCESS, "任务 #"..i.." 成功执行", "Task #"..i.." executed successfully")
|
||
else
|
||
log(LOG_LEVEL.SKIPPED, "任务 #"..i.." 未执行传输", "Task #"..i.." no transfer performed")
|
||
end
|
||
end
|
||
os.sleep(settings.delay)
|
||
end
|
||
end
|
||
|
||
-- 命令处理
|
||
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 >= 2 then
|
||
-- 合并参数为JSON字符串
|
||
local jsonStr = table.concat(args, " ", 2)
|
||
local success, task = pcall(textutils.unserializeJSON, jsonStr)
|
||
|
||
if success and type(task) == "table" then
|
||
-- 验证任务类型
|
||
if not task.type then
|
||
echo("错误: 任务缺少类型字段", "Error: Task missing type field")
|
||
return
|
||
end
|
||
|
||
if task.type ~= "item" and task.type ~= "fluid" then
|
||
echo("错误: 无效的任务类型: "..task.type, "Error: Invalid task type: "..task.type)
|
||
return
|
||
end
|
||
|
||
-- 验证输入输出
|
||
if not task.input or not task.output then
|
||
echo("错误: 任务缺少输入或输出字段", "Error: Task missing input or output fields")
|
||
return
|
||
end
|
||
|
||
table.insert(tasks, task)
|
||
saveConfig()
|
||
echo("任务添加成功", "Task added successfully")
|
||
else
|
||
echo("错误: 无效的JSON格式", "Error: Invalid JSON format")
|
||
end
|
||
|
||
elseif command == "list" then
|
||
if #tasks == 0 then
|
||
echo("没有配置任务", "No tasks configured")
|
||
else
|
||
for i, task in ipairs(tasks) do
|
||
echo("任务 #"..i.." ("..task.type..")", "Task #"..i.." ("..task.type..")")
|
||
echo(" 输入容器:", " Input containers:")
|
||
for name, config in pairs(task.input) do
|
||
local cacheStr = config.cache and "缓存" or "非缓存"
|
||
local cacheStrEn = config.cache and "cache" or "non-cache"
|
||
|
||
-- 显示过滤规则
|
||
if config.whitelist then
|
||
local items = {}
|
||
for itemName, itemConfig in pairs(config.whitelist) do
|
||
if itemConfig.count and itemConfig.count > 0 then
|
||
table.insert(items, itemName.." (count="..itemConfig.count..")")
|
||
else
|
||
table.insert(items, itemName)
|
||
end
|
||
end
|
||
echo(" "..name.." ("..cacheStr..", 白名单: "..table.concat(items, ", ")..")",
|
||
" "..name.." ("..cacheStrEn..", whitelist: "..table.concat(items, ", ")..")")
|
||
elseif config.blacklist then
|
||
local items = {}
|
||
for itemName in pairs(config.blacklist) do
|
||
table.insert(items, itemName)
|
||
end
|
||
echo(" "..name.." ("..cacheStr..", 黑名单: "..table.concat(items, ", ")..")",
|
||
" "..name.." ("..cacheStrEn..", blacklist: "..table.concat(items, ", ")..")")
|
||
else
|
||
echo(" "..name.." ("..cacheStr..")", " "..name.." ("..cacheStrEn..")")
|
||
end
|
||
end
|
||
|
||
echo(" 输出容器:", " Output containers:")
|
||
for name, config in pairs(task.output) do
|
||
local cacheStr = config.cache and "缓存" or "非缓存"
|
||
local cacheStrEn = config.cache and "cache" or "non-cache"
|
||
local priority = config.priority or 1
|
||
|
||
-- 显示过滤规则
|
||
if config.whitelist then
|
||
local items = {}
|
||
for itemName, itemConfig in pairs(config.whitelist) do
|
||
if itemConfig.count and itemConfig.count > 0 then
|
||
table.insert(items, itemName.." (count="..itemConfig.count..")")
|
||
else
|
||
table.insert(items, itemName)
|
||
end
|
||
end
|
||
echo(" "..name.." (优先级:"..priority..", "..cacheStr..", 白名单: "..table.concat(items, ", ")..")",
|
||
" "..name.." (priority:"..priority..", "..cacheStrEn..", whitelist: "..table.concat(items, ", ")..")")
|
||
elseif config.blacklist then
|
||
local items = {}
|
||
for itemName in pairs(config.blacklist) do
|
||
table.insert(items, itemName)
|
||
end
|
||
echo(" "..name.." (优先级:"..priority..", "..cacheStr..", 黑名单: "..table.concat(items, ", ")..")",
|
||
" "..name.." (priority:"..priority..", "..cacheStrEn..", blacklist: "..table.concat(items, ", ")..")")
|
||
else
|
||
echo(" "..name.." (优先级:"..priority..", "..cacheStr..")",
|
||
" "..name.." (priority:"..priority..", "..cacheStrEn..")")
|
||
end
|
||
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()
|
||
echo("任务 "..index.." 已移除", "Task "..index.." removed")
|
||
else
|
||
echo("无效的任务索引", "Invalid task index")
|
||
end
|
||
|
||
elseif command == "log" then
|
||
if #args >= 2 then
|
||
if args[2]:lower() == "on" then
|
||
settings.logEnabled = true
|
||
saveConfig()
|
||
echo("日志已启用", "Logging enabled")
|
||
elseif args[2]:lower() == "off" then
|
||
settings.logEnabled = false
|
||
saveConfig()
|
||
echo("日志已禁用", "Logging disabled")
|
||
else
|
||
echo("无效参数,使用 'log on' 或 'log off'", "Invalid argument, use 'log on' or 'log off'")
|
||
end
|
||
else
|
||
echo("当前日志状态: "..(settings.logEnabled and "启用" or "禁用"),
|
||
"Current log status: "..(settings.logEnabled and "enabled" or "disabled"))
|
||
end
|
||
|
||
-- 添加 set 命令
|
||
elseif command == "set" and #args >= 3 then
|
||
local key = args[2]:lower()
|
||
local value = args[3]
|
||
|
||
if key == "log" then
|
||
if value == "true" then
|
||
settings.logEnabled = true
|
||
saveConfig()
|
||
echo("日志已启用", "Logging enabled")
|
||
elseif value == "false" then
|
||
settings.logEnabled = false
|
||
saveConfig()
|
||
echo("日志已禁用", "Logging disabled")
|
||
else
|
||
echo("无效值,使用 'true' 或 'false'", "Invalid value, use 'true' or 'false'")
|
||
end
|
||
elseif key == "zh" then
|
||
if value == "true" then
|
||
settings.zhlog = true
|
||
saveConfig()
|
||
echo("中文日志已启用", "Chinese log enabled")
|
||
elseif value == "false" then
|
||
settings.zhlog = false
|
||
saveConfig()
|
||
echo("中文日志已禁用", "Chinese log disabled")
|
||
else
|
||
echo("无效值,使用 'true' 或 'false'", "Invalid value, use 'true' or 'false'")
|
||
end
|
||
elseif key == "delay" then
|
||
local numValue = tonumber(value)
|
||
if numValue and numValue > 0 then
|
||
settings.delay = numValue
|
||
saveConfig()
|
||
echo("轮询延迟已设置为: "..numValue.." 秒", "Polling delay set to: "..numValue.." seconds")
|
||
else
|
||
echo("无效值,请输入大于0的数字", "Invalid value, please enter a number greater than 0")
|
||
end
|
||
else
|
||
echo("无效设置项,可用选项: logEnabled, zhlog, delay", "Invalid setting, available options: logEnabled, zhlog, delay")
|
||
end
|
||
|
||
elseif command == "help" then
|
||
echo("可用命令:", "Available commands:")
|
||
echo("add <JSON任务> - 添加新任务", "add <JSON task> - Add new task")
|
||
echo(" 示例: add {\"type\":\"item\",\"input\":{\"left\":{\"cache\":true,\"whitelist\":{\"minecraft:stone\":{\"count\":64}}}},\"output\":{\"right\":{\"priority\":1,\"blacklist\":{\"minecraft:dirt\":{}}}}",
|
||
" Example: add {\"type\":\"item\",\"input\":{\"left\":{\"cache\":true,\"whitelist\":{\"minecraft:stone\":{\"count\":64}}}},\"output\":{\"right\":{\"priority\":1,\"blacklist\":{\"minecraft:dirt\":{}}}}")
|
||
echo("list - 列出所有任务", "list - List all tasks")
|
||
echo("remove <索引> - 移除任务", "remove <index> - Remove task")
|
||
echo("log [on|off] - 启用/禁用日志", "log [on|off] - Enable/disable logging")
|
||
echo("set <key> <value> - 修改设置", "set <key> <value> - Modify settings")
|
||
echo(" 可用键: logEnabled (true/false), zhlog (true/false), delay (数字)", " Available keys: logEnabled (true/false), zhlog (true/false), delay (number)")
|
||
echo("exit - 退出程序", "exit - Exit program")
|
||
|
||
elseif command == "exit" then
|
||
echo("正在退出程序", "Exiting program")
|
||
os.sleep(0.5)
|
||
error("程序终止", 0)
|
||
end
|
||
end
|
||
|
||
-- 初始化
|
||
|
||
echo("物流系统 v5.0 已启动。输入 'help' 查看命令。",
|
||
"Turtle Logistics System v5.0 started. Type 'help' for commands.")
|
||
|
||
-- 主循环
|
||
parallel.waitForAll(
|
||
function()
|
||
while true do
|
||
write("> ")
|
||
local command = read()
|
||
processCommand(command)
|
||
end
|
||
end,
|
||
taskLoop
|
||
) |