diff --git a/configure.lua b/configure.lua index 01515b0..335085c 100644 --- a/configure.lua +++ b/configure.lua @@ -24,8 +24,13 @@ function pick_and_place.configure(pos1, pos2) if node.name == "air" then minetest.set_node(cpos, { name = "pick_and_place:handle" }) local meta = minetest.get_meta(cpos) - meta:set_string("pos1", minetest.pos_to_string(pos1)) - meta:set_string("pos2", minetest.pos_to_string(pos2)) + + -- relative positions + local rel_pos1 = vector.subtract(pos1, cpos) + local rel_pos2 = vector.subtract(pos2, cpos) + + meta:set_string("pos1", minetest.pos_to_string(rel_pos1)) + meta:set_string("pos2", minetest.pos_to_string(rel_pos2)) end end end \ No newline at end of file diff --git a/handle_node.lua b/handle_node.lua index 3dd8e40..d84e987 100644 --- a/handle_node.lua +++ b/handle_node.lua @@ -5,15 +5,25 @@ local function on_rightclick(pos, _, _, itemstack) end local meta = minetest.get_meta(pos) - local pos1 = minetest.string_to_pos(meta:get_string("pos1")) - local pos2 = minetest.string_to_pos(meta:get_string("pos2")) - local size = vector.add(vector.subtract(pos2, pos1), 1) + -- relative positions + local rel_pos1 = minetest.string_to_pos(meta:get_string("pos1")) + local rel_pos2 = minetest.string_to_pos(meta:get_string("pos2")) + + -- absolute positions + local pos1 = vector.add(pos, rel_pos1) + local pos2 = vector.add(pos, rel_pos2) + + local size = vector.add(vector.subtract(pos2, pos1), 1) local tool = ItemStack("pick_and_place:place 1") local tool_meta = tool:get_meta() tool_meta:set_string("size", minetest.pos_to_string(size)) + -- serialize schematic + local schematic = pick_and_place.serialize(pos1, pos2) + tool_meta:set_string("schematic", schematic) + return tool end diff --git a/place_tool.lua b/place_tool.lua index 5c304a8..937c404 100644 --- a/place_tool.lua +++ b/place_tool.lua @@ -6,7 +6,10 @@ minetest.register_tool("pick_and_place:place", { on_use = function(itemstack, player) print("on_use: " .. itemstack:get_name() .. ", " .. player:get_player_name()) - + local pointed_pos = pick_and_place.get_pointed_position(player) + local meta = itemstack:get_meta() + local schematic = meta:get_string("schematic") + pick_and_place.deserialize(pointed_pos, schematic) end, on_secondary_use = function(itemstack, player) print("on_secondary_use: " .. itemstack:get_name() .. ", " .. player:get_player_name()) diff --git a/serialize.lua b/serialize.lua index a9bea5f..47c01d7 100644 --- a/serialize.lua +++ b/serialize.lua @@ -1,8 +1,96 @@ +local char, byte = string.char, string.byte + +local function encode_uint16(int) + local a, b = int % 0x100, int / 0x100 + return char(a, b) +end + +local function decode_uint16(str, ofs) + ofs = ofs or 1 + local a = byte(str, ofs) + local b = byte(str, ofs + 1) + return a + b * 0x100 +end + function pick_and_place.serialize(pos1, pos2) + 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 param2 = manip:get_param2_data() + + local mapdata = {} + local metadata = {} + + 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) + table.insert(mapdata, encode_uint16(node_data[i])) + table.insert(mapdata, char(param2[i])) + end + end + end + + -- TODO: metadata + + local size = vector.add(vector.subtract(pos2, pos1), 1) + + local data = { + mapdata = table.concat(mapdata), + metadata = metadata, + size = size + } + + local serialized_data = minetest.serialize(data) + local compressed_data = minetest.compress(serialized_data, "deflate") + local encoded_data = minetest.encode_base64(compressed_data) + -- TODO + print(dump({ + fn = "pick_and_place.serialize", + size = data.size, + serialized_data_len = #serialized_data, + compressed_data_len = #compressed_data, + encoded_data_len = #encoded_data + })) + + return encoded_data end -function pick_and_place.deserialize(origin, data, rotation) - -- TODO + +function pick_and_place.deserialize(pos1, encoded_data) + + local compressed_data = minetest.decode_base64(encoded_data) + local serialized_data = minetest.decompress(compressed_data, "deflate") + local data = minetest.deserialize(serialized_data) + + local pos2 = vector.add(pos1, vector.subtract(data.size, 1)) + + 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 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] = decode_uint16(data.mapdata, j) + j = j + 2 + param2[i] = byte(data.mapdata, j) + j = j + 1 + end + end + end + + manip:set_data(node_data) + manip:set_param2_data(param2) + manip:write_to_map() end