Advertisement
samuelask

Stargate Finder Worker

Dec 17th, 2024 (edited)
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.49 KB | None | 0 0
  1. local component = require("component")
  2. local event = require("event")
  3. local serialization = require("serialization")
  4. local computer = require("computer")
  5. local modem = component.modem
  6. local fs = require("filesystem")
  7.  
  8. -- Configuration
  9. local sg = component.stargate
  10. local valid_addresses = {}
  11. local range_to_process = nil
  12. local symbols = {}
  13. local processed_ranges = {} -- Table to store successfully processed ranges
  14. local worker_data_file = "/worker_name.json"
  15. local worker_name = nil
  16. local worker_port = nil
  17. local master_address = nil
  18. master_port = 1234
  19. debugoption = 0
  20. -- Function to send an error back to the master
  21. local function send_error(message, range, worker_name, valid_addresses, last_successful_index)
  22.     local processed_range = {
  23.         start = range.start,
  24.         finish = last_successful_index
  25.     }
  26.     local error_data = {
  27.         worker_id = worker_name,
  28.         valid_addresses = valid_addresses,
  29.         error = message,
  30.         processed_ranges = processed_range,  -- Send only the summarized processed range
  31.         gate_type = gate_type, -- Use the dynamic gate_type
  32.         port = worker_port
  33.     }
  34.     print("Sending processed_ranges:", serialization.serialize(processed_range))
  35.     modem.open(master_port)
  36.     modem.send(master_address, master_port, "error", serialization.serialize(error_data))
  37.     modem.close(master_port)
  38.     print("Worker:", worker_name, "sent error message to master:", message)
  39.     valid_addresses = {}
  40. end
  41. -- Function to recursively generate addresses and return the one at the desired index
  42. local function generate_address_at_index(target_index, symbols, address_length)
  43.     local current_index = 0   -- Counter to track progress
  44.     local result_address = nil  -- To store the target address
  45.  
  46.     -- Recursive function to generate addresses
  47.     local function generate(current_address, available_symbols, depth, used_symbols)
  48.         if result_address then return end  -- Stop recursion if we found the target
  49.  
  50.         -- Base case: full address generated
  51.         if depth > address_length then
  52.             current_index = current_index + 1  -- Increment the counter
  53.             if current_index == target_index then
  54.                 -- Target index reached; copy the current address
  55.                 result_address = {}
  56.                 for i = 1, address_length do
  57.                     table.insert(result_address, current_address[i])
  58.                 end
  59.             end
  60.             return
  61.         end
  62.  
  63.         -- Recursive case: iterate through all available symbols
  64.         for _, symbol in ipairs(available_symbols) do
  65.             if not used_symbols[symbol] then
  66.                 used_symbols[symbol] = true
  67.                 current_address[depth] = symbol
  68.  
  69.                 -- Recurse deeper
  70.                 generate(current_address, available_symbols, depth + 1, used_symbols)
  71.  
  72.                 -- Cleanup for the next iteration
  73.                 used_symbols[symbol] = nil
  74.                 current_address[depth] = nil
  75.             end
  76.         end
  77.     end
  78.  
  79.     -- Initialize recursion
  80.     local current_address = {}
  81.     local used_symbols = {}
  82.     generate(current_address, symbols, 1, used_symbols)
  83.  
  84.     -- Return the result
  85.     if result_address then
  86.         return result_address
  87.     else
  88.         error("Error: Target index exceeds total combinations.")
  89.     end
  90. end
  91.  
  92. -- Function to validate a Stargate address
  93. local function validate_address(address)
  94.     local success, result = pcall(function()
  95.         return sg.getEnergyRequiredToDial(address)
  96.     end)
  97.  
  98.     table.remove(address)  -- Remove Point of Origin after validation
  99.  
  100.     if not success then
  101.         return nil, "Disconnected from Stargate component"
  102.     end
  103.  
  104.     -- Check if the 'open' energy value exists and is greater than 0
  105.     if type(result) == "table" and result.open and result.open > 0 then
  106.         return true
  107.     end
  108.     return false
  109. end
  110.  
  111. -- Function to process a batch of addresses
  112. local function process_range(range, symbols, point_of_origin, address_length, worker_name)
  113.     local start = range.start
  114.     local finish = range.finish
  115.     print(worker_name, "processing range:", start, "-", finish)
  116.  
  117.     for index = start, finish do
  118.         local address = generate_address_at_index(index, symbols, address_length)
  119.         table.insert(address, point_of_origin)  -- Add the Point of Origin dynamically
  120.         if debugoption == 1 then
  121.             print(table.concat(address, ", "))
  122.         end
  123.         local is_valid, error_message = validate_address(address)
  124.        
  125.         if error_message then
  126.             print("Error:", error_message)
  127.             send_error("Disconnected from Stargate component", range, worker_name, valid_addresses, index - 1)
  128.             return false  -- Stop processing and signal error
  129.         end
  130.        
  131.         if is_valid then
  132.             table.insert(valid_addresses, address)
  133.         end    
  134.     end
  135.     return true
  136. end
  137.  
  138. -- Function to send results back to the master
  139. local function send_results(range, gate_type, worker_name)
  140.     local mac = computer.address()
  141.     local results = {
  142.         worker_id = worker_name,
  143.         valid_addresses = valid_addresses,
  144.         range = range,
  145.         gate_type = gate_type, -- Use the dynamic gate_type
  146.         mac = mac,
  147.         worker_port = worker_port
  148.     }
  149.     modem.open(master_port)
  150.     modem.send(master_address, master_port, "result", serialization.serialize(results))
  151.     modem.close(master_port)
  152.     print("Worker:", worker_name, "sent results for range:", range.start, "-", range.finish)
  153.     valid_addresses = {}  -- Reset valid addresses for the next batch
  154.     processed_ranges = {}
  155. end
  156. -- Notify the master that the worker is ready
  157. local function send_ready_message(worker_name, worker_port)
  158.     local mac = computer.address()
  159.     local ready_data = {
  160.         name = worker_name,
  161.         port = worker_port,
  162.         mac = mac
  163.     }
  164.     modem.open(master_port)
  165.     modem.send(master_address, master_port, "ready", serialization.serialize(ready_data))
  166.     modem.close(master_port)
  167.     print("Sent ready message to master:", worker_name, "| Port:", worker_port)
  168. end
  169. local function send_goodbye_message()
  170.     local goodbye_data = {
  171.         name = worker_name,
  172.         address = modem.address,        -- Add worker's network address
  173.         mac = computer.address()
  174.     }
  175.     modem.open(master_port)
  176.     modem.send(master_address, master_port, "goodbye", serialization.serialize(goodbye_data))
  177.     modem.close(master_port)
  178. end
  179. -- Save worker name and port
  180. local function save_worker_data(name, port, master_address)
  181.     local file = io.open(worker_data_file, "w")
  182.     if file then
  183.         file:write(serialization.serialize({ name = name, port = port, master_address = master_address }))
  184.         file:close()
  185.         print("Worker data saved:", name, port, master_address)
  186.     else
  187.         print("Error: Unable to save worker data.")
  188.     end
  189. end
  190. -- Request name and port from the master node
  191. local function request_worker_data()
  192.     print("Requesting name and port from master...")
  193.     local id = computer.address()
  194.     local modemid = modem.address
  195.     local data = { id = id, modemid = modemid }
  196.     modem.open(master_port)
  197.     modem.broadcast(master_port, "request_name_port", serialization.serialize(data))
  198.  
  199.     local master_address, assigned_name, assigned_port
  200.     while true do
  201.         local _, _, from, _, _, command, name, worker_port = event.pull("modem_message")
  202.         if command == "assigned_name_port" then
  203.             master_address = from  -- The master's address
  204.             assigned_name = name   -- The worker name
  205.             assigned_port = worker_port  -- The assigned port      
  206.             print("Name and port received from master:", name, assigned_port)
  207.             save_worker_data(name, assigned_port, master_address)
  208.             modem.close(master_port)
  209.             return name, assigned_port, master_address
  210.         elseif command == "error_name_port" then
  211.             master_address = from  -- The master's address
  212.             assigned_name = name
  213.             assigned_port = worker_port    
  214.             print("Error: Master reassigned existing name and port:", name, assigned_port)
  215.             save_worker_data(name, assigned_port, master_address)
  216.             modem.close(master_port)
  217.             return name, assigned_port, master_address
  218.         end
  219.     end
  220. end
  221. -- Load worker name if available
  222. local function load_worker_data()
  223.     if fs.exists(worker_data_file) then
  224.         local file = io.open(worker_data_file, "r")
  225.         local data = file:read("*all")
  226.         file:close()
  227.         local success, loaded_data = pcall(serialization.unserialize, data)
  228.         if success and loaded_data and loaded_data.name and loaded_data.port and loaded_data.master_address then
  229.             return loaded_data.name, loaded_data.port, loaded_data.master_address
  230.         end
  231.     end
  232.     return nil, nil, nil -- No valid data found
  233. end
  234.  
  235. -- Main worker loop
  236. local function main(worker_name, worker_port, master_address)
  237.     send_ready_message(worker_name, worker_port)
  238.     modem.open(worker_port)
  239.  
  240.     while true do
  241.         print(worker_name, "listening for tasks on port", worker_port)
  242.         local _, _, from, port, _, command, data = event.pull("modem_message")
  243.         if port == worker_port then  -- Ensure messages are received only on assigned port
  244.             if command == "task" then
  245.                 local task = serialization.unserialize(data)
  246.                 local task_worker_id = task.worker_id
  247.                 -- Validate the worker ID
  248.                 if task_worker_id ~= computer.address() then
  249.                     print("Mismatch in worker ID! Requesting new worker ID and port...")
  250.                     -- Send the range back to the master for reassignment
  251.                     modem.open(master_port)
  252.                     modem.send(from, master_port, "reassign_range", serialization.serialize({
  253.                     range = range_to_process,
  254.                     worker_id = worker_name
  255.                     }))
  256.                     modem.close(master_port)
  257.                     worker_name, worker_port, master_address = request_worker_data()
  258.                     modem.open(worker_port) -- Re-open the new port
  259.                     break -- Restart main loop after getting new ID and port
  260.                 end
  261.                 modem.open(master_port)
  262.                 modem.send(from, master_port, "ok", "")  -- Sending "ok" as message1, empty for message2
  263.                 print("Sent ok to:", from, master_port)
  264.                 modem.close(master_port)
  265.                 -- Process the task as normal
  266.                 range_to_process = task.range
  267.                 symbols = task.symbols
  268.                 address_length = task.address_length
  269.                 local gate_type = task.gate_type
  270.                 local point_of_origin = task.point_of_origin
  271.                 -- Process the assigned range
  272.                 local success = process_range(range_to_process, symbols, point_of_origin, address_length, worker_name)
  273.            
  274.                 if success then
  275.                     -- Send results back to the master node
  276.                     send_results(range_to_process, gate_type, worker_name)
  277.                     print ("Sent results to:", master_address, master_port)
  278.                 else
  279.                     print("Worker encountered an issue, halting execution.")
  280.                 end
  281.             elseif command == "shutdown" then
  282.                 send_goodbye_message()
  283.                 print(worker_name, "shutting down as instructed.")
  284.                 break
  285.             elseif command == "resync" then
  286.                 print("Master has old data, resyncing.")
  287.                 worker_name, worker_port, master_address = request_worker_data()
  288.                 send_ready_message(worker_name, worker_port)
  289.             end
  290.         end
  291.     end
  292. end
  293.  
  294.  
  295. -- Worker startup logic
  296. worker_name, worker_port, master_address = load_worker_data()
  297. if not worker_name or not worker_port or not master_address then
  298.     worker_name, worker_port, master_address = request_worker_data()
  299. end
  300.  
  301. print("Worker is ready. Name:", worker_name, "Port:", worker_port)
  302. -- Start the worker
  303. main(worker_name, worker_port, master_address)
  304.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement