From bb15c78ca9897a7b2834ce7e9d2a5203f6d18088 Mon Sep 17 00:00:00 2001 From: MayaTheShy Date: Sun, 29 Mar 2026 00:23:59 -0400 Subject: [PATCH] fix: improve monitor alias detection and registration for better peripheral handling --- manager/display.lua | 127 +++++++++++++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 43 deletions(-) diff --git a/manager/display.lua b/manager/display.lua index e2d7916..0e3e756 100644 --- a/manager/display.lua +++ b/manager/display.lua @@ -120,94 +120,135 @@ end -- Monitor setup ------------------------------------------------- ---- Check whether two peripheral names refer to the same physical block. --- Needed because a monitor placed adjacent to the computer AND connected --- via wired modem appears under both its side name (e.g. "left") and its --- network name (e.g. "monitor_0"). A simple string comparison misses this. -local function sameMonitor(a, b) - if not a or not b then return false end - if a == b then return true end - -- Write a distinctive cursor position via one name and read it back - -- via the other; if they share state, they are the same peripheral. - local ok1 = pcall(peripheral.call, a, "setCursorPos", 9876, 5432) - if not ok1 then return false end - local ok2, x, y = pcall(peripheral.call, b, "getCursorPos") - pcall(peripheral.call, a, "setCursorPos", 1, 1) - return ok2 and x == 9876 and y == 5432 +--- Track peripheral names already assigned to a role. +-- A single physical monitor can appear under multiple names (e.g. "left" +-- AND "monitor_0") when it is both side-attached and on a wired modem. +-- We detect aliases by mutating text scale on one name and checking +-- whether a known monitor's getSize() changes. +D._usedMonitorNames = {} -- set of names known to be taken + +--- Detect whether 'candidateName' is the same physical block as 'knownMon' +-- (a wrapped peripheral table). We temporarily set the candidate's text +-- scale to an extreme value and check whether the known monitor reports a +-- size change. If it does, they share the same hardware. +local function isMonitorAlias(candidateName, knownMon) + if not candidateName or not knownMon then return false end + local refW, refH = knownMon.getSize() + -- Save candidate's current scale (getTextScale available CC:T 1.94+) + local ok, origScale = pcall(peripheral.call, candidateName, "getTextScale") + if not ok then origScale = 1 end + -- Pick a test scale far from the current one + local testScale = (origScale >= 3) and 0.5 or 5 + pcall(peripheral.call, candidateName, "setTextScale", testScale) + local newW, newH = knownMon.getSize() + -- Restore + pcall(peripheral.call, candidateName, "setTextScale", origScale) + return newW ~= refW or newH ~= refH end -local function findMonitor(side, excludeNames) - excludeNames = excludeNames or {} - local mon = peripheral.wrap(side) - local monName - if mon and mon.setTextScale then - monName = side - else - mon = nil - end - if not mon then - for _, name in ipairs(peripheral.getNames()) do - if peripheral.getType(name) == "monitor" then - local dominated = false - for _, ex in ipairs(excludeNames) do - if sameMonitor(name, ex) then dominated = true; break end - end - if not dominated then - mon = peripheral.wrap(name) - monName = name - break - end +--- Register all peripheral names that refer to the same physical block as +-- 'knownName' / 'knownMon'. This populates D._usedMonitorNames so that +-- later auto-detection can skip aliases by simple table lookup. +local function registerMonitorAliases(knownName, knownMon) + D._usedMonitorNames[knownName] = true + for _, name in ipairs(peripheral.getNames()) do + if name ~= knownName and peripheral.getType(name) == "monitor" then + if isMonitorAlias(name, knownMon) then + D._usedMonitorNames[name] = true + log.debug("DISPLAY", "Monitor alias: %s => %s", name, knownName) end end end - return mon, monName end function D.setupMonitor() - D.mon, D.monName = findMonitor(cfg.MONITOR_SIDE, { cfg.SMELTER_MONITOR_SIDE }) + local mon = peripheral.wrap(cfg.MONITOR_SIDE) + if not mon or not mon.setTextScale then + -- Fallback: find any monitor + for _, name in ipairs(peripheral.getNames()) do + if peripheral.getType(name) == "monitor" then + mon = peripheral.wrap(name) + if mon and mon.setTextScale then + D.mon = mon + D.monName = name + break + end + mon = nil + end + end + else + D.mon = mon + D.monName = cfg.MONITOR_SIDE + end if not D.mon then return false end mainDevice = UI.Device({ device = D.mon, textScale = 0.5, }) + + -- Register this monitor and all its aliases as taken + registerMonitorAliases(D.monName, D.mon) return true end function D.setupSmelterMonitor() - D.smelterMon, D.smelterMonName = findMonitor(cfg.SMELTER_MONITOR_SIDE, { D.monName }) - if not D.smelterMon then return false end + -- Try configured side first + local mon = peripheral.wrap(cfg.SMELTER_MONITOR_SIDE) + local monName = cfg.SMELTER_MONITOR_SIDE + if not mon or not mon.setTextScale or D._usedMonitorNames[monName] then + mon = nil + monName = nil + -- Fallback: find any unused monitor + for _, name in ipairs(peripheral.getNames()) do + if peripheral.getType(name) == "monitor" and not D._usedMonitorNames[name] then + mon = peripheral.wrap(name) + if mon and mon.setTextScale then + monName = name + break + end + mon = nil + end + end + end + if not mon then return false end + + D.smelterMon = mon + D.smelterMonName = monName smelterDevice = UI.Device({ device = D.smelterMon, textScale = 0.5, }) + + -- Register this monitor and all its aliases as taken + registerMonitorAliases(D.smelterMonName, D.smelterMon) return true end function D.setupBillboardMonitor() - -- If explicitly configured, use that name local scale = cfg.BILLBOARD_TEXT_SCALE or 1 + -- If explicitly configured, use that name if cfg.BILLBOARD_MONITOR and cfg.BILLBOARD_MONITOR ~= "" then local mon = peripheral.wrap(cfg.BILLBOARD_MONITOR) if mon and mon.setTextScale then D.billboardMon = mon D.billboardMonName = cfg.BILLBOARD_MONITOR D.billboardMon.setTextScale(scale) + registerMonitorAliases(D.billboardMonName, D.billboardMon) return true end return false end -- Auto-detect: find any monitor not already used by main/smelter for _, name in ipairs(peripheral.getNames()) do - if peripheral.getType(name) == "monitor" - and not sameMonitor(name, D.monName) - and not sameMonitor(name, D.smelterMonName) then + if peripheral.getType(name) == "monitor" and not D._usedMonitorNames[name] then local mon = peripheral.wrap(name) if mon and mon.setTextScale then D.billboardMon = mon D.billboardMonName = name D.billboardMon.setTextScale(scale) + registerMonitorAliases(D.billboardMonName, D.billboardMon) return true end end