fix(gate): 修复区块加载时检票机屏幕无显示问题 - 新增 monitor 握手阶段,所有 termDev 渲染调用加 pcall 保护,启动后 20 秒持续重绘热修复,修复 setServerConnected 重复定义丢失 queueEvent 的 bug (v1.5.30)
This commit is contained in:
@@ -1,10 +1,13 @@
|
|||||||
local DEFAULT_SERVER_BASE = "https://ticket.fse-media.group"
|
local DEFAULT_SERVER_BASE = "https://ticket.fse-media.group"
|
||||||
local DEFAULT_SERVER_PATH = "/api/tickets/check"
|
local DEFAULT_SERVER_PATH = "/api/tickets/check"
|
||||||
local GATE_OPEN_SECONDS = 2
|
local GATE_OPEN_SECONDS = 2
|
||||||
local VERSION = "v1.5.29"
|
local VERSION = "v1.5.30"
|
||||||
local VERSION_CHECK_INTERVAL = 5
|
local VERSION_CHECK_INTERVAL = 5
|
||||||
local PERIPHERAL_WAIT_INTERVAL = 0.5
|
local PERIPHERAL_WAIT_INTERVAL = 0.5
|
||||||
local PERIPHERAL_WAIT_MAX_RETRIES = 40
|
local PERIPHERAL_WAIT_MAX_RETRIES = 40
|
||||||
|
local MONITOR_HANDSHAKE_RETRIES = 20
|
||||||
|
local STARTUP_REDRAW_DURATION = 20
|
||||||
|
local STARTUP_REDRAW_INTERVAL = 0.5
|
||||||
|
|
||||||
local serverURL = nil
|
local serverURL = nil
|
||||||
|
|
||||||
@@ -118,11 +121,22 @@ end
|
|||||||
local function waitForPeripherals(requireInspection)
|
local function waitForPeripherals(requireInspection)
|
||||||
local attempts = 0
|
local attempts = 0
|
||||||
local lastDrawMsg = nil
|
local lastDrawMsg = nil
|
||||||
|
local handshakeDone = false
|
||||||
while attempts < PERIPHERAL_WAIT_MAX_RETRIES do
|
while attempts < PERIPHERAL_WAIT_MAX_RETRIES do
|
||||||
local hadChange = false
|
local hadChange = false
|
||||||
if not monitor then
|
if not monitor then
|
||||||
local m, ms = safeFindPeripheral("monitor", monitorSide)
|
local m, ms = safeFindPeripheral("monitor", monitorSide)
|
||||||
if m then monitor = m; monitorSide = ms; hadChange = true end
|
if m then
|
||||||
|
monitor = m
|
||||||
|
monitorSide = ms
|
||||||
|
hadChange = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if monitor and (hadChange or not handshakeDone) then
|
||||||
|
termDev = monitor
|
||||||
|
local ok = false
|
||||||
|
pcall(function() ok = handshakeMonitor(monitor) end)
|
||||||
|
if ok then handshakeDone = true end
|
||||||
end
|
end
|
||||||
if not speaker then
|
if not speaker then
|
||||||
local s, _ = safeFindPeripheral("speaker")
|
local s, _ = safeFindPeripheral("speaker")
|
||||||
@@ -135,12 +149,17 @@ local function waitForPeripherals(requireInspection)
|
|||||||
local ok = true
|
local ok = true
|
||||||
if not monitor then ok = false end
|
if not monitor then ok = false end
|
||||||
if requireInspection and not inspection then ok = false end
|
if requireInspection and not inspection then ok = false end
|
||||||
if ok then return true end
|
if ok and handshakeDone then return true end
|
||||||
|
if ok and not handshakeDone then
|
||||||
|
local ok2 = false
|
||||||
|
pcall(function() ok2 = handshakeMonitor(monitor) end)
|
||||||
|
if ok2 then handshakeDone = true; return true end
|
||||||
|
end
|
||||||
local msg = nil
|
local msg = nil
|
||||||
if not monitor and requireInspection and not inspection then
|
if not monitor then
|
||||||
msg = "Waiting for monitor + gate..."
|
|
||||||
elseif not monitor then
|
|
||||||
msg = "Waiting for monitor..."
|
msg = "Waiting for monitor..."
|
||||||
|
elseif not handshakeDone then
|
||||||
|
msg = "Waking monitor..."
|
||||||
elseif requireInspection and not inspection then
|
elseif requireInspection and not inspection then
|
||||||
msg = "Waiting for gate peripheral..."
|
msg = "Waiting for gate peripheral..."
|
||||||
end
|
end
|
||||||
@@ -171,7 +190,7 @@ local function waitForPeripherals(requireInspection)
|
|||||||
sleep(PERIPHERAL_WAIT_INTERVAL)
|
sleep(PERIPHERAL_WAIT_INTERVAL)
|
||||||
attempts = attempts + 1
|
attempts = attempts + 1
|
||||||
end
|
end
|
||||||
return false
|
return not not monitor
|
||||||
end
|
end
|
||||||
|
|
||||||
pcall(function() waitForPeripherals(false) end)
|
pcall(function() waitForPeripherals(false) end)
|
||||||
@@ -248,33 +267,81 @@ local function jsonDecode(str)
|
|||||||
if ok then return res else return nil end
|
if ok then return res else return nil end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function setServerConnected(ok)
|
|
||||||
if serverConnected == ok then return end
|
|
||||||
serverConnected = ok
|
|
||||||
serverLastChangeTs = os.epoch("utc")
|
|
||||||
end
|
|
||||||
|
|
||||||
local termDev = nativeTerm
|
local termDev = nativeTerm
|
||||||
if peripheral and type(peripheral.getName) == "function" and monitor then
|
if peripheral and type(peripheral.getName) == "function" and monitor then
|
||||||
pcall(function() monitorSide = peripheral.getName(monitor) end)
|
pcall(function() monitorSide = peripheral.getName(monitor) end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function safeCallTerm(method, ...)
|
||||||
|
if not termDev or type(termDev[method]) ~= "function" then return nil end
|
||||||
|
local ok, r1, r2, r3 = pcall(termDev[method], ...)
|
||||||
|
if not ok then return nil end
|
||||||
|
return r1, r2, r3
|
||||||
|
end
|
||||||
|
|
||||||
|
local function safeCallMonitor(target, method, ...)
|
||||||
|
if not target or type(target[method]) ~= "function" then return false end
|
||||||
|
local ok, r1 = pcall(target[method], ...)
|
||||||
|
if not ok then return false end
|
||||||
|
return r1 ~= false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function handshakeMonitor(target)
|
||||||
|
if not target then return false end
|
||||||
|
local scaleOk = false
|
||||||
|
local getSizeOk = false
|
||||||
|
local w, h = nil, nil
|
||||||
|
for _ = 1, MONITOR_HANDSHAKE_RETRIES do
|
||||||
|
if safeCallMonitor(target, "setTextScale", 0.5) then scaleOk = true end
|
||||||
|
w, h = safeCallTerm("getSize")
|
||||||
|
if type(w) == "number" and type(h) == "number" and w >= 2 and h >= 2 then
|
||||||
|
getSizeOk = true
|
||||||
|
end
|
||||||
|
if scaleOk and getSizeOk then
|
||||||
|
local cOk = safeCallMonitor(target, "setBackgroundColor", colors.black)
|
||||||
|
local c2Ok = safeCallMonitor(target, "setTextColor", colors.white)
|
||||||
|
local clearOk = safeCallMonitor(target, "clear")
|
||||||
|
if clearOk then return true end
|
||||||
|
end
|
||||||
|
sleep(PERIPHERAL_WAIT_INTERVAL)
|
||||||
|
local rewrapOk, rewrapped = pcall(function()
|
||||||
|
if monitorSide and peripheral and type(peripheral.isPresent) == "function" and peripheral.isPresent(monitorSide) and type(peripheral.wrap) == "function" then
|
||||||
|
local okW, wd = pcall(peripheral.wrap, monitorSide)
|
||||||
|
if okW and wd then return wd end
|
||||||
|
end
|
||||||
|
if peripheral and type(peripheral.find) == "function" then
|
||||||
|
return peripheral.find("monitor")
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end)
|
||||||
|
if rewrapOk and rewrapped then
|
||||||
|
target = rewrapped
|
||||||
|
monitor = rewrapped
|
||||||
|
termDev = rewrapped
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return scaleOk or getSizeOk
|
||||||
|
end
|
||||||
|
|
||||||
local function refreshDisplayTarget()
|
local function refreshDisplayTarget()
|
||||||
local nextMonitor = nil
|
local nextMonitor = nil
|
||||||
local nextMonitorSide = monitorSide
|
local nextMonitorSide = monitorSide
|
||||||
if peripheral then
|
if peripheral then
|
||||||
if nextMonitorSide and type(peripheral.isPresent) == "function" and peripheral.isPresent(nextMonitorSide) and type(peripheral.wrap) == "function" then
|
if nextMonitorSide and type(peripheral.isPresent) == "function" then
|
||||||
local okWrap, wrapped = pcall(peripheral.wrap, nextMonitorSide)
|
local okPres, pres = pcall(peripheral.isPresent, nextMonitorSide)
|
||||||
if okWrap and wrapped then
|
if okPres and pres and type(peripheral.wrap) == "function" then
|
||||||
nextMonitor = wrapped
|
local okWrap, wrapped = pcall(peripheral.wrap, nextMonitorSide)
|
||||||
|
if okWrap and wrapped then nextMonitor = wrapped end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not nextMonitor and type(peripheral.find) == "function" then
|
if not nextMonitor and type(peripheral.find) == "function" then
|
||||||
local foundName = nil
|
local foundName = nil
|
||||||
local found = peripheral.find("monitor", function(name, wrapped)
|
local found = nil
|
||||||
foundName = name
|
pcall(function()
|
||||||
nextMonitor = wrapped
|
found = peripheral.find("monitor", function(name, wrapped)
|
||||||
return true
|
foundName = name
|
||||||
|
return true
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
if found then
|
if found then
|
||||||
nextMonitor = found
|
nextMonitor = found
|
||||||
@@ -284,10 +351,18 @@ local function refreshDisplayTarget()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
monitor = nextMonitor
|
if nextMonitor and nextMonitor ~= monitor then
|
||||||
monitorSide = nextMonitorSide
|
monitor = nextMonitor
|
||||||
|
monitorSide = nextMonitorSide
|
||||||
|
pcall(function() handshakeMonitor(nextMonitor) end)
|
||||||
|
elseif nextMonitor then
|
||||||
|
monitor = nextMonitor
|
||||||
|
monitorSide = nextMonitorSide
|
||||||
|
end
|
||||||
if monitor then
|
if monitor then
|
||||||
pcall(monitor.setTextScale, 0.5)
|
if not safeCallMonitor(monitor, "setTextScale", 0.5) then
|
||||||
|
pcall(function() handshakeMonitor(monitor) end)
|
||||||
|
end
|
||||||
termDev = monitor
|
termDev = monitor
|
||||||
else
|
else
|
||||||
termDev = nativeTerm or term
|
termDev = nativeTerm or term
|
||||||
@@ -296,52 +371,48 @@ local function refreshDisplayTarget()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function clear()
|
local function clear()
|
||||||
refreshDisplayTarget()
|
pcall(refreshDisplayTarget)
|
||||||
termDev.setBackgroundColor(colors.black)
|
if not termDev then return end
|
||||||
termDev.setTextColor(colors.white)
|
safeCallTerm("setBackgroundColor", colors.black)
|
||||||
termDev.clear()
|
safeCallTerm("setTextColor", colors.white)
|
||||||
termDev.setCursorPos(1, 1)
|
safeCallTerm("clear")
|
||||||
|
safeCallTerm("setCursorPos", 1, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function centerText(y, text, color)
|
local function centerText(y, text, color)
|
||||||
local w = termDev.getSize()
|
if not termDev then return end
|
||||||
termDev.setTextColor(color or colors.white)
|
local w = safeCallTerm("getSize")
|
||||||
local x = math.max(1, math.floor((w - #text) / 2) + 1)
|
w = tonumber(w) or 0
|
||||||
termDev.setCursorPos(x, y)
|
if w < 2 then return end
|
||||||
termDev.write(text)
|
safeCallTerm("setTextColor", color or colors.white)
|
||||||
|
local x = math.max(1, math.floor((w - #tostring(text or "")) / 2) + 1)
|
||||||
|
safeCallTerm("setCursorPos", x, y)
|
||||||
|
safeCallTerm("write", tostring(text or ""))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function splitDisplayLines(text)
|
local lastStartupRedrawAt = 0
|
||||||
local out = {}
|
|
||||||
text = tostring(text or "")
|
|
||||||
if #text == 0 then return out end
|
|
||||||
for line in text:gmatch("([^\n]*)\n?") do
|
|
||||||
if line == "" and #out > 0 and text:sub(-1) ~= "\n" then break end
|
|
||||||
if #line > 0 then table.insert(out, line) end
|
|
||||||
end
|
|
||||||
return out
|
|
||||||
end
|
|
||||||
|
|
||||||
local function drawServerStatusIndicator(w)
|
local function drawServerStatusIndicator(w)
|
||||||
|
w = tonumber(w) or 0
|
||||||
if w < 2 then return end
|
if w < 2 then return end
|
||||||
local col = colors.yellow
|
local col = colors.yellow
|
||||||
if serverConnected == true then col = colors.lime
|
if serverConnected == true then col = colors.lime
|
||||||
elseif serverConnected == false then col = colors.red end
|
elseif serverConnected == false then col = colors.red end
|
||||||
termDev.setBackgroundColor(colors.black)
|
safeCallTerm("setBackgroundColor", colors.black)
|
||||||
termDev.setTextColor(col)
|
safeCallTerm("setTextColor", col)
|
||||||
termDev.setCursorPos(w - 1, 1)
|
safeCallTerm("setCursorPos", w - 1, 1)
|
||||||
termDev.write("S")
|
safeCallTerm("write", "S")
|
||||||
termDev.setCursorPos(w, 1)
|
safeCallTerm("setCursorPos", w, 1)
|
||||||
termDev.write("*")
|
safeCallTerm("write", "*")
|
||||||
termDev.setTextColor(colors.white)
|
safeCallTerm("setTextColor", colors.white)
|
||||||
end
|
end
|
||||||
|
|
||||||
local lastUpdateError = nil
|
local lastUpdateError = nil
|
||||||
|
|
||||||
local function drawVersionIndicator(w)
|
local function drawVersionIndicator(w)
|
||||||
|
w = tonumber(w) or 0
|
||||||
local s = tostring(VERSION or "")
|
local s = tostring(VERSION or "")
|
||||||
if #s == 0 then return end
|
if #s == 0 or w < #s then return end
|
||||||
if w < #s then return end
|
|
||||||
local markerColor = colors.lime
|
local markerColor = colors.lime
|
||||||
local markerText = "* "
|
local markerText = "* "
|
||||||
if isUpdating then
|
if isUpdating then
|
||||||
@@ -351,25 +422,31 @@ local function drawVersionIndicator(w)
|
|||||||
markerColor = colors.red
|
markerColor = colors.red
|
||||||
markerText = "* "
|
markerText = "* "
|
||||||
end
|
end
|
||||||
termDev.setBackgroundColor(colors.black)
|
safeCallTerm("setBackgroundColor", colors.black)
|
||||||
termDev.setTextColor(colors.gray)
|
safeCallTerm("setTextColor", colors.gray)
|
||||||
termDev.setCursorPos(1, 1)
|
safeCallTerm("setCursorPos", 1, 1)
|
||||||
termDev.write(s)
|
safeCallTerm("write", s)
|
||||||
termDev.setTextColor(markerColor)
|
safeCallTerm("setTextColor", markerColor)
|
||||||
termDev.write(markerText)
|
safeCallTerm("write", markerText)
|
||||||
|
|
||||||
if lastUpdateError then
|
if lastUpdateError then
|
||||||
termDev.setCursorPos(1, 2)
|
safeCallTerm("setCursorPos", 1, 2)
|
||||||
termDev.setTextColor(colors.red)
|
safeCallTerm("setTextColor", colors.red)
|
||||||
termDev.write(string.sub(tostring(lastUpdateError), 1, w))
|
safeCallTerm("write", string.sub(tostring(lastUpdateError), 1, w))
|
||||||
end
|
end
|
||||||
|
|
||||||
termDev.setTextColor(colors.white)
|
safeCallTerm("setTextColor", colors.white)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local _cachedDrawArgHash = nil
|
||||||
|
|
||||||
local function draw(statusLine1, statusLine2, statusColor)
|
local function draw(statusLine1, statusLine2, statusColor)
|
||||||
clear()
|
clear()
|
||||||
local w, h = termDev.getSize()
|
if not termDev then return end
|
||||||
|
local w, h = safeCallTerm("getSize")
|
||||||
|
w = tonumber(w) or 0
|
||||||
|
h = tonumber(h) or 0
|
||||||
|
if w < 2 or h < 2 then return end
|
||||||
centerText(2, "GATE", colors.cyan)
|
centerText(2, "GATE", colors.cyan)
|
||||||
drawVersionIndicator(w)
|
drawVersionIndicator(w)
|
||||||
drawServerStatusIndicator(w)
|
drawServerStatusIndicator(w)
|
||||||
@@ -385,9 +462,9 @@ local function draw(statusLine1, statusLine2, statusColor)
|
|||||||
centerText(y, line, statusColor or colors.white)
|
centerText(y, line, statusColor or colors.white)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
termDev.setCursorPos(1, h)
|
safeCallTerm("setCursorPos", 1, h)
|
||||||
termDev.setTextColor(colors.gray)
|
safeCallTerm("setTextColor", colors.gray)
|
||||||
termDev.write(string.rep(" ", w))
|
safeCallTerm("write", string.rep(" ", w))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function pulseLeftRedstone(seconds)
|
local function pulseLeftRedstone(seconds)
|
||||||
@@ -1726,6 +1803,23 @@ local function mainLoop()
|
|||||||
drawReadyScreen()
|
drawReadyScreen()
|
||||||
elseif ev[1] == "peripheral" or ev[1] == "peripheral_detach" or ev[1] == "monitor_resize" or ev[1] == "config_updated" then
|
elseif ev[1] == "peripheral" or ev[1] == "peripheral_detach" or ev[1] == "monitor_resize" or ev[1] == "config_updated" then
|
||||||
pcall(drawReadyScreen)
|
pcall(drawReadyScreen)
|
||||||
|
elseif ev[1] == "timer" then
|
||||||
|
pcall(drawReadyScreen)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function startupRedrawTask()
|
||||||
|
local startTs = (os.epoch and os.epoch("utc")) or (os.time() * 3600000)
|
||||||
|
local endTs = startTs + STARTUP_REDRAW_DURATION * 1000
|
||||||
|
local nextRedraw = startTs
|
||||||
|
while true do
|
||||||
|
local now = (os.epoch and os.epoch("utc")) or (os.time() * 3600000)
|
||||||
|
if now <= endTs then
|
||||||
|
pcall(drawReadyScreen)
|
||||||
|
sleep(STARTUP_REDRAW_INTERVAL)
|
||||||
|
else
|
||||||
|
sleep(60)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1797,4 +1891,4 @@ local function backgroundSyncTask()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
parallel.waitForAny(mainLoop, backgroundSyncTask)
|
parallel.waitForAny(mainLoop, startupRedrawTask, backgroundSyncTask)
|
||||||
|
|||||||
Reference in New Issue
Block a user