Aaron Suen 42f125c716 Make most recipes indexable
Register a "rootmatch" property for all
recipes that represents a broader, quicker
test for recipe eligibility.  False positives are
allowed but false negatives are not.

Since most recipes are eligible, we can
use this to build an index for fast lookups
of subsets of recipes to run and skip most
of the other ones.
2020-06-27 11:06:43 -04:00

115 lines
3.2 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local ipairs, minetest, nodecore, pairs, table, vector
= ipairs, minetest, nodecore, pairs, table, vector
local table_sort
= table.sort
-- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname()
minetest.register_tool(modname .. ":rake", {
description = "Rake",
inventory_image = modname .. "_rake.png",
tool_capabilities = nodecore.toolcaps({
snappy = 1,
uses = 10
}),
groups = {flammable = 1},
sounds = nodecore.sounds("nc_tree_sticky")
})
local rakable = {}
local stackonly = {}
minetest.after(0, function()
for k, v in pairs(minetest.registered_nodes) do
if v.groups and v.groups.falling_node and v.groups.snappy == 1 then
rakable[k] = true
if v.groups.is_stack_only then stackonly[k] = true end
end
end
end)
local rakepos = {}
for dy = -1, 1 do
for dx = -2, 2 do
for dz = -2, 2 do
rakepos[#rakepos + 1] = {x = dx, y = dy, z = dz}
end
end
end
table_sort(rakepos, function(a, b) return vector.length(a) < vector.length(b) 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_name() == modname .. ":rake"
return old_node_dig(pos, node, user, ...)
end
local function matching(_, na, pb, nb)
if stackonly[na.name] then
if not stackonly[nb.name] then return end
return (laststack and laststack:get_name()) == nodecore.stack_get(pb):get_name()
end
return na.name == nb.name
end
local function dorake(pos, node, user, ...)
local sneak = user:get_player_control().sneak
local objpos = {}
for _, rel in ipairs(rakepos) do
local p = vector.add(pos, rel)
local n = minetest.get_node(p)
if rakable[n.name] and ((not sneak) or matching(pos, node, p, n)) then
minetest.node_dig(p, n, user, ...)
end
objpos[minetest.hash_node_position(p)] = true
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, ...)
if not lastraking then return end
if not (node and node.name and rakable[node.name]) then return end
if not user:is_player() then return end
local pname = user:get_player_name()
if rakelock[pname] then return end
rakelock[pname] = true
dorake(pos, node, user, ...)
rakelock[pname] = nil
lastraking = nil
end)
local adze = {name = modname .. ":adze", wear = 0.05}
nodecore.register_craft({
label = "assemble rake",
norotate = true,
rootmatch = {"nc_tree:stick"},
nodes = {
{match = "nc_tree:stick", replace = "air"},
{x = 0, z = -1, match = adze, replace = "air"},
{x = 0, z = 1, match = adze, replace = "air"},
{x = -1, z = 0, match = adze, replace = "air"},
{x = 1, z = 0, match = adze, replace = "air"},
},
items = {
modname .. ":rake"
}
})