From f8c9da8261532f3ce17c3d877fb24109fc1f14b4 Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Sun, 31 Jul 2022 20:10:04 +0100 Subject: [PATCH] Item Callbacks: Add chapter --- _en/items/callbacks.md | 207 ++++++++++++++++++++++++++++++ _en/items/nodes_items_crafting.md | 103 +++++---------- _layouts/base.html | 2 +- _sass/_table.scss | 17 +++ static/style.scss | 1 + 5 files changed, 258 insertions(+), 72 deletions(-) create mode 100644 _en/items/callbacks.md create mode 100644 _sass/_table.scss diff --git a/_en/items/callbacks.md b/_en/items/callbacks.md new file mode 100644 index 0000000..44b8fad --- /dev/null +++ b/_en/items/callbacks.md @@ -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 + +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. diff --git a/_en/items/nodes_items_crafting.md b/_en/items/nodes_items_crafting.md index 1955783..452fc53 100644 --- a/_en/items/nodes_items_crafting.md +++ b/_en/items/nodes_items_crafting.md @@ -18,8 +18,6 @@ basic requirements for many mods. - [Item Aliases](#item-aliases) - [Textures](#textures) - [Registering a basic node](#registering-a-basic-node) -- [Actions and Callbacks](#actions-and-callbacks) - - [on_use](#onuse) - [Crafting](#crafting) - [Shaped](#shaped) - [Shapeless](#shapeless) @@ -29,25 +27,24 @@ basic requirements for many mods. ## What are Nodes and Items? -Nodes, craftitems, and tools are all Items. -An item is something that could be found in an inventory - -even though it may not be possible through normal gameplay. +Nodes, craftitems, and tools are all Items. An item is something that could be +found in an inventory - even if it isn't possible through normal gameplay. -A node is an item which can be placed or be found in the world. -Every position in the world must be occupied with one and only one node - -seemingly blank positions are usually air nodes. +A node is an item that can be placed or be found in the world. Every position +in the world must be occupied with one and only one node - seemingly blank +positions are usually air nodes. A craftitem can't be placed and is only found in inventories or as a dropped item in the world. -A tool has the ability to wear and typically has non-default digging capabilities. -In the future, it's likely that craftitems and tools will merge into one type of -item, as the distinction between them is rather artificial. +A tool has the ability to wear and typically has non-default digging +capabilities. In the future, it's likely that craftitems and tools will merge +into one type of item, as the distinction between them is rather artificial. ## Registering Items 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 minetest.register_craftitem("modname:itemname", { @@ -63,25 +60,26 @@ following format: modname:itemname -The modname is the name of the mod in which the item is registered, and the -item name is the name of the item itself. -The item name should be relevant to what the item is and can't already be registered. +The modname is the name of the mod in which the item is registered, and the item +name is the name of the item itself. The item name should be relevant to what +the item is and can't already be registered. + +Both `modname` and `itemname` should only contain lowercase letters, numbers, +and underscores. ### Item Aliases -Items can also have *aliases* pointing to their name. -An *alias* is a pseudo-item name which results in the engine treating any -occurrences of the alias as if it were the item name. -There are two main common uses of this: +Items can also have *aliases* pointing to their name. An *alias* is a +pseudo-item name that results in the engine treating any occurrences of the +alias as if it were the item name. There are two main common uses of this: * Renaming removed items to something else. There may be unknown nodes in the world and in inventories if an item is removed from a mod without any corrective code. * Adding a shortcut. `/giveme dirt` is easier than `/giveme default:dirt`. -Registering an alias is pretty simple. -A good way to remember the order of the arguments is `from → to` where -*from* is the alias and *to* is the target. +Registering an alias is pretty simple. A good way to remember the order of the +arguments is `from → to` where *from* is the alias and *to* is the target. ```lua 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. It is often better to use the PNG format. -Textures in Minetest are usually 16 by 16 pixels. -They can be any resolution, but it is recommended that they are in the order of 2, -for example, 16, 32, 64, or 128. -This is because other resolutions may not be supported correctly on older devices, -resulting in decreased performance. +Textures in Minetest are usually 16 by 16 pixels. They can be any resolution, +but it is recommended that they are in the order of 2, for example, 16, 32, 64, +or 128. This is because other resolutions may not be supported correctly on +older devices, especially phones, resulting in degraded performance. ## Registering a basic node +Registering nodes is similar to registering items, just with a different +function: + ```lua minetest.register_node("mymod: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. 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: @@ -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) Remember that +Y is upwards in Minetest, as is the convention with -3D computer graphics. +most 3D computer games. ```lua 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. 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 There are several types of crafting recipe available, indicated by the `type` @@ -327,6 +287,7 @@ minetest.register_craft({ }) ``` + ## Tools, Capabilities, and Dig Types Dig types are groups which are used to define how strong a node is when dug diff --git a/_layouts/base.html b/_layouts/base.html index 9b78984..2458bad 100644 --- a/_layouts/base.html +++ b/_layouts/base.html @@ -34,7 +34,7 @@ layout: compress {% endfor %} - +
diff --git a/_sass/_table.scss b/_sass/_table.scss new file mode 100644 index 0000000..c97fd99 --- /dev/null +++ b/_sass/_table.scss @@ -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; +} diff --git a/static/style.scss b/static/style.scss index 969916d..518d603 100644 --- a/static/style.scss +++ b/static/style.scss @@ -5,3 +5,4 @@ @import "content"; @import "code"; @import "notice"; +@import "table";