285 lines
8.3 KiB
Plaintext
285 lines
8.3 KiB
Plaintext
|
local sideNames = rs.getSides()
|
||
|
local sensorSides = {}
|
||
|
local sideSelection, targetSelection, targetOffset, detailOffset = 1, 1, 1, 1
|
||
|
local detailLines, targetNameMenuTable
|
||
|
local graphing, graphSide, graphTarget, graphMatch, graphInstance = false
|
||
|
|
||
|
os.loadAPI("ocs/apis/graph")
|
||
|
os.loadAPI("ocs/apis/sensor")
|
||
|
|
||
|
local function checkSensors()
|
||
|
for _,side in ipairs(sideNames) do
|
||
|
if peripheral.getType(side) == "sensor" then
|
||
|
sensorSides[side] = true
|
||
|
else
|
||
|
sensorSides[side] = false
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function writeEntry(menuTable, index, cursorPos)
|
||
|
if cursorPos == index then
|
||
|
term.setBackgroundColor(term.isColor() and colors.blue or colors.white)
|
||
|
term.setTextColor(term.isColor() and colors.white or colors.black)
|
||
|
term.write(string.sub(menuTable[index], 1, 16))
|
||
|
term.setBackgroundColor(colors.black)
|
||
|
term.setTextColor(colors.white)
|
||
|
else
|
||
|
term.write(string.sub(menuTable[index], 1, 16))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function toLines(currTable, linesTable, trackingTable, depth)
|
||
|
for k,v in pairs(currTable) do
|
||
|
if type(v) == "table" then
|
||
|
table.insert(linesTable, string.rep(" ", depth)..tostring(k)..":")
|
||
|
if trackingTable[v] then
|
||
|
table.insert(linesTable, string.rep(" ", depth + 1).."<Cyclic Reference: "..trackingTable[v]..">")
|
||
|
else
|
||
|
trackingTable[v] = #linesTable
|
||
|
toLines(v, linesTable, trackingTable, depth + 1)
|
||
|
end
|
||
|
else
|
||
|
table.insert(linesTable, string.rep(" ", depth)..tostring(k).."> "..tostring(v))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function drawDividerDown(startY)
|
||
|
local w, h = term.getSize()
|
||
|
for i=startY, h do
|
||
|
term.setCursorPos(17, i)
|
||
|
term.write("|")
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function redraw()
|
||
|
w, h = term.getSize()
|
||
|
--pre-fetch sensor targets and detailed target information.
|
||
|
local targetNames = nil
|
||
|
detailLines = {}
|
||
|
checkSensors()
|
||
|
if sensorSides[sideNames[sideSelection]] then
|
||
|
targetNames = sensor.call(sideNames[sideSelection], "getSensorName") and sensor.call(sideNames[sideSelection], "getTargets")
|
||
|
targetNameMenuTable = {}
|
||
|
if targetNames then
|
||
|
for k,v in pairs(targetNames) do
|
||
|
table.insert(targetNameMenuTable, k)
|
||
|
end
|
||
|
table.sort(targetNameMenuTable)
|
||
|
if #targetNameMenuTable > 0 then
|
||
|
toLines(sensor.call(sideNames[sideSelection], "getTargetDetails", targetNameMenuTable[targetSelection]), detailLines, {}, 0)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
--now draw the screen.
|
||
|
term.clear()
|
||
|
term.setCursorPos(1, 1)
|
||
|
term.write("=Sensor Info Viewer="..string.rep("=", w - 20))
|
||
|
term.setCursorPos(1, 2)
|
||
|
for n,side in ipairs(sideNames) do
|
||
|
if n == sideSelection then
|
||
|
term.setBackgroundColor(term.isColor() and colors.blue or colors.white)
|
||
|
term.setTextColor(term.isColor() and colors.white or colors.black)
|
||
|
term.write(side)
|
||
|
term.setBackgroundColor(colors.black)
|
||
|
term.setTextColor(colors.white)
|
||
|
term.write(" ")
|
||
|
else
|
||
|
term.write(side.." ")
|
||
|
end
|
||
|
end
|
||
|
term.setCursorPos(1, 3)
|
||
|
term.write("-Targets--------+-Info-"..string.rep("-", w - 23))
|
||
|
|
||
|
if targetNames then
|
||
|
--make sure we have valid targets, even if we have a valid sensor.
|
||
|
if #targetNameMenuTable > 0 then
|
||
|
term.setCursorPos(1, 4)
|
||
|
if targetOffset > 1 then
|
||
|
term.write("/\\")
|
||
|
else
|
||
|
writeEntry(targetNameMenuTable, 1, targetSelection)
|
||
|
end
|
||
|
--h-5 to leave room for top and bottom entries.
|
||
|
for i=1, math.min(h - 5, #targetNameMenuTable - 1) do
|
||
|
term.setCursorPos(1, i + 4)
|
||
|
writeEntry(targetNameMenuTable, targetOffset + i, targetSelection)
|
||
|
end
|
||
|
if #targetNameMenuTable >= h then
|
||
|
term.setCursorPos(1, h)
|
||
|
if #targetNameMenuTable > targetOffset + h - 4 then
|
||
|
term.write("\\/")
|
||
|
else
|
||
|
writeEntry(targetNameMenuTable, #targetNameMenuTable, targetSelection)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--detailed info.
|
||
|
for i=1, math.min(h - 3, #detailLines - ((detailOffset - 1) * (h - 3))) do
|
||
|
term.setCursorPos(17, i + 3)
|
||
|
term.write("|"..string.sub(detailLines[(detailOffset - 1) * (h - 3) + i], 1, w - 17))
|
||
|
end
|
||
|
local currX, currY = term.getCursorPos()
|
||
|
drawDividerDown(currY + 1)
|
||
|
else
|
||
|
term.setCursorPos(1, 4)
|
||
|
term.write("No targets found|")
|
||
|
drawDividerDown(5)
|
||
|
end
|
||
|
else
|
||
|
if peripheral.getType(sideNames[sideSelection]) == "sensor" then
|
||
|
term.setCursorPos(1, 4)
|
||
|
term.write("No sensor card |")
|
||
|
drawDividerDown(5)
|
||
|
else
|
||
|
term.setCursorPos(1, 4)
|
||
|
term.write("No sensor found |")
|
||
|
drawDividerDown(5)
|
||
|
end
|
||
|
end
|
||
|
term.setCursorPos(1, h)
|
||
|
end
|
||
|
|
||
|
local function findGraphMatch(currTable, target, matchCount, trackingTable)
|
||
|
for k, v in pairs(currTable) do
|
||
|
if type(v) == "table" then
|
||
|
if trackingTable[v] then return false end
|
||
|
trackingTable[v] = true
|
||
|
ret, path, count = findGraphMatch(v, target, matchCount, trackingTable)
|
||
|
if ret and path then
|
||
|
return ret, tostring(k).."-"..path
|
||
|
elseif count then
|
||
|
matchCount = count
|
||
|
end
|
||
|
elseif type(v) == "number" then
|
||
|
matchCount = matchCount + 1
|
||
|
if matchCount == target then return v, tostring(k) end
|
||
|
end
|
||
|
end
|
||
|
return false, nil, matchCount
|
||
|
end
|
||
|
|
||
|
local function createGraph(targetNum)
|
||
|
local monSide = ""
|
||
|
for k, side in ipairs(rs.getSides()) do
|
||
|
if peripheral.getType(side) == "monitor" then
|
||
|
monSide = side
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
if monSide and targetNum >= 1 and findGraphMatch(sensor.call(graphSide, "getTargetDetails", graphTarget), targetNum, 0, {}) then
|
||
|
graphMatch = targetNum
|
||
|
local val, name = findGraphMatch(sensor.call(graphSide, "getTargetDetails", graphTarget), targetNum, 0, {})
|
||
|
local updateFunc = function() return (findGraphMatch(sensor.call(graphSide, "getTargetDetails", graphTarget), graphMatch, 0, {})) end
|
||
|
graphInst = graph.new(peripheral.wrap(monSide), updateFunc, name)
|
||
|
return graphInst
|
||
|
end
|
||
|
end
|
||
|
|
||
|
while true do
|
||
|
redraw()
|
||
|
local e, p1 = os.pullEvent()
|
||
|
if e == "key" then
|
||
|
local w, h = term.getSize()
|
||
|
if p1 == 203 then
|
||
|
--left, selects previous side
|
||
|
if sideSelection > 1 then
|
||
|
sideSelection = sideSelection - 1
|
||
|
targetSelection = 1
|
||
|
targetOffset = 1
|
||
|
detailOffset = 1
|
||
|
detailLines = nil
|
||
|
end
|
||
|
elseif p1 == 205 then
|
||
|
--right, selects next side
|
||
|
if sideSelection < 6 then
|
||
|
sideSelection = sideSelection + 1
|
||
|
targetSelection = 1
|
||
|
targetOffset = 1
|
||
|
detailOffset = 1
|
||
|
detailLines = nil
|
||
|
end
|
||
|
elseif p1 == 200 then
|
||
|
--up, selects previous target, adjusting offset if necessary.
|
||
|
if targetSelection > 1 then
|
||
|
if targetSelection - targetOffset + 1 == 2 and targetOffset > 1 then
|
||
|
targetOffset = targetOffset - 1
|
||
|
end
|
||
|
targetSelection = targetSelection - 1
|
||
|
detailOffset = 1
|
||
|
detailLines = nil
|
||
|
end
|
||
|
elseif p1 == 208 then
|
||
|
--down, selects next target, adjusting offset if necessary.
|
||
|
if targetNameMenuTable and targetSelection < #targetNameMenuTable then
|
||
|
if targetSelection - targetOffset + 1 == h - 4 and targetSelection ~= #targetNameMenuTable - 1 then
|
||
|
targetOffset = targetOffset + 1
|
||
|
end
|
||
|
targetSelection = targetSelection + 1
|
||
|
detailOffset = 1
|
||
|
detailLines = nil
|
||
|
end
|
||
|
elseif p1 == 201 then
|
||
|
--pgup, moves detail
|
||
|
if detailOffset > 1 then
|
||
|
detailOffset = detailOffset - 1
|
||
|
end
|
||
|
elseif p1 == 209 then
|
||
|
--pgdown, moves detail
|
||
|
local w, h = term.getSize()
|
||
|
if detailLines and detailOffset < math.ceil(#detailLines / (h - 3)) then
|
||
|
detailOffset = detailOffset + 1
|
||
|
end
|
||
|
--and now, since redraw() will eat char events with the change to sensor.call:
|
||
|
elseif p1 == 31 then --s
|
||
|
if detailLines then
|
||
|
local fileHandle = io.open("sensorDetailed-"..sideNames[sideSelection].."-"..targetNameMenuTable[targetSelection], "w")
|
||
|
if fileHandle then
|
||
|
for k, v in ipairs(detailLines) do
|
||
|
fileHandle:write(v.."\n")
|
||
|
end
|
||
|
fileHandle:close()
|
||
|
end
|
||
|
end
|
||
|
elseif p1 == 16 then --q
|
||
|
sleep(0)
|
||
|
return
|
||
|
elseif p1 == 34 then --g
|
||
|
if graph then
|
||
|
graphing = not graphing
|
||
|
if not graphing then
|
||
|
graphSide = nil
|
||
|
graphTarget = nil
|
||
|
graphUpdate = nil
|
||
|
else
|
||
|
graphSide = sideNames[sideSelection]
|
||
|
graphTarget = targetNameMenuTable[targetSelection]
|
||
|
graphInstance = createGraph(1)
|
||
|
graphUpdate = os.startTimer(0.5)
|
||
|
end
|
||
|
end
|
||
|
elseif p1 == 49 then --n
|
||
|
if graphing then
|
||
|
local newGraph = createGraph(graphMatch + 1)
|
||
|
if newGraph then
|
||
|
graphInstance = newGraph
|
||
|
graphUpdate = os.startTimer(0.5)
|
||
|
end
|
||
|
end
|
||
|
elseif p1 == 25 then --p
|
||
|
if graphing then
|
||
|
local newGraph = createGraph(graphMatch - 1)
|
||
|
if newGraph then
|
||
|
graphInstance = newGraph
|
||
|
graphUpdate = os.startTimer(0.5)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
elseif e == "timer" then
|
||
|
if p1 == graphUpdate then
|
||
|
graphInstance:draw()
|
||
|
graphUpdate = os.startTimer(0.5)
|
||
|
end
|
||
|
end
|
||
|
end
|