Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --- Farm Controller ---
- --- Updated by cdbab
- --- DateTime: 11/22/2024
- local LOCAL_ID = "CONTROLLER"
- local PROTOCOL = "mobfarm"
- local nodes = {} -- List of registered nodes
- local buttonPage = 1
- local buttonsPerPage = 6
- local monitor = peripheral.wrap("right")
- rednet.open("back")
- rednet.host(PROTOCOL, LOCAL_ID)
- -- Utility Functions
- local function generateMessageUID()
- local timestamp = os.epoch("utc")
- local randomValue = math.random(1000, 9999)
- return string.format("%d-%d-%d", os.getComputerID(), timestamp, randomValue)
- end
- local function sendAndValidateCom(destID, packet, timeout, retries, uid_)
- local uid = generateMessageUID()
- if uid_ then uid = uid_ end
- packet.uid = uid
- local attempts = 0
- repeat
- attempts = attempts + 1
- rednet.send(destID, packet, PROTOCOL)
- local id, message = rednet.receive(PROTOCOL, timeout)
- if id == destID and message and message.uid == uid and message.data == "ack" then
- return true
- end
- until attempts >= retries
- return false
- end
- local function updateNodeList()
- -- Retrieve nodes via protocol lookup
- local discoveredNodes = { rednet.lookup(PROTOCOL) }
- -- Add missing nodes with a handshake
- for _, nodeID in pairs(discoveredNodes) do
- local found = false
- for _, node in ipairs(nodes) do
- if node.id == nodeID then
- found = true
- break
- end
- end
- if not found then
- rednet.send(nodeID, { request = "handshake" }, PROTOCOL)
- end
- end
- end
- local function formatHostname(hostname)
- -- Split the hostname by the underscore
- local parts = {}
- for part in string.gmatch(hostname, "([^_]+)") do
- table.insert(parts, part)
- end
- -- Format the label as "Type Farm Number"
- if #parts == 2 then
- return parts[1] .. " Farm " .. parts[2]
- else
- return hostname -- Fallback in case of unexpected format
- end
- end
- -- Monitor Rendering
- local function drawMonitor()
- monitor.clear()
- local width, height = monitor.getSize()
- -- Storage Section
- local storageXStart = math.floor(width * 0.6)
- local barWidth = math.floor(width * 0.35)
- local barY = 2
- for i, node in ipairs(nodes) do
- local percent = node.storage or 0
- local barLength = math.floor(barWidth * (percent / 100))
- local barColor = colors.green
- if percent > 90 then barColor = colors.red
- elseif percent > 70 then barColor = colors.orange
- elseif percent > 50 then barColor = colors.yellow
- end
- monitor.setCursorPos(storageXStart, barY)
- monitor.write(string.format("Storage %d: %d%%", i, percent))
- monitor.setCursorPos(storageXStart, barY + 1)
- monitor.setBackgroundColor(barColor)
- monitor.write(string.rep(" ", barLength))
- monitor.setBackgroundColor(colors.black)
- barY = barY + 3
- end
- -- XP Section
- local xpStored = 0
- for _, node in ipairs(nodes) do
- if node.type == "XP" then xpStored = node.xp or 0 end
- end
- monitor.setCursorPos(storageXStart, barY)
- monitor.write(string.format("XP Stored: %d", xpStored))
- -- Button Group Section
- local buttonXStart = 3
- local buttonWidth = math.floor((width * 0.4) / 2) - 2
- local buttonHeight = 3
- local pageStart = (buttonPage - 1) * buttonsPerPage + 1
- local pageEnd = math.min(pageStart + buttonsPerPage - 1, #nodes)
- local y = 3
- for i = pageStart, pageEnd do
- local node = nodes[i]
- local buttonColor = node.status == "Running" and colors.red or colors.green
- monitor.setBackgroundColor(buttonColor)
- local x = ((i - pageStart) % 2 == 0) and buttonXStart + buttonWidth + 2 or buttonXStart
- monitor.setCursorPos(x, y)
- monitor.write(" " .. node.label .. " ")
- monitor.setCursorPos(x, y + 1)
- monitor.write(" " .. node.status .. " ")
- monitor.setBackgroundColor(colors.black)
- if i % 2 == 0 then y = y + buttonHeight + 1 end
- end
- -- Pagination Section
- monitor.setCursorPos(2, height - 1)
- for i = 1, math.ceil(#nodes / buttonsPerPage) do
- local color = (i == buttonPage) and colors.green or colors.white
- monitor.setTextColor(color)
- monitor.write(tostring(i) .. " ")
- end
- monitor.setTextColor(colors.white)
- -- Navigation Arrows
- monitor.setCursorPos(1, height - 1)
- monitor.setTextColor(buttonPage > 1 and colors.green or colors.gray)
- monitor.write("<")
- monitor.setCursorPos(width, height - 1)
- monitor.setTextColor(buttonPage < math.ceil(#nodes / buttonsPerPage) and colors.green or colors.gray)
- monitor.write(">")
- monitor.setTextColor(colors.white)
- end
- -- Button Handling
- local function handleButtonClick(x, y)
- -- Check if < or > is clicked
- local width, height = monitor.getSize()
- if y == height - 1 then
- if x == 1 and buttonPage > 1 then
- buttonPage = buttonPage - 1
- elseif x == width and buttonPage < math.ceil(#nodes / buttonsPerPage) then
- buttonPage = buttonPage + 1
- end
- drawMonitor()
- return
- end
- -- Check button group
- local buttonXStart = 3
- local buttonWidth = math.floor((width * 0.4) / 2) - 2
- local buttonHeight = 3
- local pageStart = (buttonPage - 1) * buttonsPerPage + 1
- local pageEnd = math.min(pageStart + buttonsPerPage - 1, #nodes)
- local yIndex = 3
- for i = pageStart, pageEnd do
- local xStart = ((i - pageStart) % 2 == 0) and buttonXStart + buttonWidth + 2 or buttonXStart
- if x >= xStart and x <= xStart + buttonWidth and y >= yIndex and y <= yIndex + buttonHeight then
- local node = nodes[i]
- rednet.send(node.id, { request = "toggle" }, PROTOCOL)
- return -- Exit after sending the toggle request
- end
- if i % 2 == 0 then yIndex = yIndex + buttonHeight + 1 end
- end
- end
- -- Main Network Watcher
- local function networkWatcher()
- while true do
- local id, msg = rednet.receive(PROTOCOL)
- if type(msg) == "table" and id and msg.data == "init" then
- local packet = nil
- packet.data = "ack"
- sendAndValidateCom(id, packet, 5, 3, msg.uid)
- local exists = false
- for _, node in ipairs(nodes) do
- if node.hostName == msg.hostName then
- exists = true
- break
- end
- end
- if not exists then
- table.insert(nodes, { id = id, hostName = msg.hostName, status = "Stopped", type = msg.hostName:match("XP") and "XP" or "MOB", label = formatHostname(msg.hostName) })
- end
- elseif type(msg) == "table" and id and msg.data == "status" then
- for _, node in ipairs(nodes) do
- if node.id == id then
- node.status = msg.status
- node.storage = msg.storage
- node.xp = msg.xp
- end
- end
- end
- drawMonitor()
- end
- end
- -- Initialize
- math.randomseed(os.time())
- updateNodeList()
- drawMonitor()
- parallel.waitForAll(networkWatcher, function()
- while true do
- local event, side, x, y = os.pullEvent("monitor_touch")
- handleButtonClick(x, y)
- end
- end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement