blunty666

tinyMap

Sep 5th, 2015
240
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. local BIT_MASKS = {
  2.     SET_COORD = bit.blshift(1, 5),
  3.     SET_X_COORD = bit.blshift(1, 4),
  4.     COORD = 15,
  5.     COORD_DATA = bit.blshift(1, 4),
  6. }
  7.  
  8. local function base256_to_base64(input)
  9.     local output = {}
  10.     for i = 1, #input, 3 do
  11.         table.insert(output, bit.brshift(input[i] or 0, 2))
  12.         table.insert(output, bit.blshift(bit.band(input[i] or 0, 3), 4) + bit.brshift(input[i+1] or 0, 4))
  13.         table.insert(output, bit.blshift(bit.band(input[i+1] or 0, 15), 2) + bit.brshift(input[i+2] or 0, 6))
  14.         table.insert(output, bit.band(input[i+2] or 0, 63))
  15.     end
  16.     return output
  17. end
  18.  
  19. local function base64_to_base256(input)
  20.     local output = {}
  21.     for i = 1, #input, 4 do
  22.          table.insert(output, bit.blshift(input[i] or 0, 2) + bit.brshift(input[i+1] or 0, 4))
  23.          table.insert(output, bit.blshift(bit.band(input[i+1] or 0, 15), 4) + bit.brshift(input[i+2] or 0, 2))
  24.          table.insert(output, bit.blshift(bit.band(input[i+2] or 0, 3), 6) + (input[i+3] or 0))
  25.     end
  26.     return output
  27. end
  28.  
  29. local function isValidValue(value)
  30.     return value == nil or value == 0 or value == 1
  31. end
  32.  
  33. local function toGridCode(tVector)
  34.     return math.floor(tVector.x/16), math.floor(tVector.y/16), math.floor(tVector.z/16), tVector.x % 16, tVector.y % 16, tVector.z % 16
  35. end
  36.  
  37. local function setGrid(tMap, x, y, z, grid)
  38.     if not tMap.map[x] then
  39.         tMap.map[x] = {}
  40.     end
  41.     if not tMap.map[x][y] then
  42.         tMap.map[x][y] = {}
  43.     end
  44.     tMap.map[x][y][z] = grid
  45.     return tMap.map[x][y][z]
  46. end
  47.  
  48. local function getGrid(tMap, x, y, z)
  49.     if not tMap.map[x] or not tMap.map[x][y] or not tMap.map[x][y][z] then
  50.         return tMap:load(x, y, z)
  51.     else
  52.         return tMap.map[x][y][z]
  53.     end
  54. end
  55.  
  56. local mapMethods = {
  57.  
  58.     load = function(self, tVector, y, z)
  59.         local gX, gY, gZ
  60.         if y and z then
  61.             gX, gY, gZ = tVector, y, z
  62.         else
  63.             gX, gY, gZ = toGridCode(tVector)
  64.         end
  65.         local gridPath = fs.combine(self.mapDir, gX..","..gY..","..gZ)
  66.         if fs.exists(gridPath) then
  67.             local handle = fs.open(gridPath, "rb")
  68.             if handle then
  69.                 local grid = {}
  70.                
  71.                 local rawData = {}
  72.                 local rawDataByte = handle.read()
  73.                 while rawDataByte do
  74.                     table.insert(rawData, rawDataByte)
  75.                     rawDataByte = handle.read()
  76.                 end
  77.                 handle.close()
  78.                
  79.                 --local data = rawData
  80.                 local data = base256_to_base64(rawData)
  81.                
  82.                 --load grid data
  83.                 local currX, currY, currZ
  84.                 local dataByte
  85.                 for _, dataByte in ipairs(data) do
  86.                     if bit.band(dataByte, BIT_MASKS.SET_COORD) == BIT_MASKS.SET_COORD then
  87.                         --we are changing our currX or currY coord
  88.                         if bit.band(dataByte, BIT_MASKS.SET_X_COORD) == BIT_MASKS.SET_X_COORD then
  89.                             --we are changing our currX coord
  90.                             currX = bit.band(dataByte, BIT_MASKS.COORD)
  91.                         else
  92.                             --we are changing our currY coord
  93.                             currY = bit.band(dataByte, BIT_MASKS.COORD)
  94.                         end
  95.                     else
  96.                         --we are setting the value for a proper coord
  97.                         currZ = bit.band(dataByte, BIT_MASKS.COORD)
  98.                         if currX and currY and currZ then
  99.                             if not grid[currX] then
  100.                                 grid[currX] = {}
  101.                             end
  102.                             if not grid[currX][currY] then
  103.                                 grid[currX][currY] = {}
  104.                             end
  105.                             grid[currX][currY][currZ] = bit.brshift(bit.band(dataByte, BIT_MASKS.COORD_DATA), 4)
  106.                         end
  107.                     end
  108.                 end
  109.                 return setGrid(self, gX, gY, gZ, grid)
  110.             end
  111.         end
  112.         return setGrid(self, gX, gY, gZ, {})
  113.     end,
  114.  
  115.     loadAll = function(self)
  116.         if fs.exists(self.mapDir) and fs.isDir(self.mapDir) then
  117.             for _, gridFile in ipairs(fs.list(self.mapDir)) do
  118.                 local _, _, gX, gY, gZ = string.find(gridFile, "(.+)%,(.+)%,(.+)")
  119.                 if gX and gY and gX then
  120.                     self:load(tonumber(gX), tonumber(gY), tonumber(gZ))
  121.                 end
  122.             end
  123.         end
  124.     end,
  125.  
  126.     save = function(self)
  127.         for gX, YZmap in pairs(self.map) do
  128.             for gY, Zmap in pairs(YZmap) do
  129.                 for gZ, grid in pairs(Zmap) do
  130.                     if next(grid) then
  131.                         local rawData = {}
  132.                         for x, gridYZ in pairs(grid) do
  133.                             table.insert(rawData, BIT_MASKS.SET_COORD + BIT_MASKS.SET_X_COORD + x)
  134.                             for y, gridZ in pairs(gridYZ) do
  135.                                 table.insert(rawData, BIT_MASKS.SET_COORD + y)
  136.                                 for z, coordValue in pairs(gridZ) do
  137.                                     table.insert(rawData, bit.blshift(coordValue, 4) + z)
  138.                                 end
  139.                             end
  140.                         end
  141.                         --local data = rawData
  142.                         local data = base64_to_base256(rawData)
  143.                         local handle = fs.open(fs.combine(self.mapDir, gX..","..gY..","..gZ), "wb")
  144.                         if handle then
  145.                             for _, dataByte in ipairs(data) do
  146.                                 handle.write(dataByte)
  147.                             end
  148.                             handle.close()
  149.                         end
  150.                     else
  151.                         fs.delete(fs.combine(self.mapDir, gX..","..gY..","..gZ))
  152.                     end
  153.                 end
  154.             end
  155.         end
  156.     end,
  157.  
  158.     get = function(self, tVector)
  159.         local gX, gY, gZ, pX, pY, pZ = toGridCode(tVector)
  160.         local grid = getGrid(self, gX, gY, gZ)
  161.         if grid[pX] and grid[pX][pY] then
  162.             return grid[pX][pY][pZ]
  163.         end
  164.     end,
  165.  
  166.     set = function(self, tVector, value)
  167.         if not isValidValue(value) then
  168.             --should we throw an error or use a default value?
  169.             error("set: value is not valid", 2)
  170.         end
  171.         local gX, gY, gZ, pX, pY, pZ = toGridCode(tVector)
  172.         local grid = getGrid(self, gX, gY, gZ)
  173.         if not grid[pX] then
  174.             grid[pX] = {}
  175.         end
  176.         if not grid[pX][pY] then
  177.             grid[pX][pY] = {}
  178.         end
  179.         grid[pX][pY][pZ] = value
  180.         return grid[pX][pY][pZ]
  181.     end,
  182.  
  183.     getOrSet = function(self, tVector, value)
  184.         local gX, gY, gZ, pX, pY, pZ = toGridCode(tVector)
  185.         local grid = getGrid(self, gX, gY, gZ)
  186.         if grid[pX] and grid[pX][pY] and grid[pX][pY][pZ] then
  187.             return grid[pX][pY][pZ], false
  188.         else
  189.             if not isValidValue(value) then
  190.                 --should we throw an error or use a default value?
  191.                 error("getOrSet: value is not valid", 2)
  192.             end
  193.             if not grid[pX] then
  194.                 grid[pX] = {}
  195.             end
  196.             if not grid[pX][pY] then
  197.                 grid[pX][pY] = {}
  198.             end
  199.             grid[pX][pY][pZ] = value
  200.             return grid[pX][pY][pZ], true
  201.         end
  202.     end,
  203.  
  204. }
  205. local mapMetatable = {__index = mapMethods}
  206.  
  207. function new(mapDir)
  208.     local tMap = {}
  209.     if type(mapDir) == "string" then
  210.         if not fs.exists(mapDir) then
  211.             fs.makeDir(mapDir)
  212.         elseif not fs.isDir(mapDir) then
  213.             error("new: not a valid directory", 2)
  214.         end
  215.         tMap.mapDir = mapDir
  216.     else
  217.         error("new: directory must be string", 2)
  218.     end
  219.     tMap.map = {}
  220.     setmetatable(tMap, mapMetatable)
  221.     return tMap
  222. end
RAW Paste Data