Advertisement
HandieAndy

switcher.lua

Sep 7th, 2023 (edited)
973
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.13 KB | None | 0 0
  1. --[[
  2. This program is to be installed on a computer that controls a single rail
  3. junction. As a player with a portable computer approaches, that portable
  4. computer will be sending out a signal containing their route, and this switch
  5. will decode it and make any adjustments it needs to.
  6. ]]--
  7.  
  8. local CONFIG_FILE = "switch_config.tbl"
  9. local CHANNEL = 45450
  10. local config = nil
  11.  
  12. local modem = peripheral.wrap("top") or error("Missing top modem")
  13. if not modem.isWireless() then error("Wireless modem required") end
  14. modem.open(CHANNEL)
  15.  
  16. term.clear()
  17. term.setCursorPos(1, 1)
  18. print("Receiving routing commands on channel " .. CHANNEL)
  19.  
  20. -- Series of guided inputs for building a configuration file from user input.
  21. local function configSetupWizard()
  22.     local cfg = {range = 32, switches = {}}
  23.     term.clear()
  24.     term.setCursorPos(1, 1)
  25.     print("Switch Controller Config Setup Wizard")
  26.     print("-------------------------------------")
  27.     print("What range (blocks) does this switch have? Defaults to 32.")
  28.     local rangeStr = io.read()
  29.     if rangeStr then
  30.         local rangeInt = tonumber(rangeStr)
  31.         if rangeInt == nil or rangeInt < 1 or rangeInt > 128 then
  32.             print("Invalid range value. Should be a positive integer number. Got "..rangeStr)
  33.             return nil
  34.         end
  35.         cfg.range = rangeInt
  36.     end
  37.     print("How many switch configurations are there? Usually 1 for each possible path of travel.")
  38.     local switchCountStr = io.read()
  39.     if not switchCountStr then
  40.         print("Invalid switch configuration count.")
  41.         return nil
  42.     end
  43.     local switchCount = tonumber(switchCountStr)
  44.     if switchCount == nil or switchCount < 2 or switchCount > 32 then
  45.         print("Invalid switch configuration count. Expected a positive integer between 2 and 32.")
  46.         return nil
  47.     end
  48.     for i = 1, switchCount do
  49.         local sw = {from = nil, to = nil, controls = {}}
  50.         print("Switch Configuration #"..i..":")
  51.         print("What is name of the branch traffic comes from?")
  52.         sw.from = io.read()
  53.         print("What is the name of the branch traffic goes to?")
  54.         sw.to = io.read()
  55.         print("How many control points are needed for this switch configuration?")
  56.         local controlCountStr = io.read()
  57.         local controlCount = 0
  58.         if controlCountStr then controlCount = tonumber(controlCountStr) end
  59.         if not controlCount or controlCount < 1 then
  60.             print("Invalid control point count. Expected a positive integer.")
  61.             return nil
  62.         end
  63.         for c = 1, controlCount do
  64.             local ctl = {type = "redstone", side = "top", state = true}
  65.             print("  Control Point #"..c..":")
  66.             print("  What type of control is this?")
  67.             print("  1. redstone")
  68.             print("  2. redstoneIntegrator")
  69.             local typeStr = io.read()
  70.             if not typeStr or typeStr == "1" or typeStr == "redstone" then
  71.                 ctl.type = "redstone"
  72.                 print("  What side is redstone output on?")
  73.                 ctl.side = io.read()
  74.                 print("  What state should the output be? [T/F]")
  75.                 local stateStr = io.read()
  76.                 ctl.state = stateStr == "T" or stateStr == "True" or stateStr == "t" or stateStr == "true"
  77.             elseif typeStr == "2" or typeStr == "redstoneIntegrator" then
  78.                 ctl.type = "redstoneIntegrator"
  79.                 print("  What is the peripheral name?")
  80.                 ctl.name = io.read()
  81.                 print("  What side is output on?")
  82.                 ctl.side = io.read()
  83.                 print("  What state should the output be? [T/F]")
  84.                 local stateStr = io.read()
  85.                 ctl.state = stateStr == "T" or stateStr == "True" or stateStr == "t" or stateStr == "true"
  86.             else
  87.                 print("  Unsupported control type.")
  88.                 return nil
  89.             end
  90.             table.insert(sw.controls, ctl)
  91.         end
  92.         table.insert(cfg.switches, sw)
  93.     end
  94.     local f = io.open(CONFIG_FILE, "w")
  95.     f:write(textutils.serialize(cfg))
  96.     f:close()
  97.     return cfg
  98. end
  99.  
  100. local function loadConfig()
  101.     if fs.exists(CONFIG_FILE) then
  102.         local f = io.open(CONFIG_FILE, "r")
  103.         local cfg = textutils.unserialize(f:read("*a"))
  104.         f:close()
  105.         print("Loaded configuration from file:")
  106.         print("  "..tostring(#cfg.switches).." switch configurations.")
  107.         print("  "..tostring(cfg.range).." block range.")
  108.         return cfg
  109.     else
  110.         print("File "..CONFIG_FILE.." doesn't exist. Start setup wizard? [y/n]")
  111.         local response = io.read()
  112.         if response == "y" or response == "Y" or response == "yes" then
  113.             return configSetupWizard()
  114.         else
  115.             return nil
  116.         end
  117.     end
  118. end
  119.  
  120. local function findSwitchConfiguration(cfg, from, to)
  121.     if from == nil or to == nil then return nil end
  122.     for _, sw in pairs(cfg.switches) do
  123.         if sw.from == from and sw.to == to then return sw end
  124.     end
  125.     return nil
  126. end
  127.  
  128. local function isSwitchConfigurationActive(sw)
  129.     for _, control in pairs(sw.controls) do
  130.         if control.type == "redstone" then
  131.             local state = redstone.getOutput(control.side)
  132.             if state ~= control.state then return false end
  133.         elseif control.type == "redstoneIntegrator" then
  134.             local state = peripheral.call(control.name, "getOutput", control.side)
  135.             if state ~= control.state then return false end
  136.         else
  137.             error("Invalid control type: "..control.type)
  138.         end
  139.     end
  140.     return true
  141. end
  142.  
  143. local function activateSwitchConfiguration(sw)
  144.     print("Activating switch: FROM="..sw.from..", TO="..sw.to)
  145.     for _, control in pairs(sw.controls) do
  146.         if control.type == "redstone" then
  147.             redstone.setOutput(control.side, control.state)
  148.         elseif control.type == "redstoneIntegrator" then
  149.             peripheral.call(control.name, "setOutput", control.side, control.state)
  150.         else
  151.             error("Invalid control type: "..control.type)
  152.         end
  153.     end
  154. end
  155.  
  156. -- Handles incoming rail messages that consist of a list of branch names
  157. -- that the user would like to traverse.
  158. local function handleModemMsg(replyChannel, msg)
  159.     -- Ignore invalid messages.
  160.     if not msg or #msg < 2 then return end
  161.     -- Find the switch configuration(s) that pertain to this route.
  162.     for i = 1, #msg - 1 do
  163.         local sw = findSwitchConfiguration(config, msg[i], msg[i+1])
  164.         if sw and not isSwitchConfigurationActive(sw) then
  165.             activateSwitchConfiguration(sw)
  166.         end
  167.     end
  168. end
  169.  
  170. config = loadConfig()
  171. if not config then
  172.     print("Unable to load configuration. Exiting.")
  173.     return
  174. end
  175.  
  176. while true do
  177.     local event, p1, p2, p3, p4, p5 = os.pullEvent()
  178.     if event == "modem_message" then
  179.         local channel = p2
  180.         local replyChannel = p3
  181.         local msg = p4
  182.         local dist = p5
  183.         if channel == CHANNEL and dist ~= nil and dist < config.range and msg ~= nil then
  184.             handleModemMsg(replyChannel, msg)
  185.         end
  186.     end
  187. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement