Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local BIT_MASKS = {
- SET_COORD = bit.blshift(1, 5),
- SET_X_COORD = bit.blshift(1, 4),
- COORD = 15,
- COORD_DATA = bit.blshift(1, 4),
- }
- local function base256_to_base64(input)
- local output = {}
- for i = 1, #input, 3 do
- table.insert(output, bit.brshift(input[i] or 0, 2))
- table.insert(output, bit.blshift(bit.band(input[i] or 0, 3), 4) + bit.brshift(input[i+1] or 0, 4))
- table.insert(output, bit.blshift(bit.band(input[i+1] or 0, 15), 2) + bit.brshift(input[i+2] or 0, 6))
- table.insert(output, bit.band(input[i+2] or 0, 63))
- end
- return output
- end
- local function base64_to_base256(input)
- local output = {}
- for i = 1, #input, 4 do
- table.insert(output, bit.blshift(input[i] or 0, 2) + bit.brshift(input[i+1] or 0, 4))
- table.insert(output, bit.blshift(bit.band(input[i+1] or 0, 15), 4) + bit.brshift(input[i+2] or 0, 2))
- table.insert(output, bit.blshift(bit.band(input[i+2] or 0, 3), 6) + (input[i+3] or 0))
- end
- return output
- end
- local function isValidValue(value)
- return value == nil or value == 0 or value == 1
- end
- local function toGridCode(tVector)
- 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
- end
- local function setGrid(tMap, x, y, z, grid)
- if not tMap.map[x] then
- tMap.map[x] = {}
- end
- if not tMap.map[x][y] then
- tMap.map[x][y] = {}
- end
- tMap.map[x][y][z] = grid
- return tMap.map[x][y][z]
- end
- local function getGrid(tMap, x, y, z)
- if not tMap.map[x] or not tMap.map[x][y] or not tMap.map[x][y][z] then
- return tMap:load(x, y, z)
- else
- return tMap.map[x][y][z]
- end
- end
- local mapMethods = {
- load = function(self, tVector, y, z)
- local gX, gY, gZ
- if y and z then
- gX, gY, gZ = tVector, y, z
- else
- gX, gY, gZ = toGridCode(tVector)
- end
- local gridPath = fs.combine(self.mapDir, gX..","..gY..","..gZ)
- if fs.exists(gridPath) then
- local handle = fs.open(gridPath, "rb")
- if handle then
- local grid = {}
- local rawData = {}
- local rawDataByte = handle.read()
- while rawDataByte do
- table.insert(rawData, rawDataByte)
- rawDataByte = handle.read()
- end
- handle.close()
- --local data = rawData
- local data = base256_to_base64(rawData)
- --load grid data
- local currX, currY, currZ
- local dataByte
- for _, dataByte in ipairs(data) do
- if bit.band(dataByte, BIT_MASKS.SET_COORD) == BIT_MASKS.SET_COORD then
- --we are changing our currX or currY coord
- if bit.band(dataByte, BIT_MASKS.SET_X_COORD) == BIT_MASKS.SET_X_COORD then
- --we are changing our currX coord
- currX = bit.band(dataByte, BIT_MASKS.COORD)
- else
- --we are changing our currY coord
- currY = bit.band(dataByte, BIT_MASKS.COORD)
- end
- else
- --we are setting the value for a proper coord
- currZ = bit.band(dataByte, BIT_MASKS.COORD)
- if currX and currY and currZ then
- if not grid[currX] then
- grid[currX] = {}
- end
- if not grid[currX][currY] then
- grid[currX][currY] = {}
- end
- grid[currX][currY][currZ] = bit.brshift(bit.band(dataByte, BIT_MASKS.COORD_DATA), 4)
- end
- end
- end
- return setGrid(self, gX, gY, gZ, grid)
- end
- end
- return setGrid(self, gX, gY, gZ, {})
- end,
- loadAll = function(self)
- if fs.exists(self.mapDir) and fs.isDir(self.mapDir) then
- for _, gridFile in ipairs(fs.list(self.mapDir)) do
- local _, _, gX, gY, gZ = string.find(gridFile, "(.+)%,(.+)%,(.+)")
- if gX and gY and gX then
- self:load(tonumber(gX), tonumber(gY), tonumber(gZ))
- end
- end
- end
- end,
- save = function(self)
- for gX, YZmap in pairs(self.map) do
- for gY, Zmap in pairs(YZmap) do
- for gZ, grid in pairs(Zmap) do
- if next(grid) then
- local rawData = {}
- for x, gridYZ in pairs(grid) do
- table.insert(rawData, BIT_MASKS.SET_COORD + BIT_MASKS.SET_X_COORD + x)
- for y, gridZ in pairs(gridYZ) do
- table.insert(rawData, BIT_MASKS.SET_COORD + y)
- for z, coordValue in pairs(gridZ) do
- table.insert(rawData, bit.blshift(coordValue, 4) + z)
- end
- end
- end
- --local data = rawData
- local data = base64_to_base256(rawData)
- local handle = fs.open(fs.combine(self.mapDir, gX..","..gY..","..gZ), "wb")
- if handle then
- for _, dataByte in ipairs(data) do
- handle.write(dataByte)
- end
- handle.close()
- end
- else
- fs.delete(fs.combine(self.mapDir, gX..","..gY..","..gZ))
- end
- end
- end
- end
- end,
- get = function(self, tVector)
- local gX, gY, gZ, pX, pY, pZ = toGridCode(tVector)
- local grid = getGrid(self, gX, gY, gZ)
- if grid[pX] and grid[pX][pY] then
- return grid[pX][pY][pZ]
- end
- end,
- set = function(self, tVector, value)
- if not isValidValue(value) then
- --should we throw an error or use a default value?
- error("set: value is not valid", 2)
- end
- local gX, gY, gZ, pX, pY, pZ = toGridCode(tVector)
- local grid = getGrid(self, gX, gY, gZ)
- if not grid[pX] then
- grid[pX] = {}
- end
- if not grid[pX][pY] then
- grid[pX][pY] = {}
- end
- grid[pX][pY][pZ] = value
- return grid[pX][pY][pZ]
- end,
- getOrSet = function(self, tVector, value)
- local gX, gY, gZ, pX, pY, pZ = toGridCode(tVector)
- local grid = getGrid(self, gX, gY, gZ)
- if grid[pX] and grid[pX][pY] and grid[pX][pY][pZ] then
- return grid[pX][pY][pZ], false
- else
- if not isValidValue(value) then
- --should we throw an error or use a default value?
- error("getOrSet: value is not valid", 2)
- end
- if not grid[pX] then
- grid[pX] = {}
- end
- if not grid[pX][pY] then
- grid[pX][pY] = {}
- end
- grid[pX][pY][pZ] = value
- return grid[pX][pY][pZ], true
- end
- end,
- }
- local mapMetatable = {__index = mapMethods}
- function new(mapDir)
- local tMap = {}
- if type(mapDir) == "string" then
- if not fs.exists(mapDir) then
- fs.makeDir(mapDir)
- elseif not fs.isDir(mapDir) then
- error("new: not a valid directory", 2)
- end
- tMap.mapDir = mapDir
- else
- error("new: directory must be string", 2)
- end
- tMap.map = {}
- setmetatable(tMap, mapMetatable)
- return tMap
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement