gknova61

GPS Tower

Nov 26th, 2012
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.89 KB | None | 0 0
  1. --Originally by MysticT
  2. --TODO: Implement HTTP Publishing total amount of GPS Requests served
  3.  
  4. local tLocations = {}
  5. local tKnownLocations = {}
  6. local bDebug = false
  7.  
  8. local function printUsage()
  9.     local sName = fs.getName(shell.getRunningProgram())
  10.     print("Usage:")
  11.     print(sName, " receive [debug]")
  12.     print(sName, " host id x y z")
  13.     return false
  14. end
  15.  
  16. --Download config API
  17. local function pastebinGet(code,path)
  18.     local sCode = code
  19.     local sFile = path
  20.     local sPath = shell.resolve( sFile )
  21.     if fs.exists( sPath ) then
  22.         fs.delete(sPath)
  23.     end
  24.  
  25.     local response = http.get(
  26.         "http://pastebin.com/raw.php?i="..textutils.urlEncode( sCode )
  27.         )
  28.        
  29.     if response then
  30.         local sResponse = response.readAll()
  31.         response.close()
  32.        
  33.         local file = fs.open( sPath, "w" )
  34.         file.write( sResponse )
  35.         file.close()
  36.                 return true
  37.        
  38.     else
  39.         return false
  40.     end
  41. end
  42.  
  43. if not http then
  44.     print( "GPS requires the HTTP API" )
  45.     print( "Set enableAPI_http to 1 in mod_ComputerCraft.cfg" )
  46.     return false
  47. end
  48.  
  49. if not fs.exists("archiveAPI") then
  50.     fs.makeDir("archiveAPI")
  51. end
  52.  
  53. fs.delete("archiveAPI/config")
  54. fs.delete("archiveAPI/gbang")
  55.  
  56. if not fs.exists("archiveAPI/config") then
  57.     if pastebinGet("fkcMT9CE","archiveAPI/config") then
  58.     else
  59.         print("Something went wrong! No response!")
  60.         return false
  61.     end
  62. end
  63.  
  64. if not fs.exists("archiveAPI/gbang") then
  65.     if pastebinGet("MT2FLYq0","archiveAPI/gbang") then
  66.     else
  67.         print("Something went wrong! No response!")
  68.         return false
  69.     end
  70. end
  71.  
  72. -- Helper functions
  73.  
  74. local function clear()
  75.     term.clear()
  76.     term.setCursorPos(1, 1)
  77. end
  78.  
  79. local function table_size(t)
  80.     local i = 0
  81.     for _,_ in pairs(t) do
  82.         i = i + 1
  83.     end
  84.     return i
  85. end
  86.  
  87. local function connect()
  88.     for _,s in ipairs(rs.getSides()) do
  89.         if peripheral.isPresent(s) and peripheral.getType(s) == "modem" then
  90.             rednet.open(s)
  91.             return true
  92.         end
  93.     end
  94.     print("No modem attached")
  95.     return false
  96. end
  97.  
  98. local function _print(...)
  99.     if bDebug then
  100.         print(...)
  101.     end
  102. end
  103.  
  104. local function vector_equal(v1, v2)
  105.     return v1.x == v2.x and v1.y == v2.y and v1.z == v2.z
  106. end
  107.  
  108. -- Load/Save functions
  109.  
  110. local function save()
  111.     _print("Saving locations...")
  112.     local file = fs.open("locations.dat", "w")
  113.     if file then
  114.         for id, loc in pairs(tKnownLocations) do
  115.             file.writeLine(tostring(id)..": "..tostring(loc.x)..", "..tostring(loc.y)..", "..tostring(loc.z))
  116.         end
  117.         file.close()
  118.         _print("Locations saved")
  119.         return true
  120.     end
  121.     _print("Error saving locations")
  122.     return false
  123. end
  124.  
  125. local function load()
  126.     _print("Loading locations")
  127.     local file = fs.open("locations.dat", "r")
  128.     if file then
  129.         local i = 0
  130.         local sLine = file.readLine()
  131.         while sLine do
  132.             local sId, sX, sY, sZ = string.match(sLine, "(%d+): (%-?%d+), (%-?%d+), (%-?%d+)")
  133.             local id, x, y, z = tonumber(sId), tonumber(sX), tonumber(sY), tonumber(sZ)
  134.             if id and x and y and z then
  135.                 tKnownLocations[id] = vector.new(x, y, z)
  136.                 i = i + 1
  137.             end
  138.             sLine = file.readLine()
  139.         end
  140.         file.close()
  141.         _print(n, " locations loaded")
  142.         return true, i
  143.     end
  144.     _print("Error loading locations")
  145.     return false
  146. end
  147.  
  148. -- Location functions
  149.  
  150. local function trilaterate(A, B, C)
  151.     local a2b = B.position - A.position
  152.     local a2c = C.position - A.position
  153.     if math.abs( a2b:normalize():dot( a2c:normalize() ) ) > 0.999 then
  154.         return nil
  155.     end
  156.     local d = a2b:length()
  157.     local ex = a2b:normalize( )
  158.     local i = ex:dot( a2c )
  159.     local ey = (a2c - (ex * i)):normalize()
  160.     local j = ey:dot( a2c )
  161.     local ez = ex:cross( ey )
  162.     local r1 = A.distance
  163.     local r2 = B.distance
  164.     local r3 = C.distance
  165.     local x = (r1*r1 - r2*r2 + d*d) / (2*d)
  166.     local y = (r1*r1 - r3*r3 - x*x + (x-i)*(x-i) + j*j) / (2*j)
  167.     local result = A.position + (ex * x) + (ey * y)
  168.     local zSquared = r1*r1 - x*x - y*y
  169.     if zSquared > 0 then
  170.         local z = math.sqrt(zSquared)
  171.         local result1 = result + (ez * z)
  172.         local result2 = result - (ez * z)
  173.         local rounded1, rounded2 = result1:round(), result2:round()
  174.         if rounded1.x ~= rounded2.x or rounded1.y ~= rounded2.y or rounded1.z ~= rounded2.z then
  175.             return result1, result2
  176.         else
  177.             return rounded1
  178.         end
  179.     end
  180.     return result:round()
  181. end
  182.  
  183. local function narrow(p1, p2, fix)
  184.     local dist1 = math.abs((p1 - fix.position):length() - fix.distance)
  185.     local dist2 = math.abs((p2 - fix.position):length() - fix.distance)
  186.     if math.abs(dist1 - dist2) < 0.05 then
  187.         return p1, p2
  188.     elseif dist1 < dist2 then
  189.         return p1:round()
  190.     else
  191.         return p2:round()
  192.     end
  193. end
  194.  
  195. function locate(id)
  196.     local tFixes = {}
  197.     local p1, p2
  198.     for _,t in pairs(tLocations[id]) do
  199.         table.insert(tFixes, { ["position"] = vector.new(t.x, t.y, t.z), ["distance"] = t.d })
  200.     end
  201.     local i = 3
  202.     while (p1 == nil or p2 ~= nil) and i <= #tFixes do
  203.         if not p1 then
  204.             p1, p2 = trilaterate(tFixes[1], tFixes[2], tFixes[i])
  205.         else
  206.             p1, p2 = narrow(p1, p2, tFixes[i])
  207.         end
  208.         i = i + 1
  209.     end
  210.     if p1 and p2 then
  211.         _print("Ambiguous position")
  212.         _print("Could be "..p1.x..","..p1.y..","..p1.z.." or "..p2.x..","..p2.y..","..p2.z)
  213.     elseif p1 then
  214.         if not tKnownLocations[id] or not vector_equal(tKnownLocations[id], p1) then
  215.             print("Location added:")
  216.             print(id, ": ", p1)
  217.             tKnownLocations[id] = p1
  218.             save()
  219.         end
  220.     else
  221.         _print("Couldn't determine location for ", id)
  222.     end
  223. end
  224.  
  225. local function addLocation(id, t)
  226.     if not tLocations[t.id] then
  227.         tLocations[t.id] = {}
  228.     end
  229.     local tLoc = {}
  230.     tLoc.x = t.x
  231.     tLoc.y = t.y
  232.     tLoc.z = t.z
  233.     tLoc.d = t.d
  234.     tLocations[t.id][id] = tLoc
  235.     if table_size(tLocations[t.id]) >= 3 then
  236.         _print("Trying to locate #", t.id)
  237.         locate(t.id)
  238.     end
  239. end
  240.  
  241. -- Event handlers
  242.  
  243. local function handle_message(id, msg)
  244.     local st = string.match(msg, "<LOCATION> (.+)")
  245.     if st then
  246.         local t = textutils.unserialize(st)
  247.         if t and type(t) == "table" then
  248.             _print("Location received from ", id, ":")
  249.             _print(t.id, ": ", "(", t.x, ", ", t.y, ", ", t.z, ", ", t.d, ")")
  250.             addLocation(id, t)
  251.         end
  252.     end
  253. end
  254.  
  255. local function handle_char(c)
  256.     c = string.lower(c)
  257.     if c == "l" then
  258.         print("Locations:")
  259.         for id, loc in pairs(tKnownLocations) do
  260.             print(id, ": ", loc)
  261.         end
  262.     elseif c == "c" then
  263.         clear()
  264.     end
  265. end
  266.  
  267. -- Start program
  268.  
  269. local function host()
  270.     print("Stuff")
  271.     os.loadAPI("archiveAPI/config")
  272.     config.load("configs","config")
  273.     local nMasterID = tonumber(config.readVal("mId"))
  274.     local tLoc = {}
  275.     tLoc.x = tonumber(config.readVal("x"))
  276.     tLoc.y = tonumber(config.readVal("y"))
  277.     tLoc.z = tonumber(config.readVal("z"))
  278.     config.save()
  279.     os.unloadAPI("archiveAPI/config")
  280.     if not nMasterID or not tLoc.x or not tLoc.y or not tLoc.z then
  281.         print("If not")
  282.         printUsage()
  283.         return false
  284.     end
  285.     clear()
  286.     if not connect() then
  287.         print("No modem attached")
  288.         return false
  289.     end
  290.     print("==================================================")
  291.     print("Powered by G&K Industries. Contact representative, gknova61 if any issues.")
  292.     print("==================================================")
  293.     print( "Position is "..tLoc.x..","..tLoc.y..","..tLoc.z )
  294.     print( "Serving GPS requests" )
  295.     local x1,y1 = term.getCursorPos()
  296.     print("0 GPS Requests served")
  297.     term.setCursorPos(x1,y1)
  298.     local nServed = 0
  299.     --print("Waiting for messages...")
  300.     while true do
  301.         local id, msg, dist = rednet.receive()
  302.         --print("Message received from ", id, " at ", dist, " meters.")
  303.         if msg == "PING" then
  304.             rednet.send(id,textutils.serialize({tLoc.x,tLoc.y,tLoc.z}))
  305.             nServed = nServed + 1
  306.             if nServed > 1 then
  307.                 local x,y = term.getCursorPos()
  308.                 term.setCursorPos(1,y-1)
  309.             end
  310.             print(nServed.." GPS Requests served")
  311.         end
  312.         tLoc.id = id
  313.         tLoc.d = dist
  314.         rednet.send(nMasterID, "<LOCATION> "..textutils.serialize(tLoc))
  315.     end
  316. end
  317. local tArgs = {...}
  318. local sAction = tArgs[1]
  319. if sAction == "host" and not fs.exists("configs/config") then
  320.     if #tArgs < 5 then
  321.         print("Check 2")
  322.         printUsage()
  323.         return false
  324.     end
  325.     local mId = tArgs[2]
  326.     local x = tArgs[3]
  327.     local y = tArgs[4]
  328.     local z = tArgs[5]
  329.     os.loadAPI("archiveAPI/config")
  330.     config.load("configs","config")
  331.     config.writeVal("mId",mId)
  332.     config.writeVal("x",x)
  333.     config.writeVal("y",y)
  334.     config.writeVal("z",z)
  335.     config.save()
  336.     os.unloadAPI("archiveAPI/config")
  337.     host()
  338. elseif sAction == "host" and fs.exists("configs/config") then
  339.     host()
  340. end
  341. if sAction == "receive" then
  342.     if #tArgs > 1 then
  343.         if string.lower(tArgs[2]) == "debug" then
  344.             bDebug = true
  345.         else
  346.             print("Chekc 3")
  347.             printUsage()
  348.             return
  349.         end
  350.     end
  351.     clear()
  352.     if not connect() then
  353.         return
  354.     end
  355.     local ok, n = load()
  356.     if ok then
  357.         print("Loaded ", n, " locations")
  358.     end
  359.     print("Press l to list located computers")
  360.     print("Press c to clear the screen")
  361.     while true do
  362.         local evt, arg1, arg2 = os.pullEvent()
  363.         if evt == "rednet_message" then
  364.             handle_message(arg1, arg2)
  365.         elseif evt == "char" then
  366.             handle_char(arg1)
  367.         end
  368.     end
  369. end
  370. if sAction ~= "host" or sAction ~= "receive" then
  371.     if fs.exists("configs/config") then
  372.         host()
  373.     end
  374. end
Advertisement
Add Comment
Please, Sign In to add comment