nodecore-cd2025/mods/nc_api/item_tool_rakes.lua
Aaron Suen 64462f7265 Revert "Simplify and tidy up rake hook"
This reverts commit 03f8d32967cc35e418d8ffb46b00f65eaf34e685.

Apparently this causes item destruction: when stack nodes are
secondarily dug by a rake, their items are not given to the
player.
2020-09-17 07:10:09 -04:00

127 lines
3.9 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local ipairs, math, minetest, nodecore, pairs, table, vector
= ipairs, math, minetest, nodecore, pairs, table, vector
local math_abs, math_max, table_sort
= math.abs, math.max, table.sort
-- LUALOCALS > ---------------------------------------------------------
-- To register a tool as a rake, provie a callback:
-- on_rake(pos, node, user) returns volume, checkfunc
-- volume: ordered array of relative positions to be dug by rake
-- checkfunc(pos, node, rel): determine if item can be dug
-- rel: relative vector taken from volume array
-- returns true to dig, nil to not dig, false to abort loop
local volcache = {}
function nodecore.rake_volume(dxmax, dymax, dzmax)
dzmax = dzmax or dxmax
local key = minetest.pos_to_string({x = dxmax, y = dymax, z = dzmax})
local rakepos = volcache[key]
if rakepos then return rakepos end
rakepos = {}
for dy = -dymax, dymax do
for dx = -dxmax, dxmax do
for dz = -dzmax, dzmax do
local v = {x = dx, y = dy, z = dz}
v.d = vector.length(v)
v.rxz = math_max(math_abs(dx), math_abs(dz))
v.ry = math_abs(dy)
rakepos[#rakepos + 1] = v
end
end
end
table_sort(rakepos, function(a, b) return a.d < b.d end)
volcache[key] = rakepos
return rakepos
end
function nodecore.rake_index(filterfunc)
local rakable = {}
minetest.after(0, function()
for k, v in pairs(minetest.registered_nodes) do
if filterfunc(v, k) then
rakable[k] = true
end
end
end)
return function(_, node) return rakable[node.name] end
end
local function deferfall(func, ...)
local oldfall = minetest.check_for_falling
minetest.check_for_falling = nodecore.fallcheck
local function helper(...)
minetest.check_for_falling = oldfall
return ...
end
return helper(func(...))
end
local laststack
local lastraking
local old_node_dig = minetest.node_dig
minetest.node_dig = function(pos, node, user, ...)
laststack = nodecore.stack_get(pos)
local wield = user and user:is_player() and user:get_wielded_item()
lastraking = wield and (wield:get_definition() or {}).on_rake
if lastraking then return deferfall(old_node_dig, pos, node, user, ...) end
return old_node_dig(pos, node, user, ...)
end
local stackonly = {}
minetest.after(0, function()
for k, v in pairs(minetest.registered_nodes) do
if v.groups.is_stack_only then stackonly[k] = true end
end
end)
local function matching(_, na, pb, nb)
if stackonly[na.name] then
if not stackonly[nb.name] then return end
return (laststack and nodecore.stack_family(laststack))
== nodecore.stack_family(nodecore.stack_get(pb))
end
return nodecore.stack_family(na.name) == nodecore.stack_family(nb.name)
end
local function dorake(volume, check, pos, node, user, ...)
local sneak = user:get_player_control().sneak
local objpos = {}
for _, rel in ipairs(volume) do
local p = vector.add(pos, rel)
local n = minetest.get_node(p)
local allow = (rel.d > 0 or nil) and check(p, n, rel)
if allow == false then break end
if allow and ((not sneak) or matching(pos, node, p, n)) then
minetest.node_dig(p, n, user, ...)
objpos[minetest.hash_node_position(p)] = true
end
end
for _, lua in pairs(minetest.luaentities) do
if lua.name == "__builtin:item" then
local p = lua.object and lua.object:get_pos()
if p and objpos[minetest.hash_node_position(
vector.round(p))] then
lua.object:set_pos(pos)
end
end
end
end
local rakelock = {}
nodecore.register_on_dignode("rake handling", function(pos, node, user, ...)
local nowraking = lastraking
if not nowraking then return end
lastraking = nil
if not (pos and node and user and user:is_player()) then return end
local volume, check = nowraking(pos, node, user, ...)
if not (volume and check) then return end
local pname = user:get_player_name()
if rakelock[pname] then return end
rakelock[pname] = true
deferfall(dorake, volume, check, pos, node, user, ...)
rakelock[pname] = nil
end)