|
|
|
local minetest, nodecore
|
|
|
|
= minetest, nodecore
|
|
|
|
|
|
|
|
-- Table of nodes that can be rotated by the mod.
|
|
|
|
local registered_rotatables = {}
|
|
|
|
|
|
|
|
local registry = {}
|
|
|
|
|
|
|
|
-- Override `nc_scaling`'s default empty hand right-click behavior so we can use it
|
|
|
|
-- to rotate things when holding sneak, which doesn't trigger a node's `on_rightclick`.
|
|
|
|
local default_on_place = minetest.registered_items[""].on_place
|
|
|
|
minetest.registered_items[""].on_place = function(item_stack, placer, pointed_thing, ...)
|
|
|
|
if pointed_thing.type == "node" then
|
|
|
|
-- Player must sneak in order for this to run.
|
|
|
|
-- Non-sneak is handled by node's `on_rightclick`.
|
|
|
|
if minetest.is_player(placer) and placer:get_player_control().sneak then
|
|
|
|
local pos = pointed_thing.under
|
|
|
|
local node = minetest.get_node(pos)
|
|
|
|
if registry.is_rotatable(node) then
|
|
|
|
local def = minetest.registered_nodes[node.name]
|
|
|
|
def.on_rightclick(pos, node, placer, item_stack, pointed_thing)
|
|
|
|
return -- Skip default behavior.
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
-- Call the default function, so we can still get the "scaling" functionality.
|
|
|
|
default_on_place(item_stack, placer, pointed_thing, ...)
|
|
|
|
end
|
|
|
|
|
|
|
|
local rotate_node = nc_extended_rotating.rotate.rotate_node
|
|
|
|
-- local get_rotating_state = nc_extended_rotating.state.get_rotating_state
|
|
|
|
function registry.register_rotatable(name, def, facedir_lookup, rightclick_filter_func)
|
|
|
|
def = def or minetest.registered_nodes[name] or error("Unknown node '" .. name .. "'")
|
|
|
|
if def.paramtype2 ~= "facedir" then error("Node '" .. name .. "' must be 'facedir'") end
|
|
|
|
|
|
|
|
-- Replace the default `on_rightclick` function so
|
|
|
|
-- we can call our custom rotation handling code.
|
|
|
|
local default_on_rightclick = def.on_rightclick
|
|
|
|
def.on_rightclick = function(pos, node, clicker, ...)
|
|
|
|
-- If `rightclick_filter_func` is set and returns true, call the default `on_rightclick`.
|
|
|
|
if registry.is_rightclick_filtered(pos, node, clicker, ...) then
|
|
|
|
default_on_rightclick(pos, node, clicker, ...)
|
|
|
|
else
|
|
|
|
if nodecore.protection_test(pos, clicker) then return end
|
|
|
|
local state = nc_extended_rotating.state.get_rotating_state(clicker, pos, node)
|
|
|
|
if (not state) or (not state.success) then return end
|
|
|
|
rotate_node(pos, node, state.facedir)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
registered_rotatables[name] = {
|
|
|
|
facedir_lookup = facedir_lookup,
|
|
|
|
rightclick_filter_func = rightclick_filter_func,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Returns whether the specified `node` is rotatable by this mod.
|
|
|
|
function registry.is_rotatable(node)
|
|
|
|
return registered_rotatables[node.name] ~= nil
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Returns whether the `on_rightclick` is filtered and the default
|
|
|
|
-- implementation should be called, instead of the custom rotation logic.
|
|
|
|
function registry.is_rightclick_filtered(pos, node, player, item_stack, pointed_thing)
|
|
|
|
local entry = registered_rotatables[node.name]
|
|
|
|
return entry and entry.rightclick_filter_func
|
|
|
|
and entry.rightclick_filter_func(pos, node, player, item_stack, pointed_thing)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Fixes facedir for the specified `node` when rotated to `facedir`.
|
|
|
|
-- * Returns `nil` if the node can't rotate this way.
|
|
|
|
-- * Returns `facedir` when the node can rotate this way.
|
|
|
|
-- * Returns another facedir when the node should rotate another equivalent way.
|
|
|
|
function registry.fix_rotatable_facedir(node, facedir)
|
|
|
|
local name = node and node.name or ""
|
|
|
|
local entry = registered_rotatables[name]
|
|
|
|
if not entry then return nil end
|
|
|
|
if not entry.facedir_lookup then return facedir end
|
|
|
|
return entry.facedir_lookup[facedir]
|
|
|
|
end
|
|
|
|
|
|
|
|
return registry
|