cc物流系统V5

This commit is contained in:
HKXluo
2025-10-24 02:43:59 +08:00
parent b6dea93a18
commit c38a55330c
15 changed files with 4804 additions and 0 deletions

148
Logistics/V5/README.md Normal file
View File

@@ -0,0 +1,148 @@
# 物流系统 v5.0 文档
## 概述
物流系统 v5.0 是一个高级物品和流体传输系统,支持多容器操作和缓存模式。系统通过配置文件管理任务,支持复杂的过滤规则和优先级设置。
## 核心功能
### 1. 传输类型
- **物品传输**:在容器间移动物品
- **流体传输**:在容器间移动流体
### 2. 缓存模式
- 适用于及作为输出也作为输入的容器
- 物品被送如时添加临时黑名单 这些物品不会被再次传输到别的容器
### 3. 过滤规则
- **白名单**:只允许特定物品传输
- **黑名单**:禁止特定物品传输
- **数量限制**:设置一次传输物品数量
### 4. 优先级系统
- 输出容器按优先级分组
- 高优先级容器优先接收物品
- 同优先级采用轮询机制
## 配置文件结构
配置文件存储在 `config.cfg` 中,包含以下部分:
```lua
{
settings = {
logEnabled = false, -- 日志开关
zhlog = false, -- 中文日志开关
delay = 0.01 -- 轮询延迟(秒)
},
tasks = { -- 任务列表
-- 任务示例
{
type = "item", -- 或 "fluid"
input = {
["容器名"] = {
cache = true/false,
whitelist = {["物品名"] = {}},
blacklist = {["物品名"] = {}}
}
},
output = {
["容器名"] = {
priority = 数字,
cache = true/false,
whitelist = {["物品名"] = {count = 数量}},
blacklist = {["物品名"] = {}}
}
}
}
},
Tlist = {} -- 缓存传输列表
}
```
## 使用命令
### 基本命令
| 命令 | 描述 | 示例 |
|------|------|------|
| `add <JSON>` | 添加新任务 | `add {"type":"item","input":{"left":{...}},"output":{"right":{...}}}` |
| `list` | 列出所有任务 | `list` |
| `remove <索引>` | 移除任务 | `remove 1` |
| `set <key> <value>` | 修改设置 | `set delay 0.05` |
| `help` | 显示帮助信息 | `help` |
| `exit` | 退出程序 | `exit` |
### 设置命令
| 键 | 值 | 描述 |
|----|----|------|
| `log` | true/false | 启用/禁用日志 |
| `zh` | true/false | 启用/禁用中文日志 |
| `delay` | 数字 | 设置轮询延迟(秒) |
## 任务配置示例
### 物品传输任务
```json
{
"type": "item",
"input": {
"left": {
"cache": true,
"whitelist": {
"minecraft:stone": {}
}
}
},
"output": {
"right": {
"priority": 1,
"whitelist": {
"minecraft:stone": {"count": 64}
},
"blacklist": {
"minecraft:dirt": {}
}
}
}
}
```
### 流体传输任务
```json
{
"type": "fluid",
"input": {
"tank_left": {
"whitelist": {
"water": {}
}
}
},
"output": {
"tank_right": {
"priority": 2
}
}
}
```
## 日志系统
- **日志级别**
- SUCCESS (绿色):成功操作
- SKIPPED (橙色):跳过操作
- INFO (白色):一般信息
- WARNING (黄色):警告信息
- ERROR (红色):错误信息
- DEBUG (浅灰色):调试信息
- **日志格式**
```
[时间] 级别: 消息
```
## 注意事项
1. 确保所有容器名称正确且可访问
2. 确保所有容器链接到电脑的同一个调制解调器
3. 流体容器必须支持流体接口
4. 复杂的过滤规则可能影响性能
5. 轮询延迟设置过低可能导致CPU占用过高
系统通过高效的缓存机制和优先级处理,实现了复杂的多容器物流管理,适用于各种自动化场景。

942
Logistics/V5/startup.lua Normal file
View File

@@ -0,0 +1,942 @@
-- 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)
log(LOG_LEVEL.INFO, "开始执行物品任务", "Starting item transfer task")
-- 收集所有输入容器的物品
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 startIdx = lastOutput[priority] or 1
local idx = startIdx
local attempts = 0
repeat
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
-- 更新轮询索引
lastOutput[priority] = 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)
log(LOG_LEVEL.INFO, "开始执行流体任务", "Starting fluid transfer task")
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 startIdx = lastOutput[priority] 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[priority] = 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)
if task.type == "item" then
return executeItemTask(task)
elseif task.type == "fluid" then
return executeFluidTask(task)
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)
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
)

935
Logistics/V5/web/1.txt Normal file
View File

@@ -0,0 +1,935 @@
-- Turtle 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 directions = {
up = "up", down = "down", forward = "forward"
}
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)
log(LOG_LEVEL.INFO, "开始执行物品任务", "Starting item transfer task")
-- 收集所有输入容器的物品
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
-- 如果数量大于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
-- 如果数量大于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 startIdx = lastOutput[priority] or 1
local idx = startIdx
local attempts = 0
repeat
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
log(LOG_LEVEL.DEBUG, "尝试推送到 "..output.name.." (优先级 "..priority..")", "Attempting push to "..output.name.." (priority "..priority..")")
-- 推送物品
local pushedCount = sourceContainer.pushItems(
output.name,
itemData.slot,
itemData.count
)
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
-- 更新轮询索引
lastOutput[priority] = 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)
log(LOG_LEVEL.INFO, "开始执行流体任务", "Starting fluid transfer task")
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 startIdx = lastOutput[priority] 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[priority] = 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)
if task.type == "item" then
return executeItemTask(task)
elseif task.type == "fluid" then
return executeFluidTask(task)
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)
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
)
{"type":"item","input":{"create:basin_6":{"cache":true,"whitelist":{"minecraft:iron_ingot":{}}}},"output":{"create:basin_7":{"priority":1,"whitelist":{"minecraft:iron_ingot":{"count":10}}}}}
我在输出容器的白名单定理了数量,但程序不遵循数量参数而是直接传输了所有

View File

@@ -0,0 +1,18 @@
#文件前32个十六进制位是头部数据
分别是[4位表示的version][4位表示的header_size][4位表示的timestamp][4位表示的unknown1][4位表示的unknown2][4位表示的unknown3][4位表示的material_count][4位表示的reserved]
其中header_size不知为何总为错误的
#下面为蓝图材料数据:
[4位表示的路径长度(包括00结束符)] [材料路径(结束用1位的00表示)] [4位表示的数量] [4位表示的参数]
当所有材料结束时在末尾添加4个十六进制未表示的0代表材料部分结束
注:[4位表示的参数] 目前具体是什么未知. 但只有蓝图的最后一个材料才会有数据其他都为0. 其数值可能和蓝图绑定不得修改,蓝图的最后一个的参数必须有数据
#下面为建筑部分:
[4位表示的路径长度(包括00结束符)] [建筑路径(结束用1位的00表示)] [4位表示的参数]
当建筑部分结束时尾部添加4个十六进制未的22222222代表建筑部分结束
注:[4位表示的参数] 目前具体是什么未知. 但只有蓝图的最后一个建筑才会有数据其他都为0. 其数值可能和蓝图绑定不得修改,蓝图的最后一个的参数必须有数据
#下面是压缩部分:
此部分为Zlib压缩后数据 具体内容没分析 不做分析

View File

@@ -0,0 +1,13 @@
<!doctype html>
<html data-theme="emerald">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>web</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

