full circle

This commit is contained in:
BuckarooBanzay 2022-12-19 20:59:51 +01:00
parent 42cd70a862
commit 0725bf67fc
6 changed files with 171 additions and 14 deletions

61
deserialize.lua Normal file
View File

@ -0,0 +1,61 @@
local global_env = ...
-- local vars for faster access
local insert, byte, decode_uint16 = table.insert, string.byte, mapsync.decode_uint16
function mapsync.deserialize_chunk(chunk_pos, filename)
local f = global_env.io.open(filename)
local zip, err_msg = mtzip.unzip(f)
if not zip then
return false, err_msg
end
-- parse manifest
local manifest_str, m_err_msg = zip:get("manifest.json")
if not manifest_str then
return false, m_err_msg
end
local manifest = minetest.parse_json(manifest_str)
-- parse metadata
local metadata_str, md_err_msg = zip:get("metadata.json")
if not metadata_str then
return false, md_err_msg
end
local metadata = minetest.parse_json(metadata_str)
-- parse mapdata
local mapdata, map_err_msg = zip:get("mapdata.bin")
if not mapdata then
return false, map_err_msg
end
local min_mapblock = mapsync.get_mapblock_bounds_from_chunk(chunk_pos)
local mapblock_count = #manifest.block_pos
for mbi, rel_mapblock_pos in ipairs(manifest.block_pos) do
local blockdata = {
node_ids = {},
param1 = {},
param2 = {},
metadata = metadata[minetest.pos_to_string(rel_mapblock_pos)]
}
for i=1,4096 do
local node_id = decode_uint16(mapdata, ((mbi-1) * 4096 * 2) + (i * 2) - 2)
local param1 = byte(mapdata, (4096 * 2 * mapblock_count) + ((mbi-1) * 4096) + i)
local param2 = byte(mapdata, (4096 * 3 * mapblock_count) + ((mbi-1) * 4096) + i)
insert(blockdata.node_ids, node_id)
insert(blockdata.param1, param1)
insert(blockdata.param2, param2)
end
mapsync.localize_nodeids(manifest.node_mapping, blockdata.node_ids)
local mapblock_pos = vector.add(rel_mapblock_pos, min_mapblock)
mapsync.deserialize_mapblock(mapblock_pos, blockdata)
end
return true
end

51
deserialize_mapblock.lua Normal file
View File

@ -0,0 +1,51 @@
function mapsync.deserialize_mapblock(mapblock_pos, blockdata)
local pos1 = vector.multiply(mapblock_pos, 16)
local pos2 = vector.add(pos1, 15) -- inclusive
local manip = minetest.get_voxel_manip()
local e1, e2 = manip:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge=e1, MaxEdge=e2})
local node_data = manip:get_data()
local param1 = manip:get_light_data()
local param2 = manip:get_param2_data()
local j = 1
for z=pos1.z,pos2.z do
for x=pos1.x,pos2.x do
for y=pos1.y,pos2.y do
local i = area:index(x,y,z)
node_data[i] = blockdata.node_ids[j]
param1[i] = blockdata.param1[j]
param2[i] = blockdata.param2[j]
j = j + 1
end
end
end
manip:set_data(node_data)
manip:set_light_data(param1)
manip:set_param2_data(param2)
manip:write_to_map(false)
-- deserialize metadata
if blockdata.metadata and blockdata.metadata.meta then
for pos_str, md in pairs(blockdata.metadata.meta) do
local relative_pos = minetest.string_to_pos(pos_str)
local absolute_pos = vector.add(pos1, relative_pos)
minetest.get_meta(absolute_pos):from_table(md)
end
end
-- deserialize node timers
if blockdata.metadata and blockdata.metadata.timers then
for pos_str, timer_data in pairs(blockdata.metadata.timers) do
local relative_pos = minetest.string_to_pos(pos_str)
local absolute_pos = vector.add(pos1, relative_pos)
minetest.get_node_timer(absolute_pos):set(timer_data.timeout, timer_data.elapsed)
end
end
return true
end

View File

@ -30,3 +30,9 @@ function mapsync.encode_uint32(v)
local b4 = bitand( rshift(v, 24), 0xFF )
return string.char(b1, b2, b3, b4)
end
function mapsync.decode_uint16(str, ofs)
ofs = ofs or 0
local a, b = string.byte(str, ofs + 1, ofs + 2)
return a + b * 0x100
end

View File

@ -9,7 +9,6 @@ mapsync = {
-- secure/insecure environment
local global_env = _G
local ie = minetest.request_insecure_environment and minetest.request_insecure_environment()
if ie then
print("[mapsync] using insecure environment")
@ -17,14 +16,21 @@ if ie then
global_env = ie
end
-- api surface
dofile(MP.."/api.lua")
dofile(MP.."/encode.lua")
-- utilities / helpers
dofile(MP.."/encoding.lua")
dofile(MP.."/serialize_mapblock.lua")
dofile(MP.."/deserialize_mapblock.lua")
dofile(MP.."/localize_nodeids.lua")
-- pass on global env (secure/insecure)
loadfile(MP.."/functions.lua")(global_env)
loadfile(MP.."/serialize.lua")(global_env)
dofile(MP.."/serialize_mapblock.lua")
loadfile(MP.."/deserialize.lua")(global_env)
-- testing
if minetest.get_modpath("mtt") and mtt.enabled then
dofile(MP.."/mtt.lua")
end

30
localize_nodeids.lua Normal file
View File

@ -0,0 +1,30 @@
local air_content_id = minetest.get_content_id("air")
-- local nodename->id cache
local local_nodename_to_id_mapping = {} -- name -> id
function mapsync.localize_nodeids(node_mapping, node_ids)
local foreign_nodeid_to_name_mapping = {} -- id -> name
for k, v in pairs(node_mapping) do
foreign_nodeid_to_name_mapping[v] = k
end
for i, node_id in ipairs(node_ids) do
local node_name = foreign_nodeid_to_name_mapping[node_id]
local local_node_id = local_nodename_to_id_mapping[node_name]
if not local_node_id then
if minetest.registered_nodes[node_name] then
-- node is locally available
local_node_id = minetest.get_content_id(node_name)
else
-- node is not available here
-- TODO: make replacements configurable
local_node_id = air_content_id
end
local_nodename_to_id_mapping[node_name] = local_node_id
end
node_ids[i] = local_node_id
end
end

25
mtt.lua
View File

@ -17,17 +17,20 @@ mtt.register("register and export", function(callback)
end)
end)
local pos = { x=0, y=0, z=0 }
mtt.emerge_area(pos, pos)
mtt.register("serialize and deserialize chunk", function(callback)
mtt.register("serialize_chunk", function(callback)
local pos1 = { x=0, y=0, z=0 }
local pos2 = { x=20, y=20, z=20 }
local chunk_pos = {x=0, y=0, z=0}
local filename = minetest.get_worldpath() .. "/chunk.zip"
minetest.emerge_area(pos1, pos2, function(_, _, calls_remaining)
if calls_remaining == 0 then
local success, err_msg = mapsync.serialize_chunk({x=0, y=0, z=0}, minetest.get_worldpath() .. "/chunk.zip")
assert(success)
assert(not err_msg)
callback()
end
end)
local success, err_msg = mapsync.serialize_chunk(chunk_pos, filename)
assert(success)
assert(not err_msg)
success, err_msg = mapsync.deserialize_chunk(chunk_pos, filename)
assert(success)
assert(not err_msg)
callback()
end)