parent
00624c60b0
commit
dc59ab7abf
3 changed files with 90 additions and 55 deletions
@ -1,65 +1,20 @@ |
||||
local math, ipairs, tostring |
||||
= math, ipairs, tostring |
||||
|
||||
local minetest, vector, include |
||||
= minetest, vector, include |
||||
|
||||
local function debug_tell(...) |
||||
local text = "" |
||||
for _, v in ipairs({...}) do text = text .. tostring(v) end |
||||
minetest.chat_send_all(text) |
||||
end |
||||
|
||||
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 |
||||
} |
||||
|
||||
local function unit_vector_to_axis_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 |
||||
end |
||||
error("Not a unit vector") |
||||
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 = unit_vector_to_axis_index(back) |
||||
FACEDIR_LOOKUP[up_index][back_index] = facedir |
||||
end |
||||
end |
||||
local rotate = include("rotate") |
||||
|
||||
minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing) |
||||
local def = minetest.registered_nodes[node.name] |
||||
if def.paramtype2 == "facedir" and pointed_thing.above and pointed_thing.under then |
||||
local facedir = node.param2 |
||||
-- Vector that points away from the punched face. |
||||
local punched_face = vector.subtract(pointed_thing.above, pointed_thing.under) |
||||
|
||||
local up = AXIS_LOOKUP[1 + math.floor(facedir / 4)] |
||||
local back = minetest.facedir_to_dir(facedir) |
||||
if def.paramtype2 ~= "facedir" then return end |
||||
|
||||
up = up:rotate_around_axis(punched_face, math.rad(-90)):round() |
||||
back = back:rotate_around_axis(punched_face, math.rad(-90)):round() |
||||
-- Vector that points away from the punched face. |
||||
if (not pointed_thing.above) or (not pointed_thing.under) then return end |
||||
local axis = vector.subtract(pointed_thing.above, pointed_thing.under) |
||||
|
||||
local up_index = unit_vector_to_axis_index(up) |
||||
local back_index = unit_vector_to_axis_index(back) |
||||
-- Rotate clockwise by default. |
||||
local degrees = -90 |
||||
-- If player is sneaking, reverse the rotation. |
||||
if minetest.is_player(puncher) and puncher:get_player_control().sneak then degrees = -degrees end |
||||
|
||||
facedir = FACEDIR_LOOKUP[up_index][back_index] |
||||
if facedir == nil then minetest.chat_send_all("Could not look up facedir") end |
||||
node.param2 = facedir |
||||
minetest.set_node(pos, node) |
||||
end |
||||
rotate.rotate_node(pos, node, axis, degrees) |
||||
end) |
||||
|
@ -0,0 +1,64 @@ |
||||
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 |
@ -0,0 +1,16 @@ |
||||
local ipairs, tostring |
||||
= ipairs, tostring |
||||
|
||||
local minetest |
||||
= minetest |
||||
|
||||
local utility = {} |
||||
|
||||
local function debug_tell(...) |
||||
local text = "" |
||||
for _, v in ipairs({...}) do text = text .. tostring(v) end |
||||
minetest.chat_send_all(text) |
||||
end |
||||
utility.debug_tell = debug_tell |
||||
|
||||
return utility |
Loading…
Reference in new issue