Fix default item callbacks to work with nil users (#5819)

* Fix default item callbacks to work with nil users

* item.lua: Handle node drops for invalid players

The if-condition for the dropping loop is the same as `inv`, which means that the 2nd possible definition of `give_item` is never used.
Remove redundant `local _, dropped_item`
This commit is contained in:
raymoo 2017-10-28 01:30:50 -07:00 committed by Loïc Blot
parent 2efccb3536
commit a5d5728f24
4 changed files with 97 additions and 62 deletions

@ -667,8 +667,8 @@ core.register_chatcommand("pulverize", {
core.rollback_punch_callbacks = {} core.rollback_punch_callbacks = {}
core.register_on_punchnode(function(pos, node, puncher) core.register_on_punchnode(function(pos, node, puncher)
local name = puncher:get_player_name() local name = puncher and puncher:get_player_name()
if core.rollback_punch_callbacks[name] then if name and core.rollback_punch_callbacks[name] then
core.rollback_punch_callbacks[name](pos, node, puncher) core.rollback_punch_callbacks[name](pos, node, puncher)
core.rollback_punch_callbacks[name] = nil core.rollback_punch_callbacks[name] = nil
end end

@ -215,6 +215,8 @@ function core.get_node_drops(node, toolname)
end end
if item.tools ~= nil then if item.tools ~= nil then
good_tool = false good_tool = false
end
if item.tools ~= nil and toolname then
for _, tool in ipairs(item.tools) do for _, tool in ipairs(item.tools) do
if tool:sub(1, 1) == '~' then if tool:sub(1, 1) == '~' then
good_tool = toolname:find(tool:sub(2)) ~= nil good_tool = toolname:find(tool:sub(2)) ~= nil
@ -225,7 +227,7 @@ function core.get_node_drops(node, toolname)
break break
end end
end end
end end
if good_rarity and good_tool then if good_rarity and good_tool then
got_count = got_count + 1 got_count = got_count + 1
for _, add_item in ipairs(item.items) do for _, add_item in ipairs(item.items) do
@ -245,6 +247,20 @@ function core.get_node_drops(node, toolname)
return got_items return got_items
end end
local function user_name(user)
return user and user:get_player_name() or ""
end
local function is_protected(pos, name)
return core.is_protected(pos, name) and
not minetest.check_player_privs(name, "protection_bypass")
end
-- Returns a logging function. For empty names, does not log.
local function make_log(name)
return name ~= "" and core.log or function() end
end
function core.item_place_node(itemstack, placer, pointed_thing, param2) function core.item_place_node(itemstack, placer, pointed_thing, param2)
local def = itemstack:get_definition() local def = itemstack:get_definition()
if def.type ~= "node" or pointed_thing.type ~= "node" then if def.type ~= "node" or pointed_thing.type ~= "node" then
@ -255,10 +271,11 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
local oldnode_under = core.get_node_or_nil(under) local oldnode_under = core.get_node_or_nil(under)
local above = pointed_thing.above local above = pointed_thing.above
local oldnode_above = core.get_node_or_nil(above) local oldnode_above = core.get_node_or_nil(above)
local playername = placer:get_player_name() local playername = user_name(placer)
local log = make_log(playername)
if not oldnode_under or not oldnode_above then if not oldnode_under or not oldnode_above then
core.log("info", playername .. " tried to place" log("info", playername .. " tried to place"
.. " node in unloaded position " .. core.pos_to_string(above)) .. " node in unloaded position " .. core.pos_to_string(above))
return itemstack, false return itemstack, false
end end
@ -269,7 +286,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
olddef_above = olddef_above or core.nodedef_default olddef_above = olddef_above or core.nodedef_default
if not olddef_above.buildable_to and not olddef_under.buildable_to then if not olddef_above.buildable_to and not olddef_under.buildable_to then
core.log("info", playername .. " tried to place" log("info", playername .. " tried to place"
.. " node in invalid position " .. core.pos_to_string(above) .. " node in invalid position " .. core.pos_to_string(above)
.. ", replacing " .. oldnode_above.name) .. ", replacing " .. oldnode_above.name)
return itemstack, false return itemstack, false
@ -280,13 +297,12 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
-- If node under is buildable_to, place into it instead (eg. snow) -- If node under is buildable_to, place into it instead (eg. snow)
if olddef_under.buildable_to then if olddef_under.buildable_to then
core.log("info", "node under is buildable to") log("info", "node under is buildable to")
place_to = {x = under.x, y = under.y, z = under.z} place_to = {x = under.x, y = under.y, z = under.z}
end end
if core.is_protected(place_to, playername) and if is_protected(place_to, playername) then
not minetest.check_player_privs(placer, "protection_bypass") then log("action", playername
core.log("action", playername
.. " tried to place " .. def.name .. " tried to place " .. def.name
.. " at protected position " .. " at protected position "
.. core.pos_to_string(place_to)) .. core.pos_to_string(place_to))
@ -294,7 +310,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
return itemstack return itemstack
end end
core.log("action", playername .. " places node " log("action", playername .. " places node "
.. def.name .. " at " .. core.pos_to_string(place_to)) .. def.name .. " at " .. core.pos_to_string(place_to))
local oldnode = core.get_node(place_to) local oldnode = core.get_node(place_to)
@ -314,7 +330,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
-- Calculate the direction for furnaces and chests and stuff -- Calculate the direction for furnaces and chests and stuff
elseif (def.paramtype2 == "facedir" or elseif (def.paramtype2 == "facedir" or
def.paramtype2 == "colorfacedir") and not param2 then def.paramtype2 == "colorfacedir") and not param2 then
local placer_pos = placer:getpos() local placer_pos = placer and placer:getpos()
if placer_pos then if placer_pos then
local dir = { local dir = {
x = above.x - placer_pos.x, x = above.x - placer_pos.x,
@ -322,7 +338,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
z = above.z - placer_pos.z z = above.z - placer_pos.z
} }
newnode.param2 = core.dir_to_facedir(dir) newnode.param2 = core.dir_to_facedir(dir)
core.log("action", "facedir: " .. newnode.param2) log("action", "facedir: " .. newnode.param2)
end end
end end
@ -348,7 +364,7 @@ function core.item_place_node(itemstack, placer, pointed_thing, param2)
-- Check if the node is attached and if it can be placed there -- Check if the node is attached and if it can be placed there
if core.get_item_group(def.name, "attached_node") ~= 0 and if core.get_item_group(def.name, "attached_node") ~= 0 and
not builtin_shared.check_attached_node(place_to, newnode) then not builtin_shared.check_attached_node(place_to, newnode) then
core.log("action", "attached node " .. def.name .. log("action", "attached node " .. def.name ..
" can not be placed at " .. core.pos_to_string(place_to)) " can not be placed at " .. core.pos_to_string(place_to))
return itemstack, false return itemstack, false
end end
@ -419,25 +435,24 @@ function core.item_secondary_use(itemstack, placer)
end end
function core.item_drop(itemstack, dropper, pos) function core.item_drop(itemstack, dropper, pos)
if dropper and dropper:is_player() then local dropper_is_player = dropper and dropper:is_player()
local dir = dropper:get_look_dir() local p = table.copy(pos)
local p = {x = pos.x, y = pos.y + 1.2, z = pos.z} local cnt = itemstack:get_count()
local cnt = itemstack:get_count() if dropper_is_player then
local item = itemstack:take_item(cnt) p.y = p.y + 1.2
local obj = core.add_item(p, item) end
if obj then local item = itemstack:take_item(cnt)
local obj = core.add_item(p, item)
if obj then
if dropper_is_player then
local dir = dropper:get_look_dir()
dir.x = dir.x * 2.9 dir.x = dir.x * 2.9
dir.y = dir.y * 2.9 + 2 dir.y = dir.y * 2.9 + 2
dir.z = dir.z * 2.9 dir.z = dir.z * 2.9
obj:set_velocity(dir) obj:set_velocity(dir)
obj:get_luaentity().dropped_by = dropper:get_player_name() obj:get_luaentity().dropped_by = dropper:get_player_name()
return itemstack
end
else
if core.add_item(pos, itemstack) then
return itemstack
end end
return itemstack
end end
-- If we reach this, adding the object to the -- If we reach this, adding the object to the
-- environment failed -- environment failed
@ -458,7 +473,8 @@ function core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed
itemstack:add_item(replace_with_item) itemstack:add_item(replace_with_item)
else else
local inv = user:get_inventory() local inv = user:get_inventory()
if inv:room_for_item("main", {name=replace_with_item}) then -- Check if inv is null, since non-players don't have one
if inv and inv:room_for_item("main", {name=replace_with_item}) then
inv:add_item("main", replace_with_item) inv:add_item("main", replace_with_item)
else else
local pos = user:getpos() local pos = user:getpos()
@ -473,7 +489,9 @@ end
function core.item_eat(hp_change, replace_with_item) function core.item_eat(hp_change, replace_with_item)
return function(itemstack, user, pointed_thing) -- closure return function(itemstack, user, pointed_thing) -- closure
return core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing) if user then
return core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
end
end end
end end
@ -490,63 +508,75 @@ end
function core.handle_node_drops(pos, drops, digger) function core.handle_node_drops(pos, drops, digger)
-- Add dropped items to object's inventory -- Add dropped items to object's inventory
if digger:get_inventory() then local inv = digger and digger:get_inventory()
local _, dropped_item local give_item
for _, dropped_item in ipairs(drops) do if inv then
local left = digger:get_inventory():add_item("main", dropped_item) give_item = function(item)
if not left:is_empty() then return inv:add_item("main", item)
local p = { end
x = pos.x + math.random()/2-0.25, else
y = pos.y + math.random()/2-0.25, give_item = function(item)
z = pos.z + math.random()/2-0.25, return item
} end
core.add_item(p, left) end
end
for _, dropped_item in pairs(drops) do
local left = give_item(dropped_item)
if not left:is_empty() then
local p = {
x = pos.x + math.random()/2-0.25,
y = pos.y + math.random()/2-0.25,
z = pos.z + math.random()/2-0.25,
}
core.add_item(p, left)
end end
end end
end end
function core.node_dig(pos, node, digger) function core.node_dig(pos, node, digger)
local diggername = user_name(digger)
local log = make_log(diggername)
local def = core.registered_nodes[node.name] local def = core.registered_nodes[node.name]
if def and (not def.diggable or if def and (not def.diggable or
(def.can_dig and not def.can_dig(pos, digger))) then (def.can_dig and not def.can_dig(pos, digger))) then
core.log("info", digger:get_player_name() .. " tried to dig " log("info", diggername .. " tried to dig "
.. node.name .. " which is not diggable " .. node.name .. " which is not diggable "
.. core.pos_to_string(pos)) .. core.pos_to_string(pos))
return return
end end
if core.is_protected(pos, digger:get_player_name()) and if is_protected(pos, diggername) then
not minetest.check_player_privs(digger, "protection_bypass") then log("action", diggername
core.log("action", digger:get_player_name()
.. " tried to dig " .. node.name .. " tried to dig " .. node.name
.. " at protected position " .. " at protected position "
.. core.pos_to_string(pos)) .. core.pos_to_string(pos))
core.record_protection_violation(pos, digger:get_player_name()) core.record_protection_violation(pos, diggername)
return return
end end
core.log('action', digger:get_player_name() .. " digs " log('action', diggername .. " digs "
.. node.name .. " at " .. core.pos_to_string(pos)) .. node.name .. " at " .. core.pos_to_string(pos))
local wielded = digger:get_wielded_item() local wielded = digger and digger:get_wielded_item()
local drops = core.get_node_drops(node, wielded:get_name()) local drops = core.get_node_drops(node, wielded and wielded:get_name())
local wdef = wielded:get_definition() if wielded then
local tp = wielded:get_tool_capabilities() local wdef = wielded:get_definition()
local dp = core.get_dig_params(def and def.groups, tp) local tp = wielded:get_tool_capabilities()
if wdef and wdef.after_use then local dp = core.get_dig_params(def and def.groups, tp)
wielded = wdef.after_use(wielded, digger, node, dp) or wielded if wdef and wdef.after_use then
else wielded = wdef.after_use(wielded, digger, node, dp) or wielded
-- Wear out tool else
if not core.settings:get_bool("creative_mode") then -- Wear out tool
wielded:add_wear(dp.wear) if not core.settings:get_bool("creative_mode") then
if wielded:get_count() == 0 and wdef.sound and wdef.sound.breaks then wielded:add_wear(dp.wear)
core.sound_play(wdef.sound.breaks, {pos = pos, gain = 0.5}) if wielded:get_count() == 0 and wdef.sound and wdef.sound.breaks then
core.sound_play(wdef.sound.breaks, {pos = pos, gain = 0.5})
end
end end
end end
digger:set_wielded_item(wielded)
end end
digger:set_wielded_item(wielded)
-- Handle drops -- Handle drops
core.handle_node_drops(pos, drops, digger) core.handle_node_drops(pos, drops, digger)

@ -2444,6 +2444,7 @@ Call these functions only at load time!
* `minetest.register_on_placenode(func(pos, newnode, placer, oldnode, itemstack, pointed_thing))` * `minetest.register_on_placenode(func(pos, newnode, placer, oldnode, itemstack, pointed_thing))`
* Called when a node has been placed * Called when a node has been placed
* If return `true` no item is taken from `itemstack` * If return `true` no item is taken from `itemstack`
* `placer` may be any valid ObjectRef or nil.
* **Not recommended**; use `on_construct` or `after_place_node` in node definition * **Not recommended**; use `on_construct` or `after_place_node` in node definition
whenever possible whenever possible
* `minetest.register_on_dignode(func(pos, oldnode, digger))` * `minetest.register_on_dignode(func(pos, oldnode, digger))`
@ -3219,6 +3220,7 @@ These functions return the leftover itemstack.
* Returns true, if player `name` shouldn't be abled to dig at `pos` or do other * Returns true, if player `name` shouldn't be abled to dig at `pos` or do other
actions, defineable by mods, due to some mod-defined ownership-like concept. actions, defineable by mods, due to some mod-defined ownership-like concept.
Returns false or nil, if the player is allowed to do such actions. Returns false or nil, if the player is allowed to do such actions.
* `name` will be "" for non-players or unknown players.
* This function should be overridden by protection mods and should be used to * This function should be overridden by protection mods and should be used to
check if a player can interact at a position. check if a player can interact at a position.
* This function should call the old version of itself if the position is not * This function should call the old version of itself if the position is not
@ -4608,6 +4610,7 @@ Definition tables
^ Called after constructing node when node was placed using ^ Called after constructing node when node was placed using
minetest.item_place_node / minetest.place_node minetest.item_place_node / minetest.place_node
^ If return true no item is taken from itemstack ^ If return true no item is taken from itemstack
^ `placer` may be any valid ObjectRef or nil
^ default: nil ]] ^ default: nil ]]
after_dig_node = func(pos, oldnode, oldmetadata, digger), --[[ after_dig_node = func(pos, oldnode, oldmetadata, digger), --[[
^ oldmetadata is in table format ^ oldmetadata is in table format

@ -1270,7 +1270,9 @@ minetest.register_node("default:chest_locked", {
sounds = default.node_sound_wood_defaults(), sounds = default.node_sound_wood_defaults(),
after_place_node = function(pos, placer) after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name() or "") local pname =
placer and placer:get_player_name() or ""
meta:set_string("owner", pname)
meta:set_string("infotext", "Locked Chest (owned by ".. meta:set_string("infotext", "Locked Chest (owned by "..
meta:get_string("owner")..")") meta:get_string("owner")..")")
end, end,