fix: improve monitor alias detection and registration for better peripheral handling
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user