Files
computer-craft-AEspatial/panel/startup.lua
2025-12-05 16:13:12 +08:00

366 lines
11 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 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)