pick_and_place-cd2025/serialize.lua
Buckaroo Banzai 9cd093046d
schematic rotation (#1)
* schematic rotation

* fixes

* remove auto-rotation code

* schematic encoding v2

* testing

* working encode/decode

* rotate schematic

* spec

* rotate dialog

* skip if rotation == 0

* wip

* wip

* wip

* fix order

* fix metadata rotation

---------

Co-authored-by: BuckarooBanzay <BuckarooBanzay@users.noreply.github.com>
2024-02-29 13:15:18 +01:00

102 lines
2.8 KiB
Lua

local air_cid = minetest.get_content_id("air")
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 node_id_data = {}
local param2_data = {}
local metadata = {}
for z=pos1.z,pos2.z do
for y=pos1.y,pos2.y do
for x=pos1.x,pos2.x do
local i = area:index(x,y,z)
table.insert(node_id_data, node_data[i])
table.insert(param2_data, param2[i])
end
end
end
-- store metadata
local nodes_with_meta = minetest.find_nodes_with_meta(pos1, pos2)
for _, pos in ipairs(nodes_with_meta) do
local rel_pos = vector.subtract(pos, pos1)
local meta = minetest.get_meta(pos)
local meta_table = meta:to_table()
-- Convert metadata item stacks to item strings
for _, invlist in pairs(meta_table.inventory) do
for index = 1, #invlist do
local itemstack = invlist[index]
if itemstack.to_string then
invlist[index] = itemstack:to_string()
end
end
end
metadata[minetest.pos_to_string(rel_pos)] = meta_table
end
local schematic = {
node_id_data = node_id_data,
param2_data = param2_data,
metadata = metadata,
size = vector.add(vector.subtract(pos2, pos1), 1)
}
return pick_and_place.encode_schematic(schematic)
end
function pick_and_place.deserialize(pos1, encoded_data)
local schematic, err = pick_and_place.decode_schematic(encoded_data)
if err then
return false, "Decode error: " .. err
end
local pos2 = vector.add(pos1, vector.subtract(schematic.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 y=pos1.y,pos2.y do
for x=pos1.x,pos2.x do
local i = area:index(x,y,z)
local nodeid = schematic.node_id_data[j]
if nodeid ~= air_cid then
node_data[i] = nodeid
param2[i] = schematic.param2_data[j]
end
j = j + 1
end
end
end
-- set metadata
for pos_str, meta_table in pairs(schematic.metadata) do
local pos = minetest.string_to_pos(pos_str)
local abs_pos = vector.add(pos1, pos)
local meta = minetest.get_meta(abs_pos)
meta:from_table(meta_table)
end
-- set nodeid's and param2
manip:set_data(node_data)
manip:set_param2_data(param2)
manip:write_to_map()
return true
end