|
|
|
local minetest, vector, nodecore, include
|
|
|
|
= minetest, vector, nodecore, include
|
|
|
|
|
|
|
|
local hud = include("hud")
|
|
|
|
local rotate = include("rotate")
|
|
|
|
local utility = include("utility")
|
|
|
|
|
|
|
|
-- TODO: Add crosshair indicators for rotating around edges.
|
|
|
|
-- TODO: Register only the nodes that should be rotatable.
|
|
|
|
-- TODO: Replace `on_rightclick` of intended nodes.
|
|
|
|
-- TODO: Add some more comments.
|
|
|
|
|
|
|
|
-- Distance at which we want to rotate by "pushing" on an edge.
|
|
|
|
local EDGE_DISTANCE = 1.5 / 16 -- 1.5 texels (at 16² texture resolution)
|
|
|
|
|
|
|
|
local rotating_state = {}
|
|
|
|
|
|
|
|
nodecore.register_playerstep({
|
|
|
|
label = "extended rotating update",
|
|
|
|
action = function(player, player_data)
|
|
|
|
local name = player:get_player_name()
|
|
|
|
local state = {}; rotating_state[name] = state
|
|
|
|
|
|
|
|
local pointed_thing = player_data.raycast()
|
|
|
|
if (not pointed_thing) or pointed_thing.type ~= "node" then return nil end
|
|
|
|
|
|
|
|
state.pos = pointed_thing.under
|
|
|
|
state.node = minetest.get_node(state.pos)
|
|
|
|
if not rotate.is_rotatable(state.node) then return end
|
|
|
|
|
|
|
|
if vector.equals(pointed_thing.above, pointed_thing.under) then return end
|
|
|
|
state.face = pointed_thing.above - pointed_thing.under
|
|
|
|
|
|
|
|
local edge, distance = utility.find_closest_edge(state.node, pointed_thing)
|
|
|
|
if edge and distance > EDGE_DISTANCE then
|
|
|
|
state.axis = state.face
|
|
|
|
state.mode = "face"
|
|
|
|
else
|
|
|
|
state.axis = state.face:cross(edge):normalize():round()
|
|
|
|
state.mode = "edge"
|
|
|
|
end
|
|
|
|
|
|
|
|
state.invert = player:get_player_control().sneak
|
|
|
|
hud.update_player_hud(player, state)
|
|
|
|
end,
|
|
|
|
})
|
|
|
|
|
|
|
|
minetest.register_on_leaveplayer(function(player)
|
|
|
|
local name = player:get_player_name()
|
|
|
|
rotating_state[name] = nil
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing)
|
|
|
|
if not minetest.is_player(puncher) then return end
|
|
|
|
local name = puncher:get_player_name()
|
|
|
|
local state = rotating_state[name]
|
|
|
|
if not state then return end
|
|
|
|
|
|
|
|
-- Make sure we're still the same node that we raycasted in `playerstep`.
|
|
|
|
if not vector.equals(pos, state.pos) then return end
|
|
|
|
if node.name ~= state.node.name or node.param2 ~= state.node.param2 then return end
|
|
|
|
|
|
|
|
local degrees = state.invert and 90 or -90
|
|
|
|
rotate.rotate_node(state.pos, state.node, state.axis, degrees)
|
|
|
|
end)
|