Skip to content

Commit

Permalink
Add an item pick up callback (2) (minetest#7712)
Browse files Browse the repository at this point in the history
Co-authored-by: SmallJoker <[email protected]>
Co-authored-by: Jude Melton-Houghton <[email protected]>
  • Loading branch information
3 people committed Oct 1, 2022
1 parent 977f656 commit 22cbc05
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 13 deletions.
9 changes: 8 additions & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ https://www.apache.org/licenses/LICENSE-2.0.html
Textures by Zughy are under CC BY-SA 4.0
https://creativecommons.org/licenses/by-sa/4.0/

Media files by DS are under CC BY-SA 4.0
https://creativecommons.org/licenses/by-sa/4.0/

textures/base/pack/server_public.png is under CC-BY 4.0, taken from Twitter's Twemoji set
https://creativecommons.org/licenses/by/4.0/

Expand Down Expand Up @@ -62,7 +65,7 @@ Zughy:

appgurueu:
textures/base/pack/server_incompatible.png

erlehmann, Warr1024, rollerozxa:
textures/base/pack/no_screenshot.png

Expand All @@ -73,6 +76,10 @@ SmallJoker:
textures/base/pack/cdb_clear.png
textures/base/pack/server_favorite_delete.png (based on server_favorite.png)

DS:
games/devtest/mods/testitems/textures/testitems_callback_1.png
games/devtest/mods/testitems/textures/testitems_callback_2.png

License of Minetest source code
-------------------------------

Expand Down
26 changes: 24 additions & 2 deletions builtin/game/item.lua
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,26 @@ function core.item_drop(itemstack, dropper, pos)
-- environment failed
end

function core.item_pickup(itemstack, picker, pointed_thing, ...)
itemstack = ItemStack(itemstack)
-- Invoke global on_item_pickup callbacks.
for _, callback in ipairs(core.registered_on_item_pickups) do
local result = callback(itemstack, picker, pointed_thing, ...)
if result then
return ItemStack(result)
end
end

-- Pickup item.
local inv = picker and picker:get_inventory()
if inv then
return inv:add_item("main", itemstack)
end
return itemstack
end

function core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
for _, callback in pairs(core.registered_on_item_eats) do
for _, callback in ipairs(core.registered_on_item_eats) do
local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing)
if result then
return result
Expand Down Expand Up @@ -589,6 +607,7 @@ core.nodedef_default = {
-- Interaction callbacks
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
on_pickup = redef_wrapper(core, 'item_pickup'), -- core.item_pickup
on_use = nil,
can_dig = nil,

Expand Down Expand Up @@ -641,6 +660,7 @@ core.craftitemdef_default = {
-- Interaction callbacks
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
on_pickup = redef_wrapper(core, 'item_pickup'), -- core.item_pickup
on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
on_use = nil,
}
Expand All @@ -661,6 +681,7 @@ core.tooldef_default = {
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
on_drop = redef_wrapper(core, 'item_drop'), -- core.item_drop
on_pickup = redef_wrapper(core, 'item_pickup'), -- core.item_pickup
on_use = nil,
}

Expand All @@ -677,8 +698,9 @@ core.noneitemdef_default = { -- This is used for the hand and unknown items
tool_capabilities = nil,

-- Interaction callbacks
on_place = redef_wrapper(core, 'item_place'),
on_place = redef_wrapper(core, 'item_place'), -- core.item_place
on_secondary_use = redef_wrapper(core, 'item_secondary_use'),
on_pickup = redef_wrapper(core, 'item_pickup'), -- core.item_pickup
on_drop = nil,
on_use = nil,
}
33 changes: 23 additions & 10 deletions builtin/game/item_entity.lua
Original file line number Diff line number Diff line change
Expand Up @@ -318,16 +318,29 @@ core.register_entity(":__builtin:item", {
end
end,

on_punch = function(self, hitter)
local inv = hitter:get_inventory()
if inv and self.itemstring ~= "" then
local left = inv:add_item("main", self.itemstring)
if left and not left:is_empty() then
self:set_item(left)
return
end
on_punch = function(self, hitter, ...)
if self.itemstring == "" then
self.object:remove()
return
end

-- Call on_pickup callback in item definition.
local itemstack = ItemStack(self.itemstring)
local callback = itemstack:get_definition().on_pickup

local ret = callback(itemstack, hitter, {type = "object", ref = self.object}, ...)
if not ret then
-- Don't modify (and don't reset rotation)
return
end
itemstack = ItemStack(ret)

-- Handle the leftover itemstack
if itemstack:is_empty() then
self.itemstring = ""
self.object:remove()
else
self:set_item(itemstack)
end
self.itemstring = ""
self.object:remove()
end,
})
1 change: 1 addition & 0 deletions builtin/game/register.lua
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,7 @@ core.registered_on_crafts, core.register_on_craft = make_registration()
core.registered_craft_predicts, core.register_craft_predict = make_registration()
core.registered_on_protection_violation, core.register_on_protection_violation = make_registration()
core.registered_on_item_eats, core.register_on_item_eat = make_registration()
core.registered_on_item_pickups, core.register_on_item_pickup = make_registration()
core.registered_on_punchplayers, core.register_on_punchplayer = make_registration()
core.registered_on_priv_grant, core.register_on_priv_grant = make_registration()
core.registered_on_priv_revoke, core.register_on_priv_revoke = make_registration()
Expand Down
25 changes: 25 additions & 0 deletions doc/lua_api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5318,6 +5318,13 @@ Call these functions only at load time!
* `minetest.register_on_item_eat(function(hp_change, replace_with_item, itemstack, user, pointed_thing))`
* Called when an item is eaten, by `minetest.item_eat`
* Return `itemstack` to cancel the default item eat response (i.e.: hp increase).
* `minetest.register_on_item_pickup(function(itemstack, picker, pointed_thing, time_from_last_punch, ...))`
* Called by `minetest.item_pickup` before an item is picked up.
* Function is added to `minetest.registered_on_item_pickups`.
* Oldest functions are called first.
* Parameters are the same as in the `on_pickup` callback.
* Return an itemstack to cancel the default item pick-up response (i.e.: adding
the item into inventory).
* `minetest.register_on_priv_grant(function(name, granter, priv))`
* Called when `granter` grants the priv `priv` to `name`.
* Note that the callback will be called twice if it's done by a player,
Expand Down Expand Up @@ -5964,6 +5971,11 @@ Defaults for the `on_place` and `on_drop` item definition functions
* `param2` overrides facedir and wallmounted `param2`
* returns `itemstack, position`
* `position`: the location the node was placed to. `nil` if nothing was placed.
* `minetest.item_pickup(itemstack, picker, pointed_thing, time_from_last_punch, ...)`
* Runs callbacks registered by `minetest.register_on_item_pickup` and adds
the item to the picker's `"main"` inventory list.
* Parameters are the same as in `on_pickup`.
* Returns the leftover itemstack.
* `minetest.item_drop(itemstack, dropper, pos)`
* Drop the item
* returns the leftover itemstack
Expand Down Expand Up @@ -8074,6 +8086,19 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and
-- The dropper may be any ObjectRef or nil.
-- default: minetest.item_drop

