Item Callbacks: Add chapter

This commit is contained in:
rubenwardy 2022-07-31 20:10:04 +01:00
parent bc8820c4b6
commit f8c9da8261
5 changed files with 258 additions and 72 deletions

207
_en/items/callbacks.md Normal file
View File

@ -0,0 +1,207 @@
---
title: Node and Item Callbacks
layout: default
root: ../..
idx: 2.15
description: Learn how to register node, items, and craft recipes using register_node, register_item, and register_craft.
redirect_from: /en/chapters/nodes_items_crafting.html
---
## Introduction <!-- omit in toc -->
Minetest heavily uses a callback-based modding design. A callback is a function
that you give to an API and is called when an event happens. For example, you
can provide an `on_punch` function in a node definition to be called when a player
punches a node. There are also global callbacks like
`minetest.register_on_punchnode` to receive events for all nodes.
- [Item Callbacks](#item-callbacks)
- [on_use](#on_use)
- [on_place and on_secondary_use](#on_place-and-on_secondary_use)
- [on_drop](#on_drop)
- [after_use](#after_use)
- [item_place vs place_item](#item_place-vs-place_item)
- [Node Callbacks](#node-callbacks)
- [Right-clicking and placing a node](#right-clicking-and-placing-a-node)
- [Punching and digging](#punching-and-digging)
- [...and more!](#and-more)
## Item Callbacks
When a player has a node, craftitem, or tool in their inventory, they may trigger
certain events:
| Callback | Default binding | Default value |
|------------------|---------------------------|----------------------------------------------|
| on_use | left-click | nil |
| on_place | right-click on a node | `minetest.item_place` |
| on_secondary_use | right-click not on a node | `minetest.item_secondary_use` (does nothing) |
| on_drop | Q | `minetest.item_drop` |
| after_use | digging a node | nil |
### on_use
Having a use callback prevents the item from being used to dig nodes. One common
use of the use callback is for food:
```lua
minetest.register_craftitem("mymod:mudpie", {
description = "Alien Mud Pie",
inventory_image = "myfood_mudpie.png",
on_use = minetest.item_eat(20),
})
```
The number supplied to the minetest.item_eat function is the number of hit
points healed when this food is consumed. Each heart icon the player has is
worth two hitpoints. A player can usually have up to 10 hearts, which is equal
to 20 hitpoints.
minetest.item_eat() is a function that returns a function, setting it as the
on_use callback. This means the code above is equivalent to this:
```lua
minetest.register_craftitem("mymod:mudpie", {
description = "Alien Mud Pie",
inventory_image = "myfood_mudpie.png",
on_use = function(...)
return minetest.do_item_eat(20, nil, ...)
end,
})
```
By understanding how item_eat works by simply returning a function, it's
possible to modify it to do more complex behaviour like playing a custom sound.
### on_place and on_secondary_use
The difference between `on_place` and `on_secondary_use` is that `on_place` is
called when the player is pointing at a node and `on_secondary_use` when the
player isn't.
Both callbacks are called for all types of items. `on_place` defaults to the
`minetest.item_place` function, which handles calling the `on_rightclick`
callback of the pointed node or placing the wielded item if it is a node.
### on_drop
on_drop is called when the player requests to drop an item, for example using
the drop key (Q) or dragging it outside of the inventory. It defaults to the
`minetest.item_drop` function, which will handle dropping the item.
### after_use
`after_use` is called when digging a node and allows you to customise how wear
is applied to a tool. If after_use doesn't exist, then it is the same as:
```lua
after_use = function(itemstack, user, node, digparams)
itemstack:add_wear(digparams.wear)
return itemstack
end
```
## item_place vs place_item
Minetest's API includes many different built-in callback implementations for you
to use. These callbacks are named with the item type first, for example,
`minetest.item_place` and `minetest.node_dig`. Some callback implementations are
used directly whereas some are functions that return the callback:
```lua
minetest.register_item("mymod:example", {
on_place = minetest.item_place,
on_use = minetest.item_eat(10),
})
```
Minetest's API also includes built-in functions that _do_ something. These are
often named in a confusingly similar way to built-in callback implementations
but have the verb first. Examples include `minetest.place_item` and
`minetest.dig_node` - these functions allow you to dig and place nodes with a
similar effect to players.
## Node Callbacks
When a node is in an inventory, it uses Item Callbacks, as discussed above. When
a node is placed in the world, it uses Node Callbacks. There are quite a lot of
node callbacks, too many to discuss in this book. However, quite a few of them
will be talked about later in the book.
Several of the callbacks are related to node operations such as placing and
removing from the world. It's important to note that node operation callbacks
like these aren't called from bulk changes - those that set a large number of
nodes at once - for performance reasons. Therefore, you can't rely on these
callbacks to always be called.
### Right-clicking and placing a node
When the user right-clicks with an item whilst pointing at a node, the item's
`on_place` callback is called. By default, this is set to `minetest.item_place`.
If the pointed node has an `on_rightclick` callback and sneak (shift) is held,
then the `on_rightclick` callback is called. Otherwise, `minetest.item_place`
will place the node.
Placing a node will call both `on_construct` and `after_place_node`.
`on_construct` is called by any node set event that wasn't in bulk and is just
given the node's position and value .`after_place_node` is only called by node
place, and so has more information - such as the placer and itemstack.
It's important to note that players aren't the only objects that can place
nodes; it's common for mobs and mods to place nodes. To account for this,
`placer` could be a player, entity, or nil.
```lua
minetest.register_node("mymod:mynode", {
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing),
if clicker:is_player() then
minetest.chat_send_player(clicker:get_player_name(), "Hello world!")
end
end,
on_construct = function(pos, node)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", "My node!")
end,
after_place_node = function(pos, placer, itemstack, pointed_thing)
-- Make sure to check placer
if placer and placer:is_player() then
local meta = minetest.get_meta(pos)
meta:set_string("owner", placer:get_player_name())
end
end,
})
```
### Punching and digging
Punching is when the player left-clicks for a short period. If the wielded item
has an `on_use` callback, this will be called. Otherwise, the `on_punch`
callback on the pointed node will be called.
When the player attempts to dig a node, the `on_dig` callback on the node will be called.
This defaults to `minetest.node_dig`, which will check for area protection, wear
out the tool, remove the node, and run the `after_dig_node` callback.
```lua
minetest.register_node("mymod:mynode", {
on_punch = function(pos, node, puncher, pointed_thing)
if clicker:is_player() then
minetest.chat_send_player(clicker:get_player_name(), "Ow!")
end
end,
})
```
### ...and more!
Check out Minetest's Lua API reference for a list of all node callbacks, and
more information on the callbacks above.

View File

@ -18,8 +18,6 @@ basic requirements for many mods.
- [Item Aliases](#item-aliases) - [Item Aliases](#item-aliases)
- [Textures](#textures) - [Textures](#textures)
- [Registering a basic node](#registering-a-basic-node) - [Registering a basic node](#registering-a-basic-node)
- [Actions and Callbacks](#actions-and-callbacks)
- [on_use](#onuse)
- [Crafting](#crafting) - [Crafting](#crafting)
- [Shaped](#shaped) - [Shaped](#shaped)
- [Shapeless](#shapeless) - [Shapeless](#shapeless)
@ -29,25 +27,24 @@ basic requirements for many mods.
## What are Nodes and Items? ## What are Nodes and Items?
Nodes, craftitems, and tools are all Items. Nodes, craftitems, and tools are all Items. An item is something that could be
An item is something that could be found in an inventory - found in an inventory - even if it isn't possible through normal gameplay.
even though it may not be possible through normal gameplay.
A node is an item which can be placed or be found in the world. A node is an item that can be placed or be found in the world. Every position
Every position in the world must be occupied with one and only one node - in the world must be occupied with one and only one node - seemingly blank
seemingly blank positions are usually air nodes. positions are usually air nodes.
A craftitem can't be placed and is only found in inventories or as a dropped item A craftitem can't be placed and is only found in inventories or as a dropped item
in the world. in the world.
A tool has the ability to wear and typically has non-default digging capabilities. A tool has the ability to wear and typically has non-default digging
In the future, it's likely that craftitems and tools will merge into one type of capabilities. In the future, it's likely that craftitems and tools will merge
item, as the distinction between them is rather artificial. into one type of item, as the distinction between them is rather artificial.
## Registering Items ## Registering Items
Item definitions consist of an *item name* and a *definition table*. Item definitions consist of an *item name* and a *definition table*.
The definition table contains attributes which affect the behaviour of the item. The definition table contains attributes that affect the behaviour of the item.
```lua ```lua
minetest.register_craftitem("modname:itemname", { minetest.register_craftitem("modname:itemname", {
@ -63,25 +60,26 @@ following format:
modname:itemname modname:itemname
The modname is the name of the mod in which the item is registered, and the The modname is the name of the mod in which the item is registered, and the item
item name is the name of the item itself. name is the name of the item itself. The item name should be relevant to what
The item name should be relevant to what the item is and can't already be registered. the item is and can't already be registered.
Both `modname` and `itemname` should only contain lowercase letters, numbers,
and underscores.
### Item Aliases ### Item Aliases
Items can also have *aliases* pointing to their name. Items can also have *aliases* pointing to their name. An *alias* is a
An *alias* is a pseudo-item name which results in the engine treating any pseudo-item name that results in the engine treating any occurrences of the
occurrences of the alias as if it were the item name. alias as if it were the item name. There are two main common uses of this:
There are two main common uses of this:
* Renaming removed items to something else. * Renaming removed items to something else.
There may be unknown nodes in the world and in inventories if an item is There may be unknown nodes in the world and in inventories if an item is
removed from a mod without any corrective code. removed from a mod without any corrective code.
* Adding a shortcut. `/giveme dirt` is easier than `/giveme default:dirt`. * Adding a shortcut. `/giveme dirt` is easier than `/giveme default:dirt`.
Registering an alias is pretty simple. Registering an alias is pretty simple. A good way to remember the order of the
A good way to remember the order of the arguments is `from → to` where arguments is `from → to` where *from* is the alias and *to* is the target.
*from* is the alias and *to* is the target.
```lua ```lua
minetest.register_alias("dirt", "default:dirt") minetest.register_alias("dirt", "default:dirt")
@ -103,14 +101,16 @@ JPEG textures are supported, but they do not support transparency and are genera
bad quality at low resolutions. bad quality at low resolutions.
It is often better to use the PNG format. It is often better to use the PNG format.
Textures in Minetest are usually 16 by 16 pixels. Textures in Minetest are usually 16 by 16 pixels. They can be any resolution,
They can be any resolution, but it is recommended that they are in the order of 2, but it is recommended that they are in the order of 2, for example, 16, 32, 64,
for example, 16, 32, 64, or 128. or 128. This is because other resolutions may not be supported correctly on
This is because other resolutions may not be supported correctly on older devices, older devices, especially phones, resulting in degraded performance.
resulting in decreased performance.
## Registering a basic node ## Registering a basic node
Registering nodes is similar to registering items, just with a different
function:
```lua ```lua
minetest.register_node("mymod:diamond", { minetest.register_node("mymod:diamond", {
description = "Alien Diamond", description = "Alien Diamond",
@ -120,6 +120,9 @@ minetest.register_node("mymod:diamond", {
}) })
``` ```
Node definitions can contain any property in an item definition, and also
contain additional properties specific to nodes.
The `tiles` property is a table of texture names the node will use. The `tiles` property is a table of texture names the node will use.
When there is only one texture, this texture is used on every side. When there is only one texture, this texture is used on every side.
To give a different texture per-side, supply the names of 6 textures in this order: To give a different texture per-side, supply the names of 6 textures in this order:
@ -128,7 +131,7 @@ To give a different texture per-side, supply the names of 6 textures in this ord
(+Y, -Y, +X, -X, +Z, -Z) (+Y, -Y, +X, -X, +Z, -Z)
Remember that +Y is upwards in Minetest, as is the convention with Remember that +Y is upwards in Minetest, as is the convention with
3D computer graphics. most 3D computer games.
```lua ```lua
minetest.register_node("mymod:diamond", { minetest.register_node("mymod:diamond", {
@ -152,49 +155,6 @@ The `is_ground_content` attribute allows caves to be generated over the stone.
This is essential for any node which may be placed during map generation underground. This is essential for any node which may be placed during map generation underground.
Caves are cut out of the world after all the other nodes in an area have generated. Caves are cut out of the world after all the other nodes in an area have generated.
## Actions and Callbacks
Minetest heavily uses a callback-based modding design.
Callbacks can be placed in the item definition table to allow response to various
different user events.
### on_use
By default, the use callback is triggered when a player left-clicks with an item.
Having a use callback prevents the item being used to dig nodes.
One common use of the use callback is for food:
```lua
minetest.register_craftitem("mymod:mudpie", {
description = "Alien Mud Pie",
inventory_image = "myfood_mudpie.png",
on_use = minetest.item_eat(20),
})
```
The number supplied to the minetest.item_eat function is the number of hit points
healed when this food is consumed.
Each heart icon the player has is worth two hitpoints.
A player can usually have up to 10 hearts, which is equal to 20 hitpoints.
Hitpoints don't have to be integers (whole numbers); they can be decimals.
minetest.item_eat() is a function which returns a function, setting it
as the on_use callback.
This means the code above is roughly similar to this:
```lua
minetest.register_craftitem("mymod:mudpie", {
description = "Alien Mud Pie",
inventory_image = "myfood_mudpie.png",
on_use = function(...)
return minetest.do_item_eat(20, nil, ...)
end,
})
```
By understanding how item_eat works by simply returning a function, it's
possible to modify it to do more complex behaviour such as play a custom sound.
## Crafting ## Crafting
There are several types of crafting recipe available, indicated by the `type` There are several types of crafting recipe available, indicated by the `type`
@ -327,6 +287,7 @@ minetest.register_craft({
}) })
``` ```
## Tools, Capabilities, and Dig Types ## Tools, Capabilities, and Dig Types
Dig types are groups which are used to define how strong a node is when dug Dig types are groups which are used to define how strong a node is when dug

View File

@ -34,7 +34,7 @@ layout: compress
{% endfor %} {% endfor %}
<style>body,html,nav{background:#333}nav,nav li,nav li a{display:block}body,html,main,nav li{margin:0;padding:0}main,nav{position:absolute;top:0}body,html{font-size:17px;color:#000}#container{width:100%;max-width:1100px;margin:auto;position:relative}nav{left:0;width:280px;list-style:none;color:#fff}nav li a{padding:5px;color:#ccc;text-decoration:none}main{left:280px;right:0}article{background:#fff;padding:0 20px 20px}</style> <style>body,html,nav{background:#333}nav,nav li,nav li a{display:block}body,html,main,nav li{margin:0;padding:0}main,nav{position:absolute;top:0}body,html{font-size:17px;color:#000}#container{width:100%;max-width:1100px;margin:auto;position:relative}nav{left:0;width:280px;list-style:none;color:#fff}nav li a{padding:5px;color:#ccc;text-decoration:none}main{left:280px;right:0}article{background:#fff;padding:0 20px 20px}</style>
<link rel="stylesheet" href="{{ page.root }}/static/style.css?v=2"> <link rel="stylesheet" href="{{ page.root }}/static/style.css?v=3">
</head> </head>
<body> <body>
<div id="container"> <div id="container">

17
_sass/_table.scss Normal file
View File

@ -0,0 +1,17 @@
table {
width: 100%;
border-collapse: collapse;
}
table td, table th {
border: 1px solid #ddd;
padding: 8px;
}
table tr:nth-child(even) {
background-color: #f2f2f2;
}
table th {
padding: 12px 8px;
text-align: left;
background-color: #04AA6D;
color: white;
}

View File

@ -5,3 +5,4 @@
@import "content"; @import "content";
@import "code"; @import "code";
@import "notice"; @import "notice";
@import "table";