diff --git a/deserialize.lua b/deserialize.lua new file mode 100644 index 0000000..9098998 --- /dev/null +++ b/deserialize.lua @@ -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 \ No newline at end of file diff --git a/deserialize_mapblock.lua b/deserialize_mapblock.lua new file mode 100644 index 0000000..a1bd387 --- /dev/null +++ b/deserialize_mapblock.lua @@ -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 \ No newline at end of file diff --git a/encode.lua b/encoding.lua similarity index 86% rename from encode.lua rename to encoding.lua index 3fedd87..a6363c3 100644 --- a/encode.lua +++ b/encoding.lua @@ -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 \ No newline at end of file diff --git a/init.lua b/init.lua index 3bd17d5..1e885c7 100644 --- a/init.lua +++ b/init.lua @@ -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 \ No newline at end of file diff --git a/localize_nodeids.lua b/localize_nodeids.lua new file mode 100644 index 0000000..dda3a0c --- /dev/null +++ b/localize_nodeids.lua @@ -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 diff --git a/mtt.lua b/mtt.lua index c9070b0..2e839e3 100644 --- a/mtt.lua +++ b/mtt.lua @@ -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) \ No newline at end of file