on_pickup = function(itemstack, picker, pointed_thing, time_from_last_punch, ...),
-- Called when a dropped item is punched by a player.
-- Shall pick-up the item and return the leftover itemstack or nil to not
-- modify the dropped item.
-- Parameters:
-- * `itemstack`: The `ItemStack` to be picked up.
-- * `picker`: Any `ObjectRef` or `nil`.
-- * `pointed_thing` (optional): The dropped item (a `"__builtin:item"`
-- luaentity) as `type="object"` `pointed_thing`.
-- * `time_from_last_punch, ...` (optional): Other parameters from
-- `luaentity:on_punch`.
-- default: `minetest.item_pickup`

on_use = function(itemstack, user, pointed_thing),
-- default: nil
-- When user pressed the 'punch/mine' key with the item in hand.
Expand Down
108 changes: 108 additions & 0 deletions games/devtest/mods/testitems/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,111 @@ minetest.register_craftitem("testitems:overlay_global", {
})


--
-- Item callbacks
--

minetest.register_craftitem("testitems:callback_1", {
description = "Callback test item 1\n(Use/Drop + Sneak to switch to item 2)",
inventory_image = "testitems_callback_1.png",
wield_image = "testitems_callback_1.png",

on_secondary_use = function(itemstack, user, pointed_thing)
minetest.log("[testitems:callback_1 on_secondary_use] " .. itemstack:get_name())
local ctrl = user and user:get_player_control() or {}
if ctrl.sneak then
itemstack = ItemStack(itemstack)
itemstack:set_name("testitems:callback_2")
return itemstack
end
end,

on_drop = function(itemstack, dropper, pos)
minetest.log("[testitems:callback_1 on_drop] " .. itemstack:get_name())
local ctrl = dropper and dropper:get_player_control() or {}
if ctrl.sneak then
itemstack = ItemStack(itemstack)
itemstack:set_name("testitems:callback_2")
end

return minetest.item_drop(itemstack, dropper, pos)
end,

on_pickup = function(itemstack, picker, pointed_thing, ...)
minetest.log("[testitems:callback_1 on_pickup]")
assert(pointed_thing.ref:get_luaentity().name == "__builtin:item")
local ctrl = picker and picker:get_player_control() or {}
if ctrl.aux1 then
-- Debug message
minetest.log(dump({...}))
end
if ctrl.sneak then
-- Pick up one item of the other kind at once
local taken = itemstack:take_item()
taken:set_name("testitems:callback_2")
local leftover = minetest.item_pickup(taken, picker, pointed_thing, ...)
leftover:set_name("testitems:callback_1")
itemstack:add_item(leftover)
return itemstack
elseif ctrl.up then
-- Don't pick up
return
elseif ctrl.left then
-- Eat it
return minetest.do_item_eat(2, nil, itemstack, picker, pointed_thing)
else
-- Normal: pick up everything
return minetest.item_pickup(itemstack, picker, pointed_thing, ...)
end
end,

on_use = function(itemstack, user, pointed_thing)
minetest.log("[testitems:callback_1 on_use] " .. itemstack:get_name())
local ctrl = user and user:get_player_control() or {}
if ctrl.sneak then
itemstack = ItemStack(itemstack)
itemstack:set_name("testitems:callback_2")
return itemstack
end
end,

after_use = function(itemstack, user, node, digparams) -- never called
minetest.log("[testitems:callback_1 after_use]")
local ctrl = user and user:get_player_control() or {}
if ctrl.up then
itemstack = ItemStack(itemstack)
itemstack:set_name("testitems:callback_2")
return itemstack
end
end,
})

minetest.register_craftitem("testitems:callback_2", {
description = "Callback test item 2\n(Use to switch to item 1)",
inventory_image = "testitems_callback_2.png",
wield_image = "testitems_callback_2.png",

on_use = function(itemstack, user, pointed_thing)
minetest.log("[testitems:callback_2 on_use]")
itemstack = ItemStack(itemstack)
itemstack:set_name("testitems:callback_1")
return itemstack
end,
})

minetest.register_on_item_pickup(function(itemstack, picker, pointed_thing, time_from_last_punch, ...)
assert(not pointed_thing or pointed_thing.ref:get_luaentity().name == "__builtin:item")

local item_name = itemstack:get_name()
if item_name ~= "testitems:callback_1" and item_name ~= "testitems:callback_2" then
return
end
minetest.log("["..item_name.." register_on_item_pickup]")

local ctrl = picker and picker:get_player_control() or {}
if item_name == "testitems:callback_2" and not ctrl.sneak then
-- Same here. Pick up the other item type.
itemstack:set_name("testitems:callback_1")
return picker:get_inventory():add_item("main", itemstack)
end
end)
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 22cbc05

Please sign in to comment.