Advertisement
osmarks

ARR Switch

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