April_The_Sergal

Controller

Nov 23rd, 2024 (edited)
304
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 25.08 KB | None | 0 0
  1. -- Controller Script
  2.  
  3. -- Variables
  4. local PROTOCOL = "mobFarm"
  5. local LOCAL_ID = "controller"
  6. -- Mapping between hostName and computerID
  7. local nodeIDs = {}
  8. --Mapping buttons
  9. local buttonMap = {}
  10. local messageBuffer = {} -- Stores incoming messages
  11. local updateAcknowledgments = {}
  12. local stateFile = "stayOnlineStates.json"
  13. local version = "1.0.2" -- Version of the startup.lua
  14.  
  15. -- Ensure update.lua exists with version and Pastebin checks
  16.  
  17. local pastebinID = "vMG1SPAL" -- Pastebin ID for update.lua
  18. local pastebinURL = "https://pastebin.com/raw/" .. pastebinID
  19. local updateScriptName = "update.lua"
  20. local localVersionFile = "update_version.txt" -- File to store the local version
  21.  
  22. -- Function to check if the Pastebin file exists
  23. local function checkPastebinFileExists()
  24.     print("Checking if Pastebin file exists...")
  25.     local response = http.get(pastebinURL)
  26.     if response then
  27.         response.close()
  28.         print("Pastebin file exists.")
  29.         return true
  30.     else
  31.         print("Pastebin file does not exist or cannot be accessed.")
  32.         return false
  33.     end
  34. end
  35.  
  36. -- Function to read the local version of update.lua
  37. local function readLocalVersion()
  38.     if fs.exists(localVersionFile) then
  39.         local file = fs.open(localVersionFile, "r")
  40.         local version = file.readLine()
  41.         file.close()
  42.         return version
  43.     else
  44.         return nil -- No local version exists
  45.     end
  46. end
  47.  
  48. -- Function to write the local version of update.lua
  49. local function writeLocalVersion(version)
  50.     local file = fs.open(localVersionFile, "w")
  51.     file.writeLine(version)
  52.     file.close()
  53. end
  54.  
  55. -- Function to fetch the remote version from Pastebin
  56. local function fetchRemoteVersion()
  57.     print("Fetching remote version from Pastebin...")
  58.     local response = http.get(pastebinURL)
  59.     if response then
  60.         local content = response.readAll()
  61.         response.close()
  62.  
  63.         -- Extract the version from the script content
  64.         local remoteVersion = content:match('local version%s*=%s*"(.-)"')
  65.         if remoteVersion then
  66.             print("Remote version found: " .. remoteVersion)
  67.             return remoteVersion
  68.         else
  69.             print("Failed to extract version from remote script.")
  70.             return nil
  71.         end
  72.     else
  73.         print("Failed to fetch remote script. Check network or Pastebin ID.")
  74.         return nil
  75.     end
  76. end
  77.  
  78. -- Function to compare versions
  79. local function isUpdateRequired(localVersion, remoteVersion)
  80.     if not localVersion then
  81.         print("No local version found. Update required.")
  82.         return true
  83.     end
  84.  
  85.     if localVersion ~= remoteVersion then
  86.         print("Version mismatch: Local (" .. localVersion .. ") vs Remote (" .. remoteVersion .. "). Update required.")
  87.         return true
  88.     else
  89.         print("Local version (" .. localVersion .. ") is up-to-date.")
  90.         return false
  91.     end
  92. end
  93.  
  94. -- Main logic to ensure update.lua exists and is up-to-date
  95. print("Checking update.lua...")
  96.  
  97. -- Check if the Pastebin file exists
  98. if not checkPastebinFileExists() then
  99.     print("Pastebin file does not exist. Aborting check.")
  100.     return
  101. end
  102.  
  103. -- Read local version
  104. local localVersion = readLocalVersion()
  105.  
  106. -- Fetch remote version
  107. local remoteVersion = fetchRemoteVersion()
  108.  
  109. -- Check if an update is required
  110. if remoteVersion and isUpdateRequired(localVersion, remoteVersion) then
  111.     -- Remove outdated update.lua
  112.     if fs.exists(updateScriptName) then
  113.         print("Removing outdated " .. updateScriptName)
  114.         fs.delete(updateScriptName)
  115.     end
  116.  
  117.     -- Download the new update.lua
  118.     print("Downloading updated " .. updateScriptName .. " from Pastebin...")
  119.     local success = shell.run("pastebin get " .. pastebinID .. " " .. updateScriptName)
  120.     if success then
  121.         print(updateScriptName .. " downloaded successfully.")
  122.         -- Write the new version to the local version file
  123.         writeLocalVersion(remoteVersion)
  124.     else
  125.         print("Failed to download " .. updateScriptName .. ". Please check the Pastebin ID or your connection.")
  126.     end
  127. else
  128.     print(updateScriptName .. " is up-to-date. No action required.")
  129. end
  130.  
  131.  
  132. -- Peripherals
  133. peripheral.find("modem", rednet.open)
  134. local monitor = peripheral.find("monitor")
  135.  
  136. -- Host controller as 'controller' on network
  137. rednet.host(PROTOCOL, LOCAL_ID)
  138.  
  139. if not monitor then
  140.     error("Monitor not found!")
  141. end
  142.  
  143. if not rednet.isOpen() then
  144.     error("Rednet is not open! Check the modem.")
  145. end
  146.  
  147. -- Configuration
  148. monitor.setTextScale(0.5)
  149. monitor.clear()
  150. local screenHeight = monitor.getSize()
  151. itemsPerPage = 6
  152. local nodes = {}
  153. local messageBuffer = {}
  154. local currentPage = 1
  155.  
  156. -- Utility Functions
  157. -- Updated addNode Function
  158. local function addNode(hostName, computerID)
  159.     if not nodes[hostName] then
  160.         nodes[hostName] = {
  161.             type = hostName:match("^(%a+)_"),
  162.             id = tonumber(hostName:match("_(%d+)$")),
  163.             status = "UNKNOWN",
  164.             stayOnline = false, -- Default to not required to stay online
  165.             storage = 0
  166.         }
  167.         nodeIDs[hostName] = computerID -- Map hostName to computerID
  168.     end
  169. end
  170.  
  171. local function getNodeLabel(hostName)
  172.     local node = nodes[hostName]
  173.     return string.format("%s FARM %d", node.type, node.id)
  174. end
  175.  
  176. -- UI Functions
  177. local function countTableItems(tbl)
  178.     local count = 0
  179.     for _ in pairs(tbl) do
  180.         count = count + 1
  181.     end
  182.     return count
  183. end
  184.  
  185. -- Save stayOnline states and statuses to a file
  186. local function saveNodeStates()
  187.     local data = {}
  188.     for hostName, node in pairs(nodes) do
  189.         data[hostName] = {
  190.             stayOnline = node.stayOnline,
  191.             status = node.status,
  192.         }
  193.     end
  194.  
  195.     local file = fs.open(stateFile, "w")
  196.     if file then
  197.         file.write(textutils.serializeJSON(data))
  198.         file.close()
  199.         print("Node states saved to file.")
  200.     else
  201.         print("Error saving node states!")
  202.     end
  203. end
  204.  
  205.  
  206. -- Regenerate the state file with default values
  207. local function regenerateNodeStates()
  208.     local defaultStates = {}
  209.     for hostName, node in pairs(nodes) do
  210.         defaultStates[hostName] = {
  211.             stayOnline = node.stayOnline or false,
  212.             storage = node.storage or 0
  213.         }
  214.     end
  215.  
  216.     local file = fs.open(stateFile, "w")
  217.     if file then
  218.         file.write(textutils.serializeJSON(defaultStates))
  219.         file.close()
  220.         print("Regenerated state file with default values.")
  221.     else
  222.         print("Error regenerating state file!")
  223.     end
  224. end
  225.  
  226. -- Load stayOnline states and other node data from the state file
  227. local function loadNodeStates()
  228.     if not fs.exists(stateFile) then
  229.         print("No state file found. Skipping load.")
  230.         regenerateNodeStates()
  231.         return
  232.     end
  233.  
  234.     local file = fs.open(stateFile, "r")
  235.     if not file then
  236.         print("Error opening state file! Regenerating...")
  237.         regenerateNodeStates()
  238.         return
  239.     end
  240.  
  241.     local data = textutils.unserializeJSON(file.readAll())
  242.     file.close()
  243.  
  244.     if type(data) ~= "table" then
  245.         print("Invalid state file format. Regenerating...")
  246.         regenerateNodeStates()
  247.         return
  248.     end
  249.  
  250.     for hostName, nodeData in pairs(data) do
  251.         if type(nodeData) == "table" then
  252.             if not nodes[hostName] then
  253.                 -- Add the node if it doesn't already exist
  254.                 addNode(hostName, nodeData.computerID or nil)
  255.             end
  256.  
  257.             -- Update node properties
  258.             nodes[hostName].stayOnline = nodeData.stayOnline or false
  259.             nodes[hostName].storage = nodeData.storage or 0
  260.             print("Loaded state for node " .. hostName)
  261.         else
  262.             print("Skipping invalid data for node:", hostName)
  263.         end
  264.     end
  265.  
  266.     -- Ensure the file is valid even if there are partial issues
  267.     regenerateNodeStates()
  268. end
  269.  
  270.  
  271. --Sort Node buttons in asc order
  272. local function getSortedNodeKeys()
  273.     local keys = {}
  274.     for hostName in pairs(nodes) do
  275.         table.insert(keys, hostName)
  276.     end
  277.     table.sort(keys, function(a, b)
  278.         local aID = tonumber(a:match("_(%d+)$")) or 0
  279.         local bID = tonumber(b:match("_(%d+)$")) or 0
  280.         return aID < bID
  281.     end)
  282.     return keys
  283. end
  284.  
  285. -- Toggle a node's state
  286. local function toggleNode(hostName)
  287.     if not nodes[hostName] then return end
  288.  
  289.     local currentStatus = nodes[hostName].status
  290.     local newStatus = (currentStatus == "RUNNING") and "STOPPED" or "RUNNING"
  291.  
  292.     local computerID = nodeIDs[hostName]  -- Get the computerID for the node
  293.     if not computerID then
  294.         print("No computer ID found for node: " .. hostName)
  295.         return
  296.     end
  297.  
  298.     -- Send the toggle message to the computerID
  299.     rednet.send(computerID, { type = "toggle" }, PROTOCOL)
  300.     nodes[hostName].status = "PENDING"  -- Update the status to "PENDING"
  301.     saveNodeStates() -- Save state after toggling
  302.  
  303.     print("Toggled node " .. hostName .. " to " .. newStatus)
  304. end
  305.  
  306. -- Define drawStorageBar BEFORE calling it in drawButtons
  307. local function drawStorageBar(x, y, storagePercent)
  308.     x = x + 2
  309.     -- Determine the color for the filled portion of the bar
  310.     local barColor = colors.green
  311.     if storagePercent >= 90 then
  312.         barColor = colors.red
  313.     elseif storagePercent >= 75 then
  314.         barColor = colors.orange
  315.     elseif storagePercent >= 50 then
  316.         barColor = colors.yellow
  317.     end
  318.  
  319.     -- Calculate the filled and unfilled width
  320.     local totalWidth = 10 -- Width of the storage bar
  321.     local filledWidth = math.floor(totalWidth * (storagePercent / 100))
  322.     local unfilledWidth = totalWidth - filledWidth
  323.  
  324.     -- Draw the filled portion of the bar
  325.     monitor.setCursorPos(x, y)
  326.     monitor.setBackgroundColor(barColor)
  327.     monitor.write(string.rep(" ", filledWidth))
  328.  
  329.     -- Draw the unfilled portion of the bar in gray
  330.     monitor.setBackgroundColor(colors.gray)
  331.     monitor.write(string.rep(" ", unfilledWidth))
  332.  
  333.     -- Reset the background color
  334.     monitor.setBackgroundColor(colors.black)
  335.  
  336.     -- Write the percentage text in the middle of the bar
  337.     local percentText = storagePercent .. "%"
  338.     local foreground = string.rep(colors.toBlit(colors.white), #tostring(percentText))
  339.     local color = storagePercent <= 40 and colors.gray or barColor
  340.     local background = string.rep(colors.toBlit(color), #tostring(percentText))
  341.     monitor.setCursorPos(x + math.floor((totalWidth - #percentText) / 2), y)
  342.     monitor.blit(tostring(percentText), foreground, background )
  343. end
  344.  
  345.  
  346. -- Draw Buttons
  347. local function drawButtons()
  348.     monitor.clear()
  349.     monitor.setCursorPos(1, 1)
  350.     monitor.write("Mob Farm Controller")
  351.     buttonMap = {}
  352.     local screenWidth, screenHeight = monitor.getSize()
  353.  
  354.     local sortedNodeKeys = getSortedNodeKeys()
  355.     local nodeCount = #sortedNodeKeys
  356.  
  357.     if nodeCount == 0 then
  358.         monitor.setCursorPos(2, 3)
  359.         monitor.write("No nodes available")
  360.         return
  361.     end
  362.  
  363.     local x, y = 2, 2 -- Initial position for buttons
  364.     local progressBarWidth = 10 -- Storage bar width
  365.     local startIndex = (currentPage - 1) * itemsPerPage + 1
  366.     local endIndex = math.min(startIndex + itemsPerPage - 1, nodeCount)
  367.  
  368.     for i = startIndex, endIndex do
  369.         local hostName = sortedNodeKeys[i]
  370.         local node = nodes[hostName]
  371.         local label = getNodeLabel(hostName)
  372.         local status = node.status or "UNKNOWN"
  373.         local storagePercent = node.storage or 0
  374.         local color = (status == "RUNNING") and colors.red or colors.green
  375.  
  376.         -- Draw Node Label and Status
  377.         local labelText = label .. " (" .. status .. ")"
  378.         local textLength = #labelText
  379.         local foreground = string.rep(colors.toBlit(colors.white), textLength)
  380.         local background = string.rep(colors.toBlit(color), textLength)
  381.  
  382.         monitor.setCursorPos(x, y)
  383.         monitor.blit(labelText, foreground, background)
  384.  
  385.         -- Draw Persistence Toggle Button
  386.         local stayOnline = node.stayOnline or false
  387.         local toggleText = stayOnline and "ON" or "OFF"
  388.         local toggleColor = stayOnline and colors.green or colors.red
  389.         local toggleStartX = x + textLength + 2
  390.         local toggleEndX = toggleStartX + 3 -- Button width is 4 characters
  391.         monitor.setCursorPos(toggleStartX, y)
  392.         monitor.setBackgroundColor(toggleColor)
  393.         monitor.write(" " .. toggleText .. " ")
  394.         monitor.setBackgroundColor(colors.black)
  395.  
  396.         -- Add Toggle Button to Button Map
  397.         table.insert(buttonMap, {
  398.             name = "StayOnline_" .. hostName,
  399.             x1 = toggleStartX,
  400.             y1 = y,
  401.             x2 = toggleEndX,
  402.             y2 = y,
  403.             action = function()
  404.                 print("Toggling stayOnline for " .. hostName)
  405.                 node.stayOnline = not node.stayOnline
  406.                 saveNodeStates() -- Save state after toggle
  407.                 drawButtons() -- Refresh the display
  408.             end
  409.         })
  410.  
  411.         -- Draw Storage Progress Bar
  412.         local storageBarStartX = toggleEndX + 2 -- Space after the toggle button
  413.         drawStorageBar(storageBarStartX, y, storagePercent)
  414.  
  415.         -- Add Node Toggle Button to Button Map
  416.         table.insert(buttonMap, {
  417.             name = "NodeToggle_" .. hostName,
  418.             x1 = x,
  419.             y1 = y,
  420.             x2 = x + textLength - 1,
  421.             y2 = y,
  422.             action = function()
  423.                 print("Toggling node:", hostName)
  424.                 toggleNode(hostName)
  425.             end
  426.         })
  427.  
  428.         y = y + 2 -- Move to the next row
  429.     end
  430.  
  431.     -- Draw Pagination
  432.     local totalPages = math.ceil(nodeCount / itemsPerPage)
  433.     local paginationText = "Page " .. currentPage .. " of " .. totalPages
  434.     monitor.setCursorPos(math.floor((screenWidth - #paginationText) / 2), 17)
  435.     monitor.write(paginationText)
  436.     local xPos = math.floor((screenWidth - #paginationText) / 2)
  437.     local prevPos = xPos - 3
  438.     local nextPos = xPos + #paginationText + 2
  439.     -- Add Pagination Buttons
  440.     if currentPage > 1 then
  441.         monitor.setCursorPos(prevPos, 17)
  442.         monitor.write("<")
  443.         table.insert(buttonMap, {
  444.             name = "PreviousPage",
  445.             x1 = prevPos,
  446.             y1 = 17,
  447.             x2 = prevPos,
  448.             y2 = 17,
  449.             action = function()
  450.                 currentPage = currentPage - 1
  451.                 drawButtons()
  452.             end
  453.         })
  454.     end
  455.  
  456.     if currentPage < totalPages then
  457.         monitor.setCursorPos(nextPos, 17)
  458.         monitor.write(">")
  459.         table.insert(buttonMap, {
  460.             name = "NextPage",
  461.             x1 = nextPos,
  462.             y1 = 17,
  463.             x2 = nextPos,
  464.             y2 = 17,
  465.             action = function()
  466.                 currentPage = currentPage + 1
  467.                 drawButtons()
  468.             end
  469.         })
  470.     end
  471. end
  472.  
  473. -- Validate nodes and retry toggling states if needed
  474. local function validateNodesAgainstStates()
  475.     for hostName, node in pairs(nodes) do
  476.         if node.stayOnline and node.status ~= "RUNNING" then
  477.             print("Node " .. hostName .. " should be running. Toggling...")
  478.             toggleNode(hostName) -- Attempt to start the node
  479.         elseif not node.stayOnline and node.status == "RUNNING" then
  480.             print("Node " .. hostName .. " should be stopped. Toggling...")
  481.             toggleNode(hostName) -- Attempt to stop the node
  482.         end
  483.     end
  484. end
  485.  
  486. -- Force status update requests from all nodes immediately after startup
  487. local function requestInitialStatuses()
  488.     print("Requesting initial statuses from all nodes...")
  489.     for hostName, computerID in pairs(nodeIDs) do
  490.         if nodes[hostName] then
  491.             rednet.send(computerID, { type = "requestStatus" }, PROTOCOL)
  492.             nodes[hostName].status = "PENDING" -- Temporarily mark as PENDING until the response arrives
  493.         end
  494.     end
  495. end
  496.  
  497. -- Network Functions
  498. -- Discover Nodes with Debug Logs and Retries
  499. local function discoverNodes()
  500.     print("Discovering nodes...")
  501.     local computers = { rednet.lookup(PROTOCOL) }
  502.     print("Discovered computers:", textutils.serialize(computers))
  503.  
  504.     if #computers == 0 then
  505.         print("No nodes discovered, awaiting contact from nodes as they come online.")
  506.     else
  507.         for _, computerID in ipairs(computers) do
  508.             if computerID ~= os.getComputerID() then
  509.                 print("Requesting CLIENT_ID from computer ID:", computerID)
  510.                 rednet.send(computerID, { type = "requestId", controllerId = LOCAL_ID }, PROTOCOL)
  511.  
  512.                 -- Retry receiving response a few times
  513.                 local attempts = 3
  514.                 while attempts > 0 do
  515.                     local senderId, response = rednet.receive(PROTOCOL, 3) -- 3-second timeout
  516.                     if senderId == computerID and response and response.type == "responseId" then
  517.                         local clientId = response.CLIENT_ID
  518.                         print("Received CLIENT_ID:", clientId, "from computer ID:", computerID)
  519.                         addNode(clientId, computerID)
  520.                         drawButtons() -- Update UI after adding node
  521.                         break
  522.                     else
  523.                         print("No response or invalid response from computer ID:", computerID, "Retrying...")
  524.                         attempts = attempts - 1
  525.                         if attempts == 0 then
  526.                             print("Failed to get CLIENT_ID from computer ID:", computerID)
  527.                         end
  528.                     end
  529.                 end
  530.             end
  531.         end
  532.     end
  533. end
  534.  
  535. -- Request Status Update Function
  536. local function requestStatusUpdates()
  537.     while true do
  538.         for hostName, node in pairs(nodes) do
  539.             if node.status == "UNKNOWN" then
  540.                 local computerID = nodeIDs[hostName]
  541.                 if computerID then
  542.                     print("Requesting status update from node: " .. hostName)
  543.                     rednet.send(computerID, { type = "requestStatus" }, PROTOCOL)
  544.                 else
  545.                     print("No computer ID found for node: " .. hostName)
  546.                 end
  547.             end
  548.         end
  549.         sleep(5) -- Wait 5 seconds before rechecking
  550.     end
  551. end
  552.  
  553. local function handleControllerCommands()
  554.     while true do
  555.         write("> ")
  556.         local input = read()
  557.  
  558.         if input == "update" then
  559.             print("Initiating update process...")
  560.  
  561.             -- Clear previous acknowledgments
  562.             updateAcknowledgments = {}
  563.  
  564.             -- Notify all nodes to update
  565.             for hostName, computerID in pairs(nodeIDs) do
  566.                 rednet.send(computerID, { type = "update" }, PROTOCOL)
  567.                 print("Sent update command to node:", hostName)
  568.             end
  569.  
  570.             -- Wait for acknowledgments from all nodes
  571.             print("Waiting for all nodes to acknowledge update...")
  572.             while true do
  573.                 local allAcknowledged = true
  574.                 for hostName, _ in pairs(nodeIDs) do
  575.                     if not updateAcknowledgments[hostName] then
  576.                         allAcknowledged = false
  577.                         break
  578.                     end
  579.                 end
  580.  
  581.                 if allAcknowledged then
  582.                     print("All nodes acknowledged update.")
  583.                     break
  584.                 end
  585.  
  586.                 sleep(1) -- Wait briefly before checking again
  587.             end
  588.  
  589.             -- Perform controller update
  590.             print("Updating controller...")
  591.             shell.run("rm startup.lua") -- Delete existing startup.lua
  592.             shell.run("pastebin get RkmNxEg1 startup.lua") -- Download new script
  593.             os.reboot() -- Reboot controller
  594.         else
  595.             print("Unknown command. Available commands: update")
  596.         end
  597.     end
  598. end
  599.  
  600. -- Handle Incoming Messages
  601. local function processMessageBuffer()
  602.     while true do
  603.         if #messageBuffer > 0 then
  604.             local messageData = table.remove(messageBuffer, 1)
  605.             local senderId = messageData.senderId
  606.             local message = messageData.message
  607.  
  608.             if message.type == "storageUpdate" then
  609.                 -- Update storage percentage for the node
  610.                 local hostName = message.hostName
  611.                 local storagePercent = message.storagePercent
  612.                 if nodes[hostName] then
  613.                     nodes[hostName].storage = storagePercent
  614.                     print("Updated storage for node " .. hostName .. " to " .. storagePercent .. "%")
  615.                     drawButtons() -- Refresh UI with updated storage
  616.                 else
  617.                     print("Received storage update for unknown node: " .. hostName)
  618.                 end
  619.             elseif message.type == "status" then
  620.                 -- Handle status updates
  621.                 local hostName = message.hostName
  622.                 if nodes[hostName] then
  623.                     nodes[hostName].status = message.status
  624.                     print("Updated status for node: " .. hostName .. " to " .. message.status)
  625.                     drawButtons()
  626.                 else
  627.                     print("Unknown node status received: " .. hostName)
  628.                 end
  629.             end
  630.         else
  631.             sleep(0.1) -- Avoid busy-waiting
  632.         end
  633.     end
  634. end
  635.  
  636. local function rediscoverUnknownNodes()
  637.     print("Checking for nodes with unknown statuses...")
  638.     local rediscovered = false
  639.  
  640.     for hostName, node in pairs(nodes) do
  641.         if node.status == "UNKNOWN" then
  642.             print("Node " .. hostName .. " has an unknown status. Attempting rediscovery...")
  643.  
  644.             -- Get the node's computer ID from rednet lookup
  645.             local computerID = rednet.lookup(PROTOCOL, hostName)
  646.             if computerID then
  647.                 print("Rediscovered node:", hostName)
  648.                 nodeIDs[hostName] = computerID -- Map hostName to computerID
  649.                 rednet.send(computerID, { type = "requestStatus" }, PROTOCOL) -- Request status
  650.                 rediscovered = true
  651.             else
  652.                 print("Failed to rediscover node:", hostName)
  653.             end
  654.         end
  655.     end
  656.  
  657.     if not rediscovered then
  658.         print("No nodes required rediscovery.")
  659.     else
  660.         print("Rediscovery completed. Waiting for status updates...")
  661.         sleep(5) -- Allow time for responses
  662.         validateNodesAgainstStates() -- Ensure node states are valid
  663.     end
  664. end
  665.  
  666. local function monitorNodeStatuses()
  667.     while true do
  668.         -- Check for nodes with "UNKNOWN" statuses
  669.         local hasUnknown = false
  670.         for _, node in pairs(nodes) do
  671.             if node.status == "UNKNOWN" then
  672.                 hasUnknown = true
  673.                 break
  674.             end
  675.         end
  676.  
  677.         -- If any node has an unknown status, trigger rediscovery
  678.         if hasUnknown then
  679.             print("Unknown statuses detected. Initiating rediscovery...")
  680.             rediscoverUnknownNodes()
  681.         end
  682.  
  683.         sleep(10) -- Check every 10 seconds
  684.     end
  685. end
  686.  
  687. -- Handle Incoming Messages (Modified to process status responses)
  688. local function handleIncomingMessage()
  689.     while true do
  690.         local senderId, message = rednet.receive(PROTOCOL)
  691.         print("Received message from ID:", senderId, "Type:", message.type)
  692.  
  693.         -- Add the message to the buffer
  694.         table.insert(messageBuffer, { senderId = senderId, message = message })
  695.     end
  696. end
  697.  
  698. -- Function to check for mouse click
  699. local function handleMouseClick()
  700.     while true do
  701.         local _, _, x, y = os.pullEvent("monitor_touch") -- Capture monitor touch event
  702.         print("Monitor clicked at x:", x, "y:", y)
  703.  
  704.         for _, button in ipairs(buttonMap) do
  705.             if x >= button.x1 and x <= button.x2 and y >= button.y1 and y <= button.y2 then
  706.                 print("Button clicked:", button.name)
  707.                 if button.action then
  708.                     button.action() -- Call the action associated with the button
  709.                 else
  710.                     print("No action assigned to button:", button.name)
  711.                 end
  712.                 break
  713.             end
  714.         end
  715.     end
  716. end
  717.  
  718.  
  719. -- Main Loop
  720. discoverNodes()               -- Discover nodes on startup
  721. loadNodeStates()              -- Load saved states (stayOnline and status)
  722. requestInitialStatuses()      -- Request updated statuses immediately
  723. validateNodesAgainstStates()  -- Validate and restore node states
  724.  
  725. parallel.waitForAll(
  726.         handleIncomingMessage,    -- Receive and buffer messages from nodes
  727.         processMessageBuffer,     -- Process messages from the buffer
  728.         requestStatusUpdates,     -- Periodic status updates for nodes
  729.         handleMouseClick,         -- Handle monitor clicks for buttons
  730.         handleControllerCommands, -- Listen for user input commands
  731.         monitorNodeStatuses,      -- Periodically check for unknown statuses
  732.         function()
  733.             -- Monitor update loop
  734.             while true do
  735.                 drawButtons()      -- Periodically refresh the monitor interface
  736.                 sleep(1)           -- Update every second
  737.             end
  738.         end
  739. )
Comments
  • April_The_Sergal
    241 days
    # text 0.40 KB | 0 0
    1. This is the lua script to designate a CC:Tweaked computer as the controller module for the farm. It will receive updates from various nodes (No limit atm) and display them to a monitor. From the monitor, you can see the storage used, toggle on or off various farms, and toggle persistence so you do not have to chunckload areas the computers are in for the nodes to remember if they were previously running or not.
Add Comment
Please, Sign In to add comment