You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
65 lines
2.3 KiB
65 lines
2.3 KiB
1 year ago
|
local math, ipairs
|
||
|
= math, ipairs
|
||
|
|
||
|
local minetest, vector
|
||
|
= minetest, vector
|
||
|
|
||
|
local rotate = {}
|
||
|
|
||
|
-- Axis lookup table based on how Minetest's `facedir` operates.
|
||
|
local AXIS_LOOKUP = {
|
||
|
vector.new( 0, 1, 0), -- +Y
|
||
|
vector.new( 0, 0, 1), -- +Z
|
||
|
vector.new( 0, 0, -1), -- -Z
|
||
|
vector.new( 1, 0, 0), -- +X
|
||
|
vector.new(-1, 0, 0), -- -X
|
||
|
vector.new( 0, -1, 0), -- -Y
|
||
|
}
|
||
|
|
||
|
-- Takes an axis vector and returns its index in the `AXIS_LOOKUP` table.
|
||
|
-- Returns `nil` for any vector that is not a valid axis vector.
|
||
|
local function axis_vector_to_index(vec)
|
||
|
if vec.y == 1 then if vec.x == 0 and vec.z == 0 then return 1 end
|
||
|
elseif vec.z == 1 then if vec.x == 0 and vec.y == 0 then return 2 end
|
||
|
elseif vec.z == -1 then if vec.x == 0 and vec.y == 0 then return 3 end
|
||
|
elseif vec.x == 1 then if vec.y == 0 and vec.z == 0 then return 4 end
|
||
|
elseif vec.x == -1 then if vec.y == 0 and vec.z == 0 then return 5 end
|
||
|
elseif vec.y == -1 then if vec.x == 0 and vec.z == 0 then return 6 end
|
||
|
else return nil end
|
||
|
end
|
||
|
|
||
|
local FACEDIR_LOOKUP = {}
|
||
|
for up_index, up in ipairs(AXIS_LOOKUP) do
|
||
|
FACEDIR_LOOKUP[up_index] = {}
|
||
|
for rot = 0, 3 do
|
||
|
local facedir = (up_index - 1) * 4 + rot
|
||
|
local back = minetest.facedir_to_dir(facedir)
|
||
|
local back_index = axis_vector_to_index(back)
|
||
|
FACEDIR_LOOKUP[up_index][back_index] = facedir
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Rotates `node` at the specified `pos` around `axis` by `degrees` counter-clockwise.
|
||
|
local function rotate_node(pos, node, axis, degrees)
|
||
|
if degrees % 90 ~= 0 then error("degrees must be divisible by 90") end
|
||
|
if axis_vector_to_index(axis) == nil then error("axis must be an axis vector") end
|
||
|
|
||
|
local def = minetest.registered_nodes[node.name]
|
||
|
if def.paramtype2 ~= "facedir" then error("node's paramtype2 is not 'facedir'") end
|
||
|
|
||
|
local up = AXIS_LOOKUP[1 + math.floor(node.param2 / 4)]
|
||
|
local back = minetest.facedir_to_dir(node.param2)
|
||
|
|
||
|
up = up :rotate_around_axis(axis, math.rad(degrees)):round()
|
||
|
back = back:rotate_around_axis(axis, math.rad(degrees)):round()
|
||
|
|
||
|
local up_index = axis_vector_to_index(up)
|
||
|
local back_index = axis_vector_to_index(back)
|
||
|
|
||
|
node.param2 = FACEDIR_LOOKUP[up_index][back_index]
|
||
|
minetest.set_node(pos, node)
|
||
|
end
|
||
|
rotate.rotate_node = rotate_node
|
||
|
|
||
|
return rotate
|