Aaron Suen 8bfdc211a3 Convert some action logs to info
We were using action log level for a lot of
things because by default MT does not seem
to capture info logs to stderr.  On "production"
servers though this makes too much noise and
makes it hard to find actual player actions.
Servers that want info logging will just have
to configure/compile it in.
2021-12-11 21:26:18 -05:00

243 lines
6.9 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local ItemStack, error, ipairs, math, minetest, nodecore, pairs, type
= ItemStack, error, ipairs, math, minetest, nodecore, pairs, type
local math_random
= math.random
-- LUALOCALS > ---------------------------------------------------------
local function addgroups(sum, pos)
local node = minetest.get_node(pos)
local def = minetest.registered_items[node.name] or {}
if not def.groups then return end
for k, v in pairs(def.groups) do
sum[k] = (sum[k] or 0) + v
end
end
local function craftcheck(recipe, pos, node, data, xx, xz, zx, zz)
local function rel(x, y, z)
return {
x = pos.x + xx * x + zx * z,
y = pos.y + y,
z = pos.z + xz * x + zz * z
}
end
data.rel = rel
data.wield = ItemStack(data.wield or data.crafter and data.crafter:get_wielded_item())
if recipe.check and not recipe.check(pos, data) then return end
if recipe.wield and (not data.wield or not nodecore.match(
{stack = data.wield}, recipe.wield)) then return end
if recipe.normal then
if data.pointed.type ~= "node" or
recipe.normal.y ~= data.pointed.above.y - data.pointed.under.y then return end
local rx = recipe.normal.x * xx + recipe.normal.z * zx
if rx ~= data.pointed.above.x - data.pointed.under.x then return end
local rz = recipe.normal.x * xz + recipe.normal.z * zz
if rz ~= data.pointed.above.z - data.pointed.under.z then return end
end
for _, v in pairs(recipe.nodes) do
if v ~= recipe.root and v.match then
local p = rel(v.x, v.y, v.z)
if not nodecore.match(p, v.match) then return end
end
end
if recipe.touchgroups then
local sum = {}
addgroups(sum, rel(1, 0, 0))
addgroups(sum, rel(-1, 0, 0))
addgroups(sum, rel(0, 1, 0))
addgroups(sum, rel(0, -1, 0))
addgroups(sum, rel(0, 0, 1))
addgroups(sum, rel(0, 0, -1))
if data.touchgroupmodify then
data.touchgroupmodify(sum)
end
for k, v in pairs(recipe.touchgroups) do
local w = sum[k] or 0
if v > 0 and w < v then return end
if v <= 0 and w > -v then return end
end
end
local mindur = recipe.duration or 0
if type(mindur) == "function" then mindur = mindur(recipe, pos, node, data) end
if recipe.toolgroups then
local dg = data.toolgroupcaps or (data.wield
and data.wield:get_tool_capabilities().groupcaps)
if not dg then return end
local t
for gn, lv in pairs(recipe.toolgroups) do
local gt = dg[gn]
gt = gt and gt.times
gt = gt and gt[lv]
if gt and (gt <= 4) and (not t or t > gt) then t = gt end
end
if not t then return end
mindur = mindur + t
end
mindur = mindur / recipe.rate_adjust
if mindur > 0 then
if not data.duration then return end
local dur = data.duration
if type(dur) == "function" then dur = dur(pos, data) end
if not dur or dur < mindur then
if data.inprogress then data.inprogress(pos, data) end
return false
end
end
return function()
if data.before then data.before(pos, data) end
if recipe.before then recipe.before(pos, data) end
for _, v in ipairs(recipe.nodes) do
if v.replace and ((not v.chance)
or (math_random(1, v.chance) == 1)) then
local p = rel(v.x, v.y, v.z)
local r = v.replace
while type(r) == "function" do
r = r(p, v)
end
if r and type(r) == "string" then
r = {name = r}
end
if v.match.excess then
local s = nodecore.stack_get(p)
local x = s:get_count() - (v.match.count or 1)
if x > 0 then
s:set_count(x)
nodecore.item_eject(p, s)
end
nodecore.stack_set(p, ItemStack(""))
end
if r then
local n = minetest.get_node(p)
r.param2 = n.param2
nodecore.set_loud(p, r)
nodecore.fallcheck(p)
end
end
if v.dig then
local p = rel(v.x, v.y, v.z)
minetest.node_dig(p, minetest.get_node(p))
end
end
if recipe.items then
for _, v in pairs(recipe.items) do
nodecore.item_eject(rel(v.x or 0, v.y or 0, v.z or 0),
v.name, v.scatter, v.count, v.velocity)
end
end
if recipe.consumewield then
nodecore.consume_wield(data.crafter, recipe.consumewield)
elseif recipe.toolgroups and recipe.toolwear and data.crafter then
nodecore.wear_wield(data.crafter, recipe.toolgroups, recipe.toolwear)
end
if recipe.after then recipe.after(pos, data) end
if data.after then data.after(pos, data) end
local discover = {recipe.action, recipe.label, data.discover, recipe.discover}
nodecore.player_discover(data.crafter, discover, "craft:")
if data.witness or recipe.witness then nodecore.witness(pos, discover) end
local pname = data.crafter and data.crafter:get_player_name()
nodecore.log(pname and "action" or "info", (pname or "unknown")
.. " completed recipe \"" .. recipe.label .. "\" at " ..
minetest.pos_to_string(pos) .. " upon " .. node.name)
end
end
local function tryall(rc, pos, node, data)
local function go(xx, xz, zx, zz)
return craftcheck(rc, pos, node, data, xx, xz, zx, zz)
end
local r = go(1, 0, 0, 1)
if r then return r end
if not rc.norotate then
r = go(0, -1, 1, 0)
or go(-1, 0, 0, -1)
or go(0, 1, -1, 0)
if r then return r end
if not rc.nomirror then
r = go(-1, 0, 0, 1)
or go(0, 1, 1, 0)
or go(1, 0, 0, -1)
or go(0, -1, -1, 0)
end
end
return r
end
local craftidx, rebuildidx = nodecore.item_matching_index(
nodecore.registered_recipes,
function(i) return i.indexkeys or {true} end,
"register_craft",
true,
function(n, i) return i.action .. "|" .. n end
)
do
local oldreg = nodecore.register_craft
local function rebuildhelper(...)
rebuildidx()
return ...
end
function nodecore.register_craft(...)
return rebuildhelper(oldreg(...))
end
end
local function checkall(pos, node, data, set)
for _, rc in ipairs(set) do
if data.action == rc.action
and nodecore.match(node, rc.root.match) then
data.recipe = rc
if data.rootmatch then data.rootmatch(data) end
local r = tryall(rc, pos, node, data)
if r == false then return end
if r then return r end
end
end
end
function nodecore.craft_search(pos, node, data)
if not data or not data.action then
return error("craft_check without data.action")
end
node.x = pos.x
node.y = pos.y
node.z = pos.z
data.pos = pos
data.node = node
local seen = {}
if node and node.name then
local key = data.action .. "|" .. node.name
local set = craftidx[key]
if set then
local found = checkall(pos, node, data, set)
if found then return found end
for _, i in pairs(set) do seen[i] = true end
end
end
local stack = pos and nodecore.stack_get(pos)
if not stack:is_empty() then
local key = data.action .. "|" .. stack:get_name()
local set = craftidx[key]
if set then
local unique = {}
for _, i in ipairs(set) do
if not seen[i] then unique[#unique + 1] = i end
end
if #unique > 0 then
local found = checkall(pos, node, data, unique)
if found then return found end
end
end
end
end
function nodecore.craft_check(...)
local commit = nodecore.craft_search(...)
if not commit then return end
commit()
return true
end