Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local drone = component.proxy(component.list "drone"())
- local net = component.proxy(component.list "internet"())
- local wlan = component.proxy(component.list "modem"())
- local comp = component.proxy(component.list "computer"())
- wlan.setWakeMessage("poweron", true)
- local central_point = { x = 297, y = 80, z = 294 }
- local statuses = {
- loading = { text = "LOAD", color = 0x000000 },
- moving = { text = "GO", color = 0xFFFF00 },
- idle = { text = "IDLE", color = 0x00FFFF },
- error = { text = "ERROR", color = 0xFF0000 },
- low_battery = { text = "ELOW", 0xFF8800 }
- }
- local function set_status(status)
- local stat = statuses[status]
- drone.setLightColor(stat.color or 0xFFFFFF)
- drone.setStatusText((stat.text or status) .. (" "):rep(8))
- end
- set_status "loading"
- comp.beep(600, 1)
- local function energy()
- return computer.energy() / computer.maxEnergy()
- end
- local GPS_PING_CHANNEL, GPS_RESPONSE_CHANNEL, TIMEOUT = 2048, 2047, 1
- wlan.setStrength(math.huge)
- local function fetch(url)
- local res, err = net.request(url)
- if not res then error(url .. " error: " .. err) end
- local out = {}
- while true do
- local chunk, err = res.read()
- if err then error(url .. " error: " .. err) end
- if chunk then table.insert(out, chunk)
- else return table.concat(out) end
- end
- end
- local function round(v, m)
- m = m or 1.0
- return {
- x = math.floor((v.x+(m*0.5))/m)*m,
- y = math.floor((v.y+(m*0.5))/m)*m,
- z = math.floor((v.z+(m*0.5))/m)*m
- }
- end
- local function len(v)
- return math.sqrt(v.x^2 + v.y^2 + v.z^2)
- end
- local function cross(v, b)
- 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}
- end
- local function dot(v, b)
- return v.x*b.x + v.y*b.y + v.z*b.z
- end
- local function add(v, b)
- return {x = v.x+b.x, y = v.y+b.y, z = v.z+b.z}
- end
- local function sub(v, b)
- return {x = v.x-b.x, y = v.y-b.y, z = v.z-b.z}
- end
- local function mul(v, m)
- return {x = v.x*m, y = v.y*m, z = v.z*m}
- end
- local function norm(v)
- return mul(v, 1/len(v))
- end
- local function trilaterate(A, B, C)
- local a2b = {x = B.x-A.x, y = B.y-A.y, z = B.z-A.z}
- local a2c = {x = C.x-A.x, y = C.y-A.y, z = C.z-A.z}
- if math.abs(dot(norm(a2b), norm(a2c))) > 0.999 then
- return nil
- end
- local d = len(a2b)
- local ex = norm(a2b)
- local i = dot(ex, a2c)
- local ey = norm(sub(mul(ex, i), a2c))
- local j = dot(ey, a2c)
- local ez = cross(ex, ey)
- local r1 = A.d
- local r2 = B.d
- local r3 = C.d
- local x = (r1^2 - r2^2 + d^2) / (2*d)
- local y = (r1^2 - r3^2 - x^2 + (x-i)^2 + j^2) / (2*j)
- local result = add(A, add(mul(ex, x), mul(ey, y)))
- local zSquared = r1^2 - x^2 - y^2
- if zSquared > 0 then
- local z = math.sqrt(zSquared)
- local result1 = add(result, mul(ez, z))
- local result2 = add(result, mul(ez, z))
- local rounded1, rounded2 = round(result1, 0.01), round(result2, 0.01)
- if rounded1.x ~= rounded2.x or
- rounded1.y ~= rounded2.y or
- rounded1.z ~= rounded2.z then
- return rounded1, rounded2
- else
- return rounded1
- end
- end
- return round(result, 0.01)
- end
- local function narrow(p1, p2, fix)
- local dist1 = math.abs(len(sub(p1, fix)) - fix.d)
- local dist2 = math.abs(len(sub(p2, fix)) - fix.d)
- if math.abs(dist1 - dist2) < 0.01 then
- return p1, p2
- elseif dist1 < dist2 then
- return round(p1, 0.01)
- else
- return round(p2, 0.01)
- end
- end
- local function locate(timeout)
- local timeout = timeout or TIMEOUT
- wlan.open(GPS_RESPONSE_CHANNEL)
- wlan.broadcast(GPS_PING_CHANNEL, "PING")
- local fixes = {}
- local pos1, pos2 = nil, nil
- local deadline = computer.uptime() + timeout
- local dim
- repeat
- local event, _, from, port, distance, x, y, z, dimension = computer.pullSignal(deadline - computer.uptime())
- if event == "modem_message" and port == GPS_RESPONSE_CHANNEL and x and y and z then
- if type(dim) == "string" then dim = dimension end
- local fix = {x = x, y = y, z = z, d = distance}
- if fix.d == 0 then
- pos1, pos2 = {fix.x, fix.y, fix.z}, nil
- else
- table.insert(fixes, fix)
- if #fixes >= 3 then
- if not pos1 then
- pos1, pos2 = trilaterate(fixes[1], fixes[2], fixes[#fixes])
- else
- pos1, pos2 = narrow(pos1, pos2, fixes[#fixes])
- end
- end
- end
- if pos1 and not pos2 then
- break
- end
- end
- until computer.uptime() >= deadline
- wlan.close(GPS_RESPONSE_CHANNEL)
- if pos1 and pos2 then
- return nil
- elseif pos1 then
- return pos1, dim
- else
- return nil
- end
- end
- 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
- local function sleep(timeout)
- local deadline = computer.uptime() + (timeout or 0)
- repeat
- computer.pullSignal(deadline - computer.uptime())
- until computer.uptime() >= deadline
- end
- local function moveraw(x, y, z)
- set_status "moving"
- drone.move(x, y, z)
- repeat
- sleep(0.5)
- until drone.getVelocity() < 0.1
- set_status "idle"
- end
- local function move(pos)
- moveraw(0, 32, 0)
- moveraw(pos.x, pos.y, pos.z)
- moveraw(0, -32, 0)
- end
- local function follow(currpos)
- local data = json_decode(fetch "https://dynmap.codersnet.pw/up/world/world/1588704574112")
- local possibles = {}
- for _, p in pairs(data.players) do
- local plrpos = { x = p.x, y = p.y, z = p.z }
- local dist = len(sub(plrpos, central_point))
- if dist < 100 and p.world == "world" then
- table.insert(possibles, plrpos)
- end
- end
- if #possibles == 0 then return false, "TNF" end
- local targpos = possibles[math.random(1, #possibles)]
- local offset = sub(targpos, currpos)
- comp.beep(400, 0.5)
- move(offset)
- return true
- end
- while true do
- set_status "idle"
- local currpos = locate()
- if currpos then
- wlan.broadcast(1033, drone.name(), "LOC", currpos.x, currpos.y, currpos.z)
- local offset_from_hub = sub(central_point, currpos)
- if len(offset_from_hub) then
- move(offset_from_hub)
- else
- local ok, err = follow(currpos)
- if not ok then set_status "error" drone.setStatusText("E" .. err) sleep(10) end
- sleep(1)
- end
- end
- if energy() < 0.3 then
- wlan.broadcast(1033, drone.name(), "LOW")
- comp.beep(2000, 1.5)
- status "low_battery"
- move(sub(central_point, locate()))
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement