master_manager.lua
- local MODEM_SIDE = "bottom"
- local MONITOR_SIDE = "left"
- local DB_FILE = "switchmap.db"
- local PROTOCOL = "rtm_switch"
- local native = term.current()
- local map = {
- version = 1,
- gridW = 20,
- gridH = 12,
- tiles = {},
- }
- local selectedX, selectedY = 1, 1
- local currentTool = "rail_h"
- local status = "Indulas..."
- local monitor = nil
- local lastTouch = nil
- local running = true
- local tileTypes = {
- "empty",
- "rail_h",
- "rail_v",
- "curve_ne",
- "curve_nw",
- "curve_se",
- "curve_sw",
- "cross",
- "switch_cross",
- "signal",
- "label",
- }
- local tileChars = {
- empty = " ",
- rail_h = "=",
- rail_v = "|",
- curve_ne = "/",
- curve_nw = "\\",
- curve_se = "\\",
- curve_sw = "/",
- cross = "X",
- switch_cross = "S",
- signal = "!",
- label = "L",
- }
- local function center(text, y, txt, bg)
- local w, _ = term.getSize()
- term.setCursorPos(math.max(1, math.floor((w - #text) / 2) + 1), y)
- if bg then term.setBackgroundColor(bg) end
- if txt then term.setTextColor(txt) end
- term.write(text)
- end
- local function setStatus(msg)
- status = msg
- end
- local function openNet()
- if peripheral.getType(MODEM_SIDE) ~= "modem" then
- setStatus("Nincs modem a bottom oldalon")
- return false
- end
- if not rednet.isOpen(MODEM_SIDE) then
- rednet.open(MODEM_SIDE)
- end
- return true
- end
- local function getTile(x, y)
- for i = 1, #map.tiles do
- local t = map.tiles[i]
- if t.x == x and t.y == y then return t, i end
- end
- return nil, nil
- end
- local function setTile(x, y, data)
- local _, idx = getTile(x, y)
- if data.type == "empty" then
- if idx then table.remove(map.tiles, idx) end
- return
- end
- if idx then
- map.tiles[idx] = data
- else
- table.insert(map.tiles, data)
- end
- end
- local function saveDb()
- local h = fs.open(DB_FILE, "w")
- h.write(textutils.serialize(map))
- h.close()
- setStatus("Mentve: " .. DB_FILE)
- end
- local function loadDb()
- if not fs.exists(DB_FILE) then
- setStatus("Nincs adatbazis, uj keszul")
- return
- end
- local h = fs.open(DB_FILE, "r")
- local raw = h.readAll()
- h.close()
- local t = textutils.unserialize(raw)
- if type(t) == "table" then
- map = t
- setStatus("Betoltve: " .. DB_FILE)
- else
- setStatus("Hibas adatbazis")
- end
- end
- local function tileColor(tile)
- if not tile then return colors.black, colors.gray end
- if tile.type == "rail_h" or tile.type == "rail_v" or tile.type == "curve_ne" or tile.type == "curve_nw" or tile.type == "curve_se" or tile.type == "curve_sw" or tile.type == "cross" then
- return colors.black, colors.lightGray
- elseif tile.type == "switch_cross" then
- if tile.offline then return colors.black, colors.red end
- if tile.state == "cross" then return colors.black, colors.orange end
- return colors.black, colors.lime
- elseif tile.type == "signal" then
- return colors.black, colors.red
- elseif tile.type == "label" then
- return colors.black, colors.cyan
- end
- return colors.black, colors.white
- end
- local function drawMap()
- if not monitor then return end
- monitor.setBackgroundColor(colors.black)
- monitor.clear()
- local mw, mh = monitor.getSize()
- local ox, oy = 2, 2
- monitor.setCursorPos(2, 1)
- monitor.setTextColor(colors.cyan)
- monitor.write("RTM TERKEP")
- for y = 1, map.gridH do
- for x = 1, map.gridW do
- local sx = ox + (x - 1) * 2
- local sy = oy + (y - 1)
- if sx <= mw - 1 and sy <= mh - 2 then
- local tile = getTile(x, y)
- local bg = colors.black
- local txt = colors.gray
- local ch = "."
- if tile then
- bg, txt = tileColor(tile)
- ch = tileChars[tile.type] or "?"
- end
- if x == selectedX and y == selectedY then
- monitor.setBackgroundColor(colors.blue)
- monitor.setTextColor(colors.white)
- else
- monitor.setBackgroundColor(bg)
- monitor.setTextColor(txt)
- end
- monitor.setCursorPos(sx, sy)
- monitor.write(ch .. " ")
- end
- end
- end
- monitor.setBackgroundColor(colors.black)
- monitor.setTextColor(colors.white)
- monitor.setCursorPos(2, mh)
- monitor.write("Erintes: valto/kurzor")
- end
- local function prompt(text, default)
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.white)
- write(text)
- local v = read(nil, nil, nil, default)
- return v
- end
- local function editTileAt(x, y)
- term.redirect(native)
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.white)
- term.clear()
- term.setCursorPos(1,1)
- local tile = getTile(x, y) or {x = x, y = y, type = currentTool}
- print("Szerkesztes: " .. x .. "," .. y)
- print("Tipusok:")
- for i = 1, #tileTypes do
- print(i .. " - " .. tileTypes[i])
- end
- write("Tipus szama [" .. tile.type .. "]: ")
- local choice = tonumber(read())
- if choice and tileTypes[choice] then tile.type = tileTypes[choice] end
- if tile.type == "empty" then
- setTile(x, y, {x = x, y = y, type = "empty"})
- setStatus("Torolve: " .. x .. "," .. y)
- return
- end
- tile.x = x
- tile.y = y
- if tile.type == "switch_cross" then
- tile.name = prompt("Nev [" .. (tile.name or "Valto") .. "]: ", tile.name or "Valto")
- tile.slaveId = tonumber(prompt("Slave ID [" .. tostring(tile.slaveId or "") .. "]: ", tile.slaveId and tostring(tile.slaveId) or ""))
- tile.state = prompt("Allapot (straight/cross) [" .. (tile.state or "straight") .. "]: ", tile.state or "straight")
- tile.protocol = PROTOCOL
- tile.offline = false
- elseif tile.type == "label" then
- tile.text = prompt("Felirat [" .. (tile.text or "") .. "]: ", tile.text or "")
- elseif tile.type == "signal" then
- tile.name = prompt("Jelzo neve [" .. (tile.name or "Jelzo") .. "]: ", tile.name or "Jelzo")
- end
- setTile(x, y, tile)
- setStatus("Elem mentve: " .. tile.type .. " @ " .. x .. "," .. y)
- end
- local function sendSwitch(tile, newState)
- if not tile or tile.type ~= "switch_cross" then return end
- if not tile.slaveId then
- setStatus("Nincs slave ID")
- return
- end
- if not openNet() then return end
- rednet.send(tile.slaveId, {cmd = "set", state = newState}, tile.protocol or PROTOCOL)
- local timer = os.startTimer(2)
- while true do
- local e, a, b, c = os.pullEvent()
- if e == "rednet_message" then
- local senderId, msg, protocol = a, b, c
- if senderId == tile.slaveId and protocol == (tile.protocol or PROTOCOL) and type(msg) == "table" and msg.ok then
- tile.state = msg.state or newState
- tile.offline = false
- setStatus("Valasz: " .. (tile.name or "valt") .. " -> " .. tile.state)
- return
- end
- elseif e == "timer" and a == timer then
- tile.offline = true
- setStatus("Timeout slave #" .. tile.slaveId)
- return
- end
- end
- end
- local function pingAllSwitches()
- if not openNet() then return end
- for _, tile in ipairs(map.tiles) do
- if tile.type == "switch_cross" and tile.slaveId then
- rednet.send(tile.slaveId, {cmd = "ping"}, tile.protocol or PROTOCOL)
- tile.offline = true
- end
- end
- local timer = os.startTimer(1.5)
- while true do
- local e, a, b, c = os.pullEvent()
- if e == "rednet_message" then
- local senderId, msg, protocol = a, b, c
- if type(msg) == "table" and msg.ok and protocol == PROTOCOL then
- for _, tile in ipairs(map.tiles) do
- if tile.type == "switch_cross" and tile.slaveId == senderId then
- tile.offline = false
- tile.state = msg.state or tile.state
- end
- end
- end
- elseif e == "timer" and a == timer then
- setStatus("Ping kesz")
- return
- end
- end
- end
- local function handleMonitorTouch(side, x, y)
- if side ~= MONITOR_SIDE then return end
- local gx = math.floor((x - 2) / 2) + 1
- local gy = (y - 2) + 1
- if gx >= 1 and gx <= map.gridW and gy >= 1 and gy <= map.gridH then
- selectedX, selectedY = gx, gy
- lastTouch = {x = gx, y = gy}
- local tile = getTile(gx, gy)
- if tile and tile.type == "switch_cross" then
- local ns = tile.state == "straight" and "cross" or "straight"
- sendSwitch(tile, ns)
- else
- setStatus("Kijelolve: " .. gx .. "," .. gy)
- end
- end
- end
- local function uiLoop()
- while running do
- term.redirect(native)
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.white)
- term.clear()
- term.setCursorPos(1,1)
- print("RTM HALOZATI MANAGER")
- print("====================")
- print("Kijelolt tile: " .. selectedX .. "," .. selectedY)
- local tile = getTile(selectedX, selectedY)
- if tile then
- print("Tipus: " .. tile.type)
- if tile.type == "switch_cross" then
- print("Slave: " .. tostring(tile.slaveId or "nincs"))
- print("Allapot: " .. tostring(tile.state or "?"))
- print("Offline: " .. tostring(tile.offline or false))
- end
- else
- print("Tipus: ures")
- end
- print("")
- print("1 - Tile szerkesztes")
- print("2 - Kurzor mozgas")
- print("3 - Valto valtasa")
- print("4 - Osszes slave ping")
- print("5 - Mentes")
- print("6 - Betoltes")
- print("7 - Palya meret")
- print("8 - Kilepes")
- print("")
- print("Status: " .. status)
- write("> ")
- local cmd = read()
- if cmd == "1" then
- editTileAt(selectedX, selectedY)
- elseif cmd == "2" then
- local nx = tonumber(prompt("X: ", tostring(selectedX))) or selectedX
- local ny = tonumber(prompt("Y: ", tostring(selectedY))) or selectedY
- selectedX = math.max(1, math.min(map.gridW, nx))
- selectedY = math.max(1, math.min(map.gridH, ny))
- setStatus("Kurzor mozgatva")
- elseif cmd == "3" then
- local t = getTile(selectedX, selectedY)
- if t and t.type == "switch_cross" then
- sendSwitch(t, t.state == "straight" and "cross" or "straight")
- else
- setStatus("Itt nincs valto")
- end
- elseif cmd == "4" then
- pingAllSwitches()
- elseif cmd == "5" then
- saveDb()
- elseif cmd == "6" then
- loadDb()
- elseif cmd == "7" then
- local gw = tonumber(prompt("Grid W: ", tostring(map.gridW))) or map.gridW
- local gh = tonumber(prompt("Grid H: ", tostring(map.gridH))) or map.gridH
- map.gridW = math.max(5, gw)
- map.gridH = math.max(5, gh)
- setStatus("Palya meret frissitve")
- elseif cmd == "8" then
- running = false
- break
- else
- setStatus("Ismeretlen parancs")
- end
- drawMap()
- end
- end
- local function monitorLoop()
- while running do
- drawMap()
- local e, side, x, y = os.pullEvent()
- if e == "monitor_touch" then
- handleMonitorTouch(side, x, y)
- drawMap()
- elseif e == "monitor_resize" then
- drawMap()
- end
- end
- end
- local function netLoop()
- while running do
- local senderId, msg, protocol = rednet.receive(PROTOCOL)
- if type(msg) == "table" and msg.ok then
- for _, tile in ipairs(map.tiles) do
- if tile.type == "switch_cross" and tile.slaveId == senderId then
- tile.offline = false
- tile.state = msg.state or tile.state
- setStatus("Frissult: " .. (tile.name or ("#" .. senderId)))
- end
- end
- drawMap()
- end
- end
- end
- loadDb()
- openNet()
- if peripheral.getType(MONITOR_SIDE) == "monitor" then
- monitor = peripheral.wrap(MONITOR_SIDE)
- monitor.setTextScale(0.5)
- else
- setStatus("Nincs monitor a left oldalon")
- end
- if monitor then
- parallel.waitForAny(uiLoop, monitorLoop, netLoop)
- else
- parallel.waitForAny(uiLoop, netLoop)
- end
- term.redirect(native)
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.white)
- term.clear()
- term.setCursorPos(1,1)
- print("Manager leallva")
Pasted 2026-04-25 18:19:43
Short link:
Short link: