CCCPaste

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")