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