pick_and_place-cd2025/schematic_orient.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

89 lines
2.4 KiB
Lua

local node_id_to_name_cache = {}
local node_ids_rotateable = {}
local wallmounted = {
[90] = {0, 1, 5, 4, 2, 3, 0, 0},
[180] = {0, 1, 3, 2, 5, 4, 0, 0},
[270] = {0, 1, 4, 5, 3, 2, 0, 0}
}
local facedir = {
[90] = { 1, 2, 3, 0, 13, 14, 15, 12, 17, 18, 19, 16,
9, 10, 11, 8, 5, 6, 7, 4, 23, 20, 21, 22},
[180] = { 2, 3, 0, 1, 10, 11, 8, 9, 6, 7, 4, 5,
18, 19, 16, 17, 14, 15, 12, 13, 22, 23, 20, 21},
[270] = { 3, 0, 1, 2, 19, 16, 17, 18, 15, 12, 13, 14,
7, 4, 5, 6, 11, 8, 9, 10, 21, 22, 23, 20}
}
local function rotate_param2(node_name, param2, angle)
if not angle or angle == 0 then
return param2
end
local def = minetest.registered_nodes[node_name]
if def then
local wallmounted_substitution = wallmounted[angle]
local facedir_substitution = facedir[angle]
local paramtype2 = def.paramtype2
if paramtype2 == "wallmounted" or paramtype2 == "colorwallmounted" then
local orient = param2 % 8
return param2 - orient + wallmounted_substitution[orient + 1]
elseif paramtype2 == "facedir" or paramtype2 == "colorfacedir" then
local orient = param2 % 32
return param2 - orient + facedir_substitution[orient + 1]
end
end
end
local min = { x=0, y=0, z=0 }
local rotate_param2types = {
["wallmounted"] = true,
["colorwallmounted"] = true,
["facedir"] = true,
["colorfacedir"] = true
}
function pick_and_place.schematic_orient(node_ids, param2_data, max, rotation)
-- https://github.com/Uberi/Minetest-WorldEdit/blob/master/worldedit/manipulations.lua#L555
local area = VoxelArea:new({MinEdge=min, MaxEdge=max})
local pos = {x=0, y=0, z=0}
while pos.x <= max.x do
pos.y = 0
while pos.y <= max.y do
pos.z = 0
while pos.z <= max.z do
local index = area:indexp(pos)
local param2 = param2_data[index]
local node_id = node_ids[index]
local node_name = node_id_to_name_cache[node_id]
if not node_name then
-- cache association
node_name = minetest.get_name_from_content_id(node_id)
node_id_to_name_cache[node_id] = node_name
-- check if param2 is facedir
local def = minetest.registered_nodes[node_name]
node_ids_rotateable[node_id] = rotate_param2types[def.paramtype2]
end
if node_ids_rotateable[node_id] then
-- rotate only the non-disabled and supported nodes
param2 = rotate_param2(node_name, param2, rotation)
param2_data[index] = param2
end
pos.z = pos.z + 1
end
pos.y = pos.y + 1
end
pos.x = pos.x + 1
end
end