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] return def.on_rightclick(pos, node, placer, item_stack, pointed_thing) -- Skip default behavior. end end end -- Call the default function, so we can still get the "scaling" functionality. return 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, 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 return 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] = { 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 return registry