diff --git a/gate.lua b/gate.lua index 67c2834..1b79ddf 100644 --- a/gate.lua +++ b/gate.lua @@ -1,7 +1,7 @@ local DEFAULT_SERVER_BASE = "https://ticket.fse-media.group" local DEFAULT_SERVER_PATH = "/api/tickets/check" local GATE_OPEN_SECONDS = 2 -local VERSION = "v1.5.27" +local VERSION = "v1.5.28" local VERSION_CHECK_INTERVAL = 5 local serverURL = nil @@ -88,9 +88,11 @@ end local nativeTerm = (term and type(term.current) == "function" and term.current()) or term local monitor = peripheral.find("monitor") +local tmGpu = peripheral.find("tm_gpu") local speaker = peripheral.find("speaker") local inspection = peripheral.find("ticket_inspection_machine") local monitorSide = nil +local tmGpuSide = nil local serverConnected = nil local isUpdating = false @@ -170,15 +172,198 @@ local function setServerConnected(ok) serverLastChangeTs = os.epoch("utc") end +local GPU_CHAR_WIDTH = 4 +local GPU_CHAR_HEIGHT = 6 + +local GPU_COLOR_MAP = { + [colors.white] = 0xFFFFFFFF, + [colors.orange] = 0xFFFFA500, + [colors.magenta] = 0xFFFF00FF, + [colors.lightBlue] = 0xFF66CCFF, + [colors.yellow] = 0xFFFFFF00, + [colors.lime] = 0xFF00FF00, + [colors.pink] = 0xFFFFB6C1, + [colors.gray] = 0xFF808080, + [colors.lightGray] = 0xFFD3D3D3, + [colors.cyan] = 0xFF00FFFF, + [colors.purple] = 0xFF800080, + [colors.blue] = 0xFF0000FF, + [colors.brown] = 0xFF8B4513, + [colors.green] = 0xFF008000, + [colors.red] = 0xFFFF0000, + [colors.black] = 0xFF000000, +} + +local function ccColorToARGB(col) + return GPU_COLOR_MAP[col] or GPU_COLOR_MAP[colors.white] +end + +local function isTmGpu(dev) + return type(dev) == "table" + and type(dev.getSize) == "function" + and type(dev.drawText) == "function" + and type(dev.fill) == "function" + and type(dev.sync) == "function" +end + +local function buildTmGpuTerm(dev) + local gpuTerm = { + kind = "tm_gpu", + device = dev, + cursorX = 1, + cursorY = 1, + textColor = colors.white, + backgroundColor = colors.black, + width = 1, + height = 1, + pixelWidth = 0, + pixelHeight = 0, + resolutionConfigured = false, + } + + local function syncSize() + if type(gpuTerm.device.refreshSize) == "function" then + pcall(gpuTerm.device.refreshSize) + end + + for _ = 1, 3 do + local size = pack(pcall(gpuTerm.device.getSize)) + local px = tonumber(size[2]) or 0 + local py = tonumber(size[3]) or 0 + if size[1] and px > 0 and py > 0 then + if not gpuTerm.resolutionConfigured and type(gpuTerm.device.setSize) == "function" then + gpuTerm.resolutionConfigured = true + local resolution = tonumber(size[6]) or 0 + if resolution > 0 and resolution < 32 then + pcall(gpuTerm.device.setSize, 32) + os.sleep(0) + size = pack(pcall(gpuTerm.device.getSize)) + px = tonumber(size[2]) or px + py = tonumber(size[3]) or py + end + end + gpuTerm.pixelWidth = px + gpuTerm.pixelHeight = py + gpuTerm.width = math.max(1, math.floor(px / GPU_CHAR_WIDTH)) + gpuTerm.height = math.max(1, math.floor(py / GPU_CHAR_HEIGHT)) + return gpuTerm.width, gpuTerm.height + end + os.sleep(0) + end + + if gpuTerm.pixelWidth <= 0 then gpuTerm.pixelWidth = 64 end + if gpuTerm.pixelHeight <= 0 then gpuTerm.pixelHeight = 32 end + gpuTerm.width = math.max(1, math.floor(gpuTerm.pixelWidth / GPU_CHAR_WIDTH)) + gpuTerm.height = math.max(1, math.floor(gpuTerm.pixelHeight / GPU_CHAR_HEIGHT)) + return gpuTerm.width, gpuTerm.height + end + + function gpuTerm.getSize() + return syncSize() + end + + function gpuTerm.setCursorPos(x, y) + gpuTerm.cursorX = math.max(1, math.floor(tonumber(x) or 1)) + gpuTerm.cursorY = math.max(1, math.floor(tonumber(y) or 1)) + end + + function gpuTerm.setTextColor(col) + gpuTerm.textColor = GPU_COLOR_MAP[col] and col or colors.white + end + + function gpuTerm.setBackgroundColor(col) + gpuTerm.backgroundColor = GPU_COLOR_MAP[col] and col or colors.black + end + + function gpuTerm.clear() + syncSize() + pcall(gpuTerm.device.fill, ccColorToARGB(gpuTerm.backgroundColor)) + gpuTerm.cursorX = 1 + gpuTerm.cursorY = 1 + end + + function gpuTerm.write(text) + text = tostring(text or "") + if #text == 0 then return end + + local width, height = syncSize() + local originalLen = #text + local x = gpuTerm.cursorX + local y = gpuTerm.cursorY + + if y < 1 or y > height or x > width then + gpuTerm.cursorX = x + originalLen + return + end + + if x < 1 then + local shift = 1 - x + if shift >= #text then + gpuTerm.cursorX = x + originalLen + return + end + text = text:sub(shift + 1) + x = 1 + end + + local visible = text:sub(1, math.max(0, width - x + 1)) + if #visible > 0 then + local px = ((x - 1) * GPU_CHAR_WIDTH) + 1 + local py = ((y - 1) * GPU_CHAR_HEIGHT) + 1 + local bg = ccColorToARGB(gpuTerm.backgroundColor) + local fg = ccColorToARGB(gpuTerm.textColor) + pcall(gpuTerm.device.filledRectangle, px, py, #visible * GPU_CHAR_WIDTH, GPU_CHAR_HEIGHT, bg) + pcall(gpuTerm.device.drawText, px, py, visible, fg, bg, 1, 0) + end + + gpuTerm.cursorX = gpuTerm.cursorX + originalLen + end + + function gpuTerm.sync() + pcall(gpuTerm.device.sync) + end + + return gpuTerm +end + local termDev = nativeTerm -if peripheral and type(peripheral.getName) == "function" and monitor then - pcall(function() monitorSide = peripheral.getName(monitor) end) +if peripheral and type(peripheral.getName) == "function" then + if tmGpu then + pcall(function() tmGpuSide = peripheral.getName(tmGpu) end) + end + if monitor then + pcall(function() monitorSide = peripheral.getName(monitor) end) + end end local function refreshDisplayTarget() + local nextGpu = nil + local nextGpuSide = tmGpuSide local nextMonitor = nil local nextMonitorSide = monitorSide if peripheral then + if nextGpuSide and type(peripheral.isPresent) == "function" and peripheral.isPresent(nextGpuSide) and type(peripheral.wrap) == "function" then + local okWrap, wrapped = pcall(peripheral.wrap, nextGpuSide) + if okWrap and isTmGpu(wrapped) then + nextGpu = wrapped + end + end + if not nextGpu and type(peripheral.find) == "function" then + local foundGpuName = nil + local foundGpu = peripheral.find("tm_gpu", function(name, wrapped) + if isTmGpu(wrapped) then + foundGpuName = name + nextGpu = wrapped + return true + end + end) + if foundGpu and isTmGpu(foundGpu) then + nextGpu = foundGpu + nextGpuSide = foundGpuName + else + nextGpuSide = nil + end + end if nextMonitorSide and type(peripheral.isPresent) == "function" and peripheral.isPresent(nextMonitorSide) and type(peripheral.wrap) == "function" then local okWrap, wrapped = pcall(peripheral.wrap, nextMonitorSide) if okWrap and wrapped then @@ -200,9 +385,13 @@ local function refreshDisplayTarget() end end end + tmGpu = nextGpu + tmGpuSide = nextGpuSide monitor = nextMonitor monitorSide = nextMonitorSide - if monitor then + if tmGpu then + termDev = buildTmGpuTerm(tmGpu) + elseif monitor then pcall(monitor.setTextScale, 0.5) termDev = monitor else @@ -287,6 +476,9 @@ local function draw(statusLine1, statusLine2, statusColor) termDev.setCursorPos(1, h) termDev.setTextColor(colors.gray) termDev.write(string.rep(" ", w)) + if type(termDev.sync) == "function" then + termDev.sync() + end end local function pulseLeftRedstone(seconds)