Advertisement
osmarks

Drone OS Thing

May 26th, 2020
1,399
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.33 KB | None | 0 0
  1. local drone = component.proxy(component.list "drone"())
  2. local net = component.proxy(component.list "internet"())
  3. local wlan = component.proxy(component.list "modem"())
  4. local comp = component.proxy(component.list "computer"())
  5. wlan.setWakeMessage("poweron", true)
  6.  
  7. local central_point = { x = 297, y = 80, z = 294 }
  8.  
  9. local statuses = {
  10.     loading = { text = "LOAD", color = 0x000000 },
  11.     moving = { text = "GO", color = 0xFFFF00 },
  12.     idle = { text = "IDLE", color = 0x00FFFF },
  13.     error = { text = "ERROR", color = 0xFF0000 },
  14.     low_battery = { text = "ELOW", 0xFF8800 }
  15. }
  16.  
  17. local function set_status(status)
  18.     local stat = statuses[status]
  19.     drone.setLightColor(stat.color or 0xFFFFFF)
  20.     drone.setStatusText((stat.text or status) .. (" "):rep(8))
  21. end
  22.  
  23. set_status "loading"
  24. comp.beep(600, 1)
  25.  
  26. local function energy()
  27.     return computer.energy() / computer.maxEnergy()
  28. end
  29.  
  30. local GPS_PING_CHANNEL, GPS_RESPONSE_CHANNEL, TIMEOUT = 2048, 2047, 1
  31.  
  32. wlan.setStrength(math.huge)
  33.  
  34. local function fetch(url)
  35.     local res, err = net.request(url)
  36.     if not res then error(url .. " error: " .. err) end
  37.     local out = {}
  38.     while true do
  39.         local chunk, err = res.read()
  40.         if err then error(url .. " error: " .. err) end
  41.         if chunk then table.insert(out, chunk)
  42.         else return table.concat(out) end
  43.     end
  44. end
  45.  
  46. local function round(v, m)
  47.     m = m or 1.0
  48.     return {
  49.         x = math.floor((v.x+(m*0.5))/m)*m,
  50.         y = math.floor((v.y+(m*0.5))/m)*m,
  51.         z = math.floor((v.z+(m*0.5))/m)*m
  52.     }
  53. end
  54.  
  55. local function len(v)
  56.     return math.sqrt(v.x^2 + v.y^2 + v.z^2)
  57. end
  58.  
  59. local function cross(v, b)
  60.     return {x = v.y*b.z-v.z*b.y, y = v.z*b.x-v.x*b.z, z = v.x*b.y-v.y*b.x}
  61. end
  62.  
  63. local function dot(v, b)
  64.     return v.x*b.x + v.y*b.y + v.z*b.z
  65. end
  66.  
  67. local function add(v, b)
  68.     return {x = v.x+b.x, y = v.y+b.y, z = v.z+b.z}
  69. end
  70.  
  71. local function sub(v, b)
  72.     return {x = v.x-b.x, y = v.y-b.y, z = v.z-b.z}
  73. end
  74.  
  75. local function mul(v, m)
  76.     return {x = v.x*m, y = v.y*m, z = v.z*m}
  77. end
  78.  
  79. local function norm(v)
  80.     return mul(v, 1/len(v))
  81. end
  82.  
  83. local function trilaterate(A, B, C)
  84.     local a2b = {x = B.x-A.x, y = B.y-A.y, z = B.z-A.z}
  85.     local a2c = {x = C.x-A.x, y = C.y-A.y, z = C.z-A.z}
  86.     if math.abs(dot(norm(a2b), norm(a2c))) > 0.999 then
  87.         return nil
  88.     end
  89.     local d = len(a2b)
  90.     local ex = norm(a2b)
  91.     local i = dot(ex, a2c)
  92.     local ey = norm(sub(mul(ex, i), a2c))
  93.     local j = dot(ey, a2c)
  94.     local ez = cross(ex, ey)
  95.     local r1 = A.d
  96.     local r2 = B.d
  97.     local r3 = C.d
  98.     local x = (r1^2 - r2^2 + d^2) / (2*d)
  99.     local y = (r1^2 - r3^2 - x^2 + (x-i)^2 + j^2) / (2*j)
  100.     local result = add(A, add(mul(ex, x), mul(ey, y)))
  101.     local zSquared = r1^2 - x^2 - y^2
  102.     if zSquared > 0 then
  103.         local z = math.sqrt(zSquared)
  104.         local result1 = add(result, mul(ez, z))
  105.         local result2 = add(result, mul(ez, z))
  106.         local rounded1, rounded2 = round(result1, 0.01), round(result2, 0.01)
  107.         if rounded1.x ~= rounded2.x or
  108.              rounded1.y ~= rounded2.y or
  109.              rounded1.z ~= rounded2.z then
  110.             return rounded1, rounded2
  111.         else
  112.             return rounded1
  113.         end
  114.     end
  115.     return round(result, 0.01)
  116. end
  117.  
  118. local function narrow(p1, p2, fix)
  119.     local dist1 = math.abs(len(sub(p1, fix)) - fix.d)
  120.     local dist2 = math.abs(len(sub(p2, fix)) - fix.d)
  121.     if math.abs(dist1 - dist2) < 0.01 then
  122.         return p1, p2
  123.     elseif dist1 < dist2 then
  124.         return round(p1, 0.01)
  125.     else
  126.         return round(p2, 0.01)
  127.     end
  128. end
  129.  
  130. local function locate(timeout)
  131.     local timeout = timeout or TIMEOUT
  132.     wlan.open(GPS_RESPONSE_CHANNEL)
  133.     wlan.broadcast(GPS_PING_CHANNEL, "PING")
  134.     local fixes = {}
  135.     local pos1, pos2 = nil, nil
  136.     local deadline = computer.uptime() + timeout
  137.     local dim
  138.     repeat
  139.         local event, _, from, port, distance, x, y, z, dimension = computer.pullSignal(deadline - computer.uptime())
  140.         if event == "modem_message" and port == GPS_RESPONSE_CHANNEL and x and y and z then
  141.             if type(dim) == "string" then dim = dimension end
  142.             local fix = {x = x, y = y, z = z, d = distance}
  143.             if fix.d == 0 then
  144.                 pos1, pos2 = {fix.x, fix.y, fix.z}, nil
  145.             else
  146.                 table.insert(fixes, fix)
  147.                 if #fixes >= 3 then
  148.                     if not pos1 then
  149.                         pos1, pos2 = trilaterate(fixes[1], fixes[2], fixes[#fixes])
  150.                     else
  151.                         pos1, pos2 = narrow(pos1, pos2, fixes[#fixes])
  152.                     end
  153.                 end            
  154.             end
  155.             if pos1 and not pos2 then
  156.                 break
  157.             end
  158.         end
  159.     until computer.uptime() >= deadline
  160.     wlan.close(GPS_RESPONSE_CHANNEL)
  161.     if pos1 and pos2 then
  162.         return nil
  163.     elseif pos1 then
  164.         return pos1, dim
  165.     else
  166.         return nil
  167.     end
  168. end
  169.  
  170. local a={["\\"]="\\\\",["\""]="\\\"",["\b"]="\\b",["\f"]="\\f",["\n"]="\\n",["\r"]="\\r",["\t"]="\\t"}local b={["\\/"]="/"}for c,d in pairs(a)do b[d]=c end;local e;local function f(...)local g={}for h=1,select("#",...)do g[select(h,...)]=true end;return g end;local i=f(" ","\t","\r","\n")local j=f(" ","\t","\r","\n","]","}",",")local k=f("\\","/",'"',"b","f","n","r","t","u")local l=f("true","false","null")local m={["true"]=true,["false"]=false,["null"]=nil}local function n(o,p,q,r)for h=p,#o do if q[o:sub(h,h)]~=r then return h end end;return#o+1 end;local function s(o,p,t)local u=1;local v=1;for h=1,p-1 do v=v+1;if o:sub(h,h)=="\n"then u=u+1;v=1 end end;error(string.format("%s at line %d col %d",t,u,v))end;local function w(x)local y=math.floor;if x<=0x7f then return string.char(x)elseif x<=0x7ff then return string.char(y(x/64)+192,x%64+128)elseif x<=0xffff then return string.char(y(x/4096)+224,y(x%4096/64)+128,x%64+128)elseif x<=0x10ffff then return string.char(y(x/262144)+240,y(x%262144/4096)+128,y(x%4096/64)+128,x%64+128)end;error(string.format("invalid unicode codepoint '%x'",x))end;local function z(A)local B=tonumber(A:sub(3,6),16)local C=tonumber(A:sub(9,12),16)if C then return w((B-0xd800)*0x400+C-0xdc00+0x10000)else return w(B)end end;local function D(o,h)local E=false;local F=false;local G=false;local H;for I=h+1,#o do local J=o:byte(I)if J<32 then s(o,I,"control character in string")end;if H==92 then if J==117 then local K=o:sub(I+1,I+5)if not K:find("%x%x%x%x")then s(o,I,"invalid unicode escape in string")end;if K:find("^[dD][89aAbB]")then F=true else E=true end else local L=string.char(J)if not k[L]then s(o,I,"invalid escape char '"..L.."' in string")end;G=true end;H=nil elseif J==34 then local A=o:sub(h+1,I-1)if F then A=A:gsub("\\u[dD][89aAbB]..\\u....",z)end;if E then A=A:gsub("\\u....",z)end;if G then A=A:gsub("\\.",b)end;return A,I+1 else H=J end end;s(o,h,"expected closing quote for string")end;local function M(o,h)local J=n(o,h,j)local A=o:sub(h,J-1)local x=tonumber(A)if not x then s(o,h,"invalid number '"..A.."'")end;return x,J end;local function N(o,h)local J=n(o,h,j)local O=o:sub(h,J-1)if not l[O]then s(o,h,"invalid literal '"..O.."'")end;return m[O],J end;local function P(o,h)local g={}local x=1;h=h+1;while 1 do local J;h=n(o,h,i,true)if o:sub(h,h)=="]"then h=h+1;break end;J,h=e(o,h)g[x]=J;x=x+1;h=n(o,h,i,true)local Q=o:sub(h,h)h=h+1;if Q=="]"then break end;if Q~=","then s(o,h,"expected ']' or ','")end end;return g,h end;local function R(o,h)local g={}h=h+1;while 1 do local S,T;h=n(o,h,i,true)if o:sub(h,h)=="}"then h=h+1;break end;if o:sub(h,h)~='"'then s(o,h,"expected string for key")end;S,h=e(o,h)h=n(o,h,i,true)if o:sub(h,h)~=":"then s(o,h,"expected ':' after key")end;h=n(o,h+1,i,true)T,h=e(o,h)g[S]=T;h=n(o,h,i,true)local Q=o:sub(h,h)h=h+1;if Q=="}"then break end;if Q~=","then s(o,h,"expected '}' or ','")end end;return g,h end;local U={['"']=D,["0"]=M,["1"]=M,["2"]=M,["3"]=M,["4"]=M,["5"]=M,["6"]=M,["7"]=M,["8"]=M,["9"]=M,["-"]=M,["t"]=N,["f"]=N,["n"]=N,["["]=P,["{"]=R}e=function(o,p)local Q=o:sub(p,p)local y=U[Q]if y then return y(o,p)end;s(o,p,"unexpected character '"..Q.."'")end;local function json_decode(o)if type(o)~="string"then error("expected argument of type string, got "..type(o))end;local g,p=e(o,n(o,1,i,true))p=n(o,p,i,true)if p<=#o then s(o,p,"trailing garbage")end;return g end
  171.  
  172. local function sleep(timeout)
  173.     local deadline = computer.uptime() + (timeout or 0)
  174.     repeat
  175.         computer.pullSignal(deadline - computer.uptime())
  176.     until computer.uptime() >= deadline
  177. end
  178.  
  179. local function moveraw(x, y, z)
  180.     set_status "moving"
  181.     drone.move(x, y, z)
  182.     repeat
  183.         sleep(0.5)
  184.     until drone.getVelocity() < 0.1
  185.     set_status "idle"
  186. end
  187.  
  188. local function move(pos)
  189.     moveraw(0, 32, 0)
  190.     moveraw(pos.x, pos.y, pos.z)
  191.     moveraw(0, -32, 0)
  192. end
  193.  
  194. local function follow(currpos)
  195.     local data = json_decode(fetch "https://dynmap.codersnet.pw/up/world/world/1588704574112")
  196.     local possibles = {}
  197.     for _, p in pairs(data.players) do
  198.         local plrpos = { x = p.x, y = p.y, z = p.z }
  199.         local dist = len(sub(plrpos, central_point))
  200.         if dist < 100 and p.world == "world" then
  201.             table.insert(possibles, plrpos)
  202.         end
  203.     end
  204.     if #possibles == 0 then return false, "TNF" end
  205.     local targpos = possibles[math.random(1, #possibles)]
  206.     local offset = sub(targpos, currpos)
  207.     comp.beep(400, 0.5)
  208.     move(offset)
  209.     return true
  210. end
  211.  
  212. while true do
  213.     set_status "idle"
  214.     local currpos = locate()
  215.     if currpos then
  216.         wlan.broadcast(1033, drone.name(), "LOC", currpos.x, currpos.y, currpos.z)
  217.         local offset_from_hub = sub(central_point, currpos)
  218.         if len(offset_from_hub) then
  219.             move(offset_from_hub)
  220.         else
  221.             local ok, err = follow(currpos)
  222.             if not ok then set_status "error" drone.setStatusText("E" .. err) sleep(10) end
  223.             sleep(1)
  224.         end
  225.     end
  226.     if energy() < 0.3 then
  227.         wlan.broadcast(1033, drone.name(), "LOW")
  228.         comp.beep(2000, 1.5)
  229.         status "low_battery"
  230.         move(sub(central_point, locate()))
  231.     end
  232. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement