osmarks

ARR Switch

Feb 27th, 2022 (edited)
731
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.10 KB | None | 0 0
  1. local monitor = peripheral.find "monitor"
  2.  
  3. local function set_color(c)
  4.     monitor.setBackgroundColor(c)
  5.     monitor.clear()
  6. end
  7.  
  8. set_color(colors.lime)
  9. local sensor = peripheral.find "plethora:sensor"
  10. local label = os.getComputerLabel()
  11. local switch_config = dofile "config.lua"
  12.  
  13. local function spudnet()
  14.     if not http or not http.websocket then return "Websockets do not actually exist on this platform" end
  15.  
  16.     local ws
  17.  
  18.     local function send_packet(msg)
  19.         local ok, err = pcall(ws.send, textutils.serialiseJSON(msg))
  20.         if not ok then printError(err) try_connect_loop() end
  21.     end
  22.  
  23.     local function send(data)
  24.         send_packet { type = "send", channel = "comm:arr", data = data }
  25.     end
  26.  
  27.     local function connect()
  28.         if ws then ws.close() end
  29.         ws, err = http.websocket "wss://spudnet.osmarks.net/v4?enc=json"
  30.         if not ws then print("websocket failure %s", err) return false end
  31.         ws.url = "wss://spudnet.osmarks.net/v4?enc=json"
  32.  
  33.         send_packet { type = "identify", implementation = "ARR switching unit", key = settings.get "spudnet_key" }
  34.         send_packet { type = "set_channels", channels = { "comm:arr" } }
  35.  
  36.         print("websocket connected")
  37.  
  38.         return true
  39.     end
  40.  
  41.     local function try_connect_loop()
  42.         while not connect() do
  43.             sleep(0.5)
  44.         end
  45.     end
  46.  
  47.     try_connect_loop()
  48.  
  49.     local function recv()
  50.         while true do
  51.             local e, u, x = os.pullEvent "websocket_message"
  52.             if u == ws.url then return textutils.unserialiseJSON(x) end
  53.         end
  54.     end
  55.  
  56.     local ping_timeout_timer = nil
  57.  
  58.     local function ping_timer()
  59.         while true do
  60.             local _, t = os.pullEvent "timer"
  61.             if t == ping_timeout_timer and ping_timeout_timer then
  62.                 -- 15 seconds since last ping, we probably got disconnected
  63.                 print "SPUDNET timed out, attempting reconnect"
  64.                 try_connect_loop()
  65.             end
  66.         end
  67.     end
  68.  
  69.     local function main()
  70.         while true do
  71.             local packet = recv()
  72.             if packet.type == "ping" then
  73.                 send_packet { type = "pong", seq = packet.seq }
  74.                 if ping_timeout_timer then os.cancelTimer(ping_timeout_timer) end
  75.                 ping_timeout_timer = os.startTimer(15)
  76.             elseif packet.type == "error" then
  77.                 print("SPUDNET error", packet["for"], packet.error, packet.detail, textutils.serialise(packet))
  78.             elseif packet.type == "message" then
  79.                 os.queueEvent("spudnet_message", packet.data)
  80.             end
  81.         end
  82.     end
  83.  
  84.     return send, function() parallel.waitForAll(ping_timer, main) end
  85. end
  86.  
  87. local spudnet_send, spudnet_handler = spudnet()
  88.  
  89. local directions = {
  90.     ["+ "] = "east",
  91.     [" +"] = "south",
  92.     ["- "] = "west",
  93.     [" -"] = "north"
  94. }
  95.  
  96. local function direction_name(vec)
  97.     local function symbol(v)
  98.         if math.abs(v) < 0.1 then return " "
  99.         elseif v < 0 then return "-"
  100.         else return "+" end
  101.     end
  102.     return directions[symbol(vec.x) .. symbol(vec.z)]
  103. end
  104.  
  105. local function main()
  106.     while true do
  107.         local entities = sensor.sense()
  108.         for _, entity in pairs(entities) do
  109.             entity.position = vector.new(entity.x, entity.y, entity.z) + switch_config.offset
  110.             entity.velocity = vector.new(entity.motionX, entity.motionY, entity.motionZ)
  111.         end
  112.         table.sort(entities, function(a, b) return a.position:length() < b.position:length() end)
  113.         local carts = {}
  114.         for _, entity in pairs(entities) do
  115.             if entity.displayName == "entity.MinecartRideable.name" then
  116.                 entity.riders = {}
  117.                 table.insert(carts, entity)
  118.                 break
  119.             end
  120.         end
  121.         local new_carts = {}
  122.         local relevant_carts = 0
  123.         for _, cart in pairs(carts) do
  124.             local new = {
  125.                 pos = direction_name(cart.position), dir = direction_name(cart.velocity),
  126.                 distance = cart.position:length(),
  127.                 riders = {},
  128.                 id = cart.id
  129.             }
  130.             for _, entity in pairs(entities) do
  131.                 if entity.displayName ~= "entity.MinecartRideable.name" and entity ~= cart and (cart.position - entity.position):length() < 1 then
  132.                         table.insert(new.riders, entity.displayName)
  133.                     break
  134.                 end
  135.             end
  136.             if new.dir and #new.riders > 0 then
  137.                 relevant_carts = relevant_carts + 1
  138.             end
  139.             table.insert(new_carts, new)
  140.         end
  141.         spudnet_send { id = label, type = "sw_ping", carts = new_carts }
  142.         if relevant_carts == 0 then sleep(0.5) elseif relevant_carts == 1 then sleep(0.25) else sleep(0.1) end
  143.     end
  144. end
  145.  
  146. local function spudnet_listen()
  147.     while true do
  148.         local _, data = os.pullEvent "spudnet_message"
  149.         if type(data) == "table" and data.type == "sw_cmd" and (data.id == label or data.id == nil) then
  150.             --print(data.type, data.cmd)
  151.             if data.cmd == "set" then
  152.                 print("set", data.switch)
  153.                 if data.lamp then set_color(colors[data.lamp]) end
  154.                 if data.switch ~= nil then rs.setOutput(switch_config.side, data.switch) end
  155.                 spudnet_send { type = "sw_ack", cid = data.cid }
  156.             elseif data.cmd == "update" then
  157.                 local h, e = http.get "https://pastebin.com/raw/g9gfxwsb"
  158.                 if not h then printError(e)
  159.                 else
  160.                     set_color(colors.purple)
  161.                     local t = h.readAll()
  162.                     h.close()
  163.                     local f, e = load(t)
  164.                     if f then
  165.                         local f = fs.open("startup", "w")
  166.                         f.write(t)
  167.                         f.close()
  168.                         print "reboot"
  169.                         sleep(1)
  170.                         os.reboot()
  171.                     else printError(e) end
  172.  
  173.                 end
  174.             end
  175.         end
  176.     end
  177. end
  178.  
  179. parallel.waitForAll(spudnet_handler, main, spudnet_listen)
  180.  
Advertisement
Add Comment
Please, Sign In to add comment