2193
Logistics/V5/web/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
{
"name": "web",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@tailwindcss/vite": "^4.1.14",
"axios": "^1.12.2",
"daisyui": "^5.3.7",
"tailwindcss": "^4.1.14",
"vue": "^3.5.22"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.1",
"vite": "^7.1.7"
}
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,496 @@
<template>
<div id="app" class="container mx-auto px-4 py-8">
<div class="text-center mb-8">
<h1 class="text-3xl font-bold text-gray-800">物流系统 v5.0</h1>
<p class="text-gray-600">任务配置创建工具</p>
</div>
<div class="bg-white rounded-xl shadow-lg p-6 mb-8">
<div class="flex flex-col md:flex-row gap-6">
<!-- 左侧配置区域 -->
<div class="w-full md:w-2/3">
<div class="mb-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4">创建新任务</h2>
<!-- 传输类型选择 -->
<div class="mb-6">
<label class="block text-gray-700 font-medium mb-2">传输类型</label>
<div class="flex gap-4">
<label class="flex items-center">
<input type="radio" v-model="task.type" value="item" class="radio radio-primary mr-2">
<span>物品传输</span>
</label>
<label class="flex items-center">
<input type="radio" v-model="task.type" value="fluid" class="radio radio-primary mr-2">
<span>流体传输</span>
</label>
</div>
</div>
<!-- 输入容器配置 -->
<div class="container-box">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-800">输入容器</h3>
<button @click="addInputContainer" class="btn btn-sm btn-primary">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
添加容器
</button>
</div>
<div v-for="(input, index) in task.input" :key="'input-'+index" class="mb-6 p-4 bg-gray-50 rounded-lg">
<div class="flex justify-between items-center mb-3">
<h4 class="font-medium text-gray-700">容器 #{{ index + 1 }}</h4>
<button @click="removeInputContainer(index)" class="btn btn-xs btn-error">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-1">容器名称</label>
<input v-model="input.containerName" type="text" placeholder="例如: chest_left" class="input input-bordered w-full">
</div>
<div class="mb-4">
<label class="flex items-center">
<input type="checkbox" v-model="input.cache" class="checkbox checkbox-primary mr-2">
<span>启用缓存模式</span>
</label>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-2">过滤规则</label>
<div class="tabs mb-3">
<a class="tab tab-bordered" :class="{'tab-active': input.filterType === 'whitelist'}" @click="input.filterType = 'whitelist'">白名单</a>
<a class="tab tab-bordered" :class="{'tab-active': input.filterType === 'blacklist'}" @click="input.filterType = 'blacklist'">黑名单</a>
</div>
<div v-if="input.filterType === 'whitelist'">
<div class="mb-2">
<div class="item-entry" v-for="(item, itemIndex) in input.whitelist" :key="'input-wl-'+itemIndex">
<input v-model="item.name" type="text" placeholder="物品ID (例如: minecraft:stone)" class="input input-bordered flex-grow">
<button @click="removeWhitelistItem(input.whitelist, itemIndex)" class="btn btn-xs btn-error">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
<button @click="addWhitelistItem(input.whitelist)" class="btn btn-sm btn-outline">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
添加白名单项目
</button>
</div>
<div v-else>
<div class="mb-2">
<div class="item-entry" v-for="(item, itemIndex) in input.blacklist" :key="'input-bl-'+itemIndex">
<input v-model="item.name" type="text" placeholder="物品ID (例如: minecraft:dirt)" class="input input-bordered flex-grow">
<button @click="removeBlacklistItem(input.blacklist, itemIndex)" class="btn btn-xs btn-error">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
<button @click="addBlacklistItem(input.blacklist)" class="btn btn-sm btn-outline">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
添加黑名单项目
</button>
</div>
</div>
</div>
</div>
<!-- 输出容器配置 -->
<div class="container-box">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-800">输出容器</h3>
<button @click="addOutputContainer" class="btn btn-sm btn-primary">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
添加容器
</button>
</div>
<div v-for="(output, index) in task.output" :key="'output-'+index" class="mb-6 p-4 bg-gray-50 rounded-lg">
<div class="flex justify-between items-center mb-3">
<h4 class="font-medium text-gray-700">容器 #{{ index + 1 }}</h4>
<button @click="removeOutputContainer(index)" class="btn btn-xs btn-error">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-1">容器名称</label>
<input v-model="output.containerName" type="text" placeholder="例如: chest_right" class="input input-bordered w-full">
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-1">优先级</label>
<input v-model="output.priority" type="number" min="1" class="input input-bordered w-full">
</div>
<div class="mb-4">
<label class="flex items-center">
<input type="checkbox" v-model="output.cache" class="checkbox checkbox-primary mr-2">
<span>启用缓存模式</span>
</label>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-2">过滤规则</label>
<div class="tabs mb-3">
<a class="tab tab-bordered" :class="{'tab-active': output.filterType === 'whitelist'}" @click="output.filterType = 'whitelist'">白名单</a>
<a class="tab tab-bordered" :class="{'tab-active': output.filterType === 'blacklist'}" @click="output.filterType = 'blacklist'">黑名单</a>
</div>
<div v-if="output.filterType === 'whitelist'">
<div class="mb-2">
<div class="item-entry" v-for="(item, itemIndex) in output.whitelist" :key="'output-wl-'+itemIndex">
<input v-model="item.name" type="text" placeholder="物品ID (例如: minecraft:stone)" class="input input-bordered flex-grow">
<input v-model="item.count" type="number" min="1" placeholder="数量" class="input input-bordered w-24">
<button @click="removeWhitelistItem(output.whitelist, itemIndex)" class="btn btn-xs btn-error">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
<button @click="addWhitelistItem(output.whitelist)" class="btn btn-sm btn-outline">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
添加白名单项目
</button>
</div>
<div v-else>
<div class="mb-2">
<div class="item-entry" v-for="(item, itemIndex) in output.blacklist" :key="'output-bl-'+itemIndex">
<input v-model="item.name" type="text" placeholder="物品ID (例如: minecraft:dirt)" class="input input-bordered flex-grow">
<button @click="removeBlacklistItem(output.blacklist, itemIndex)" class="btn btn-xs btn-error">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
<button @click="addBlacklistItem(output.blacklist)" class="btn btn-sm btn-outline">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
添加黑名单项目
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 右侧预览区域 -->
<div class="w-full md:w-1/3">
<div class="sticky top-4">
<div class="bg-white rounded-xl shadow-lg p-6">
<h3 class="text-lg font-semibold text-gray-800 mb-4">配置预览</h3>
<div class="mb-4">
<label class="block text-gray-700 mb-2">生成的任务配置</label>
<pre class="bg-gray-800 text-green-200 p-4 rounded-lg overflow-auto max-h-96">{{ formattedJson }}</pre>
</div>
<!-- 新增命令文本区域 -->
<div class="mb-4">
<label class="block text-gray-700 mb-2">命令文本</label>
<pre class="bg-gray-800 text-blue-200 p-4 rounded-lg overflow-auto">{{ commandString }}</pre>
</div>
<div class="flex gap-2">
<button @click="copyToClipboard" class="btn btn-primary flex-grow">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
</svg>
复制命令
</button>
<button @click="resetForm" class="btn btn-outline">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
重置
</button>
</div>
<div v-if="copySuccess" class="mt-3 text-center text-green-500">
命令已复制到剪贴板
</div>
</div>
<div class="bg-white rounded-xl shadow-lg p-6 mt-4">
<h3 class="text-lg font-semibold text-gray-800 mb-4">使用说明</h3>
<ul class="text-gray-600 space-y-2">
<li class="flex items-start">
<div class="bg-blue-100 text-blue-800 rounded-full w-6 h-6 flex items-center justify-center mr-2 flex-shrink-0">1</div>
<span>配置输入和输出容器信息</span>
</li>
<li class="flex items-start">
<div class="bg-blue-100 text-blue-800 rounded-full w-6 h-6 flex items-center justify-center mr-2 flex-shrink-0">2</div>
<span>设置过滤规则白名单或黑名单</span>
</li>
<li class="flex items-start">
<div class="bg-blue-100 text-blue-800 rounded-full w-6 h-6 flex items-center justify-center mr-2 flex-shrink-0">3</div>
<span>为输出容器设置优先级</span>
</li>
<li class="flex items-start">
<div class="bg-blue-100 text-blue-800 rounded-full w-6 h-6 flex items-center justify-center mr-2 flex-shrink-0">4</div>
<span>复制生成的命令文本</span>
</li>
<li class="flex items-start">
<div class="bg-blue-100 text-blue-800 rounded-full w-6 h-6 flex items-center justify-center mr-2 flex-shrink-0">5</div>
<span>在物流系统中粘贴并执行命令</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
task: {
type: 'item',
input: [
{
containerName: '',
cache: false,
filterType: 'whitelist',
whitelist: [{ name: '' }],
blacklist: [{ name: '' }]
}
],
output: [
{
containerName: '',
priority: 1,
cache: false,
filterType: 'whitelist',
whitelist: [{ name: '', count: null }],
blacklist: [{ name: '' }]
}
]
},
copySuccess: false
}
},
computed: {
taskConfig() {
const task = JSON.parse(JSON.stringify(this.task));
// 转换输入容器
const inputObj = {};
task.input.forEach(container => {
const containerName = container.containerName || 'unnamed_container';
inputObj[containerName] = {
cache: container.cache
};
// 处理白名单 - 只有当有实际内容时才添加
const whitelistItems = container.whitelist.filter(item => item.name && item.name.trim() !== '');
if (whitelistItems.length > 0) {
inputObj[containerName].whitelist = {};
whitelistItems.forEach(item => {
inputObj[containerName].whitelist[item.name] = {};
});
}
// 处理黑名单 - 只有当有实际内容时才添加
const blacklistItems = container.blacklist.filter(item => item.name && item.name.trim() !== '');
if (blacklistItems.length > 0) {
inputObj[containerName].blacklist = {};
blacklistItems.forEach(item => {
inputObj[containerName].blacklist[item.name] = {};
});
}
});
// 转换输出容器
const outputObj = {};
task.output.forEach(container => {
const containerName = container.containerName || 'unnamed_container';
outputObj[containerName] = {
priority: parseInt(container.priority) || 1,
cache: container.cache
};
// 处理白名单 - 只有当有实际内容时才添加
const whitelistItems = container.whitelist.filter(item => item.name && item.name.trim() !== '');
if (whitelistItems.length > 0) {
outputObj[containerName].whitelist = {};
whitelistItems.forEach(item => {
if (item.count) {
outputObj[containerName].whitelist[item.name] = { count: parseInt(item.count) };
} else {
outputObj[containerName].whitelist[item.name] = {};
}
});
}
// 处理黑名单 - 只有当有实际内容时才添加
const blacklistItems = container.blacklist.filter(item => item.name && item.name.trim() !== '');
if (blacklistItems.length > 0) {
outputObj[containerName].blacklist = {};
blacklistItems.forEach(item => {
outputObj[containerName].blacklist[item.name] = {};
});
}
});
return {
type: task.type,
input: inputObj,
output: outputObj
};
},
formattedJson() {
return JSON.stringify(this.taskConfig, null, 2);
},
compressedJson() {
return JSON.stringify(this.taskConfig);
},
commandString() {
return `add ${this.compressedJson}`;
}
},
methods: {
addInputContainer() {
this.task.input.push({
containerName: '',
cache: false,
filterType: 'whitelist',
whitelist: [{ name: '' }],
blacklist: [{ name: '' }]
});
},
removeInputContainer(index) {
if (this.task.input.length > 1) {
this.task.input.splice(index, 1);
}
},
addOutputContainer() {
this.task.output.push({
containerName: '',
priority: 1,
cache: false,
filterType: 'whitelist',
whitelist: [{ name: '', count: null }],
blacklist: [{ name: '' }]
});
},
removeOutputContainer(index) {
if (this.task.output.length > 1) {
this.task.output.splice(index, 1);
}
},
addWhitelistItem(list) {
list.push(this.task.type === 'item' ? { name: '', count: null } : { name: '' });
},
removeWhitelistItem(list, index) {
if (list.length > 1) {
list.splice(index, 1);
}
},
addBlacklistItem(list) {
list.push({ name: '' });
},
removeBlacklistItem(list, index) {
if (list.length > 1) {
list.splice(index, 1);
}
},
copyToClipboard() {
const textarea = document.createElement('textarea');
textarea.value = this.commandString;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
this.copySuccess = true;
setTimeout(() => {
this.copySuccess = false;
}, 3000);
},
resetForm() {
this.task = {
type: 'item',
input: [
{
containerName: '',
cache: false,
filterType: 'whitelist',
whitelist: [{ name: '' }],
blacklist: [{ name: '' }]
}
],
output: [
{
containerName: '',
priority: 1,
cache: false,
filterType: 'whitelist',
whitelist: [{ name: '', count: null }],
blacklist: [{ name: '' }]
}
]
};
}
}
}
</script>
<style>
.container-box {
background-color: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.item-entry {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.5rem;
}
.drag-handle {
cursor: move;
opacity: 0.6;
}
.drag-handle:hover {
opacity: 1;
}
.transition-all {
transition: all 0.3s ease;
}
</style>

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

After

Width:  |  Height:  |  Size: 496 B

View File

@@ -0,0 +1,5 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
createApp(App).mount('#app')

View File

@@ -0,0 +1,18 @@
import { createRouter, createWebHistory } from 'vue-router';
import BlueprintEditorView from '@/views/BlueprintEditorView.vue';
const routes = [
{
path: '/blueprint-editor',
name: 'BlueprintEditor',
component: BlueprintEditorView
},
// 其他路由...
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
});
export default router;

View File

@@ -0,0 +1,2 @@
@import "tailwindcss";
@plugin "daisyui";

View File

@@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindcss from '@tailwindcss/vite';
// https://vite.dev/config/
export default defineConfig({
plugins: [vue(),tailwindcss()],
})