初始
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.history
|
||||
222
panel.lua
222
panel.lua
@@ -1,222 +0,0 @@
|
||||
-- ME空间原件控制器测试客户端
|
||||
-- 在另一台计算机上运行,用于测试和控制海龟
|
||||
printUtf8 = load(http.get("https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/utf8ptrint.lua").readAll())()
|
||||
basalt = require("basalt")
|
||||
|
||||
-- 配置文件常量
|
||||
local CLIENT_CONFIG_FILE = "disk_client_cfg"
|
||||
|
||||
-- 默认端口配置
|
||||
local DEFAULT_PORTS = {
|
||||
control = 101, -- 控制信道(发送切换命令)
|
||||
response = 102, -- 响应接收信道
|
||||
status = 100 -- 状态接收信道(原INVENTORY_CHANNEL)
|
||||
}
|
||||
|
||||
-- 读取客户端配置文件
|
||||
local function readClientConfig()
|
||||
if not fs.exists(CLIENT_CONFIG_FILE) then
|
||||
-- 创建默认配置文件
|
||||
local defaultConfig = {
|
||||
rednet_ports = DEFAULT_PORTS
|
||||
}
|
||||
|
||||
local file = fs.open(CLIENT_CONFIG_FILE, "w")
|
||||
file.write(textutils.serialize(defaultConfig))
|
||||
file.close()
|
||||
|
||||
print("已创建客户端默认配置文件: " .. CLIENT_CONFIG_FILE)
|
||||
return defaultConfig
|
||||
end
|
||||
|
||||
local file = fs.open(CLIENT_CONFIG_FILE, "r")
|
||||
local content = file.readAll()
|
||||
file.close()
|
||||
|
||||
local config = textutils.unserialize(content) or {rednet_ports = DEFAULT_PORTS}
|
||||
|
||||
-- 确保端口配置完整
|
||||
if not config.rednet_ports then
|
||||
config.rednet_ports = DEFAULT_PORTS
|
||||
else
|
||||
-- 设置默认值
|
||||
config.rednet_ports.control = config.rednet_ports.control or DEFAULT_PORTS.control
|
||||
config.rednet_ports.response = config.rednet_ports.response or DEFAULT_PORTS.response
|
||||
config.rednet_ports.status = config.rednet_ports.status or DEFAULT_PORTS.status
|
||||
end
|
||||
|
||||
return config
|
||||
end
|
||||
|
||||
-- 读取配置
|
||||
local config = readClientConfig()
|
||||
|
||||
-- 初始化红网
|
||||
local function initRednet()
|
||||
local sides = {"left", "right", "front", "back", "top", "bottom"}
|
||||
local modem = nil
|
||||
|
||||
for _, side in ipairs(sides) do
|
||||
if peripheral.getType(side) == "modem" then
|
||||
modem = peripheral.wrap(side)
|
||||
-- 打开所有需要的端口
|
||||
modem.open(config.rednet_ports.control)
|
||||
modem.open(config.rednet_ports.response)
|
||||
modem.open(config.rednet_ports.status)
|
||||
print("找到网卡在: " .. side)
|
||||
print("端口配置:")
|
||||
print(" 控制端口: " .. config.rednet_ports.control)
|
||||
print(" 响应端口: " .. config.rednet_ports.response)
|
||||
print(" 状态端口: " .. config.rednet_ports.status)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not modem then
|
||||
error("未找到可用的网卡!")
|
||||
end
|
||||
|
||||
return modem
|
||||
end
|
||||
|
||||
local modem = initRednet()
|
||||
|
||||
-- 发送切换命令
|
||||
local function sendSwitchCommand(diskName)
|
||||
local message = {
|
||||
type = "switch_disk",
|
||||
disk_name = diskName
|
||||
}
|
||||
|
||||
modem.transmit(config.rednet_ports.control, config.rednet_ports.control, message)
|
||||
print("已发送切换命令: " .. diskName)
|
||||
end
|
||||
|
||||
disks = {}
|
||||
|
||||
local mainf = basalt.createFrame()
|
||||
local main = {
|
||||
panel = mainf:addFrame():setPosition(1, 1):setSize("parent.w", "parent.h"):setBackground(colors.white),
|
||||
}
|
||||
|
||||
UI = {}
|
||||
|
||||
-- 生成界面
|
||||
function addFrameS(disks)
|
||||
SY = {}
|
||||
local SYI = 1
|
||||
local h = 2
|
||||
for name,slot in pairs(disks) do
|
||||
UI[name] = {}
|
||||
UI[name]["Back"] = main["panel"]:addFrame():setPosition(1, h):setSize("parent.w", 3):setBackground(colors.gray)
|
||||
UI[name]["XZ"] = UI[name]["Back"]:addPane():setPosition(1, 1):setSize(1, 3):setBackground(false, "\149", colors.gray)
|
||||
UI[name]["Name"] = UI[name]["Back"]:addProgram():setPosition(2, 1):setSize(35, 4):execute(function()
|
||||
term.setBackgroundColor(colors.gray)
|
||||
term.clear()
|
||||
printUtf8(name, colors.white, colors.gray)
|
||||
end):injectEvent("char", false, "w"):disable()
|
||||
SY[SYI] = name
|
||||
SYI = SYI + 1
|
||||
h = h+4
|
||||
end
|
||||
end
|
||||
|
||||
-- 辅助函数:比较两个表是否相等
|
||||
local function areTablesEqual(t1, t2)
|
||||
if t1 == t2 then return true end
|
||||
if type(t1) ~= "table" or type(t2) ~= "table" then return false end
|
||||
|
||||
for k, v in pairs(t1) do
|
||||
if t2[k] ~= v then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in pairs(t2) do
|
||||
if t1[k] == nil then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- 处理红网消息
|
||||
local function handleRednetMessage(message)
|
||||
if message.type == "status_update" then
|
||||
-- 只有当两个表数值不一样时才执行
|
||||
if not areTablesEqual(message.disks, disks) then
|
||||
disks = message.disks
|
||||
addFrameS(disks)
|
||||
end
|
||||
|
||||
for name,slot in pairs(disks) do
|
||||
if name == message.current_disk then
|
||||
UI[name]["Back"]:setBackground(colors.red)
|
||||
else
|
||||
UI[name]["Back"]:setBackground(colors.gray)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DSY = 1
|
||||
on = false
|
||||
|
||||
-- 主循环 - 消息监听
|
||||
local function main1()
|
||||
while true do
|
||||
-- 检查红网消息
|
||||
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
||||
|
||||
-- 检查是否是状态端口或响应端口的消息
|
||||
if (channel == config.rednet_ports.status or channel == config.rednet_ports.response) and type(message) == "table" then
|
||||
handleRednetMessage(message)
|
||||
if not on then
|
||||
if SY and SY[DSY] then
|
||||
UI[SY[DSY]]["XZ"]:setBackground(false, "\149", colors.lime)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function main2()
|
||||
while true do
|
||||
local event, key, is_held = os.pullEvent("key")
|
||||
if keys.getName(key) == "down" then
|
||||
if SY and DSY ~= #SY then
|
||||
DSY = DSY + 1
|
||||
end
|
||||
|
||||
for k,v in pairs(SY or {}) do
|
||||
if k == DSY then
|
||||
UI[v]["XZ"]:setBackground(false, "\149", colors.lime)
|
||||
else
|
||||
UI[v]["XZ"]:setBackground(false, "\149", colors.gray)
|
||||
end
|
||||
end
|
||||
sleep(0.5)
|
||||
elseif keys.getName(key) == "up" then
|
||||
if DSY > 1 then
|
||||
DSY = DSY -1
|
||||
end
|
||||
|
||||
for k,v in pairs(SY or {}) do
|
||||
if k == DSY then
|
||||
UI[v]["XZ"]:setBackground(false, "\149", colors.lime)
|
||||
else
|
||||
UI[v]["XZ"]:setBackground(false, "\149", colors.gray)
|
||||
end
|
||||
end
|
||||
sleep(0.5)
|
||||
elseif keys.getName(key) == "enter" then
|
||||
if SY and SY[DSY] then
|
||||
sendSwitchCommand(SY[DSY])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
parallel.waitForAny(main1, main2, basalt.autoUpdate)
|
||||
7
panel/config.cfg
Normal file
7
panel/config.cfg
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
rednet_ports = {
|
||||
status = 100,
|
||||
response = 102,
|
||||
control = 101,
|
||||
},
|
||||
}
|
||||
366
panel/startup.lua
Normal file
366
panel/startup.lua
Normal file
@@ -0,0 +1,366 @@
|
||||
-- ME空间原件控制器测试客户端
|
||||
-- 在另一台计算机上运行,用于测试和控制海龟
|
||||
printUtf8 = load(http.get("https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/utf8ptrint.lua").readAll())()
|
||||
--检测basalt
|
||||
if not fs.exists("basalt.lua") then shell.run("wget https://git.liulikeji.cn/GitHub/Basalt/releases/download/v1.6.6/basalt.lua basalt.lua") end
|
||||
basalt = require("basalt")
|
||||
|
||||
|
||||
|
||||
-- 配置文件常量
|
||||
local CLIENT_CONFIG_FILE = "config.cfg"
|
||||
|
||||
-- 默认端口配置
|
||||
local DEFAULT_PORTS = {
|
||||
control = 101, -- 控制信道(发送切换命令)
|
||||
response = 102, -- 响应接收信道
|
||||
status = 100 -- 状态接收信道(原INVENTORY_CHANNEL)
|
||||
}
|
||||
|
||||
-- 读取客户端配置文件
|
||||
local function readClientConfig()
|
||||
if not fs.exists(CLIENT_CONFIG_FILE) then
|
||||
-- 创建默认配置文件
|
||||
local defaultConfig = {
|
||||
rednet_ports = DEFAULT_PORTS
|
||||
}
|
||||
|
||||
local file = fs.open(CLIENT_CONFIG_FILE, "w")
|
||||
file.write(textutils.serialize(defaultConfig))
|
||||
file.close()
|
||||
|
||||
print("已创建客户端默认配置文件: " .. CLIENT_CONFIG_FILE)
|
||||
return defaultConfig
|
||||
end
|
||||
|
||||
local file = fs.open(CLIENT_CONFIG_FILE, "r")
|
||||
local content = file.readAll()
|
||||
file.close()
|
||||
|
||||
local config = textutils.unserialize(content) or {rednet_ports = DEFAULT_PORTS}
|
||||
|
||||
-- 确保端口配置完整
|
||||
if not config.rednet_ports then
|
||||
config.rednet_ports = DEFAULT_PORTS
|
||||
else
|
||||
-- 设置默认值
|
||||
config.rednet_ports.control = config.rednet_ports.control or DEFAULT_PORTS.control
|
||||
config.rednet_ports.response = config.rednet_ports.response or DEFAULT_PORTS.response
|
||||
config.rednet_ports.status = config.rednet_ports.status or DEFAULT_PORTS.status
|
||||
end
|
||||
|
||||
return config
|
||||
end
|
||||
|
||||
-- 读取配置
|
||||
local config = readClientConfig()
|
||||
|
||||
-- 初始化红网
|
||||
local function initRednet()
|
||||
local sides = {"left", "right", "front", "back", "top", "bottom"}
|
||||
local modem = nil
|
||||
|
||||
for _, side in ipairs(sides) do
|
||||
if peripheral.getType(side) == "modem" then
|
||||
modem = peripheral.wrap(side)
|
||||
-- 打开所有需要的端口
|
||||
modem.open(config.rednet_ports.control)
|
||||
modem.open(config.rednet_ports.response)
|
||||
modem.open(config.rednet_ports.status)
|
||||
print("找到网卡在: " .. side)
|
||||
print("端口配置:")
|
||||
print(" 控制端口: " .. config.rednet_ports.control)
|
||||
print(" 响应端口: " .. config.rednet_ports.response)
|
||||
print(" 状态端口: " .. config.rednet_ports.status)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not modem then
|
||||
error("未找到可用的网卡!")
|
||||
end
|
||||
|
||||
return modem
|
||||
end
|
||||
|
||||
local modem = initRednet()
|
||||
|
||||
-- 发送切换命令
|
||||
local function sendSwitchCommand(diskName)
|
||||
local message = {
|
||||
type = "switch_disk",
|
||||
disk_name = diskName
|
||||
}
|
||||
|
||||
modem.transmit(config.rednet_ports.control, config.rednet_ports.control, message)
|
||||
print("已发送切换命令: " .. diskName)
|
||||
end
|
||||
|
||||
disks = {}
|
||||
|
||||
local mainf = basalt.createFrame()
|
||||
local main = {
|
||||
panel = mainf:addFrame():setPosition(1, 1):setSize("parent.w", "parent.h"):setBackground(colors.white),
|
||||
}
|
||||
|
||||
-- 分页相关变量
|
||||
MAX_DISPLAY = 5 -- 每页最大显示数量
|
||||
currentPage = 1 -- 当前页码
|
||||
totalPages = 1 -- 总页数
|
||||
pageDisks = {} -- 当前页显示的磁盘
|
||||
|
||||
UI = {}
|
||||
|
||||
-- 更新分页信息
|
||||
local function updatePagination()
|
||||
-- 获取排序后的磁盘名称
|
||||
local sortedNames = {}
|
||||
for name, _ in pairs(disks) do
|
||||
table.insert(sortedNames, name)
|
||||
end
|
||||
table.sort(sortedNames)
|
||||
|
||||
-- 计算总页数
|
||||
totalPages = math.ceil(#sortedNames / MAX_DISPLAY)
|
||||
if totalPages == 0 then totalPages = 1 end
|
||||
|
||||
-- 确保当前页在有效范围内
|
||||
if currentPage > totalPages then
|
||||
currentPage = totalPages
|
||||
elseif currentPage < 1 then
|
||||
currentPage = 1
|
||||
end
|
||||
|
||||
-- 获取当前页的磁盘
|
||||
pageDisks = {}
|
||||
local startIndex = (currentPage - 1) * MAX_DISPLAY + 1
|
||||
local endIndex = math.min(startIndex + MAX_DISPLAY - 1, #sortedNames)
|
||||
|
||||
for i = startIndex, endIndex do
|
||||
pageDisks[i - startIndex + 1] = sortedNames[i]
|
||||
end
|
||||
end
|
||||
|
||||
-- 显示/隐藏磁盘项
|
||||
local function updateDiskVisibility()
|
||||
for name, uiElements in pairs(UI) do
|
||||
-- 隐藏所有磁盘项
|
||||
uiElements.Back:hide()
|
||||
end
|
||||
|
||||
-- 显示当前页的磁盘项
|
||||
for i, diskName in ipairs(pageDisks) do
|
||||
if UI[diskName] then
|
||||
local yPos = 2 + (i - 1) * 4
|
||||
UI[diskName].Back:setPosition(1, yPos):show()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 生成界面
|
||||
function addFrameS(disks)
|
||||
-- 清除旧的UI
|
||||
for name, uiElements in pairs(UI) do
|
||||
|
||||
if uiElements and uiElements.Back then
|
||||
uiElements.Back:remove()
|
||||
end
|
||||
end
|
||||
UI = {}
|
||||
|
||||
-- 更新分页信息
|
||||
updatePagination()
|
||||
|
||||
local h = 1
|
||||
for i, name in ipairs(pageDisks) do
|
||||
UI[name] = {}
|
||||
UI[name]["Back"] = main["panel"]:addFrame():setPosition(1, h):setSize("parent.w", 3):setBackground(colors.gray):onClick(function()
|
||||
-- 找到被点击的磁盘在当前页的索引
|
||||
local clickedIndex = nil
|
||||
for i, diskName in ipairs(pageDisks) do
|
||||
if diskName == name then
|
||||
clickedIndex = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if clickedIndex then
|
||||
-- 更新选择索引
|
||||
DSY = clickedIndex
|
||||
|
||||
-- 更新选择指示器
|
||||
for i, diskName in ipairs(pageDisks) do
|
||||
if i == DSY then
|
||||
UI[diskName]["XZ"]:setBackground(false, "\149", colors.lime)
|
||||
else
|
||||
UI[diskName]["XZ"]:setBackground(false, "\149", colors.gray)
|
||||
end
|
||||
end
|
||||
|
||||
-- 发送切换命令
|
||||
sendSwitchCommand(name)
|
||||
end
|
||||
end)
|
||||
UI[name]["XZ"] = UI[name]["Back"]:addPane():setPosition(1, 1):setSize(1, 3):setBackground(false, "\149", colors.gray)
|
||||
UI[name]["Name"] = UI[name]["Back"]:addProgram():setPosition(2, 1):setSize(35, 4):execute(function()
|
||||
term.setBackgroundColor(colors.gray)
|
||||
term.clear()
|
||||
printUtf8(name, colors.white, colors.gray)
|
||||
end):injectEvent("char", false, "w"):disable()
|
||||
h = h + 4
|
||||
end
|
||||
|
||||
local ym = currentPage.."/".. totalPages.." >"
|
||||
|
||||
-- 添加页码显示
|
||||
if not UI.pageText then
|
||||
main["panel"]:addLabel():setPosition(1,"parent.h"):setSize(1, 1):setText("<")
|
||||
UI.pageText = main["panel"]:addLabel():setPosition("parent.w - ".. #ym -1, "parent.h"):setSize("parent.w", 1):setText(ym)
|
||||
else
|
||||
UI.pageText:setText(ym):setPosition("parent.w - ".. #ym -1, "parent.h")
|
||||
end
|
||||
end
|
||||
|
||||
-- 辅助函数:比较两个表是否相等
|
||||
local function areTablesEqual(t1, t2)
|
||||
if t1 == t2 then return true end
|
||||
if type(t1) ~= "table" or type(t2) ~= "table" then return false end
|
||||
|
||||
for k, v in pairs(t1) do
|
||||
if t2[k] ~= v then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in pairs(t2) do
|
||||
if t1[k] == nil then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- 处理红网消息
|
||||
local function handleRednetMessage(message)
|
||||
if message.type == "status_update" then
|
||||
-- 只有当两个表数值不一样时才执行
|
||||
if not areTablesEqual(message.disks, disks) then
|
||||
disks = message.disks
|
||||
addFrameS(disks)
|
||||
end
|
||||
|
||||
-- 修复这里的问题:添加安全检查
|
||||
for name, slot in pairs(disks) do
|
||||
if UI[name] and UI[name].Back then -- 添加安全检查
|
||||
if name == message.current_disk then
|
||||
UI[name]["Back"]:setBackground(colors.red)
|
||||
else
|
||||
UI[name]["Back"]:setBackground(colors.gray)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DSY = 1
|
||||
on = false
|
||||
|
||||
-- 切换页面
|
||||
local function switchPage(direction)
|
||||
if direction == "next" and currentPage < totalPages then
|
||||
currentPage = currentPage + 1
|
||||
elseif direction == "prev" and currentPage > 1 then
|
||||
currentPage = currentPage - 1
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
-- 更新分页信息
|
||||
updatePagination()
|
||||
|
||||
-- 重新生成界面
|
||||
addFrameS(disks)
|
||||
|
||||
-- 重置选择索引
|
||||
DSY = 1
|
||||
|
||||
-- 更新选择指示器
|
||||
for i, diskName in ipairs(pageDisks) do
|
||||
if i == DSY then
|
||||
UI[diskName]["XZ"]:setBackground(false, "\149", colors.lime)
|
||||
else
|
||||
UI[diskName]["XZ"]:setBackground(false, "\149", colors.gray)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 主循环 - 消息监听
|
||||
local function main1()
|
||||
while true do
|
||||
-- 检查红网消息
|
||||
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
||||
|
||||
-- 检查是否是状态端口或响应端口的消息
|
||||
if (channel == config.rednet_ports.status or channel == config.rednet_ports.response) and type(message) == "table" then
|
||||
handleRednetMessage(message)
|
||||
if not on then
|
||||
if pageDisks and pageDisks[DSY] then
|
||||
UI[pageDisks[DSY]]["XZ"]:setBackground(false, "\149", colors.lime)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function main2()
|
||||
while true do
|
||||
local event, key, is_held = os.pullEvent("key")
|
||||
local keyName = keys.getName(key)
|
||||
|
||||
if keyName == "down" or keyName == "s" then
|
||||
if pageDisks and DSY < #pageDisks then
|
||||
DSY = DSY + 1
|
||||
end
|
||||
|
||||
for i, diskName in ipairs(pageDisks) do
|
||||
if i == DSY then
|
||||
UI[diskName]["XZ"]:setBackground(false, "\149", colors.lime)
|
||||
else
|
||||
UI[diskName]["XZ"]:setBackground(false, "\149", colors.gray)
|
||||
end
|
||||
end
|
||||
sleep(0.1)
|
||||
|
||||
elseif keyName == "up" or keyName == "w" then
|
||||
if DSY > 1 then
|
||||
DSY = DSY - 1
|
||||
end
|
||||
|
||||
for i, diskName in ipairs(pageDisks) do
|
||||
if i == DSY then
|
||||
UI[diskName]["XZ"]:setBackground(false, "\149", colors.lime)
|
||||
else
|
||||
UI[diskName]["XZ"]:setBackground(false, "\149", colors.gray)
|
||||
end
|
||||
end
|
||||
sleep(0.1)
|
||||
|
||||
elseif keyName == "enter" or keyName == "space" then
|
||||
if pageDisks and pageDisks[DSY] then
|
||||
sendSwitchCommand(pageDisks[DSY])
|
||||
end
|
||||
|
||||
-- 翻页控制
|
||||
elseif keyName == "right" or keyName == "d" then
|
||||
switchPage("next")
|
||||
sleep(0.1)
|
||||
|
||||
elseif keyName == "left" or keyName == "a" then
|
||||
switchPage("prev")
|
||||
sleep(0.1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
parallel.waitForAny(main1, main2, basalt.autoUpdate)
|
||||
12
server/config.cfg
Normal file
12
server/config.cfg
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
disks = {
|
||||
[ "区域1" ] = 1,
|
||||
[ "区域2" ] = 2,
|
||||
[ "区域3" ] = 3,
|
||||
},
|
||||
rednet_ports = {
|
||||
status = 100,
|
||||
response = 302,
|
||||
listen = 101,
|
||||
},
|
||||
}
|
||||
@@ -1,435 +1,435 @@
|
||||
-- ME空间原件控制器
|
||||
-- 功能: 管理ME空间原件的存储和切换
|
||||
--printUtf8 = load(http.get("https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/utf8ptrint.lua").readAll())()
|
||||
|
||||
--function print(a)
|
||||
-- printUtf8(a,colors.white,colors.lightGray)
|
||||
--end
|
||||
|
||||
-- 全局变量
|
||||
CONFIG_FILE = "disk_cfg"
|
||||
CHECK_INTERVAL = 2 -- 检测间隔(秒)
|
||||
REDSTONE_PULSE_INTERVAL = 0.1 -- 红石脉冲间隔(秒)
|
||||
MAX_WAIT_CYCLES = 30 -- 最大等待循环次数
|
||||
|
||||
peripherals = nil
|
||||
config = nil
|
||||
|
||||
-- 初始化外围设备
|
||||
local function initPeripherals()
|
||||
-- 左侧: 红网网卡
|
||||
local left = peripheral.getType("left")
|
||||
if left ~= "modem" then
|
||||
error("左侧没有找到红网网卡!")
|
||||
end
|
||||
|
||||
-- 从配置读取监听端口
|
||||
local listenPort = config.rednet_ports and config.rednet_ports.listen or 101
|
||||
peripheral.wrap("left").open(listenPort) -- 打开监听端口
|
||||
|
||||
-- 右侧: 扬声器
|
||||
local right = peripheral.getType("right")
|
||||
if right ~= "speaker" then
|
||||
print("警告: 右侧没有找到扬声器")
|
||||
end
|
||||
|
||||
-- 前方: 空间IO端口
|
||||
local front = peripheral.getType("front")
|
||||
if front ~= "ae2:spatial_io_port" then
|
||||
error("前方没有找到空间IO端口!")
|
||||
end
|
||||
|
||||
return {
|
||||
modem = peripheral.wrap("left"),
|
||||
speaker = peripheral.wrap("right"),
|
||||
spatial_io = peripheral.wrap("front")
|
||||
}
|
||||
end
|
||||
|
||||
-- 读取配置文件
|
||||
local function readConfig()
|
||||
if not fs.exists(CONFIG_FILE) then
|
||||
-- 创建默认配置文件
|
||||
local defaultConfig = {
|
||||
current_disk = nil,
|
||||
current_slot = nil,
|
||||
disks = {}, -- 格式: {["显示名称"] = 槽位编号}
|
||||
rednet_ports = {
|
||||
listen = 101, -- 监听端口
|
||||
status = 100, -- 状态发送端口
|
||||
response = 102 -- 响应发送端口
|
||||
}
|
||||
}
|
||||
|
||||
local file = fs.open(CONFIG_FILE, "w")
|
||||
file.write(textutils.serialize(defaultConfig))
|
||||
file.close()
|
||||
|
||||
print("已创建默认配置文件,请手动编辑 " .. CONFIG_FILE .. " 配置原件映射")
|
||||
return defaultConfig
|
||||
end
|
||||
|
||||
local file = fs.open(CONFIG_FILE, "r")
|
||||
local content = file.readAll()
|
||||
file.close()
|
||||
|
||||
local loadedConfig = textutils.unserialize(content) or {
|
||||
current_disk = nil,
|
||||
current_slot = nil,
|
||||
disks = {}
|
||||
}
|
||||
|
||||
-- 确保端口配置存在
|
||||
if not loadedConfig.rednet_ports then
|
||||
loadedConfig.rednet_ports = {
|
||||
listen = 101,
|
||||
status = 100,
|
||||
response = 102
|
||||
}
|
||||
else
|
||||
-- 设置默认值
|
||||
loadedConfig.rednet_ports.listen = loadedConfig.rednet_ports.listen or 101
|
||||
loadedConfig.rednet_ports.status = loadedConfig.rednet_ports.status or 100
|
||||
loadedConfig.rednet_ports.response = loadedConfig.rednet_ports.response or 102
|
||||
end
|
||||
|
||||
return loadedConfig
|
||||
end
|
||||
|
||||
-- 写入配置文件
|
||||
-- 写入配置文件
|
||||
local function writeConfig()
|
||||
-- 创建按槽位排序的disks表
|
||||
local sortedDisks = {}
|
||||
|
||||
-- 先将disks转换为数组形式进行排序
|
||||
local tempArray = {}
|
||||
for name, slot in pairs(config.disks) do
|
||||
table.insert(tempArray, {name = name, slot = slot})
|
||||
end
|
||||
|
||||
-- 按槽位排序
|
||||
table.sort(tempArray, function(a, b)
|
||||
return a.slot < b.slot
|
||||
end)
|
||||
|
||||
-- 重新构建有序的disks表
|
||||
for _, item in ipairs(tempArray) do
|
||||
sortedDisks[item.name] = item.slot
|
||||
end
|
||||
|
||||
-- 创建临时配置,使用排序后的disks
|
||||
local configToSave = {
|
||||
rednet_ports = config.rednet_ports,
|
||||
current_disk = config.current_disk,
|
||||
current_slot = config.current_slot,
|
||||
disks = sortedDisks
|
||||
}
|
||||
|
||||
local file = fs.open(CONFIG_FILE, "w")
|
||||
file.write(textutils.serialize(configToSave))
|
||||
file.close()
|
||||
end
|
||||
|
||||
-- 播放声音提示
|
||||
local function playSound(soundType)
|
||||
if peripherals.speaker then
|
||||
pcall(function()
|
||||
if soundType == "success" then
|
||||
peripherals.speaker.playSound("block.note_block.pling", 1.0, 2.0)
|
||||
elseif soundType == "working" then
|
||||
for i=1,3 do
|
||||
peripherals.speaker.playSound("block.note_block.bass", 3, 1)
|
||||
sleep(1)
|
||||
end
|
||||
elseif soundType == "error" then
|
||||
peripherals.speaker.playSound("block.note_block.bass", 1.0, 0.5)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- 发送红石脉冲
|
||||
local function sendRedstonePulse()
|
||||
redstone.setOutput("front", true)
|
||||
sleep(0.1)
|
||||
redstone.setOutput("front", false)
|
||||
end
|
||||
|
||||
-- 发送状态信息到红网
|
||||
local function sendStatusUpdate()
|
||||
-- 从配置读取端口
|
||||
local statusPort = config.rednet_ports.status
|
||||
local listenPort = config.rednet_ports.listen
|
||||
|
||||
-- 通过红网发送状态
|
||||
peripherals.modem.transmit(statusPort, listenPort, {
|
||||
type = "status_update",
|
||||
current_disk = config.current_disk,
|
||||
disks = config.disks,
|
||||
timestamp = os.time()
|
||||
})
|
||||
|
||||
print("状态已发送到端口 " .. statusPort .. ": 当前原件=" .. (config.current_disk or "无"))
|
||||
end
|
||||
|
||||
-- 检查空间IO端口状态
|
||||
local function checkSpatialIOState()
|
||||
local slots = peripherals.spatial_io.list()
|
||||
local state = {
|
||||
slot1 = slots[1], -- 第一格: 未放出/已收回
|
||||
slot2 = slots[2] -- 第二格: 已放出
|
||||
}
|
||||
return state
|
||||
end
|
||||
|
||||
-- 验证槽位是否有物品
|
||||
local function validateSlotHasItem(slot)
|
||||
local item = turtle.getItemDetail(slot)
|
||||
return item ~= nil
|
||||
end
|
||||
|
||||
-- 收回当前原件
|
||||
local function retractCurrentDisk()
|
||||
if not config.current_disk or not config.current_slot then
|
||||
return true -- 没有当前原件,直接返回成功
|
||||
end
|
||||
|
||||
print("开始收回原件: " .. config.current_disk)
|
||||
|
||||
-- 切换到当前原件槽位
|
||||
turtle.select(config.current_slot)
|
||||
|
||||
-- 尝试从空间IO端口拿取
|
||||
if turtle.suck() then
|
||||
print("235 原件已取回")
|
||||
end
|
||||
|
||||
-- 将原件放入空间IO端口
|
||||
if not turtle.drop() then
|
||||
error("无法放入空间IO端口")
|
||||
end
|
||||
|
||||
print("通过红石信号收回原件...")
|
||||
|
||||
local waitCycles = 0
|
||||
while waitCycles < MAX_WAIT_CYCLES do
|
||||
-- 发送红石脉冲
|
||||
sendRedstonePulse()
|
||||
|
||||
-- 检查空间IO端口状态
|
||||
local state = checkSpatialIOState()
|
||||
|
||||
if state.slot2 and not state.slot1 then
|
||||
-- 原件已回到第2格,尝试拿取
|
||||
if turtle.suck() then
|
||||
print("原件收回成功")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
sleep(REDSTONE_PULSE_INTERVAL)
|
||||
waitCycles = waitCycles + 1
|
||||
end
|
||||
|
||||
print("收回原件超时!")
|
||||
return false
|
||||
end
|
||||
|
||||
-- 放出目标原件
|
||||
local function deployTargetDisk(targetDisk)
|
||||
local targetSlot = config.disks[targetDisk]
|
||||
if not targetSlot then
|
||||
error("未找到原件: " .. targetDisk)
|
||||
end
|
||||
|
||||
-- 验证槽位
|
||||
if not validateSlotHasItem(targetSlot) then
|
||||
error("槽位 " .. targetSlot .. " 没有物品,无法放出")
|
||||
end
|
||||
|
||||
print("开始放出原件: " .. targetDisk)
|
||||
|
||||
-- 切换到目标槽位
|
||||
turtle.select(targetSlot)
|
||||
|
||||
-- 将原件放入空间IO端口
|
||||
if not turtle.drop() then
|
||||
error("无法放入空间IO端口")
|
||||
end
|
||||
|
||||
-- 通过红石信号激活放出
|
||||
print("通过红石信号放出原件...")
|
||||
|
||||
local waitCycles = 0
|
||||
while waitCycles < MAX_WAIT_CYCLES do
|
||||
-- 发送红石脉冲
|
||||
sendRedstonePulse()
|
||||
|
||||
-- 检查空间IO端口状态
|
||||
local state = checkSpatialIOState()
|
||||
|
||||
if state.slot2 and not state.slot1 then
|
||||
-- 原件已移动到第二格,放出成功
|
||||
print("原件放出成功")
|
||||
return true
|
||||
end
|
||||
|
||||
sleep(REDSTONE_PULSE_INTERVAL)
|
||||
waitCycles = waitCycles + 1
|
||||
end
|
||||
|
||||
print("放出原件超时!")
|
||||
return false
|
||||
end
|
||||
|
||||
-- 切换到指定原件
|
||||
local function switchToDisk(targetDisk)
|
||||
print("收到切换命令: " .. targetDisk)
|
||||
|
||||
-- 检查是否已经是目标原件
|
||||
if config.current_disk == targetDisk then
|
||||
print("已经是目标原件,无需切换")
|
||||
playSound("success")
|
||||
return true
|
||||
end
|
||||
|
||||
-- 检查目标原件是否存在
|
||||
if not config.disks[targetDisk] then
|
||||
print("错误: 未配置原件 '" .. targetDisk .. "'")
|
||||
playSound("error")
|
||||
return false
|
||||
end
|
||||
|
||||
playSound("working")
|
||||
|
||||
-- 收回当前原件
|
||||
if not retractCurrentDisk() then
|
||||
playSound("error")
|
||||
return false
|
||||
end
|
||||
|
||||
-- 放出目标原件
|
||||
if not deployTargetDisk(targetDisk) then
|
||||
playSound("error")
|
||||
return false
|
||||
end
|
||||
|
||||
-- 更新配置文件
|
||||
config.current_disk = targetDisk
|
||||
config.current_slot = config.disks[targetDisk]
|
||||
writeConfig()
|
||||
|
||||
playSound("success")
|
||||
print("切换完成: " .. targetDisk)
|
||||
sendStatusUpdate() -- 发送状态更新
|
||||
return true
|
||||
end
|
||||
|
||||
-- 处理红网消息
|
||||
local function handleRednetMessage(message)
|
||||
local responsePort = config.rednet_ports.response
|
||||
local listenPort = config.rednet_ports.listen
|
||||
|
||||
if message.type == "switch_disk" and message.disk_name then
|
||||
local success = switchToDisk(message.disk_name)
|
||||
|
||||
-- 发送响应
|
||||
peripherals.modem.transmit(responsePort, listenPort, {
|
||||
type = "switch_response",
|
||||
disk_name = message.disk_name,
|
||||
success = success,
|
||||
timestamp = os.time()
|
||||
})
|
||||
|
||||
elseif message.type == "status_request" then
|
||||
-- 发送状态信息
|
||||
peripherals.modem.transmit(responsePort, listenPort, {
|
||||
type = "status_response",
|
||||
current_disk = config.current_disk,
|
||||
disks = config.disks,
|
||||
timestamp = os.time()
|
||||
})
|
||||
elseif message.type == "reload_config" then
|
||||
-- 重新加载配置
|
||||
config = readConfig()
|
||||
peripherals.modem.transmit(responsePort, listenPort, {
|
||||
type = "reload_response",
|
||||
success = true,
|
||||
timestamp = os.time()
|
||||
})
|
||||
print("配置已重新加载")
|
||||
end
|
||||
end
|
||||
|
||||
-- 主循环 - 状态发送
|
||||
local function main()
|
||||
print("ME空间原件控制器启动中...")
|
||||
|
||||
|
||||
print("1 外围设备初始化完成")
|
||||
print("2 当前原件: " .. (config.current_disk or "无"))
|
||||
print("3 配置的原件: ")
|
||||
for name, slot in pairs(config.disks) do
|
||||
print(" " .. name .. " -> 槽位 " .. slot)
|
||||
end
|
||||
print("4 红网端口配置: ")
|
||||
print(" 监听端口: " .. config.rednet_ports.listen)
|
||||
print(" 状态端口: " .. config.rednet_ports.status)
|
||||
print(" 响应端口: " .. config.rednet_ports.response)
|
||||
|
||||
-- 初始状态发送
|
||||
sendStatusUpdate()
|
||||
|
||||
while true do
|
||||
sleep(CHECK_INTERVAL)
|
||||
sendStatusUpdate()
|
||||
end
|
||||
end
|
||||
|
||||
-- 主循环 - 消息监听
|
||||
local function main1()
|
||||
local listenPort = config.rednet_ports.listen
|
||||
|
||||
while true do
|
||||
-- 检查红网消息
|
||||
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
||||
if channel == listenPort and type(message) == "table" then
|
||||
handleRednetMessage(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 初始化检查
|
||||
if not turtle then
|
||||
error("这个脚本需要在海龟上运行!")
|
||||
end
|
||||
|
||||
-- 检查配置文件是否存在,如果不存在则创建并提示
|
||||
if not fs.exists(CONFIG_FILE) then
|
||||
config = readConfig() -- 这会创建默认配置文件
|
||||
print("请编辑 " .. CONFIG_FILE .. " 文件配置原件映射,格式如下:")
|
||||
print("{")
|
||||
print(' current_disk = "原件A",')
|
||||
print(' current_slot = 1,')
|
||||
print(' disks = {')
|
||||
print(' ["原件A"] = 1,')
|
||||
print(' ["原件B"] = 2,')
|
||||
print(' ["原件C"] = 3')
|
||||
print(" },")
|
||||
print(' rednet_ports = {')
|
||||
print(' listen = 101, -- 监听端口')
|
||||
print(' status = 100, -- 状态发送端口')
|
||||
print(' response = 102 -- 响应发送端口')
|
||||
print(" }")
|
||||
print("}")
|
||||
print("配置完成后重新启动脚本")
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
config = readConfig()
|
||||
peripherals = initPeripherals()
|
||||
|
||||
-- 启动程序
|
||||
-- ME空间原件控制器
|
||||
-- 功能: 管理ME空间原件的存储和切换
|
||||
--printUtf8 = load(http.get("https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/utf8ptrint.lua").readAll())()
|
||||
|
||||
--function print(a)
|
||||
-- printUtf8(a,colors.white,colors.lightGray)
|
||||
--end
|
||||
|
||||
-- 全局变量
|
||||
CONFIG_FILE = "config.cfg"
|
||||
CHECK_INTERVAL = 2 -- 检测间隔(秒)
|
||||
REDSTONE_PULSE_INTERVAL = 0.1 -- 红石脉冲间隔(秒)
|
||||
MAX_WAIT_CYCLES = 30 -- 最大等待循环次数
|
||||
|
||||
peripherals = nil
|
||||
config = nil
|
||||
|
||||
-- 初始化外围设备
|
||||
local function initPeripherals()
|
||||
-- 左侧: 红网网卡
|
||||
local left = peripheral.getType("left")
|
||||
if left ~= "modem" then
|
||||
error("左侧没有找到红网网卡!")
|
||||
end
|
||||
|
||||
-- 从配置读取监听端口
|
||||
local listenPort = config.rednet_ports and config.rednet_ports.listen or 101
|
||||
peripheral.wrap("left").open(listenPort) -- 打开监听端口
|
||||
|
||||
-- 右侧: 扬声器
|
||||
local right = peripheral.getType("right")
|
||||
if right ~= "speaker" then
|
||||
print("警告: 右侧没有找到扬声器")
|
||||
end
|
||||
|
||||
-- 前方: 空间IO端口
|
||||
local front = peripheral.getType("front")
|
||||
if front ~= "ae2:spatial_io_port" then
|
||||
error("前方没有找到空间IO端口!")
|
||||
end
|
||||
|
||||
return {
|
||||
modem = peripheral.wrap("left"),
|
||||
speaker = peripheral.wrap("right"),
|
||||
spatial_io = peripheral.wrap("front")
|
||||
}
|
||||
end
|
||||
|
||||
-- 读取配置文件
|
||||
local function readConfig()
|
||||
if not fs.exists(CONFIG_FILE) then
|
||||
-- 创建默认配置文件
|
||||
local defaultConfig = {
|
||||
current_disk = nil,
|
||||
current_slot = nil,
|
||||
disks = {}, -- 格式: {["显示名称"] = 槽位编号}
|
||||
rednet_ports = {
|
||||
listen = 101, -- 监听端口
|
||||
status = 100, -- 状态发送端口
|
||||
response = 102 -- 响应发送端口
|
||||
}
|
||||
}
|
||||
|
||||
local file = fs.open(CONFIG_FILE, "w")
|
||||
file.write(textutils.serialize(defaultConfig))
|
||||
file.close()
|
||||
|
||||
print("已创建默认配置文件,请手动编辑 " .. CONFIG_FILE .. " 配置原件映射")
|
||||
return defaultConfig
|
||||
end
|
||||
|
||||
local file = fs.open(CONFIG_FILE, "r")
|
||||
local content = file.readAll()
|
||||
file.close()
|
||||
|
||||
local loadedConfig = textutils.unserialize(content) or {
|
||||
current_disk = nil,
|
||||
current_slot = nil,
|
||||
disks = {}
|
||||
}
|
||||
|
||||
-- 确保端口配置存在
|
||||
if not loadedConfig.rednet_ports then
|
||||
loadedConfig.rednet_ports = {
|
||||
listen = 101,
|
||||
status = 100,
|
||||
response = 102
|
||||
}
|
||||
else
|
||||
-- 设置默认值
|
||||
loadedConfig.rednet_ports.listen = loadedConfig.rednet_ports.listen or 101
|
||||
loadedConfig.rednet_ports.status = loadedConfig.rednet_ports.status or 100
|
||||
loadedConfig.rednet_ports.response = loadedConfig.rednet_ports.response or 102
|
||||
end
|
||||
|
||||
return loadedConfig
|
||||
end
|
||||
|
||||
-- 写入配置文件
|
||||
-- 写入配置文件
|
||||
local function writeConfig()
|
||||
-- 创建按槽位排序的disks表
|
||||
local sortedDisks = {}
|
||||
|
||||
-- 先将disks转换为数组形式进行排序
|
||||
local tempArray = {}
|
||||
for name, slot in pairs(config.disks) do
|
||||
table.insert(tempArray, {name = name, slot = slot})
|
||||
end
|
||||
|
||||
-- 按槽位排序
|
||||
table.sort(tempArray, function(a, b)
|
||||
return a.slot < b.slot
|
||||
end)
|
||||
|
||||
-- 重新构建有序的disks表
|
||||
for _, item in ipairs(tempArray) do
|
||||
sortedDisks[item.name] = item.slot
|
||||
end
|
||||
|
||||
-- 创建临时配置,使用排序后的disks
|
||||
local configToSave = {
|
||||
rednet_ports = config.rednet_ports,
|
||||
current_disk = config.current_disk,
|
||||
current_slot = config.current_slot,
|
||||
disks = sortedDisks
|
||||
}
|
||||
|
||||
local file = fs.open(CONFIG_FILE, "w")
|
||||
file.write(textutils.serialize(configToSave))
|
||||
file.close()
|
||||
end
|
||||
|
||||
-- 播放声音提示
|
||||
local function playSound(soundType)
|
||||
if peripherals.speaker then
|
||||
pcall(function()
|
||||
if soundType == "success" then
|
||||
peripherals.speaker.playSound("block.note_block.pling", 1.0, 2.0)
|
||||
elseif soundType == "working" then
|
||||
for i=1,3 do
|
||||
peripherals.speaker.playSound("block.note_block.bass", 3, 1)
|
||||
sleep(1)
|
||||
end
|
||||
elseif soundType == "error" then
|
||||
peripherals.speaker.playSound("block.note_block.bass", 1.0, 0.5)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- 发送红石脉冲
|
||||
local function sendRedstonePulse()
|
||||
redstone.setOutput("front", true)
|
||||
sleep(0.1)
|
||||
redstone.setOutput("front", false)
|
||||
end
|
||||
|
||||
-- 发送状态信息到红网
|
||||
local function sendStatusUpdate()
|
||||
-- 从配置读取端口
|
||||
local statusPort = config.rednet_ports.status
|
||||
local listenPort = config.rednet_ports.listen
|
||||
|
||||
-- 通过红网发送状态
|
||||
peripherals.modem.transmit(statusPort, listenPort, {
|
||||
type = "status_update",
|
||||
current_disk = config.current_disk,
|
||||
disks = config.disks,
|
||||
timestamp = os.time()
|
||||
})
|
||||
|
||||
print("状态已发送到端口 " .. statusPort .. ": 当前原件=" .. (config.current_disk or "无"))
|
||||
end
|
||||
|
||||
-- 检查空间IO端口状态
|
||||
local function checkSpatialIOState()
|
||||
local slots = peripherals.spatial_io.list()
|
||||
local state = {
|
||||
slot1 = slots[1], -- 第一格: 未放出/已收回
|
||||
slot2 = slots[2] -- 第二格: 已放出
|
||||
}
|
||||
return state
|
||||
end
|
||||
|
||||
-- 验证槽位是否有物品
|
||||
local function validateSlotHasItem(slot)
|
||||
local item = turtle.getItemDetail(slot)
|
||||
return item ~= nil
|
||||
end
|
||||
|
||||
-- 收回当前原件
|
||||
local function retractCurrentDisk()
|
||||
if not config.current_disk or not config.current_slot then
|
||||
return true -- 没有当前原件,直接返回成功
|
||||
end
|
||||
|
||||
print("开始收回原件: " .. config.current_disk)
|
||||
|
||||
-- 切换到当前原件槽位
|
||||
turtle.select(config.current_slot)
|
||||
|
||||
-- 尝试从空间IO端口拿取
|
||||
if turtle.suck() then
|
||||
print("235 原件已取回")
|
||||
end
|
||||
|
||||
-- 将原件放入空间IO端口
|
||||
if not turtle.drop() then
|
||||
error("无法放入空间IO端口")
|
||||
end
|
||||
|
||||
print("通过红石信号收回原件...")
|
||||
|
||||
local waitCycles = 0
|
||||
while waitCycles < MAX_WAIT_CYCLES do
|
||||
-- 发送红石脉冲
|
||||
sendRedstonePulse()
|
||||
|
||||
-- 检查空间IO端口状态
|
||||
local state = checkSpatialIOState()
|
||||
|
||||
if state.slot2 and not state.slot1 then
|
||||
-- 原件已回到第2格,尝试拿取
|
||||
if turtle.suck() then
|
||||
print("原件收回成功")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
sleep(REDSTONE_PULSE_INTERVAL)
|
||||
waitCycles = waitCycles + 1
|
||||
end
|
||||
|
||||
print("收回原件超时!")
|
||||
return false
|
||||
end
|
||||
|
||||
-- 放出目标原件
|
||||
local function deployTargetDisk(targetDisk)
|
||||
local targetSlot = config.disks[targetDisk]
|
||||
if not targetSlot then
|
||||
error("未找到原件: " .. targetDisk)
|
||||
end
|
||||
|
||||
-- 验证槽位
|
||||
if not validateSlotHasItem(targetSlot) then
|
||||
error("槽位 " .. targetSlot .. " 没有物品,无法放出")
|
||||
end
|
||||
|
||||
print("开始放出原件: " .. targetDisk)
|
||||
|
||||
-- 切换到目标槽位
|
||||
turtle.select(targetSlot)
|
||||
|
||||
-- 将原件放入空间IO端口
|
||||
if not turtle.drop() then
|
||||
error("无法放入空间IO端口")
|
||||
end
|
||||
|
||||
-- 通过红石信号激活放出
|
||||
print("通过红石信号放出原件...")
|
||||
|
||||
local waitCycles = 0
|
||||
while waitCycles < MAX_WAIT_CYCLES do
|
||||
-- 发送红石脉冲
|
||||
sendRedstonePulse()
|
||||
|
||||
-- 检查空间IO端口状态
|
||||
local state = checkSpatialIOState()
|
||||
|
||||
if state.slot2 and not state.slot1 then
|
||||
-- 原件已移动到第二格,放出成功
|
||||
print("原件放出成功")
|
||||
return true
|
||||
end
|
||||
|
||||
sleep(REDSTONE_PULSE_INTERVAL)
|
||||
waitCycles = waitCycles + 1
|
||||
end
|
||||
|
||||
print("放出原件超时!")
|
||||
return false
|
||||
end
|
||||
|
||||
-- 切换到指定原件
|
||||
local function switchToDisk(targetDisk)
|
||||
print("收到切换命令: " .. targetDisk)
|
||||
|
||||
-- 检查是否已经是目标原件
|
||||
if config.current_disk == targetDisk then
|
||||
print("已经是目标原件,无需切换")
|
||||
playSound("success")
|
||||
return true
|
||||
end
|
||||
|
||||
-- 检查目标原件是否存在
|
||||
if not config.disks[targetDisk] then
|
||||
print("错误: 未配置原件 '" .. targetDisk .. "'")
|
||||
playSound("error")
|
||||
return false
|
||||
end
|
||||
|
||||
playSound("working")
|
||||
|
||||
-- 收回当前原件
|
||||
if not retractCurrentDisk() then
|
||||
playSound("error")
|
||||
return false
|
||||
end
|
||||
|
||||
-- 放出目标原件
|
||||
if not deployTargetDisk(targetDisk) then
|
||||
playSound("error")
|
||||
return false
|
||||
end
|
||||
|
||||
-- 更新配置文件
|
||||
config.current_disk = targetDisk
|
||||
config.current_slot = config.disks[targetDisk]
|
||||
writeConfig()
|
||||
|
||||
playSound("success")
|
||||
print("切换完成: " .. targetDisk)
|
||||
sendStatusUpdate() -- 发送状态更新
|
||||
return true
|
||||
end
|
||||
|
||||
-- 处理红网消息
|
||||
local function handleRednetMessage(message)
|
||||
local responsePort = config.rednet_ports.response
|
||||
local listenPort = config.rednet_ports.listen
|
||||
|
||||
if message.type == "switch_disk" and message.disk_name then
|
||||
local success = switchToDisk(message.disk_name)
|
||||
|
||||
-- 发送响应
|
||||
peripherals.modem.transmit(responsePort, listenPort, {
|
||||
type = "switch_response",
|
||||
disk_name = message.disk_name,
|
||||
success = success,
|
||||
timestamp = os.time()
|
||||
})
|
||||
|
||||
elseif message.type == "status_request" then
|
||||
-- 发送状态信息
|
||||
peripherals.modem.transmit(responsePort, listenPort, {
|
||||
type = "status_response",
|
||||
current_disk = config.current_disk,
|
||||
disks = config.disks,
|
||||
timestamp = os.time()
|
||||
})
|
||||
elseif message.type == "reload_config" then
|
||||
-- 重新加载配置
|
||||
config = readConfig()
|
||||
peripherals.modem.transmit(responsePort, listenPort, {
|
||||
type = "reload_response",
|
||||
success = true,
|
||||
timestamp = os.time()
|
||||
})
|
||||
print("配置已重新加载")
|
||||
end
|
||||
end
|
||||
|
||||
-- 主循环 - 状态发送
|
||||
local function main()
|
||||
print("ME空间原件控制器启动中...")
|
||||
|
||||
|
||||
print("1 外围设备初始化完成")
|
||||
print("2 当前原件: " .. (config.current_disk or "无"))
|
||||
print("3 配置的原件: ")
|
||||
for name, slot in pairs(config.disks) do
|
||||
print(" " .. name .. " -> 槽位 " .. slot)
|
||||
end
|
||||
print("4 红网端口配置: ")
|
||||
print(" 监听端口: " .. config.rednet_ports.listen)
|
||||
print(" 状态端口: " .. config.rednet_ports.status)
|
||||
print(" 响应端口: " .. config.rednet_ports.response)
|
||||
|
||||
-- 初始状态发送
|
||||
sendStatusUpdate()
|
||||
|
||||
while true do
|
||||
sleep(CHECK_INTERVAL)
|
||||
sendStatusUpdate()
|
||||
end
|
||||
end
|
||||
|
||||
-- 主循环 - 消息监听
|
||||
local function main1()
|
||||
local listenPort = config.rednet_ports.listen
|
||||
|
||||
while true do
|
||||
-- 检查红网消息
|
||||
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
||||
if channel == listenPort and type(message) == "table" then
|
||||
handleRednetMessage(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- 初始化检查
|
||||
if not turtle then
|
||||
error("这个脚本需要在海龟上运行!")
|
||||
end
|
||||
|
||||
-- 检查配置文件是否存在,如果不存在则创建并提示
|
||||
if not fs.exists(CONFIG_FILE) then
|
||||
config = readConfig() -- 这会创建默认配置文件
|
||||
print("请编辑 " .. CONFIG_FILE .. " 文件配置原件映射,格式如下:")
|
||||
print("{")
|
||||
print(' current_disk = "原件A",')
|
||||
print(' current_slot = 1,')
|
||||
print(' disks = {')
|
||||
print(' ["原件A"] = 1,')
|
||||
print(' ["原件B"] = 2,')
|
||||
print(' ["原件C"] = 3')
|
||||
print(" },")
|
||||
print(' rednet_ports = {')
|
||||
print(' listen = 101, -- 监听端口')
|
||||
print(' status = 100, -- 状态发送端口')
|
||||
print(' response = 102 -- 响应发送端口')
|
||||
print(" }")
|
||||
print("}")
|
||||
print("配置完成后重新启动脚本")
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
config = readConfig()
|
||||
peripherals = initPeripherals()
|
||||
|
||||
-- 启动程序
|
||||
parallel.waitForAny(main, main1)
|
||||
7
sospanel/config.cfg
Normal file
7
sospanel/config.cfg
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
rednet_ports = {
|
||||
response = 102,
|
||||
control = 101,
|
||||
},
|
||||
name = "区域1",
|
||||
}
|
||||
@@ -1,122 +1,122 @@
|
||||
printUtf8 = load(http.get("https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/utf8ptrint.lua").readAll())()
|
||||
|
||||
f = fs.open("config","rb")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- 简易空间控制端
|
||||
-- 功能: 通过配置文件读取参数,检测按键并发送切换命令
|
||||
|
||||
-- 配置文件名称
|
||||
local CONFIG_FILE = "config"
|
||||
|
||||
-- 读取配置文件
|
||||
local function readConfig()
|
||||
if not fs.exists(CONFIG_FILE) then
|
||||
-- 创建默认配置文件
|
||||
local defaultConfig = {
|
||||
rednet_ports = {
|
||||
control = 101, -- 控制信道
|
||||
response = 102 -- 响应信道
|
||||
},
|
||||
name = "默认空间" -- 空间名称
|
||||
}
|
||||
|
||||
local file = fs.open(CONFIG_FILE, "w")
|
||||
file.write(textutils.serialize(defaultConfig))
|
||||
file.close()
|
||||
|
||||
print("已创建默认配置文件,请编辑 " .. CONFIG_FILE)
|
||||
return defaultConfig
|
||||
end
|
||||
|
||||
local file = fs.open(CONFIG_FILE, "r")
|
||||
local content = file.readAll()
|
||||
file.close()
|
||||
|
||||
local config = textutils.unserialize(content)
|
||||
if not config then
|
||||
error("配置文件格式错误!")
|
||||
end
|
||||
|
||||
-- 验证必要字段
|
||||
if not config.name then
|
||||
error("配置文件中缺少 'name' 字段")
|
||||
end
|
||||
|
||||
if not config.rednet_ports then
|
||||
config.rednet_ports = {
|
||||
control = 101,
|
||||
response = 102
|
||||
}
|
||||
else
|
||||
config.rednet_ports.control = config.rednet_ports.control or 101
|
||||
config.rednet_ports.response = config.rednet_ports.response or 102
|
||||
end
|
||||
|
||||
return config
|
||||
end
|
||||
|
||||
-- 初始化红网
|
||||
local function initRednet()
|
||||
local sides = {"left", "right", "front", "back", "top", "bottom"}
|
||||
local modem = nil
|
||||
|
||||
for _, side in ipairs(sides) do
|
||||
if peripheral.getType(side) == "modem" then
|
||||
modem = peripheral.wrap(side)
|
||||
print("找到网卡在: " .. side)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not modem then
|
||||
error("未找到可用的网卡!")
|
||||
end
|
||||
|
||||
return modem
|
||||
end
|
||||
|
||||
-- 发送切换命令
|
||||
local function sendSwitchCommand(diskName, modem, controlPort)
|
||||
local message = {
|
||||
type = "switch_disk",
|
||||
disk_name = diskName
|
||||
}
|
||||
|
||||
modem.transmit(controlPort, controlPort, message)
|
||||
end
|
||||
|
||||
-- 主程序
|
||||
local function main()
|
||||
-- 读取配置
|
||||
local config = readConfig()
|
||||
|
||||
-- 初始化红网
|
||||
local modem = initRednet()
|
||||
|
||||
-- 显示提示信息
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
|
||||
printUtf8("当前空间: "..config.name,colors.white,colors.black)
|
||||
printUtf8("如果你被困在此空间中,请按下任意键",colors.white,colors.black)
|
||||
printUtf8("我将放出此空间",colors.white,colors.black)
|
||||
|
||||
|
||||
-- 检测按键
|
||||
while true do
|
||||
local event, key = os.pullEvent("key")
|
||||
|
||||
-- 发送切换命令
|
||||
sendSwitchCommand(config.name, modem, config.rednet_ports.control)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- 运行程序
|
||||
printUtf8 = load(http.get("https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/utf8ptrint.lua").readAll())()
|
||||
|
||||
f = fs.open("config","rb")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- 简易空间控制端
|
||||
-- 功能: 通过配置文件读取参数,检测按键并发送切换命令
|
||||
|
||||
-- 配置文件名称
|
||||
local CONFIG_FILE = "config.cfg"
|
||||
|
||||
-- 读取配置文件
|
||||
local function readConfig()
|
||||
if not fs.exists(CONFIG_FILE) then
|
||||
-- 创建默认配置文件
|
||||
local defaultConfig = {
|
||||
rednet_ports = {
|
||||
control = 101, -- 控制信道
|
||||
response = 102 -- 响应信道
|
||||
},
|
||||
name = "默认空间" -- 空间名称
|
||||
}
|
||||
|
||||
local file = fs.open(CONFIG_FILE, "w")
|
||||
file.write(textutils.serialize(defaultConfig))
|
||||
file.close()
|
||||
|
||||
print("已创建默认配置文件,请编辑 " .. CONFIG_FILE)
|
||||
return defaultConfig
|
||||
end
|
||||
|
||||
local file = fs.open(CONFIG_FILE, "r")
|
||||
local content = file.readAll()
|
||||
file.close()
|
||||
|
||||
local config = textutils.unserialize(content)
|
||||
if not config then
|
||||
error("配置文件格式错误!")
|
||||
end
|
||||
|
||||
-- 验证必要字段
|
||||
if not config.name then
|
||||
error("配置文件中缺少 'name' 字段")
|
||||
end
|
||||
|
||||
if not config.rednet_ports then
|
||||
config.rednet_ports = {
|
||||
control = 101,
|
||||
response = 102
|
||||
}
|
||||
else
|
||||
config.rednet_ports.control = config.rednet_ports.control or 101
|
||||
config.rednet_ports.response = config.rednet_ports.response or 102
|
||||
end
|
||||
|
||||
return config
|
||||
end
|
||||
|
||||
-- 初始化红网
|
||||
local function initRednet()
|
||||
local sides = {"left", "right", "front", "back", "top", "bottom"}
|
||||
local modem = nil
|
||||
|
||||
for _, side in ipairs(sides) do
|
||||
if peripheral.getType(side) == "modem" then
|
||||
modem = peripheral.wrap(side)
|
||||
print("找到网卡在: " .. side)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not modem then
|
||||
error("未找到可用的网卡!")
|
||||
end
|
||||
|
||||
return modem
|
||||
end
|
||||
|
||||
-- 发送切换命令
|
||||
local function sendSwitchCommand(diskName, modem, controlPort)
|
||||
local message = {
|
||||
type = "switch_disk",
|
||||
disk_name = diskName
|
||||
}
|
||||
|
||||
modem.transmit(controlPort, controlPort, message)
|
||||
end
|
||||
|
||||
-- 主程序
|
||||
local function main()
|
||||
-- 读取配置
|
||||
local config = readConfig()
|
||||
|
||||
-- 初始化红网
|
||||
local modem = initRednet()
|
||||
|
||||
-- 显示提示信息
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
|
||||
printUtf8("当前空间: "..config.name,colors.white,colors.black)
|
||||
printUtf8("如果你被困在此空间中,请按下任意键",colors.white,colors.black)
|
||||
printUtf8("我将放出此空间",colors.white,colors.black)
|
||||
|
||||
|
||||
-- 检测按键
|
||||
while true do
|
||||
local event, key = os.pullEvent("key")
|
||||
|
||||
-- 发送切换命令
|
||||
sendSwitchCommand(config.name, modem, config.rednet_ports.control)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- 运行程序
|
||||
main()
|
||||
Reference in New Issue
Block a user