Oeed

Dapper Map Server

Jun 24th, 2016
427
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.44 KB | None | 0 0
  1. local args = {...}
  2. if #args > 1 then
  3.     print("Usage: mapserver <database path>")
  4.     return
  5. end
  6.  
  7. local DAPPER_CLIENT_REQUEST_CHANNEL = 4261
  8. local DAPPER_CLIENT_DATA_CHANNEL = 4262
  9. local DAPPER_SCAN_DATA_CHANNEL = 4263
  10. local DAPPER_SCAN_ACKNOWLEDGE_CHANNEL = 4264
  11. local DAPPER_SCAN_NEXT_REQUEST_CHANNEL = 4265
  12. local DAPPER_SCAN_NEXT_REPLY_CHANNEL = 4266
  13.  
  14. local DAPPER_SCAN_REQUEST_NEXT = "nextblock"
  15. local DAPPER_CLIENT_REQUEST_MAP = "mapdata"
  16.  
  17. os.setComputerLabel("Dapper Mapper Server")
  18. print("Dapper Mapper Server by oeed")
  19. local modem = peripheral.find("modem")
  20. if not modem or not modem.isWireless() then
  21.     error("Please connect a wireless modem and re-run the program.", 0)
  22. end
  23.  
  24. print("Loading map database...")
  25. local database
  26. local databasePath = args[1] and args[1] or "/database"
  27. if fs.exists(databasePath) then
  28.     local h = fs.open(databasePath, "r")
  29.     if h then
  30.         database = textutils.unserialize(h.readAll())
  31.         h.close()
  32.     end
  33.     if not database then
  34.         error("Failed to read database '" .. databasePath .. "', it may be corrupt.", 0)
  35.     end
  36. else
  37.     database = {
  38.         blocks = {}
  39.     }
  40. end
  41.  
  42. local function saveDatabase()
  43.     local h = fs.open(databasePath, "w")
  44.     if h then
  45.         local serialised = textutils.serialize(database)
  46.         local availableSpace = fs.getFreeSpace("/") + fs.getSize(databasePath)
  47.         if availableSpace < #serialised then
  48.             printError("WARNING! Insufficient space to save database!")
  49.         else
  50.             print("Saved database. Size: " .. #serialised .. "B")
  51.             h.write(serialised)
  52.         end
  53.         h.close()
  54.     else
  55.         printError("WARNING! Failed to save database (couldn't open file).")
  56.     end
  57. end
  58.  
  59. print("Downloading latest block catalogue from GitHub...")
  60. local catalogueHandle = http.get("https://raw.githubusercontent.com/oeed/Dapper/master/Server/catalogue?"..os.time())
  61. local catalogueRaw
  62. if not catalogueHandle then
  63.     print("Failed to download catalogue, trying to read a local copy.")
  64.     local h = fs.open("catalogue", "r")
  65.     if h then
  66.         catalogueRaw = h.readAll()
  67.         h.close()
  68.     end
  69. else
  70.     catalogueRaw = catalogueHandle.readAll()
  71.     local h = fs.open("catalogue", "w")
  72.     if h then
  73.         h.write(catalogueRaw)
  74.         h.close()
  75.     end
  76. end
  77. if not catalogueRaw then
  78.     error("Couldn't access a copy of the block catalogue!", 0)
  79. end
  80. local catalogue = loadstring("return " .. catalogueRaw)()
  81. if not catalogue then
  82.     error("The catalogue was corrupt, sorry! Try deleting your local copy or check GitHub.", 0)
  83. end
  84.  
  85. modem.open(DAPPER_CLIENT_REQUEST_CHANNEL)
  86. modem.open(DAPPER_CLIENT_DATA_CHANNEL)
  87. modem.open(DAPPER_SCAN_DATA_CHANNEL)
  88. modem.open(DAPPER_SCAN_ACKNOWLEDGE_CHANNEL)
  89. modem.open(DAPPER_SCAN_NEXT_REQUEST_CHANNEL)
  90. modem.open(DAPPER_SCAN_NEXT_REPLY_CHANNEL)
  91.  
  92. print("Awaiting requests...")
  93.  
  94. -- Pixel = text, textColour, backgroundColour
  95. local function identifyBlock(block)
  96.     local name, state = block.name, block.state
  97.     if catalogue[name] then
  98.         for i, catalogueItem in ipairs(catalogue[name]) do
  99.             local catalogueState, pixel = catalogueItem[1], catalogueItem[2]
  100.             local match = true
  101.             for k, v in pairs(catalogueState) do
  102.                 if v ~= state[k] then
  103.                     match = false
  104.                     break
  105.                 end
  106.             end
  107.             if match then
  108.                 return pixel
  109.             end
  110.         end
  111.     end
  112.     return {"?", colours.lightGrey, colours.grey}
  113. end
  114.  
  115. while true do
  116.     local event, side, senderChannel, replyChannel, message, distance = os.pullEvent("modem_message")
  117.     if senderChannel == DAPPER_SCAN_DATA_CHANNEL then
  118.         print("Received new map data!")
  119.         if type(message) == "table" then
  120.             local receivedScans = {}
  121.             local lastYield = os.clock()
  122.             for i, scan in pairs(message) do
  123.                 if type(scan.x) == "number" and type(scan.z) == "number" and type(scan.block) == "table" then
  124.                     local xBlocks = database.blocks[scan.x]
  125.                     if not xBlocks then
  126.                         xBlocks = {}
  127.                         database.blocks[scan.x] = xBlocks
  128.                     end
  129.                     if i % 200 == 199 then
  130.                         local clock = os.clock()
  131.                         if clock - lastYield >= 5 then
  132.                             print("Yielding")
  133.                             os.queueEvent("blah")
  134.                             os.pullEvent()
  135.                             lastYield = clock
  136.                         end
  137.                     end
  138.                     xBlocks[scan.z] = scan.block
  139.                     table.insert(receivedScans, {x = scan.x, z = scan.z})
  140.                 end
  141.             end
  142.             modem.transmit(DAPPER_SCAN_ACKNOWLEDGE_CHANNEL, 0, receivedScans)
  143.             print("Added " .. #receivedScans .. " new blocks!")
  144.         end
  145.         saveDatabase()
  146.     elseif senderChannel == DAPPER_SCAN_NEXT_REQUEST_CHANNEL then
  147.         if type(message) == "table" then
  148.             if type(message.startX) == "number" and type(message.stopX) == "number" and type(message.startZ) == "number" and type(message.stopZ) == "number" then
  149.                 print("Request for next block...")
  150.                 local response = {}
  151.                 local found = false
  152.                 for x = message.startX, message.stopX, 1 do
  153.                     for z = message.startZ, message.stopZ, 1 do
  154.                         if not database.blocks[x] or not database.blocks[x][z] then
  155.                             print("Found " .. x .. ", " .. z)
  156.                             response.x = x
  157.                             response.z = z
  158.                             found = true
  159.                             break
  160.                         end
  161.                     end
  162.                     if found then
  163.                         break
  164.                     end
  165.                 end
  166.                 modem.transmit(DAPPER_SCAN_NEXT_REPLY_CHANNEL, 0, response)
  167.             end
  168.         end
  169.     elseif senderChannel == DAPPER_CLIENT_REQUEST_CHANNEL then
  170.         if message == DAPPER_CLIENT_REQUEST_MAP then
  171.             print("A client requested map data!")
  172.             local pixels = {}
  173.             for x, xBlocks in pairs(database.blocks) do
  174.                 local xPixels = {}
  175.                 for y, block in pairs(xBlocks) do
  176.                     xPixels[y] = identifyBlock(block)
  177.                 end
  178.                 pixels[x] = xPixels
  179.             end
  180.             modem.transmit(DAPPER_CLIENT_DATA_CHANNEL, 0, pixels)
  181.         end
  182.     end
  183. end
Add Comment
Please, Sign In to add comment