From f802a7fae1a54ba514e00d9df96aaea6f41eab54 Mon Sep 17 00:00:00 2001
From: Marco <4279489-marco_a@users.noreply.gitlab.com>
Date: Mon, 27 Apr 2020 15:11:54 +0200
Subject: [PATCH] Settings for Italian translation ready, _it folder created
---
_data/languages.yml | 3 +
_it/advmap/biomesdeco.md | 243 ++++++++++++++++
_it/advmap/lvm.md | 213 ++++++++++++++
_it/basics/getting_started.md | 221 +++++++++++++++
_it/basics/lua.md | 314 +++++++++++++++++++++
_it/games/games.md | 93 +++++++
_it/index.md | 35 +++
_it/items/creating_textures.md | 84 ++++++
_it/items/inventories.md | 342 +++++++++++++++++++++++
_it/items/node_drawtypes.md | 446 ++++++++++++++++++++++++++++++
_it/items/nodes_items_crafting.md | 382 +++++++++++++++++++++++++
_it/map/environment.md | 225 +++++++++++++++
_it/map/objects.md | 281 +++++++++++++++++++
_it/map/storage.md | 247 +++++++++++++++++
_it/map/timers.md | 120 ++++++++
_it/players/chat.md | 166 +++++++++++
_it/players/chat_complex.md | 183 ++++++++++++
_it/players/formspecs.md | 385 ++++++++++++++++++++++++++
_it/players/hud.md | 293 ++++++++++++++++++++
_it/players/player_physics.md | 76 +++++
_it/players/privileges.md | 138 +++++++++
_it/players/sfinv.md | 242 ++++++++++++++++
_it/quality/clean_arch.md | 253 +++++++++++++++++
_it/quality/common_mistakes.md | 167 +++++++++++
_it/quality/luacheck.md | 152 ++++++++++
_it/quality/readmore.md | 28 ++
_it/quality/releasing.md | 214 ++++++++++++++
_it/quality/security.md | 110 ++++++++
_it/quality/unit_testing.md | 195 +++++++++++++
_layouts/default.html | 2 +
30 files changed, 5853 insertions(+)
create mode 100644 _it/advmap/biomesdeco.md
create mode 100644 _it/advmap/lvm.md
create mode 100644 _it/basics/getting_started.md
create mode 100644 _it/basics/lua.md
create mode 100644 _it/games/games.md
create mode 100644 _it/index.md
create mode 100644 _it/items/creating_textures.md
create mode 100644 _it/items/inventories.md
create mode 100644 _it/items/node_drawtypes.md
create mode 100644 _it/items/nodes_items_crafting.md
create mode 100644 _it/map/environment.md
create mode 100644 _it/map/objects.md
create mode 100644 _it/map/storage.md
create mode 100644 _it/map/timers.md
create mode 100644 _it/players/chat.md
create mode 100644 _it/players/chat_complex.md
create mode 100644 _it/players/formspecs.md
create mode 100644 _it/players/hud.md
create mode 100644 _it/players/player_physics.md
create mode 100644 _it/players/privileges.md
create mode 100644 _it/players/sfinv.md
create mode 100644 _it/quality/clean_arch.md
create mode 100644 _it/quality/common_mistakes.md
create mode 100644 _it/quality/luacheck.md
create mode 100644 _it/quality/readmore.md
create mode 100644 _it/quality/releasing.md
create mode 100644 _it/quality/security.md
create mode 100644 _it/quality/unit_testing.md
diff --git a/_data/languages.yml b/_data/languages.yml
index de6bc3a..99124e3 100644
--- a/_data/languages.yml
+++ b/_data/languages.yml
@@ -1,3 +1,6 @@
- code: en
name: English (UK)
cta: This book is available in English
+- code: it
+ name: Italiano
+ cta: Questo libro è disponibile in italiano
diff --git a/_it/advmap/biomesdeco.md b/_it/advmap/biomesdeco.md
new file mode 100644
index 0000000..64f669f
--- /dev/null
+++ b/_it/advmap/biomesdeco.md
@@ -0,0 +1,243 @@
+---
+title: Biomes and Decorations
+author: Shara
+layout: default
+root: ../..
+idx: 6.1
+description: Create biomes and decorations to customise the map
+---
+
+## Introduction
+
+The ability to register biomes and decorations is vital when aiming to create an
+interesting and varied in-game environment. This chapter teaches you how to
+register biomes, how to control biome distribution, and how to place decorations in biomes.
+
+- [What are Biomes?](#what-are-biomes)
+- [Biome Placement](#biome-placement)
+ - [Heat and Humidity](#heat-and-humidity)
+ - [Visualising Boundaries using Voronoi Diagrams](#visualising-boundaries-using-voronoi-diagrams)
+ - [Creating a Voronoi Diagram using Geogebra](#creating-a-voronoi-diagram-using-geogebra)
+- [Registering a Biome](#registering-a-biome)
+- [What are Decorations?](#what-are-decorations)
+- [Registering a Simple Decoration](#registering-a-simple-decoration)
+- [Registering a Schematic Decoration](#registering-a-schematic-decoration)
+- [Mapgen Aliases](#mapgen-aliases)
+
+## What are Biomes?
+
+A Minetest biome is a specific in-game environment. When registering biomes, you
+can determine the types of nodes that appear in them during map generation.
+Some of the most common types of node that may vary between biomes include:
+
+* Top node: This is the node most commonly found on the surface. A well-known
+ example would be "Dirt with Grass" from Minetest Game.
+* Filler node: This is the layer immediately beneath the top node.
+ In biomes with grass, it will often be dirt.
+* Stone node: This is the node you most commonly see underground.
+* Water node: This is usually a liquid and will be the node that appears
+ where you would expect bodies of water.
+
+Other types of node can also vary between biomes, providing an opportunity
+to create vastly different environments within the same game.
+
+## Biome Placement
+
+### Heat and Humidity
+
+It is not enough to simply register a biome; you must also decide where it can
+occur in game. This is done by assigning a heat and a humidity value to each biome.
+
+You should think carefully about these values; they determine which biomes can
+be neighbours to each other. Poor decisions could result in what is meant to
+be a hot desert sharing a border with a glacier, and other improbable
+combinations which you may prefer to avoid.
+
+In game, heat and humidity values at any point of the map will usually be between
+0 and 100. The values gradually change, increasing or decreasing as you move
+around the map. The biome at any given point will be determined by which of the
+registered biomes has heat and humidity values closest to those at that position on the map.
+
+Because the changes in heat and humidity are gradual, it is good practice to assign
+heat and humidity values to biomes based on reasonable expectations about that
+biome’s environment. For example:
+
+* A desert might have high heat and low humidity.
+* A snowy forest might have low heat and a medium humidity value.
+* A swamp biome would generally have high humidity.
+*
+In practice, this means that, as long as you have a diverse range of biomes, you
+are likely to find that the biomes which border each other form a logical progression.
+
+### Visualising Boundaries using Voronoi Diagrams
+
+
+
+Fine-tuning heat and humidity values for biomes is
+easier if you can visualise the relationship between the biomes you are using.
+This is most important if you are creating a full set of your own biomes, but
+can also be helpful if you are adding a biome to an existing set.
+
+The simplest way to visualise which biomes may share borders is to create a
+Voronoi diagram, which can be used to show which point on a 2-dimensional
+diagram any given position is closest to.
+
+A Voronoi diagram can reveal where biomes that should border each other do not,
+and where biomes that should not border each other do. It can also give a
+general insight into how common biomes will be in-game, with larger and more
+central biomes being more common than smaller biomes or biomes that are located
+on the outer edge of the diagram.
+
+This is done by marking a point for each biome based on heat and humidity values,
+where the x-axis is heat and the y-axis is humidity. The diagram is then
+divided into areas, such that every position in a given area is closer to the
+point inside that area than it is to any other point on the diagram.
+
+Each area represents a biome. If two areas share a border, the biomes they
+represent in-game can be located next to each other. The length of the border
+shared between two areas, compared to the length shared with other areas, will
+tell you how frequently two biomes are likely to be found next to each other.
+
+### Creating a Voronoi Diagram using Geogebra
+
+As well as drawing them by hand, you can also create Voronoi diagrams using
+programs such as [Geogebra](https://www.geogebra.org).
+
+1. Create points by selecting the point tool in the toolbar (icon is a point with 'A'),
+ and then clicking the chart. You can drag points around or explicitly set their
+ position in the left sidebar. You should also give each point a label, to make things clearer.
+
+1. Next, create the voronoi by entering the following function into the
+ input box in the left sidebar:
+
+ ```cpp
+ Voronoi({ A, B, C, D, E })
+ ```
+
+ Where the each point is inside the curly brackets, separated by commas. You should now
+
+3. Profit! You should now have a voronoi diagram with all draggable points.
+
+
+## Registering a Biome
+
+The following code registers a simple biome named grasslands biome:
+
+```lua
+minetest.register_biome({
+ name = "grasslands",
+ node_top = "default:dirt_with_grass",
+ depth_top = 1,
+ node_filler = "default:dirt",
+ depth_filler = 3,
+ y_max = 1000,
+ y_min = -3,
+ heat_point = 50,
+ humidity_point = 50,
+})
+```
+
+This biome has one layer of Dirt with Grass nodes on the surface, and three layers
+of Dirt nodes beneath this. It does not specify a stone node, so the node defined
+in the mapgen alias registration for `mapgen_stone` will be present underneath the dirt.
+
+There are many options when registering a biome, and these are documented
+in the [Minetest Lua API Reference](https://minetest.gitlab.io/minetest/definition-tables/#biome-definition),
+as always.
+
+You don’t need to define every option for every biome you create, but in some cases failure
+to define either a specific option, or a suitable mapgen alias, can result in map generation errors.
+
+## What are Decorations?
+
+Decorations are either nodes or schematics that can be placed on the map at mapgen.
+Some common examples include flowers, bushes, and trees. Other more creative uses
+may include hanging icicles or stalagmites in caves, underground crystal formations,
+or even the placement of small buildings.
+
+Decorations can be restricted to specific biomes, by height, or by which nodes
+they can be placed on. They are often used to develop the environment of a biome
+by ensuring it has specific plants, trees or other features.
+
+## Registering a Simple Decoration
+
+Simple decorations are used to place single node decorations on the map during
+map generation. You must specify the node that is to be placed as a decoration,
+details for where it can be placed, and how frequently it occurs.
+
+For example:
+
+```lua
+minetest.register_decoration({
+ deco_type = "simple",
+ place_on = {"base:dirt_with_grass"},
+ sidelen = 16,
+ fill_ratio = 0.1,
+ biomes = {"grassy_plains"},
+ y_max = 200,
+ y_min = 1,
+ decoration = "plants:grass",
+})
+```
+
+In this example, the node named `plants:grass` will be placed in the biome named
+grassy_plains on top of `base:dirt_with_grass` nodes, between the heights of `y = 1` and `y = 200`.
+
+The fill_ratio value determines how frequently the decoration appears, with higher
+values up to 1 resulting in a great number of decorations being placed. It is possible
+to instead use noise parameters to determine placement.
+
+## Registering a Schematic Decoration
+
+Schematic decorations are very similar to simple decoration, but involve the placement
+of a schematic instead of the placement of a single node. For example:
+
+```lua
+minetest.register_decoration({
+ deco_type = "schematic",
+ place_on = {"base:desert_sand"},
+ sidelen = 16,
+ fill_ratio = 0.0001,
+ biomes = {"desert"},
+ y_max = 200,
+ y_min = 1,
+ schematic = minetest.get_modpath("plants") .. "/schematics/cactus.mts",
+ flags = "place_center_x, place_center_z",
+ rotation = "random",
+})
+```
+
+In this example the cactus.mts schematic is placed in desert biomes. You need to provide
+a path to a schematic, which in this case is stored in a dedicated schematic directory within the mod.
+
+This example also sets flags to center the placement of the schematic, and the rotation
+is set to random. The random rotation of schematics when they are placed as decorations
+helps introduce more variation when asymmetrical schematics are used.
+
+
+## Mapgen Aliases
+
+Existing games should already include suitable mapgen aliases, so you only need
+to consider registering mapgen aliases of your own if you are making your own game.
+
+Mapgen aliases provide information to the core mapgen, and can be registered in the form:
+
+```lua
+minetest.register_alias("mapgen_stone", "base:smoke_stone")
+```
+
+At a minimum you should register:
+
+* mapgen_stone
+* mapgen_water_source
+* mapgen_river_water_source
+
+If you are not defining cave liquid nodes for all biomes, you should also register:
+
+* mapgen_lava_source
diff --git a/_it/advmap/lvm.md b/_it/advmap/lvm.md
new file mode 100644
index 0000000..b5775b7
--- /dev/null
+++ b/_it/advmap/lvm.md
@@ -0,0 +1,213 @@
+---
+title: Lua Voxel Manipulators
+layout: default
+root: ../..
+idx: 6.2
+description: Learn how to use LVMs to speed up map operations.
+redirect_from:
+ - /en/chapters/lvm.html
+ - /en/map/lvm.html
+mapgen_object:
+ level: warning
+ title: LVMs and Mapgen
+ message: Don't use `minetest.get_voxel_manip()` with mapgen, as it can cause glitches.
+ Use `minetest.get_mapgen_object("voxelmanip")` instead.
+---
+
+## Introduction
+
+The functions outlined in the [Basic Map Operations](environment.html) chapter
+are convenient and easy to use, but for large areas they are inefficient.
+Every time you call `set_node` or `get_node`, your mod needs to communicate with
+the engine. This results in constant individual copying operations between the
+engine and your mod, which is slow and will quickly decrease the performance of
+your game. Using a Lua Voxel Manipulator (LVM) can be a better alternative.
+
+- [Concepts](#concepts)
+- [Reading into the LVM](#reading-into-the-lvm)
+- [Reading Nodes](#reading-nodes)
+- [Writing Nodes](#writing-nodes)
+- [Example](#example)
+- [Your Turn](#your-turn)
+
+## Concepts
+
+An LVM allows you to load large areas of the map into your mod's memory.
+You can then read and write this data without further interaction with the
+engine and without running any callbacks, which means that these
+operations are very fast. Once done, you can then write the area back into
+the engine and run any lighting calculations.
+
+## Reading into the LVM
+
+You can only load a cubic area into an LVM, so you need to work out the minimum
+and maximum positions that you need to modify. Then you can create and read into
+an LVM. For example:
+
+```lua
+local vm = minetest.get_voxel_manip()
+local emin, emax = vm:read_from_map(pos1, pos2)
+```
+
+For performance reasons, an LVM will almost never read the exact area you tell it to.
+Instead, it will likely read a larger area. The larger area is given by `emin` and `emax`,
+which stand for *emerged min pos* and *emerged max pos*. An LVM will load the area
+it contains for you - whether that involves loading from memory, from disk, or
+calling the map generator.
+
+{% include notice.html notice=page.mapgen_object %}
+
+## Reading Nodes
+
+To read the types of nodes at particular positions, you'll need to use `get_data()`.
+This returns a flat array where each entry represents the type of a
+particular node.
+
+```lua
+local data = vm:get_data()
+```
+
+You can get param2 and lighting data using the methods `get_light_data()` and `get_param2_data()`.
+
+You'll need to use `emin` and `emax` to work out where a node is in the flat arrays
+given by the above methods. There's a helper class called `VoxelArea` which handles
+the calculation for you.
+
+```lua
+local a = VoxelArea:new{
+ MinEdge = emin,
+ MaxEdge = emax
+}
+
+-- Get node's index
+local idx = a:index(x, y, z)
+
+-- Read node
+print(data[idx])
+```
+
+When you run this, you'll notice that `data[vi]` is an integer. This is because
+the engine doesn't store nodes using strings, for performance reasons.
+Instead, the engine uses an integer called a content ID.
+You can find out the content ID for a particular type of node with
+`get_content_id()`. For example:
+
+```lua
+local c_stone = minetest.get_content_id("default:stone")
+```
+
+You can then check whether the node is stone:
+
+```lua
+local idx = a:index(x, y, z)
+if data[idx] == c_stone then
+ print("is stone!")
+end
+```
+
+It is recommended that you find and store the content IDs of nodes types
+at load time because the IDs of a node type will never change. Make sure to store
+the IDs in a local variable for performance reasons.
+
+Nodes in an LVM data array are stored in reverse co-ordinate order, so you should
+always iterate in the order `z, y, x`. For example:
+
+```lua
+for z = min.z, max.z do
+ for y = min.y, max.y do
+ for x = min.x, max.x do
+ -- vi, voxel index, is a common variable name here
+ local vi = a:index(x, y, z)
+ if data[vi] == c_stone then
+ print("is stone!")
+ end
+ end
+ end
+end
+```
+
+The reason for this touches on the topic of computer architecture. Reading from RAM is rather
+costly, so CPUs have multiple levels of caching. If the data that a process requests
+is in the cache, it can very quickly retrieve it. If the data is not in the cache,
+then a cache miss occurs and it will fetch the data it needs from RAM. Any data
+surrounding the requested data is also fetched and then replaces the data in the cache. This is
+because it's quite likely that the process will ask for data near that location again. This means
+a good rule of optimisation is to iterate in a way that you read data one after
+another, and avoid *cache thrashing*.
+
+## Writing Nodes
+
+First, you need to set the new content ID in the data array:
+
+```lua
+for z = min.z, max.z do
+ for y = min.y, max.y do
+ for x = min.x, max.x do
+ local vi = a:index(x, y, z)
+ if data[vi] == c_stone then
+ data[vi] = c_air
+ end
+ end
+ end
+end
+```
+
+When you finish setting nodes in the LVM, you then need to upload the data
+array to the engine:
+
+```lua
+vm:set_data(data)
+vm:write_to_map(true)
+```
+
+For setting lighting and param2 data, use the appropriately named
+`set_light_data()` and `set_param2_data()` methods.
+
+`write_to_map()` takes a Boolean which is true if you want lighting to be
+calculated. If you pass false, you need to recalculate lighting at a future
+time using `minetest.fix_light`.
+
+## Example
+
+```lua
+-- Get content IDs during load time, and store into a local
+local c_dirt = minetest.get_content_id("default:dirt")
+local c_grass = minetest.get_content_id("default:dirt_with_grass")
+
+local function grass_to_dirt(pos1, pos2)
+ -- Read data into LVM
+ local vm = minetest.get_voxel_manip()
+ local emin, emax = vm:read_from_map(pos1, pos2)
+ local a = VoxelArea:new{
+ MinEdge = emin,
+ MaxEdge = emax
+ }
+ local data = vm:get_data()
+
+ -- Modify data
+ for z = pos1.z, pos2.z do
+ for y = pos1.y, pos2.y do
+ for x = pos1.x, pos2.x do
+ local vi = a:index(x, y, z)
+ if data[vi] == c_grass then
+ data[vi] = c_dirt
+ end
+ end
+ end
+ end
+
+ -- Write data
+ vm:set_data(data)
+ vm:write_to_map(true)
+end
+```
+
+## Your Turn
+
+* Create `replace_in_area(from, to, pos1, pos2)`, which replaces all instances of
+ `from` with `to` in the area given, where `from` and `to` are node names.
+* Make a function which rotates all chest nodes by 90°.
+* Make a function which uses an LVM to cause mossy cobble to spread to nearby
+ stone and cobble nodes.
+ Does your implementation cause mossy cobble to spread more than a distance of one node each
+ time? If so, how could you stop this?
diff --git a/_it/basics/getting_started.md b/_it/basics/getting_started.md
new file mode 100644
index 0000000..6d209f8
--- /dev/null
+++ b/_it/basics/getting_started.md
@@ -0,0 +1,221 @@
+---
+title: Getting Started
+layout: default
+root: ../..
+idx: 1.1
+description: Learn how to make a mod folder, including init.lua, mod.conf and more.
+redirect_from:
+- /en/chapters/folders.html
+- /en/basics/folders.html
+---
+
+## Introduction
+
+Understanding the basic structure of a mod's folder is an essential skill when
+creating mods.
+
+- [What are Games and Mods?](#what-are-games-and-mods)
+- [Where are mods stored?](#where-are-mods-stored)
+- [Mod Directory](#mod-directory)
+- [Dependencies](#dependencies)
+ - [mod.conf](#modconf)
+ - [depends.txt](#dependstxt)
+- [Mod Packs](#mod-packs)
+- [Example](#example)
+ - [Mod Folder](#mod-folder)
+ - [depends.txt](#dependstxt-1)
+ - [init.lua](#initlua)
+ - [mod.conf](#modconf-1)
+
+
+## What are Games and Mods?
+
+The power of Minetest is the ability to easily develop games without the need
+to create your own voxel graphics, voxel algorithms, or fancy networking code.
+
+In Minetest, a game is a collection of modules which work together to provide the
+content and behaviour of a game.
+A module, commonly known as a mod, is a collection of scripts and resources.
+It's possible to make a game using only one mod, but this is rarely done because it
+reduces the ease by which parts of the game can be adjusted and replaced
+independently of others.
+
+It's also possible to distribute mods outside of a game, in which case they
+are also *mods* in the more traditional sense - modifications. These mods adjust
+or extend the features of a game.
+
+Both the mods contained in a game and third-party mods use the same API.
+
+This book will cover the main parts of the Minetest API,
+and is applicable for both game developers and modders.
+
+
+## Where are mods stored?
+
+
+
+Each mod has its own directory where its Lua code, textures, models, and
+sounds are placed. Minetest checks in a number of different locations for
+mods. These locations are commonly called *mod load paths*.
+
+For a given world/save game, three mod locations are checked.
+They are, in order:
+
+1. Game mods. These are the mods that form the game that the world is running.
+ Eg: `minetest/games/minetest_game/mods/`, `/usr/share/minetest/games/minetest/`
+2. Global mods, the location to which mods are nearly always installed to.
+ If in doubt, place them here.
+ Eg: `minetest/mods/`
+3. World mods, the location to store mods which are specific to a
+ particular world.
+ Eg: `minetest/worlds/world/worldmods/`
+
+Minetest will check the locations in the order given above. If it encounters a mod
+with a name the same as one found previously, the later mod will be loaded in place
+of the earlier mod.
+This means that you can override game mods by placing a mod with the same name
+in the global mod location.
+
+The actual location of each mod load path depends on what operating system you're
+using, and how you installed Minetest.
+
+* **Windows:**
+ * For portable builds, ie: from a .zip file, just go to the directory where
+ you extracted the zip and look for the `games`, `mods`, and `worlds`
+ directories.
+ * For installed builds, ie: from a setup.exe,
+ look in C:\\\\Minetest or C:\\\\Games\\Minetest.
+* **GNU/Linux:**
+ * For system-wide installs, look in `~/.minetest`.
+ Note that `~` means the user home directory, and that files and directories
+ starting with a dot (`.`) are hidden.
+ * For portable installs, look in the build directory.
+ * For Flatpak installs, look in `~/.var/app/net.minetest.Minetest/.minetest/mods/`.
+* **MacOS**
+ * Look in `~/Library/Application Support/minetest/`.
+ Note that `~` means the user home, ie: `/Users/USERNAME/`.
+
+## Mod Directory
+
+![Find the mod's directory]({{ page.root }}/static/folder_modfolder.jpg)
+
+A *mod name* is used to refer to a mod. Each mod should have a unique name.
+Mod names can include letters, numbers, and underscores. A good name should
+describe what the mod does, and the directory which contains the components of a mod
+must have the same name as the mod name.
+To find out if a mod name is available, try searching for it on
+[content.minetest.net](https://content.minetest.net).
+
+ mymod
+ ├── init.lua (required) - Runs when the game loads.
+ ├── mod.conf (recommended) - Contains description and dependencies.
+ ├── textures (optional)
+ │ └── ... any textures or images
+ ├── sounds (optional)
+ │ └── ... any sounds
+ └── ... any other files or directories
+
+Only the init.lua file is required in a mod for it to run on game load;
+however, mod.conf is recommended and other components may be needed
+depending on the mod's functionality.
+
+
+## Dependencies
+
+A dependency occurs when a mod requires another mod to be loaded before itself.
+One mod may require another mod's code, items, or other resources to be available
+for it to use.
+
+There are two types of dependencies: hard and optional dependencies.
+Both require the mod to be loaded first. If the mod being depended on isn't
+available, a hard dependency will cause the mod to fail to load, while an optional
+dependency might lead to fewer features being enabled.
+
+An optional dependency is useful if you want to optionally support another mod; it can
+enable extra content if the user wishes to use both the mods at the same time.
+
+Dependencies should be listed in mod.conf.
+
+### mod.conf
+
+This file is used for mod metadata including the mod's name, description, and other
+information. For example:
+
+ name = mymod
+ description = Adds foo, bar, and bo.
+ depends = modone, modtwo
+ optional_depends = modthree
+
+### depends.txt
+
+For compatibility with 0.4.x versions of Minetest, instead of only specifying
+dependencies in mod.conf, you need to provide a depends.txt file in which
+you list all dependencies:
+
+ modone
+ modtwo
+ modthree?
+
+Each mod name is on its own line, and mod names with a question mark
+following them are optional dependencies.
+If an optional dependency is installed, it is loaded before the mod;
+however, if the dependency is not installed, the mod still loads.
+This is in contrast to normal dependencies which will cause the current
+mod not to work if the dependency is not installed.
+
+## Mod Packs
+
+Mods can be grouped into mod packs which allow multiple mods to be packaged
+and moved together. They are useful if you want to supply multiple mods to
+a player, but don't want to make them download each one individually.
+
+ modpack1
+ ├── modpack.lua (required) - signals that this is a mod pack
+ ├── mod1
+ │ └── ... mod files
+ └── mymod (optional)
+ └── ... mod files
+
+Please note that a modpack is not a *game*.
+Games have their own organisational structure which will be explained in the
+Games chapter.
+
+## Example
+
+Here is an example which puts all of this together:
+
+### Mod Folder
+ mymod
+ ├── textures
+ │ └── mymod_node.png files
+ ├── depends.txt
+ ├── init.lua
+ └── mod.conf
+
+### depends.txt
+ default
+
+### init.lua
+```lua
+print("This file will be run at load time!")
+
+minetest.register_node("mymod:node", {
+ description = "This is a node",
+ tiles = {"mymod_node.png"},
+ groups = {cracky = 1}
+})
+```
+
+### mod.conf
+ name = mymod
+ descriptions = Adds a node
+ depends = default
+
+This mod has the name "mymod". It has three text files: init.lua, mod.conf,
+and depends.txt.\\
+The script prints a message and then registers a node –
+which will be explained in the next chapter.\\
+There's a single dependency, the
+[default mod](https://content.minetest.net/metapackages/default/), which is
+usually found in Minetest Game.\\
+There is also a texture in textures/ for the node.
diff --git a/_it/basics/lua.md b/_it/basics/lua.md
new file mode 100644
index 0000000..e97f337
--- /dev/null
+++ b/_it/basics/lua.md
@@ -0,0 +1,314 @@
+---
+title: Lua Scripting
+layout: default
+root: ../..
+idx: 1.2
+description: A basic introduction to Lua, including a guide on global/local scope.
+redirect_from: /en/chapters/lua.html
+---
+
+## Introduction
+
+In this chapter we will talk about scripting in Lua, the tools required,
+and go over some techniques which you will probably find useful.
+
+- [Code Editors](#code-editors)
+- [Coding in Lua](#coding-in-lua)
+ - [Program Flow](#program-flow)
+ - [Variable Types](#variable-types)
+ - [Arithmetic Operators](#arithmetic-operators)
+ - [Selection](#selection)
+ - [Logical Operators](#logical-operators)
+- [Programming](#programming)
+- [Local and Global Scope](#local-and-global-scope)
+ - [Locals should be used as much as possible](#locals-should-be-used-as-much-as-possible)
+- [Including other Lua Scripts](#including-other-lua-scripts)
+
+## Code Editors
+
+A code editor with code highlighting is sufficient for writing scripts in Lua.
+Code highlighting gives different colours to different words and characters
+depending on what they mean. This allows you to spot mistakes.
+
+```lua
+function ctf.post(team,msg)
+ if not ctf.team(team) then
+ return false
+ end
+ if not ctf.team(team).log then
+ ctf.team(team).log = {}
+ end
+
+ table.insert(ctf.team(team).log,1,msg)
+ ctf.save()
+
+ return true
+end
+```
+
+For example, keywords in the above snippet are highlighted such as if, then, end, and return.
+table.insert is a function which comes with Lua by default.
+
+Here is a list of common editors well suited for Lua.
+Other editors are available, of course.
+
+* Windows: [Notepad++](http://notepad-plus-plus.org/), [Atom](http://atom.io/), [VS Code](https://code.visualstudio.com/)
+* Linux: Kate, Gedit, [Atom](http://atom.io/), [VS Code](https://code.visualstudio.com/)
+* OSX: [Atom](http://atom.io/), [VS Code](https://code.visualstudio.com/)
+
+## Coding in Lua
+
+### Program Flow
+
+Programs are a series of commands that run one after another.
+We call these commands "statements."
+Program flow is how these statements are executed.
+Different types of flow allow you to skip or jump over sets of commands.
+There are three main types of flow:
+
+* Sequence: Just run one statement after another, no skipping.
+* Selection: Skip over sequences depending on conditions.
+* Iteration: Repeating, looping. Keep running the same
+ statements until a condition is met.
+
+So, what do statements in Lua look like?
+
+```lua
+local a = 2 -- Set 'a' to 2
+local b = 2 -- Set 'b' to 2
+local result = a + b -- Set 'result' to a + b, which is 4
+a = a + 10
+print("Sum is "..result)
+```
+
+Whoa, what happened there?
+
+a, b, and result are *variables*. Local variables are declared
+by using the local keyword, and then given an initial value.
+Local will be discussed in a bit, as it's part of a very important concept called
+*scope*.
+
+The `=` means *assignment*, so `result = a + b` means set "result" to a + b.
+Variable names can be longer than one character unlike in mathematics, as seen with the "result" variable.
+It's also worth noting that Lua is *case-sensitive*; A is a different variable to a.
+
+### Variable Types
+
+A variable will be only one of the following types and can change type after an
+assignment.
+It's good practice to make sure a variable is only ever nil or a single non-nil type.
+
+| Type | Description | Example |
+|----------|---------------------------------|----------------|
+| Nil | Not initialised. The variable is empty, it has no value | `local A`, `D = nil` |
+| Number | A whole or decimal number. | `local A = 4` |
+| String | A piece of text | `local D = "one two three"` |
+| Boolean | True or False | `local is_true = false`, `local E = (1 == 1)` |
+| Table | Lists | Explained below |
+| Function | Can run. May require inputs and may return a value | `local result = func(1, 2, 3)` |
+
+### Arithmetic Operators
+
+Not an exhaustive list. Doesn't contain every possible operator.
+
+| Symbol | Purpose | Example |
+|--------|----------------|---------------------------|
+| A + B | Addition | 2 + 2 = 4 |
+| A - B | Subtraction | 2 - 10 = -8 |
+| A * B | Multiplication | 2 * 2 = 4 |
+| A / B | Division | 100 / 50 = 2 |
+| A ^ B | Powers | 2 ^ 2 = 22 = 4 |
+| A .. B | Join strings | "foo" .. "bar" = "foobar" |
+
+### Selection
+
+The most basic selection is the if statement. It looks like this:
+
+```lua
+local random_number = math.random(1, 100) -- Between 1 and 100.
+if random_number > 50 then
+ print("Woohoo!")
+else
+ print("No!")
+end
+```
+
+That example generates a random number between 1 and 100. It then prints
+"Woohoo!" if that number is bigger than 50, otherwise it prints "No!".
+What else can you get apart from '>'?
+
+### Logical Operators
+
+| Symbol | Purpose | Example |
+|---------|--------------------------------------|-------------------------------------------------------------|
+| A == B | Equals | 1 == 1 (true), 1 == 2 (false) |
+| A ~= B | Doesn't equal | 1 ~= 1 (false), 1 ~= 2 (true) |
+| A > B | Greater than | 5 > 2 (true), 1 > 2 (false), 1 > 1 (false) |
+| A < B | Less than | 1 < 3 (true), 3 < 1 (false), 1 < 1 (false) |
+| A >= B | Greater than or equals | 5 >= 5 (true), 5 >= 3 (true), 5 >= 6 (false) |
+| A <= B | Less than or equals | 3 <= 6 (true), 3 <= 3 (true) |
+| A and B | And (both must be correct) | (2 > 1) and (1 == 1) (true), (2 > 3) and (1 == 1) (false) |
+| A or B | either or. One or both must be true. | (2 > 1) or (1 == 2) (true), (2 > 4) or (1 == 3) (false) |
+| not A | not true | not (1 == 2) (true), not (1 == 1) (false) |
+
+That doesn't contain every possible operator, and you can combine operators like this:
+
+```lua
+if not A and B then
+ print("Yay!")
+end
+```
+
+Which prints "Yay!" if A is false and B is true.
+
+Logical and arithmetic operators work exactly the same;
+they both accept inputs and return a value which can be stored.
+
+```lua
+local A = 5
+local is_equal = (A == 5)
+if is_equal then
+ print("Is equal!")
+end
+```
+
+## Programming
+
+Programming is the action of taking a problem, such as sorting a list
+of items, and then turning it into steps that a computer can understand.
+
+Teaching you the logical process of programming is beyond the scope of this book;
+however, the following websites are quite useful in developing this:
+
+* [Codecademy](http://www.codecademy.com/) is one of the best resources for
+ learning to 'code', it provides an interactive tutorial experience.
+* [Scratch](https://scratch.mit.edu) is a good resource when starting from
+ absolute basics, learning the problem-solving techniques required to program.\\
+ Scratch is **designed to teach children** how to program and isn't a serious
+ programming language.
+
+## Local and Global Scope
+
+Whether a variable is local or global determines where it can be written to or read to.
+A local variable is only accessible from where it is defined. Here are some examples:
+
+```lua
+-- Accessible from within this script file
+local one = 1
+
+function myfunc()
+ -- Accessible from within this function
+ local two = one + one
+
+ if two == one then
+ -- Accessible from within this if statement
+ local three = one + two
+ end
+end
+```
+
+Whereas global variables can be accessed from anywhere in the script file, and from any other mod.
+
+```lua
+my_global_variable = "blah"
+
+function one()
+ my_global_variable = "three"
+end
+
+print(my_global_variable) -- Output: "blah"
+one()
+print(my_global_variable) -- Output: "three"
+```
+
+
+### Locals should be used as much as possible
+
+Lua is global by default (unlike most other programming languages).
+Local variables must be identified as such.
+
+```lua
+function one()
+ foo = "bar"
+end
+
+function two()
+ print(dump(foo)) -- Output: "bar"
+end
+
+one()
+two()
+```
+
+dump() is a function that can turn any variable into a string so the programmer can
+see what it is. The foo variable will be printed as "bar", including the quotes
+which show it is a string.
+
+This is sloppy coding and Minetest will, in fact, warn about this:
+
+ Assignment to undeclared global 'foo' inside function at init.lua:2
+
+To correct this, use "local":
+
+```lua
+function one()
+ local foo = "bar"
+end
+
+function two()
+ print(dump(foo)) -- Output: nil
+end
+
+one()
+two()
+```
+
+Remember that nil means **not initialised**.
+The variable hasn't been assigned a value yet,
+doesn't exist, or has been uninitialised (ie: set to nil).
+
+The same goes for functions. Functions are variables of a special type, and
+should be made local, as other mods could have functions of the same name.
+
+```lua
+local function foo(bar)
+ return bar * 2
+end
+```
+
+API tables should be used to allow other mods to call the functions, like so:
+
+```lua
+mymod = {}
+
+function mymod.foo(bar)
+ return "foo" .. bar
+end
+
+-- In another mod, or script:
+mymod.foo("foobar")
+```
+
+## Including other Lua Scripts
+
+The recommended way to include other Lua scripts in a mod is to use *dofile*.
+
+```lua
+dofile(minetest.get_modpath("modname") .. "/script.lua")
+```
+
+"local" variables declared outside of any functions in a script file will be local to that script.
+A script can return a value, which is useful for sharing private locals:
+
+```lua
+-- script.lua
+return "Hello world!"
+
+-- init.lua
+local ret = dofile(minetest.get_modpath("modname") .. "/script.lua")
+print(ret) -- Hello world!
+```
+
+Later chapters will discuss how to split up the code of a mod in a lot of detail.
+However, the simplistic approach for now is to have different files for different
+types of things - nodes.lua, crafts.lua, craftitems.lua, etc.
diff --git a/_it/games/games.md b/_it/games/games.md
new file mode 100644
index 0000000..2ead9eb
--- /dev/null
+++ b/_it/games/games.md
@@ -0,0 +1,93 @@
+---
+title: Creating Games
+layout: default
+root: ../..
+idx: 7.1
+---
+
+## Introduction
+
+The power of Minetest is the ability to easily develop games without the need
+to create your own voxel graphics, voxel algorithms, or fancy networking code.
+
+- [What is a Game?](#what-is-a-game)
+- [Game Directory](#game-directory)
+- [Inter-game Compatibility](#inter-game-compatibility)
+ - [API Compatibility](#api-compatibility)
+ - [Groups and Aliases](#groups-and-aliases)
+- [Your Turn](#your-turn)
+
+## What is a Game?
+
+Games are a collection of mods which work together to make a cohesive game.
+A good game has a consistent underlying theme and a direction, for example,
+it could be a classic crafter miner with hard survival elements, or
+it could be a space simulation game with a steampunk automation aesthetic.
+
+Game design is a complex topic and is actually a whole field of expertise.
+It's beyond the scope of the book to more than briefly touch on it.
+
+## Game Directory
+
+The structure and location of a game will seem rather familiar after working
+with mods.
+Games are found in a game location, such as `minetest/games/foo_game`.
+
+ foo_game
+ ├── game.conf
+ ├── menu
+ │ ├── header.png
+ │ ├── background.png
+ │ └── icon.png
+ ├── minetest.conf
+ ├── mods
+ │ └── ... mods
+ ├── README.txt
+ └── settingtypes.txt
+
+The only thing that is required is a mods folder, but `game.conf` and `menu/icon.png`
+are recommended.
+
+## Inter-game Compatibility
+
+### API Compatibility
+
+It's a good idea to try to keep as much API compatibility with Minetest Game as
+convenient, as it'll make porting mods to another game much easier.
+
+The best way to keep compatibility with another game is to keep API compatibility
+with any mods which have the same name.
+That is, if a mod uses the same name as another mod, even if third party,
+it should have a compatible API.
+For example, if a game includes a mod called `doors`, then it should have the
+same API as `doors` in Minetest Game.
+
+API compatibility for a mod is the sum of the following things:
+
+* Lua API table - All documented/advertised functions in the global table which shares the same name.
+ For example, `mobs.register_mob`.
+* Registered Nodes/Items - The presence of items.
+
+Small breakages aren't that bad, such as not having a random utility
+function that was only actually used internally, but bigger breakages
+related to core features are very bad.
+
+It's difficult to maintain API compatibility with a disgusting mega God-mod like
+*default* in Minetest Game, in which case the game shouldn't include a mod named
+default.
+
+API compatibility also applies to other third-party mods and games,
+so try to make sure that any new mods have a unique mod name.
+To check whether a mod name has been taken, search for it on
+[content.minetest.net](https://content.minetest.net/).
+
+### Groups and Aliases
+
+Groups and Aliases are both useful tools in keeping compatibility between games,
+as it allows item names to be different between different games. Common nodes
+like stone and wood should have groups to indicate the material. It's also a
+good idea to provide aliases from default nodes to any direct replacements.
+
+## Your Turn
+
+* Create a simple game where the player gains points from digging special blocks.
diff --git a/_it/index.md b/_it/index.md
new file mode 100644
index 0000000..630dc92
--- /dev/null
+++ b/_it/index.md
@@ -0,0 +1,35 @@
+---
+title: Front Cover
+layout: default
+homepage: true
+no_header: true
+root: ..
+idx: 0.1
+---
+
+
+
Minetest Modding Book
+
+ by rubenwardy
+ with editing by Shara
+
+
+## Introduction
+
+Minetest uses Lua scripts to provide modding support.
+This book aims to teach you how to create your own mods, starting from the basics.
+Each chapter focuses on a particular part of the API, and will soon get you making
+your own mods.
+
+As well as [reading this book online](https://rubenwardy.com/minetest_modding_book),
+you can also [download it in HTML form](https://github.com/rubenwardy/minetest_modding_book/releases).
+
+### Feedback and Contributions
+
+Noticed a mistake, or want to give feedback? Make sure to tell me about it.
+
+* Create a [GitHub Issue](https://github.com/rubenwardy/minetest_modding_book/issues).
+* Post in the [Forum Topic](https://forum.minetest.net/viewtopic.php?f=14&t=10729).
+* [Contact me](https://rubenwardy.com/contact/).
+* Fancy contributing?
+ [Read the README](https://github.com/rubenwardy/minetest_modding_book/blob/master/README.md).
diff --git a/_it/items/creating_textures.md b/_it/items/creating_textures.md
new file mode 100644
index 0000000..8f4b66f
--- /dev/null
+++ b/_it/items/creating_textures.md
@@ -0,0 +1,84 @@
+---
+title: Creating Textures
+layout: default
+root: ../..
+idx: 2.2
+description: An introduction to making textures in your editor of choice, an a guide on GIMP.
+redirect_from: /en/chapters/creating_textures.html
+---
+
+## Introduction
+
+Being able to create and optimise textures is a very useful skill when
+developing for Minetest.
+There are many techniques relevant to working on pixel art textures,
+and understanding these techniques will greatly improve
+the quality of the textures you create.
+
+Detailed approaches to creating good pixel art are outside the scope
+of this book, and instead only the most relevant basic techniques
+will be covered.
+There are many [good online tutorials](http://www.photonstorm.com/art/tutorials-art/16x16-pixel-art-tutorial)
+available, which cover pixel art in much more detail.
+
+- [Techniques](#techniques)
+ - [Using the Pencil](#using-the-pencil)
+ - [Tiling](#tiling)
+ - [Transparency](#transparency)
+- [Editors](#editors)
+ - [MS Paint](#ms-paint)
+ - [GIMP](#gimp)
+
+## Techniques
+
+### Using the Pencil
+
+The pencil tool is available in most editors. When set to its lowest size,
+it allows you to edit one pixel at a time without changing any other parts
+of the image. By manipulating the pixels one at a time, you create clear
+and sharp textures without unintended blurring. It also gives you a high
+level of precision and control.
+
+### Tiling
+
+Textures used for nodes should generally be designed to tile. This means
+when you place multiple nodes with the same texture together, the edges line
+up correctly.
+
+
+
+If you fail to match the edges correctly, the result is far less pleasing
+to look at.
+
+
+
+### Transparency
+
+Transparency is important when creating textures for nearly all craftitems
+and some nodes, such as glass.
+Not all editors support transparency, so make sure you choose an
+editor which is suitable for the textures you wish to create.
+
+## Editors
+
+### MS Paint
+
+MS Paint is a simple editor which can be useful for basic texture
+design; however, it does not support transparency.
+This usually won't matter when making textures for the sides of nodes,
+but if you need transparency in your textures you should choose a
+different editor.
+
+### GIMP
+
+GIMP is commonly used in the Minetest community. It has quite a high
+learning curve because many of its features are not immediately
+obvious.
+
+When using GIMP, the pencil tool can be selected from the Toolbox:
+
+
+
+It's also advisable to select the Hard edge checkbox for the eraser tool.
diff --git a/_it/items/inventories.md b/_it/items/inventories.md
new file mode 100644
index 0000000..31d35ba
--- /dev/null
+++ b/_it/items/inventories.md
@@ -0,0 +1,342 @@
+---
+title: ItemStacks and Inventories
+layout: default
+root: ../..
+idx: 2.4
+description: Manipulate InvRefs and ItemStacks
+redirect_from:
+- /en/chapters/inventories.html
+- /en/chapters/itemstacks.html
+- /en/inventories/inventories.html
+- /en/inventories/itemstacks.html
+---
+
+## Introduction
+
+In this chapter, you will learn how to use and manipulate inventories, whether
+that be a player inventory, a node inventory, or a detached inventory.
+
+- [What are ItemStacks and Inventories?](#what-are-itemstacks-and-inventories)
+- [ItemStacks](#itemstacks)
+- [Inventory Locations](#inventory-locations)
+- [Lists](#lists)
+ - [Size and Width](#size-and-width)
+ - [Checking Contents](#checking-contents)
+- [Modifying Inventories and ItemStacks](#modifying-inventories-and-itemstacks)
+ - [Adding to a List](#adding-to-a-list)
+ - [Taking Items](#taking-items)
+ - [Manipulating Stacks](#manipulating-stacks)
+- [Wear](#wear)
+- [Lua Tables](#lua-tables)
+
+## What are ItemStacks and Inventories?
+
+An ItemStack is the data behind a single cell in an inventory.
+
+An *inventory* is a collection of *inventory lists*, each of which
+is a 2D grid of ItemStacks.
+Inventory lists are simply called *lists* in the context
+of inventories.
+The point of an inventory is to allow multiple grids when Players
+and Nodes only have at most one inventory in them.
+
+## ItemStacks
+
+ItemStacks have three components to them.
+
+The item name may be the item name of a registered item, an alias, or an unknown
+item name.
+Unknown items are common when users uninstall mods, or when mods remove items without
+precautions, such as registering aliases.
+
+```lua
+print(stack:get_name())
+stack:set_name("default:dirt")
+
+if not stack:is_known() then
+ print("Is an unknown item!")
+end
+```
+
+The count will always be 0 or greater.
+Through normal gameplay, the count should be no more than the maximum stack size
+of the item - `stack_max`.
+However, admin commands and buggy mods may result in stacks exceeding the maximum
+size.
+
+```lua
+print(stack:get_stack_max())
+```
+
+
+
+
+An ItemStack can be empty, in which case the count will be 0.
+
+```lua
+print(stack:get_count())
+stack:set_count(10)
+```
+
+ItemStacks can be constructed in multiple ways using the ItemStack function.
+
+```lua
+ItemStack() -- name="", count=0
+ItemStack("default:pick_stone") -- count=1
+ItemStack("default:stone 30")
+ItemStack({ name = "default:wood", count = 10 })
+```
+
+Item metadata is an unlimited key-value store for data about the item.
+Key-value means that you use a name (called the key) to access the data (called the value).
+Some keys have special meaning, such as `description` which is used to have a per-stack
+item description.
+This will be covered in more detail in the Metadata and Storage chapter.
+
+## Inventory Locations
+
+An Inventory Location is where and how the inventory is stored.
+There are three types of inventory location: player, node, and detached.
+An inventory is directly tied to one and only one location - updating the inventory
+will cause it to update immediately.
+
+Node inventories are related to the position of a specific node, such as a chest.
+The node must be loaded because it is stored in [node metadata](../map/storage.html#metadata).
+
+```lua
+local inv = minetest.get_inventory({ type="node", pos={x=1, y=2, z=3} })
+```
+
+The above obtains an *inventory reference*, commonly referred to as *InvRef*.
+Inventory references are used to manipulate an inventory.
+*Reference* means that the data isn't actually stored inside that object,
+but the object instead directly updates the data in-place.
+
+The location of an inventory reference can be found like so:
+
+```lua
+local location = inv:get_location()
+```
+
+Player inventories can be obtained similarly or using a player reference.
+The player must be online to access their inventory.
+
+```lua
+local inv = minetest.get_inventory({ type="player", name="player1" })
+-- or
+local inv = player:get_inventory()
+```
+
+A detached inventory is one which is independent of players or nodes.
+Detached inventories also don't save over a restart.
+Detached inventories need to be created before they can be used -
+this will be covered later.
+
+```lua
+local inv = minetest.get_inventory({
+ type="detached", name="inventory_name" })
+```
+
+Unlike the other types of inventory, you must first create a detached inventory:
+
+```lua
+minetest.create_detached_inventory("inventory_name")
+```
+
+The create_detached_inventory function accepts 3 arguments, only first is required.
+The second argument takes a table of callbacks, which can be used to control how
+players interact with the inventory:
+
+```lua
+-- Input only detached inventory
+minetest.create_detached_inventory("inventory_name", {
+ allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
+ return count -- allow moving
+ end,
+
+ allow_put = function(inv, listname, index, stack, player)
+ return stack:get_count() -- allow putting
+ end,
+
+ allow_take = function(inv, listname, index, stack, player)
+ return -1 -- don't allow taking
+ end,
+
+ on_put = function(inv, listname, index, stack, player)
+ minetest.chat_send_all(player:get_player_name() ..
+ " gave " .. stack:to_string() ..
+ " to the donation chest at " .. minetest.pos_to_str(pos))
+ end,
+})
+```
+
+Permission callbacks - ie: those starting with `allow_`- return the number
+of items to transfer, with -1 being used to prevent transfer completely.
+
+Action callbacks - starting with `on_` - don't have a return value and
+can't prevent transfers.
+
+## Lists
+
+Inventory Lists are a concept used to allow multiple grids to be stored inside a single location.
+This is especially useful for the player as there are a number of common lists
+which all games have, such as the *main* inventory and *craft* slots.
+
+### Size and Width
+
+Lists have a size, which is the total number of cells in the grid, and a width,
+which is only used within the engine.
+The width of the list is not used when drawing the inventory in a window,
+because the code behind the window determines the width to use.
+
+```lua
+if inv:set_size("main", 32) then
+ inv:set_width("main", 8)
+ print("size: " .. inv.get_size("main"))
+ print("width: " .. inv:get_width("main"))
+else
+ print("Error! Invalid itemname or size to set_size()")
+end
+```
+
+`set_size` will fail and return false if the listname or size is invalid.
+For example, the new size may be too small to fit all the current items
+in the inventory.
+
+### Checking Contents
+
+`is_empty` can be used to see if a list contains any items:
+
+```lua
+if inv:is_empty("main") then
+ print("The list is empty!")
+end
+```
+
+`contains_item` can be used to see if a list contains a specific item.
+
+## Modifying Inventories and ItemStacks
+
+### Adding to a List
+
+To add items to a list named `"main"` while respecting maximum stack sizes:
+
+```lua
+local stack = ItemStack("default:stone 99")
+local leftover = inv:add_item("main", stack)
+if leftover:get_count() > 0 then
+ print("Inventory is full! " ..
+ leftover:get_count() .. " items weren't added")
+end
+```
+
+### Taking Items
+
+To remove items from a list:
+
+```lua
+local taken = inv:remove_item("main", stack)
+print("Took " .. taken:get_count())
+```
+
+### Manipulating Stacks
+
+You can modify individual stacks by first getting them:
+
+```lua
+local stack = inv:get_stack(listname, 0)
+```
+
+Then modifying them by setting properties or by using the methods which
+respect `stack_size`:
+
+
+```lua
+local stack = ItemStack("default:stone 50")
+local to_add = ItemStack("default:stone 100")
+local leftover = stack:add_item(to_add)
+local taken = stack:take_item(19)
+
+print("Could not add" .. leftover:get_count() .. " of the items.")
+-- ^ will be 51
+
+print("Have " .. stack:get_count() .. " items")
+-- ^ will be 80
+-- min(50+100, stack_max) - 19 = 80
+-- where stack_max = 99
+```
+
+`add_item` will add items to an ItemStack and return any that could not be added.
+`take_item` will take up to the number of items but may take less, and returns the stack taken.
+
+Finally, set the item stack:
+
+```lua
+inv:set_stack(listname, 0, stack)
+```
+
+## Wear
+
+Tools can have wear; wear shows a progress bar and makes the tool break when completely worn.
+Wear is a number out of 65535; the higher it is, the more worn the tool is.
+
+Wear can be manipulated using `add_wear()`, `get_wear()`, and `set_wear(wear)`.
+
+```lua
+local stack = ItemStack("default:pick_mese")
+local max_uses = 10
+
+-- This is done automatically when you use a tool that digs things
+-- It increases the wear of an item by one use.
+stack:add_wear(65535 / (max_uses - 1))
+```
+
+When digging a node, the amount of wear a tool gets may depend on the node
+being dug. So max_uses varies depending on what is being dug.
+
+## Lua Tables
+
+ItemStacks and Inventories can be converted to and from tables.
+This is useful for copying and bulk operations.
+
+```lua
+-- Entire inventory
+local data = inv1:get_lists()
+inv2:set_lists(data)
+
+-- One list
+local listdata = inv1:get_list("main")
+inv2:set_list("main", listdata)
+```
+
+The table of lists returned by `get_lists()` will be in this form:
+
+```lua
+{
+ list_one = {
+ ItemStack,
+ ItemStack,
+ ItemStack,
+ ItemStack,
+ -- inv:get_size("list_one") elements
+ },
+ list_two = {
+ ItemStack,
+ ItemStack,
+ ItemStack,
+ ItemStack,
+ -- inv:get_size("list_two") elements
+ }
+}
+```
+
+`get_list()` will return a single list as just a list of ItemStacks.
+
+One important thing to note is that the set methods above don't change the size
+of the lists.
+This means that you can clear a list by setting it to an empty table and it won't
+decrease in size:
+
+```lua
+inv:set_list("main", {})
+```
diff --git a/_it/items/node_drawtypes.md b/_it/items/node_drawtypes.md
new file mode 100644
index 0000000..b194706
--- /dev/null
+++ b/_it/items/node_drawtypes.md
@@ -0,0 +1,446 @@
+---
+title: Node Drawtypes
+layout: default
+root: ../..
+idx: 2.3
+description: Guide to all drawtypes, including node boxes/nodeboxes and mesh nodes.
+redirect_from: /en/chapters/node_drawtypes.html
+---
+
+## Introduction
+
+The method by which a node is drawn is called a *drawtype*. There are many
+available drawtypes. The behaviour of a drawtype can be controlled
+by providing properties in the node type definition. These properties
+are fixed for all instances of this node. It is possible to control some properties
+per-node using something called `param2`.
+
+In the previous chapter, the concept of nodes and items was introduced, but a
+full definition of a node wasn't given. The Minetest world is a 3D grid of
+positions. Each position is called a node, and consists of the node type
+(name) and two parameters (param1 and param2). The function
+`minetest.register_node` is a bit misleading in that it doesn't actually
+register a node - it registers a new *type* of node.
+
+The node params are used to control how a node is individually rendered.
+`param1` is used to store the lighting of a node, and the meaning of
+`param2` depends on the `paramtype2` property of the node type definition.
+
+- [Cubic Nodes: Normal and Allfaces](#cubic-nodes-normal-and-allfaces)
+- [Glasslike Nodes](#glasslike-nodes)
+ - [Glasslike_Framed](#glasslikeframed)
+- [Airlike Nodes](#airlike-nodes)
+- [Lighting and Sunlight Propagation](#lighting-and-sunlight-propagation)
+- [Liquid Nodes](#liquid-nodes)
+- [Node Boxes](#node-boxes)
+ - [Wallmounted Node Boxes](#wallmounted-node-boxes)
+- [Mesh Nodes](#mesh-nodes)
+- [Signlike Nodes](#signlike-nodes)
+- [Plantlike Nodes](#plantlike-nodes)
+- [Firelike Nodes](#firelike-nodes)
+- [More Drawtypes](#more-drawtypes)
+
+
+## Cubic Nodes: Normal and Allfaces
+
+
+
+The normal drawtype is typically used to render a cubic node.
+If the side of a normal node is against a solid side, then that side won't be rendered,
+resulting in a large performance gain.
+
+In contrast, the allfaces drawtype will still render the inner side when up against
+a solid node. This is good for nodes with partially transparent sides, such as
+leaf nodes. You can use the allfaces_optional drawtype to allow users to opt-out
+of the slower drawing, in which case it'll act like a normal node.
+
+```lua
+minetest.register_node("mymod:diamond", {
+ description = "Alien Diamond",
+ tiles = {"mymod_diamond.png"},
+ groups = {cracky = 3},
+})
+
+minetest.register_node("default:leaves", {
+ description = "Leaves",
+ drawtype = "allfaces_optional",
+ tiles = {"default_leaves.png"}
+})
+```
+
+Note: the normal drawtype is the default drawtype, so you don't need to explicitly
+specify it.
+
+
+## Glasslike Nodes
+
+The difference between glasslike and normal nodes is that placing a glasslike node
+next to a normal node won't cause the side of the normal node to be hidden.
+This is useful because glasslike nodes tend to be transparent, and so using a normal
+drawtype would result in the ability to see through the world.
+
+
+
+```lua
+minetest.register_node("default:obsidian_glass", {
+ description = "Obsidian Glass",
+ drawtype = "glasslike",
+ tiles = {"default_obsidian_glass.png"},
+ paramtype = "light",
+ is_ground_content = false,
+ sunlight_propagates = true,
+ sounds = default.node_sound_glass_defaults(),
+ groups = {cracky=3,oddly_breakable_by_hand=3},
+})
+```
+
+### Glasslike_Framed
+
+This makes the node's edge go around the whole thing with a 3D effect, rather
+than individual nodes, like the following:
+
+
+
+You can use the glasslike_framed_optional drawtype to allow the user to *opt-in*
+to the framed appearance.
+
+```lua
+minetest.register_node("default:glass", {
+ description = "Glass",
+ drawtype = "glasslike_framed",
+ tiles = {"default_glass.png", "default_glass_detail.png"},
+ inventory_image = minetest.inventorycube("default_glass.png"),
+ paramtype = "light",
+ sunlight_propagates = true, -- Sunlight can shine through block
+ groups = {cracky = 3, oddly_breakable_by_hand = 3},
+ sounds = default.node_sound_glass_defaults()
+})
+```
+
+
+## Airlike Nodes
+
+These nodes are not rendered and thus have no textures.
+
+```lua
+minetest.register_node("myair:air", {
+ description = "MyAir (you hacker you!)",
+ drawtype = "airlike",
+ paramtype = "light",
+ sunlight_propagates = true,
+
+ walkable = false, -- Would make the player collide with the air node
+ pointable = false, -- You can't select the node
+ diggable = false, -- You can't dig the node
+ buildable_to = true, -- Nodes can be replace this node.
+ -- (you can place a node and remove the air node
+ -- that used to be there)
+
+ air_equivalent = true,
+ drop = "",
+ groups = {not_in_creative_inventory=1}
+})
+```
+
+
+## Lighting and Sunlight Propagation
+
+The lighting of a node is stored in param1. In order to work out how to shade
+a node's side, the light value of the neighbouring node is used.
+Because of this, solid nodes don't have light values because they block light.
+
+By default, a node type won't allow light to be stored in any node instances.
+It's usually desirable for some nodes such as glass and air to be able to
+let light through. To do this, there are two properties which need to be defined:
+
+```lua
+paramtype = "light",
+sunlight_propagates = true,
+```
+
+The first line means that param1 does, in fact, store the light level.
+The second line means that sunlight should go through this node without decreasing in value.
+
+
+## Liquid Nodes
+
+
+
+Each type of liquid requires two node definitions - one for the liquid source, and
+another for flowing liquid.
+
+```lua
+-- Some properties have been removed as they are beyond
+-- the scope of this chapter.
+minetest.register_node("default:water_source", {
+ drawtype = "liquid",
+ paramtype = "light",
+
+ inventory_image = minetest.inventorycube("default_water.png"),
+ -- ^ this is required to stop the inventory image from being animated
+
+ tiles = {
+ {
+ name = "default_water_source_animated.png",
+ animation = {
+ type = "vertical_frames",
+ aspect_w = 16,
+ aspect_h = 16,
+ length = 2.0
+ }
+ }
+ },
+
+ special_tiles = {
+ -- New-style water source material (mostly unused)
+ {
+ name = "default_water_source_animated.png",
+ animation = {type = "vertical_frames", aspect_w = 16,
+ aspect_h = 16, length = 2.0},
+ backface_culling = false,
+ }
+ },
+
+ --
+ -- Behavior
+ --
+ walkable = false, -- The player falls through
+ pointable = false, -- The player can't highlight it
+ diggable = false, -- The player can't dig it
+ buildable_to = true, -- Nodes can be replace this node
+
+ alpha = 160,
+
+ --
+ -- Liquid Properties
+ --
+ drowning = 1,
+ liquidtype = "source",
+
+ liquid_alternative_flowing = "default:water_flowing",
+ -- ^ when the liquid is flowing
+
+ liquid_alternative_source = "default:water_source",
+ -- ^ when the liquid is a source
+
+ liquid_viscosity = WATER_VISC,
+ -- ^ how fast
+
+ liquid_range = 8,
+ -- ^ how far
+
+ post_effect_color = {a=64, r=100, g=100, b=200},
+ -- ^ colour of screen when the player is submerged
+})
+```
+
+Flowing nodes have a similar definition, but with a different name and animation.
+See default:water_flowing in the default mod in minetest_game for a full example.
+
+
+## Node Boxes
+
+
+
+Node boxes allow you to create a node which is not cubic, but is instead made out
+of as many cuboids as you like.
+
+```lua
+minetest.register_node("stairs:stair_stone", {
+ drawtype = "nodebox",
+ paramtype = "light",
+ node_box = {
+ type = "fixed",
+ fixed = {
+ {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
+ {-0.5, 0, 0, 0.5, 0.5, 0.5},
+ },
+ }
+})
+```
+
+The most important part is the node box table:
+
+```lua
+{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
+{-0.5, 0, 0, 0.5, 0.5, 0.5}
+```
+
+Each row is a cuboid which are joined to make a single node.
+The first three numbers are the co-ordinates, from -0.5 to 0.5 inclusive, of
+the bottom front left most corner, the last three numbers are the opposite corner.
+They are in the form X, Y, Z, where Y is up.
+
+You can use the [NodeBoxEditor](https://forum.minetest.net/viewtopic.php?f=14&t=2840) to
+create node boxes by dragging the edges, it is more visual than doing it by hand.
+
+
+### Wallmounted Node Boxes
+
+Sometimes you want different nodeboxes for when it is placed on the floor, wall, or ceiling like with torches.
+
+```lua
+minetest.register_node("default:sign_wall", {
+ drawtype = "nodebox",
+ node_box = {
+ type = "wallmounted",
+
+ -- Ceiling
+ wall_top = {
+ {-0.4375, 0.4375, -0.3125, 0.4375, 0.5, 0.3125}
+ },
+
+ -- Floor
+ wall_bottom = {
+ {-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 0.3125}
+ },
+
+ -- Wall
+ wall_side = {
+ {-0.5, -0.3125, -0.4375, -0.4375, 0.3125, 0.4375}
+ }
+ },
+})
+```
+
+## Mesh Nodes
+
+Whilst node boxes are generally easier to make, they are limited in that
+they can only consist of cuboids. Node boxes are also unoptimised;
+Inner faces will still be rendered even when they're completely hidden.
+
+A face is a flat surface on a mesh. An inner face occurs when the faces of two
+different node boxes overlap, causing parts of the node box model to be
+invisible but still rendered.
+
+You can register a mesh node as so:
+
+```lua
+minetest.register_node("mymod:meshy", {
+ drawtype = "mesh",
+
+ -- Holds the texture for each "material"
+ tiles = {
+ "mymod_meshy.png"
+ },
+
+ -- Path to the mesh
+ mesh = "mymod_meshy.b3d",
+})
+```
+
+Make sure that the mesh is available in a `models` directory.
+Most of the time the mesh should be in your mod's folder, however, it's okay to
+share a mesh provided by another mod you depend on. For example, a mod that
+adds more types of furniture may want to share the model provided by a basic
+furniture mod.
+
+
+## Signlike Nodes
+
+Signlike nodes are flat nodes with can be mounted on the sides of other nodes.
+
+Despite the name of this drawtype, signs don't actually tend to use signlike but
+instead use the `nodebox` drawtype to provide a 3D effect. The `signlike` drawtype
+is, however, commonly used by ladders.
+
+```lua
+minetest.register_node("default:ladder_wood", {
+ drawtype = "signlike",
+
+ tiles = {"default_ladder_wood.png"},
+
+ -- Required: store the rotation in param2
+ paramtype2 = "wallmounted",
+
+ selection_box = {
+ type = "wallmounted",
+ },
+})
+```
+
+
+## Plantlike Nodes
+
+
+
+Plantlike nodes draw their tiles in an X like pattern.
+
+```lua
+minetest.register_node("default:papyrus", {
+ drawtype = "plantlike",
+
+ -- Only one texture used
+ tiles = {"default_papyrus.png"},
+
+ selection_box = {
+ type = "fixed",
+ fixed = {-6 / 16, -0.5, -6 / 16, 6 / 16, 0.5, 6 / 16},
+ },
+})
+```
+
+## Firelike Nodes
+
+Firelike is similar to plantlike, except that it is designed to "cling" to walls
+and ceilings.
+
+
+
+```lua
+minetest.register_node("mymod:clingere", {
+ drawtype = "firelike",
+
+ -- Only one texture used
+ tiles = { "mymod:clinger" },
+})
+```
+
+## More Drawtypes
+
+This is not a comprehensive list, there are more types including:
+
+* Fencelike
+* Plantlike rooted - for underwater plants
+* Raillike - for cart tracks
+* Torchlike - for 2D wall/floor/ceiling nodes.
+ The torches in Minetest Game actually use two different node definitions of
+ mesh nodes (default:torch and default:torch_wall).
+
+As always, read the [Lua API documentation](../../lua_api.html#node-drawtypes)
+for the complete list.
diff --git a/_it/items/nodes_items_crafting.md b/_it/items/nodes_items_crafting.md
new file mode 100644
index 0000000..1d8e081
--- /dev/null
+++ b/_it/items/nodes_items_crafting.md
@@ -0,0 +1,382 @@
+---
+title: Nodes, Items, and Crafting
+layout: default
+root: ../..
+idx: 2.1
+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
+
+Registering new nodes and craftitems, and creating craft recipes, are
+basic requirements for many mods.
+
+- [What are Nodes and Items?](#what-are-nodes-and-items)
+- [Registering Items](#registering-items)
+ - [Item Names and Aliases](#item-names-and-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)
+ - [Cooking and Fuel](#cooking-and-fuel)
+- [Groups](#groups)
+- [Tools, Capabilities, and Dig Types](#tools-capabilities-and-dig-types)
+
+## 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.
+
+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 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.
+
+## 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.
+
+```lua
+minetest.register_craftitem("modname:itemname", {
+ description = "My Special Item",
+ inventory_image = "modname_itemname.png"
+})
+```
+
+### Item Names and Aliases
+
+Every item has an item name used to refer to it, which should be in the
+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.
+
+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:
+
+* 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.
+ It's important to avoid aliasing to an unobtainable node if the remove node
+ could be obtained.
+* 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.
+
+```lua
+minetest.register_alias("dirt", "default:dirt")
+```
+
+Mods need to make sure to resolve aliases before dealing directly with item names,
+as the engine won't do this.
+This is pretty simple though:
+
+```lua
+itemname = minetest.registered_aliases[itemname] or itemname
+```
+
+### Textures
+
+Textures should be placed in the textures/ folder with names in the format
+`modname_itemname.png`.\\
+JPEG textures are supported, but they do not support transparency and are generally
+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.
+
+## Registering a basic node
+
+```lua
+minetest.register_node("mymod:diamond", {
+ description = "Alien Diamond",
+ tiles = {"mymod_diamond.png"},
+ is_ground_content = true,
+ groups = {cracky=3, stone=1}
+})
+```
+
+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:
+
+ up (+Y), down (-Y), right (+X), left (-X), back (+Z), front (-Z).
+ (+Y, -Y, +X, -X, +Z, -Z)
+
+Remember that +Y is upwards in Minetest, as is the convention with
+3D computer graphics.
+
+```lua
+minetest.register_node("mymod:diamond", {
+ description = "Alien Diamond",
+ tiles = {
+ "mymod_diamond_up.png", -- y+
+ "mymod_diamond_down.png", -- y-
+ "mymod_diamond_right.png", -- x+
+ "mymod_diamond_left.png", -- x-
+ "mymod_diamond_back.png", -- z+
+ "mymod_diamond_front.png", -- z-
+ },
+ is_ground_content = true,
+ groups = {cracky = 3},
+ drop = "mymod:diamond_fragments"
+ -- ^ Rather than dropping diamond, drop mymod:diamond_fragments
+})
+```
+
+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`
+property.
+
+* shaped - Ingredients must be in the correct position.
+* shapeless - It doesn't matter where the ingredients are,
+ just that there is the right amount.
+* cooking - Recipes for the furnace to use.
+* fuel - Defines items which can be burned in furnaces.
+* tool_repair - Defines items which can be tool repaired.
+
+Craft recipes are not items, so they do not use Item Names to uniquely
+identify themselves.
+
+### Shaped
+
+Shaped recipes are when the ingredients need to be in the right shape or
+pattern to work. In the example below, the fragments need to be in a
+chair-like pattern for the craft to work.
+
+```lua
+minetest.register_craft({
+ type = "shaped",
+ output = "mymod:diamond_chair 99",
+ recipe = {
+ {"mymod:diamond_fragments", "", ""},
+ {"mymod:diamond_fragments", "mymod:diamond_fragments", ""},
+ {"mymod:diamond_fragments", "mymod:diamond_fragments", ""}
+ }
+})
+```
+
+One thing to note is the blank column on the right-hand side.
+This means that there *must* be an empty column to the right of the shape, otherwise
+this won't work.
+If this empty column shouldn't be required, then the empty strings can be left
+out like so:
+
+```lua
+minetest.register_craft({
+ output = "mymod:diamond_chair 99",
+ recipe = {
+ {"mymod:diamond_fragments", "" },
+ {"mymod:diamond_fragments", "mymod:diamond_fragments"},
+ {"mymod:diamond_fragments", "mymod:diamond_fragments"}
+ }
+})
+```
+
+The type field isn't actually needed for shaped crafts, as shaped is the
+default craft type.
+
+### Shapeless
+
+Shapeless recipes are a type of recipe which is used when it doesn't matter
+where the ingredients are placed, just that they're there.
+
+```lua
+minetest.register_craft({
+ type = "shapeless",
+ output = "mymod:diamond 3",
+ recipe = {
+ "mymod:diamond_fragments",
+ "mymod:diamond_fragments",
+ "mymod:diamond_fragments",
+ },
+})
+```
+
+### Cooking and Fuel
+
+Recipes with the type "cooking" are not made in the crafting grid,
+but are cooked in furnaces, or other cooking tools that might be found in mods.
+
+```lua
+minetest.register_craft({
+ type = "cooking",
+ output = "mymod:diamond_fragments",
+ recipe = "default:coalblock",
+ cooktime = 10,
+})
+```
+
+The only real difference in the code is that the recipe is just a single item,
+compared to being in a table (between braces).
+They also have an optional "cooktime" parameter which
+defines how long the item takes to cook.
+If this is not set, it defaults to 3.
+
+The recipe above works when the coal block is in the input slot,
+with some form of fuel below it.
+It creates diamond fragments after 10 seconds!
+
+This type is an accompaniment to the cooking type, as it defines
+what can be burned in furnaces and other cooking tools from mods.
+
+```lua
+minetest.register_craft({
+ type = "fuel",
+ recipe = "mymod:diamond",
+ burntime = 300,
+})
+```
+
+They don't have an output like other recipes, but they have a burn time
+which defines how long they will last as fuel in seconds.
+So, the diamond is good as fuel for 300 seconds!
+
+## Groups
+
+Items can be members of many groups and groups can have many members.
+Groups are defined using the `groups` property in the definition table
+and have an associated value.
+
+```lua
+groups = {cracky = 3, wood = 1}
+```
+
+There are several reasons you use groups.
+Firstly, groups are used to describe properties such as dig types and flammability.
+Secondly, groups can be used in a craft recipe instead of an item name to allow
+any item in the group to be used.
+
+```lua
+minetest.register_craft({
+ type = "shapeless",
+ output = "mymod:diamond_thing 3",
+ recipe = {"group:wood", "mymod:diamond"}
+})
+```
+
+## Tools, Capabilities, and Dig Types
+
+Dig types are groups which are used to define how strong a node is when dug
+with different tools.
+A dig type group with a higher associated value means the node is easier
+and quicker to cut.
+It's possible to combine multiple dig types to allow the more efficient use
+of multiple types of tools.
+A node with no dig types cannot be dug by any tools.
+
+
+| Group | Best Tool | Description |
+|--------|-----------|-------------|
+| crumbly | spade | Dirt, sand |
+| cracky | pickaxe | Tough (but brittle) stuff like stone |
+| snappy | *any* | Can be cut using fine tools; e.g. leaves, smallplants, wire, sheets of metal |
+| choppy | axe | Can be cut using a sharp force; e.g. trees, wooden planks |
+| fleshy | sword | Living things like animals and the player. This could imply some blood effects when hitting. |
+| explody | ? | Especially prone to explosions |
+| oddly_breakable_by_hand | *any* | Torches and such - very quick to dig |
+
+
+Every tool has a tool capability.
+A capability includes a list of supported dig types, and associated properties
+for each type such as dig times and the amount of wear.
+Tools can also have a maximum supported hardness for each type, which makes
+it possible to prevent weaker tools from digging harder nodes.
+It's very common for tools to include all dig types in their capabilities,
+with the less suitable ones having very inefficient properties.
+If the item a player is currently wielding doesn't have an explicit tool
+capability, then the capability of the current hand is used instead.
+
+```lua
+minetest.register_tool("mymod:tool", {
+ description = "My Tool",
+ inventory_image = "mymod_tool.png",
+ tool_capabilities = {
+ full_punch_interval = 1.5,
+ max_drop_level = 1,
+ groupcaps = {
+ crumbly = {
+ maxlevel = 2,
+ uses = 20,
+ times = { [1]=1.60, [2]=1.20, [3]=0.80 }
+ },
+ },
+ damage_groups = {fleshy=2},
+ },
+})
+```
+
+Groupcaps is the list of supported dig types for digging nodes.
+Damage groups are for controlling how tools damage objects, which will be
+discussed later in the Objects, Players, and Entities chapter.
diff --git a/_it/map/environment.md b/_it/map/environment.md
new file mode 100644
index 0000000..73f251d
--- /dev/null
+++ b/_it/map/environment.md
@@ -0,0 +1,225 @@
+---
+title: Basic Map Operations
+layout: default
+root: ../..
+idx: 3.1
+description: Basic operations like set_node and get_node
+redirect_from: /en/chapters/environment.html
+---
+
+## Introduction
+
+In this chapter, you will learn how to perform basic actions on the map.
+
+- [Map Structure](#map-structure)
+- [Reading](#reading)
+ - [Reading Nodes](#reading-nodes)
+ - [Finding Nodes](#finding-nodes)
+- [Writing](#writing)
+ - [Writing Nodes](#writing-nodes)
+ - [Removing Nodes](#removing-nodes)
+- [Loading Blocks](#loading-blocks)
+- [Deleting Blocks](#deleting-blocks)
+
+## Map Structure
+
+The Minetest map is split into MapBlocks, each MapBlocks being a cube of size 16.
+As players travel around the map, MapBlocks are created, loaded, and unloaded.
+Areas of the map which are not yet loaded are full of *ignore* nodes, an impassable
+unselectable placeholder node. Empty space is full of *air* nodes, an invisible node
+you can walk through.
+
+Loaded map blocks are often referred to as *active blocks*. Active Blocks can be
+read from or written to by mods or players, and have active entities. The Engine also
+performs operations on the map, such as performing liquid physics.
+
+MapBlocks can either be loaded from the world database or generated. MapBlocks
+will be generated up to the map generation limit (`mapgen_limit`) which is set
+to its maximum value, 31000, by default. Existing MapBlocks can, however, be
+loaded from the world database outside of the generation limit.
+
+## Reading
+
+### Reading Nodes
+
+You can read from the map once you have a position:
+
+```lua
+local node = minetest.get_node({ x = 1, y = 3, z = 4 })
+print(dump(node)) --> { name=.., param1=.., param2=.. }
+```
+
+If the position is a decimal, it will be rounded to the containing node.
+The function will always return a table containing the node information:
+
+* `name` - The node name, which will be *ignore* when the area is unloaded.
+* `param1` - See the node definition. This will commonly be light.
+* `param2` - See the node definition.
+
+It's worth noting that the function won't load the containing block if the block
+is inactive, but will instead return a table with `name` being `ignore`.
+
+You can use `minetest.get_node_or_nil` instead, which will return `nil` rather
+than a table with a name of `ignore`. It still won't load the block, however.
+This may still return `ignore` if a block actually contains ignore.
+This will happen near the edge of the map as defined by the map generation
+limit (`mapgen_limit`).
+
+### Finding Nodes
+
+Minetest offers a number of helper functions to speed up common map actions.
+The most commonly used of these are for finding nodes.
+
+For example, say we wanted to make a certain type of plant that grows
+better near mese; you would need to search for any nearby mese nodes,
+and adapt the growth rate accordingly.
+
+```lua
+local grow_speed = 1
+local node_pos = minetest.find_node_near(pos, 5, { "default:mese" })
+if node_pos then
+ minetest.chat_send_all("Node found at: " .. dump(node_pos))
+ grow_speed = 2
+end
+```
+
+Let's say, for example, that the growth rate increases the more mese there is
+nearby. You should then use a function which can find multiple nodes in area:
+
+```lua
+local pos1 = vector.subtract(pos, { x = 5, y = 5, z = 5 })
+local pos2 = vector.add(pos, { x = 5, y = 5, z = 5 })
+local pos_list =
+ minetest.find_nodes_in_area(pos1, pos2, { "default:mese" })
+local grow_speed = 1 + #pos_list
+```
+
+The above code doesn't quite do what we want, as it checks based on area, whereas
+`find_node_near` checks based on range. In order to fix this, we will,
+unfortunately, need to manually check the range ourselves.
+
+```lua
+local pos1 = vector.subtract(pos, { x = 5, y = 5, z = 5 })
+local pos2 = vector.add(pos, { x = 5, y = 5, z = 5 })
+local pos_list =
+ minetest.find_nodes_in_area(pos1, pos2, { "default:mese" })
+local grow_speed = 1
+for i=1, #pos_list do
+ local delta = vector.subtract(pos_list[i], pos)
+ if delta.x*delta.x + delta.y*delta.y <= 5*5 then
+ grow_speed = grow_speed + 1
+ end
+end
+```
+
+Now your code will correctly increase `grow_speed` based on mese nodes in range.
+Note how we compared the squared distance from the position, rather than square
+rooting it to obtain the actual distance. This is because computers find square
+roots computationally expensive, so you should avoid them as much as possible.
+
+There are more variations of the above two functions, such as
+`find_nodes_with_meta` and `find_nodes_in_area_under_air`, which work similarly
+and are useful in other circumstances.
+
+## Writing
+
+### Writing Nodes
+
+You can use `set_node` to write to the map. Each call to set_node will cause
+lighting to be recalculated, which means that set_node is fairly slow for large
+numbers of nodes.
+
+```lua
+minetest.set_node({ x = 1, y = 3, z = 4 }, { name = "default:mese" })
+
+local node = minetest.get_node({ x = 1, y = 3, z = 4 })
+print(node.name) --> default:mese
+```
+
+set_node will remove any associated metadata or inventory from that position.
+This isn't desirable in all circumstances, especially if you're using multiple
+node definitions to represent one conceptual node. An example of this is the
+furnace node - whilst you think conceptually of it as one node, it's actually
+two.
+
+You can set a node without deleting metadata or the inventory like so:
+
+```lua
+minetest.swap_node({ x = 1, y = 3, z = 4 }, { name = "default:mese" })
+```
+
+### Removing Nodes
+
+A node must always be present. To remove a node, you set the position to `air`.
+
+The following two lines will both remove a node, and are both identical:
+
+```lua
+minetest.remove_node(pos)
+minetest.set_node(pos, { name = "air" })
+```
+
+In fact, remove_node will call set_node with the name being air.
+
+## Loading Blocks
+
+You can use `minetest.emerge_area` to load map blocks. Emerge area is asynchronous,
+meaning the blocks won't be loaded instantly. Instead, they will be loaded
+soon in the future, and the callback will be called each time.
+
+```lua
+-- Load a 20x20x20 area
+local halfsize = { x = 10, y = 10, z = 10 }
+local pos1 = vector.subtract(pos, halfsize)
+local pos2 = vector.add (pos, halfsize)
+
+local context = {} -- persist data between callback calls
+minetest.emerge_area(pos1, pos2, emerge_callback, context)
+```
+
+Minetest will call `emerge_callback` whenever it loads a block, with some
+progress information.
+
+```lua
+local function emerge_callback(pos, action,
+ num_calls_remaining, context)
+ -- On first call, record number of blocks
+ if not context.total_blocks then
+ context.total_blocks = num_calls_remaining + 1
+ context.loaded_blocks = 0
+ end
+
+ -- Increment number of blocks loaded
+ context.loaded_blocks = context.loaded_blocks + 1
+
+ -- Send progress message
+ if context.total_blocks == context.loaded_blocks then
+ minetest.chat_send_all("Finished loading blocks!")
+ end
+ local perc = 100 * context.loaded_blocks / context.total_blocks
+ local msg = string.format("Loading blocks %d/%d (%.2f%%)",
+ context.loaded_blocks, context.total_blocks, perc)
+ minetest.chat_send_all(msg)
+ end
+end
+```
+
+This is not the only way of loading blocks; using an LVM will also cause the
+encompassed blocks to be loaded synchronously.
+
+## Deleting Blocks
+
+You can use delete_blocks to delete a range of map blocks:
+
+```lua
+-- Delete a 20x20x20 area
+local halfsize = { x = 10, y = 10, z = 10 }
+local pos1 = vector.subtract(pos, halfsize)
+local pos2 = vector.add (pos, halfsize)
+
+minetest.delete_area(pos1, pos2)
+```
+
+This will delete all map blocks in that area, *inclusive*. This means that some
+nodes will be deleted outside the area as they will be on a mapblock which overlaps
+the area bounds.
diff --git a/_it/map/objects.md b/_it/map/objects.md
new file mode 100644
index 0000000..b9fe91f
--- /dev/null
+++ b/_it/map/objects.md
@@ -0,0 +1,281 @@
+---
+title: Objects, Players, and Entities
+layout: default
+root: ../..
+idx: 3.4
+description: Using an ObjectRef
+degrad:
+ level: warning
+ title: Degrees and Radians
+ message: Attachment rotation is set in degrees, whereas object rotation is in radians.
+ Make sure to convert to the correct angle measurement.
+---
+
+## Introduction
+
+In this chapter, you will learn how to manipulate objects and how to define your
+own.
+
+- [What are Objects, Players, and Entities?](#what-are-objects-players-and-entities)
+- [Position and Velocity](#position-and-velocity)
+- [Object Properties](#object-properties)
+- [Entities](#entities)
+- [Attachments](#attachments)
+- [Your Turn](#your-turn)
+
+## What are Objects, Players, and Entities?
+
+Players and Entities are both types of Objects. An Object is something that can move
+independently of the node grid and has properties such as velocity and scale.
+Objects aren't items, and they have their own separate registration system.
+
+There are a few differences between Players and Entities.
+The biggest one is that Players are player-controlled, whereas Entities are mod-controlled.
+This means that the velocity of a player cannot be set by mods - players are client-side,
+and entities are server-side.
+Another difference is that Players will cause map blocks to be loaded, whereas Entities
+will just be saved and become inactive.
+
+This distinction is muddied by the fact that Entities are controlled using a table
+which is referred to as a Lua entity, as discussed later.
+
+## Position and Velocity
+
+`get_pos` and `set_pos` exist to allow you to get and set an entity's position.
+
+```lua
+local object = minetest.get_player_by_name("bob")
+local pos = object:get_pos()
+object:set_pos({ x = pos.x, y = pos.y + 1, z = pos.z })
+```
+
+`set_pos` immediately sets the position, with no animation. If you'd like to
+smoothly animate an object to the new position, you should use `move_to`.
+This, unfortunately, only works for entities.
+
+```lua
+object:move_to({ x = pos.x, y = pos.y + 1, z = pos.z })
+```
+
+An important thing to think about when dealing with entities is network latency.
+In an ideal world, messages about entity movements would arrive immediately,
+in the correct order, and with a similar interval as to how you sent them.
+However, unless you're in singleplayer, this isn't an ideal world.
+Messages will take a while to arrive. Position messages may arrive out of order,
+resulting in some `set_pos` calls being skipped as there's no point going to
+a position older than the current known position.
+Moves may not be similarly spaced, which makes it difficult to use them for animation.
+All this results in the client seeing different things to the server, which is something
+you need to be aware of.
+
+## Object Properties
+
+Object properties are used to tell the client how to render and deal with an
+object. It's not possible to define custom properties, because the properties are
+for the engine to use, by definition.
+
+Unlike nodes, objects have a dynamic rather than set appearance.
+You can change how an object looks, among other things, at any time by updating
+its properties.
+
+```lua
+object:set_properties({
+ visual = "mesh",
+ mesh = "character.b3d",
+ textures = {"character_texture.png"},
+ visual_size = {x=1, y=1},
+})
+```
+
+The updated properties will be sent to all players in range.
+This is very useful to get a large amount of variety very cheaply, such as having
+different skins per-player.
+
+As shown in the next section, entities can have initial properties
+provided in their definition.
+The default Player properties are defined in the engine, however, so you'll
+need to use `set_properties()` in `on_joinplayer` to set the properties for newly
+joined players.
+
+## Entities
+
+An Entity has a definition table that resembles an item definition table.
+This table can contain callback methods, initial object properties, and custom
+members.
+
+However, entities differ in one very important way from items. When an entity is
+emerged (ie: loaded or created), a new table is created for that entity that
+*inherits* from the definition table using metatables.
+This new table is commonly referred to as a Lua Entity table.
+
+Metatables are an important Lua feature that you will need
+to be aware of, as it is an essential part of the Lua language.
+
+In layman's terms, a metatable allows you to control how the table behaves when
+using certain Lua syntax. The most common use of metatables is the ability to use
+another table as a prototype, defaulting to the other table's properties and methods when
+they do not exist in the current table.
+
+Say you want to access member X on table A. If table A has that member, then
+it will be returned as normal. However, if the table doesn't have that member but
+it does have a metatable could table B, then table B will be checked to see if it
+has that member.
+
+
+
+```lua
+local MyEntity = {
+ initial_properties = {
+ hp_max = 1,
+ physical = true,
+ collide_with_objects = false,
+ collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
+ visual = "wielditem",
+ visual_size = {x = 0.4, y = 0.4},
+ textures = {""},
+ spritediv = {x = 1, y = 1},
+ initial_sprite_basepos = {x = 0, y = 0},
+ },
+
+ message = "Default message",
+}
+
+function MyEntity:set_message(msg)
+ self.message = msg
+end
+```
+
+When an entity has emerged, a table is created for it by copying everything from
+its type table.
+This table can be used to store variables for that particular entity.
+
+Both an ObjectRef and an entity table provide ways to get the counterpart:
+
+```lua
+local entity = object:get_luaentity()
+local object = entity.object
+print("entity is at " .. minetest.pos_to_string(object:get_pos()))
+```
+
+There are a number of available callbacks for use with entities.
+A complete list can be found in [lua_api.txt]({{ page.root }}/lua_api.html#registered-entities).
+
+```lua
+function MyEntity:on_step(dtime)
+ local pos = self.object:get_pos()
+ local pos_down = vector.subtract(pos, vector.new(0, 1, 0))
+
+ local delta
+ if minetest.get_node(pos_down).name == "air" then
+ delta = vector.new(0, -1, 0)
+ elseif minetest.get_node(pos).name == "air" then
+ delta = vector.new(0, 0, 1)
+ else
+ delta = vector.new(0, 1, 0)
+ end
+
+ delta = vector.multiply(delta, dtime)
+
+ self.object:move_to(vector.add(pos, delta))
+end
+
+function MyEntity:on_punch(hitter)
+ minetest.chat_send_player(hitter:get_player_name(), self.message)
+end
+```
+
+Now, if you were to spawn and use this entity, you'd notice that the message
+would be forgotten when the entity becomes inactive then active again.
+This is because the message isn't saved.
+Rather than saving everything in the entity table, Minetest gives you control over
+how to save things.
+Staticdata is a string which contains all the custom information that
+needs to stored.
+
+```lua
+function MyEntity:get_staticdata()
+ return minetest.write_json({
+ message = self.message,
+ })
+end
+
+function MyEntity:on_activate(staticdata, dtime_s)
+ if staticdata ~= "" and staticdata ~= nil then
+ local data = minetest.parse_json(staticdata) or {}
+ self:set_message(data.message)
+ end
+end
+```
+
+Minetest may call `get_staticdata()` as many times as it wants and at any time.
+This is because Minetest doesn't wait for a MapBlock to become inactive to save
+it, as this would result in data loss. MapBlocks are saved roughly every 18
+seconds, so you should notice a similar interval for `get_staticdata()` being called.
+
+`on_activate()`, on the other hand, will only be called when an entity becomes
+active either from the MapBlock becoming active or from the entity spawning.
+This means that staticdata could be empty.
+
+Finally, you need to register the type table using the aptly named `register_entity`.
+
+```lua
+minetest.register_entity("mymod:entity", MyEntity)
+```
+
+The entity can be spawned by a mod like so:
+
+```lua
+local pos = { x = 1, y = 2, z = 3 }
+local obj = minetest.add_entity(pos, "mymod:entity", nil)
+```
+
+The third parameter is the initial staticdata.
+To set the message, you can use the entity table method:
+
+```lua
+obj:get_luaentity():set_message("hello!")
+```
+
+Players with the *give* [privilege](../players/privileges.html) can
+use a [chat command](../players/chat.html) to spawn entities:
+
+ /spawnentity mymod:entity
+
+## Attachments
+
+Attached objects will move when the parent - the object they are attached to -
+is moved. An attached object is said to be a child of the parent.
+An object can have an unlimited number of children, but at most one parent.
+
+```lua
+child:set_attach(parent, bone, position, rotation)
+```
+
+An Object's `get_pos()` will always return the global position of the object, no
+matter whether it is attached or not.
+`set_attach` takes a relative position, but not as you'd expect.
+The attachment position is relative to the parent's origin as scaled up by 10 times.
+So, `0,5,0` would be half a node above the parent's origin.
+
+{% include notice.html notice=page.degrad %}
+
+For 3D models with animations, the bone argument is used to attach the entity
+to a bone.
+3D animations are based on skeletons - a network of bones in the model where
+each bone can be given a position and rotation to change the model, for example,
+to move the arm.
+Attaching to a bone is useful if you want to make a character hold something:
+
+```lua
+obj:set_attach(player,
+ "Arm_Right", -- default bone
+ {x=0.2, y=6.5, z=3}, -- default position
+ {x=-100, y=225, z=90}) -- default rotation
+```
+
+## Your Turn
+
+* Make a windmill by combining nodes and an entity.
+* Make a mob of your choice (using just the entity API, and without using any other mods).
diff --git a/_it/map/storage.md b/_it/map/storage.md
new file mode 100644
index 0000000..534e40f
--- /dev/null
+++ b/_it/map/storage.md
@@ -0,0 +1,247 @@
+---
+title: Storage and Metadata
+layout: default
+root: ../..
+idx: 3.3
+description: Mod Storage, NodeMetaRef (get_meta).
+redirect_from:
+ - /en/chapters/node_metadata.html
+ - /en/map/node_metadata.html
+---
+
+## Introduction
+
+In this chapter, you will learn how you can store data.
+
+- [Metadata](#metadata)
+ - [What is Metadata?](#what-is-metadata)
+ - [Obtaining a Metadata Object](#obtaining-a-metadata-object)
+ - [Reading and Writing](#reading-and-writing)
+ - [Special Keys](#special-keys)
+ - [Storing Tables](#storing-tables)
+ - [Private Metadata](#private-metadata)
+ - [Lua Tables](#lua-tables)
+- [Mod Storage](#mod-storage)
+- [Databases](#databases)
+- [Deciding Which to Use](#deciding-which-to-use)
+- [Your Turn](#your-turn)
+
+## Metadata
+
+### What is Metadata?
+
+In Minetest, Metadata is a key-value store used to attach custom data to something.
+You can use metadata to store information against a Node, Player, or ItemStack.
+
+Each type of metadata uses the exact same API.
+Metadata stores values as strings, but there are a number of methods to
+convert and store other primitive types.
+
+Some keys in metadata may have special meaning.
+For example, `infotext` in node metadata is used to store the tooltip which shows
+when hovering over the node using the crosshair.
+To avoid conflicts with other mods, you should use the standard namespace
+convention for keys: `modname:keyname`.
+The exception is for conventional data such as the owner name which is stored as
+`owner`.
+
+Metadata is data about data.
+The data itself, such as a node's type or an stack's count, is not metadata.
+
+### Obtaining a Metadata Object
+
+If you know the position of a node, you can retrieve its metadata:
+
+```lua
+local meta = minetest.get_meta({ x = 1, y = 2, z = 3 })
+```
+
+Player and ItemStack metadata are obtained using `get_meta()`:
+
+```lua
+local pmeta = player:get_meta()
+local imeta = stack:get_meta()
+```
+
+### Reading and Writing
+
+In most cases, `get_()` and `set_()` methods will be used to read
+and write to meta.
+Metadata stores strings, so the string methods will directly set and get the value.
+
+```lua
+print(meta:get_string("foo")) --> ""
+meta:set_string("foo", "bar")
+print(meta:get_string("foo")) --> "bar"
+```
+
+All of the typed getters will return a neutral default value if the key doesn't
+exist, such as `""` or `0`.
+You can use `get()` to return a string or nil.
+
+As Metadata is a reference, any changes will be updated to the source automatically.
+ItemStacks aren't references however, so you'll need to update the itemstack in the
+inventory.
+
+The non-typed getters and setters will convert to and from strings:
+
+```lua
+print(meta:get_int("count")) --> 0
+meta:set_int("count", 3)
+print(meta:get_int("count")) --> 3
+print(meta:get_string("count")) --> "3"
+```
+
+### Special Keys
+
+`infotext` is used in Node Metadata to show a tooltip when hovering the crosshair over a node.
+This is useful when showing the ownership or status of a node.
+
+`description` is used in ItemStack Metadata to override the description when
+hovering over the stack in an inventory.
+You can use colours by encoding them with `minetest.colorize()`.
+
+`owner` is a common key used to store the username of the player that owns the
+item or node.
+
+### Storing Tables
+
+Tables must be converted to strings before they can be stored.
+Minetest offers two formats for doing this: Lua and JSON.
+
+The Lua method tends to be a lot faster and matches the format Lua
+uses for tables, while JSON is a more standard format, is better
+structured, and is well suited when you need to exchange information
+with another program.
+
+```lua
+local data = { username = "player1", score = 1234 }
+meta:set_string("foo", minetest.serialize(data))
+
+data = minetest.deserialize(minetest:get_string("foo"))
+```
+
+### Private Metadata
+
+Entries in Node Metadata can be marked as private, and not sent to the client.
+Entries not marked as private will be sent to the client.
+
+```lua
+meta:set_string("secret", "asd34dn")
+meta:mark_as_private("secret")
+```
+
+### Lua Tables
+
+You can convert to and from Lua tables using `to_table` and `from_table`:
+
+```lua
+local tmp = meta:to_table()
+tmp.foo = "bar"
+meta:from_table(tmp)
+```
+
+## Mod Storage
+
+Mod storage uses the exact same API as Metadata, although it's not technically
+Metadata.
+Mod storage is per-mod, and can only be obtained during load time in order to
+know which mod is requesting it.
+
+```lua
+local storage = minetest.get_mod_storage()
+```
+
+You can now manipulate the storage just like metadata:
+
+```lua
+storage:set_string("foo", "bar")
+```
+
+## Databases
+
+If the mod is likely to be used on a server and will store lots of data,
+it's a good idea to offer a database storage method.
+You should make this optional by separating how the data is stored and where
+it is used.
+
+```lua
+local backend
+if use_database then
+ backend =
+ dofile(minetest.get_modpath("mymod") .. "/backend_sqlite.lua")
+else
+ backend =
+ dofile(minetest.get_modpath("mymod") .. "/backend_storage.lua")
+end
+
+backend.get_foo("a")
+backend.set_foo("a", { score = 3 })
+```
+
+The backend_storage.lua file should include a mod storage implementation:
+
+```lua
+local storage = minetest.get_mod_storage()
+local backend = {}
+
+function backend.set_foo(key, value)
+ storage:set_string(key, minetest.serialize(value))
+end
+
+function backend.get_foo(key, value)
+ return minetest.deserialize(storage:get_string(key))
+end
+
+return backend
+```
+
+The backend_sqlite would do a similar thing, but use the Lua *lsqlite3* library
+instead of mod storage.
+
+Using a database such as SQLite requires using an insecure environment.
+An insecure environment is a table that is only available to mods
+explicitly whitelisted by the user, and it contains a less restricted
+copy of the Lua API which could be abused if available to malicious mods.
+Insecure environments will be covered in more detail in the
+[Security](../quality/security.html) chapter.
+
+```lua
+local ie = minetest.request_insecure_environment()
+assert(ie, "Please add mymod to secure.trusted_mods in the settings")
+
+local _sql = ie.require("lsqlite3")
+-- Prevent other mods from using the global sqlite3 library
+if sqlite3 then
+ sqlite3 = nil
+end
+```
+
+Teaching about SQL or how to use the lsqlite3 library is out of scope for this book.
+
+## Deciding Which to Use
+
+The type of method you use depends on what the data is about,
+how it is formatted, and how large it is.
+As a guideline, small data is up to 10K, medium data is up to 10MB, and large
+data is any size above that.
+
+Node metadata is a good choice when you need to store node-related data.
+Storing medium data is fairly efficient if you make it private.
+
+Item metadata should not be used to store anything but small amounts of data as it is not
+possible to avoid sending it to the client.
+The data will also be copied every time the stack is moved, or accessed from Lua.
+
+Mod storage is good for medium data but writing large data may be inefficient.
+It's better to use a database for large data to avoid having to write all the
+data out on every save.
+
+Databases are only viable for servers due to the
+need to whitelist the mod to access an insecure environment.
+They're well suited for large data sets.
+
+## Your Turn
+
+* Make a node which disappears after it has been punched five times.
+(Use `on_punch` in the node definition and `minetest.set_node`.)
diff --git a/_it/map/timers.md b/_it/map/timers.md
new file mode 100644
index 0000000..f6239e6
--- /dev/null
+++ b/_it/map/timers.md
@@ -0,0 +1,120 @@
+---
+title: Node Timers and ABMs
+layout: default
+root: ../..
+idx: 3.2
+description: Learn how to make ABMs to change blocks.
+redirect_from:
+- /en/chapters/abms.html
+- /en/map/abms.html
+---
+
+## Introduction
+
+Periodically running a function on certain nodes is a common task.
+Minetest provides two methods of doing this: Active Block Modifiers (ABMs) and node timers.
+
+ABMs scan all loaded MapBlocks looking for nodes that match a criteria.
+They are best suited for nodes which are frequently found in the world,
+such as grass.
+They have a high CPU overhead, but a low memory and storage overhead.
+
+For nodes that are uncommon or already use metadata, such as furnaces
+and machines, node timers should be used instead.
+Node timers work by keeping track of pending timers in each MapBlock, and then
+running them when they expire.
+This means that timers don't need to search all loaded nodes to find matches,
+but instead require slightly more memory and storage for the tracking
+of pending timers.
+
+- [Node Timers](#node-timers)
+- [Active Block Modifiers](#active-block-modifiers)
+- [Your Turn](#your-turn)
+
+## Node Timers
+
+Node timers are directly tied to a single node.
+You can manage node timers by obtaining a NodeTimerRef object.
+
+```lua
+local timer = minetest.get_node_timer(pos)
+timer:start(10.5) -- in seconds
+```
+
+You can also check the status or stop the timer:
+
+```lua
+if timer:is_started() then
+ print("The timer is running, and has " .. timer:get_timeout() .. "s remaining!")
+ print(timer:get_elapsed() .. "s has elapsed.")
+end
+
+timer:stop()
+```
+
+When a node timer is up, the `on_timer` method in the node's definition table will
+be called.
+The method only takes a single parameter, the position of the node.
+
+```lua
+minetest.register_node("autodoors:door_open", {
+ on_timer = function(pos)
+ minetest.set_node(pos, { name = "autodoors:door" })
+ return false
+ end
+})
+```
+
+Returning true in `on_timer` will cause the timer to run again for the same interval.
+
+You may have noticed a limitation with timers: for optimisation reasons, it's
+only possible to have one type of timer per node type, and only one timer running per node.
+
+
+## Active Block Modifiers
+
+Alien grass, for the purposes of this chapter, is a type of grass which
+has a chance to appear near water.
+
+
+```lua
+minetest.register_node("aliens:grass", {
+ description = "Alien Grass",
+ light_source = 3, -- The node radiates light. Min 0, max 14
+ tiles = {"aliens_grass.png"},
+ groups = {choppy=1},
+ on_use = minetest.item_eat(20)
+})
+
+minetest.register_abm({
+ nodenames = {"default:dirt_with_grass"},
+ neighbors = {"default:water_source", "default:water_flowing"},
+ interval = 10.0, -- Run every 10 seconds
+ chance = 50, -- Select every 1 in 50 nodes
+ action = function(pos, node, active_object_count,
+ active_object_count_wider)
+ local pos = {x = pos.x, y = pos.y + 1, z = pos.z}
+ minetest.set_node(pos, {name = "aliens:grass"})
+ end
+})
+```
+
+This ABM runs every ten seconds, and for each matching node, there is
+a 1 in 50 chance of it running.
+If the ABM runs on a node, an alien grass node is placed above it.
+Please be warned, this will delete any node previously located in that position.
+To prevent this you should include a check using minetest.get_node to make sure there is space for the grass.
+
+Specifying a neighbour is optional.
+If you specify multiple neighbours, only one of them needs to be
+present to meet the requirements.
+
+Specifying chance is also optional.
+If you don't specify the chance, the ABM will always run when the other conditions are met.
+
+## Your Turn
+
+* Midas touch: Make water turn to gold blocks with a 1 in 100 chance, every 5 seconds.
+* Decay: Make wood turn into dirt when water is a neighbour.
+* Burnin': Make every air node catch on fire. (Tip: "air" and "fire:basic_flame").
+ Warning: expect the game to crash.
diff --git a/_it/players/chat.md b/_it/players/chat.md
new file mode 100644
index 0000000..d85238b
--- /dev/null
+++ b/_it/players/chat.md
@@ -0,0 +1,166 @@
+---
+title: Chat and Commands
+layout: default
+root: ../..
+idx: 4.2
+description: Registering a chatcommand and handling chat messages with register_on_chat_message
+redirect_from: /en/chapters/chat.html
+cmd_online:
+ level: warning
+ title: Offline players can run commands
+ message:
A player name is passed instead of a player object because mods
+ can run commands on behalf of offline players. For example, the IRC
+ bridge allows players to run commands without joining the game.
+
+
So make sure that you don't assume that the player is online.
+ You can check by seeing if
minetest.get_player_by_name
returns a player.
+
+cb_cmdsprivs:
+ level: warning
+ title: Privileges and Chat Commands
+ message: The shout privilege isn't needed for a player to trigger this callback.
+ This is because chat commands are implemented in Lua, and are just
+ chat messages that begin with a /.
+
+---
+
+## Introduction
+
+Mods can interact with player chat, including
+sending messages, intercepting messages, and registering chat commands.
+
+- [Sending Messages to All Players](#sending-messages-to-all-players)
+- [Sending Messages to Specific Players](#sending-messages-to-specific-players)
+- [Chat Commands](#chat-commands)
+- [Complex Subcommands](#complex-subcommands)
+- [Intercepting Messages](#intercepting-messages)
+
+## Sending Messages to All Players
+
+To send a message to every player in the game, call the chat_send_all function.
+
+```lua
+minetest.chat_send_all("This is a chat message to all players")
+```
+
+Here is an example of how this appears in-game:
+
+ Look at this entrance
+ This is a chat message to all players
+ What about it?
+
+The message appears on a separate line to distinguish it from in-game player chat.
+
+## Sending Messages to Specific Players
+
+To send a message to a specific player, call the chat_send_player function:
+
+```lua
+minetest.chat_send_player("player1", "This is a chat message for player1")
+```
+
+This message displays in the same manner as messages to all players, but is
+only visible to the named player, in this case, player1.
+
+## Chat Commands
+
+To register a chat command, for example `/foo`, use `register_chatcommand`:
+
+```lua
+minetest.register_chatcommand("foo", {
+ privs = {
+ interact = true,
+ },
+ func = function(name, param)
+ return true, "You said " .. param .. "!"
+ end,
+})
+```
+
+In the above snippet, `interact` is listed as a required
+[privilege](privileges.html) meaning that only players with the `interact` privilege can run the command.
+
+Chat commands can return up to two values,
+the first being a Boolean indicating success, and the second being a
+message to send to the user.
+
+{% include notice.html notice=page.cmd_online %}
+
+## Complex Subcommands
+
+It is often required to make complex chat commands, such as:
+
+* `/msg `
+* `/team join `
+* `/team leave `
+* `/team list`
+
+This is usually done using [Lua patterns](https://www.lua.org/pil/20.2.html).
+Patterns are a way of extracting stuff from text using rules.
+
+```lua
+local to, msg = string.match(param, "^([%a%d_-]+) (*+)$")
+```
+
+The above code implements `/msg `. Let's go through left to right:
+
+* `^` means match the start of the string.
+* `()` is a matching group - anything that matches stuff in here will be
+ returned from string.match.
+* `[]` means accept characters in this list.
+* `%a` means accept any letter and `%d` means accept any digit.
+* `[%d%a_-]` means accept any letter or digit or `_` or `-`.
+* `+` means match the thing before one or more times.
+* `*` means match any character in this context.
+* `$` means match the end of the string.
+
+Put simply, the pattern matches the name (a word with only letters/numbers/-/_),
+then a space, then the message (one or more of any character). The name and
+message are returned, because they're surrounded by parentheses.
+
+That's how most mods implement complex chat commands. A better guide to Lua
+Patterns would probably be the
+[lua-users.org tutorial](http://lua-users.org/wiki/PatternsTutorial)
+or the [PIL documentation](https://www.lua.org/pil/20.2.html).
+
+
+There is also a library written by the author of this book which can be used
+to make complex chat commands without patterns called
+Chat Command Builder.
+
+
+
+## Intercepting Messages
+
+To intercept a message, use register_on_chat_message:
+
+```lua
+minetest.register_on_chat_message(function(name, message)
+ print(name .. " said " .. message)
+ return false
+end)
+```
+
+By returning false, you allow the chat message to be sent by the default
+handler. You can actually remove the line `return false` and it would still
+work the same, because `nil` is returned implicitly and is treated like false.
+
+{% include notice.html notice=page.cb_cmdsprivs %}
+
+You should make sure you take into account that it may be a chat command,
+or the user may not have `shout`.
+
+```lua
+minetest.register_on_chat_message(function(name, message)
+ if message:sub(1, 1) == "/" then
+ print(name .. " ran chat command")
+ elseif minetest.check_player_privs(name, { shout = true }) then
+ print(name .. " said " .. message)
+ else
+ print(name .. " tried to say " .. message ..
+ " but doesn't have shout")
+ end
+
+ return false
+end)
+```
diff --git a/_it/players/chat_complex.md b/_it/players/chat_complex.md
new file mode 100644
index 0000000..fcbd0bd
--- /dev/null
+++ b/_it/players/chat_complex.md
@@ -0,0 +1,183 @@
+---
+title: Chat Command Builder
+layout: default
+root: ../..
+idx: 4.3
+description: Use ChatCmdBuilder to make a complex chat command
+redirect_from: /en/chapters/chat_complex.html
+---
+
+## Introduction
+
+This chapter will show you how to make complex chat commands with ChatCmdBuilder,
+such as `/msg `, `/team join ` or `/team leave `.
+
+Note that ChatCmdBuilder is a library created by the author of this book, and most
+modders tend to use the method outlined in the
+[Chat and Commands](chat.html#complex-subcommands) chapter.
+
+- [Why ChatCmdBuilder?](#why-chatcmdbuilder)
+- [Routes](#routes)
+- [Subcommand functions](#subcommand-functions)
+- [Installing ChatCmdBuilder](#installing-chatcmdbuilder)
+- [Admin complex command](#admin-complex-command)
+
+## Why ChatCmdBuilder?
+
+Traditionally mods implemented these complex commands using Lua patterns.
+
+```lua
+local name = string.match(param, "^join ([%a%d_-]+)")
+```
+
+I, however, find Lua patterns annoying to write and unreadable.
+Because of this, I created a library to do this for you.
+
+```lua
+ChatCmdBuilder.new("sethp", function(cmd)
+ cmd:sub(":target :hp:int", function(name, target, hp)
+ local player = minetest.get_player_by_name(target)
+ if player then
+ player:set_hp(hp)
+ return true, "Killed " .. target
+ else
+ return false, "Unable to find " .. target
+ end
+ end)
+end, {
+ description = "Set hp of player",
+ privs = {
+ kick = true
+ -- ^ probably better to register a custom priv
+ }
+})
+```
+
+`ChatCmdBuilder.new(name, setup_func, def)` creates a new chat command called
+`name`. It then calls the function passed to it (`setup_func`), which then creates
+subcommands. Each `cmd:sub(route, func)` is a subcommand.
+
+A subcommand is a particular response to an input param. When a player runs
+the chat command, the first subcommand that matches their input will be run,
+and no others. If no subcommands match, then the user will be told of the invalid
+syntax. For example, in the above code snippet if a player
+types something of the form `/sethp username 12` then the function passed
+to cmd:sub will be called. If they type `/sethp 12 bleh`, then a wrong
+input message will appear.
+
+`:name :hp:int` is a route. It describes the format of the param passed to /teleport.
+
+## Routes
+
+A route is made up of terminals and variables. Terminals must always be there.
+For example, `join` in `/team join :username :teamname`. The spaces also count
+as terminals.
+
+Variables can change value depending on what the user types. For example, `:username`
+and `:teamname`.
+
+Variables are defined as `:name:type`. The `name` is used in the help documentation.
+The `type` is used to match the input. If the type is not given, then the type is
+`word`.
+
+Valid types are:
+
+* `word` - default. Any string without spaces.
+* `int` - Any integer/whole number, no decimals.
+* `number` - Any number, including ints and decimals.
+* `pos` - 1,2,3 or 1.1,2,3.4567 or (1,2,3) or 1.2, 2 ,3.2
+* `text` - Any string. There can only ever be one text variable,
+ no variables or terminals can come afterwards.
+
+In `:name :hp:int`, there are two variables:
+
+* `name` - type of `word` as no type is specified. Accepts any string without spaces.
+* `hp` - type of `int`
+
+## Subcommand functions
+
+The first argument is the caller's name. The variables are then passed to the
+function in order.
+
+```lua
+cmd:sub(":target :hp:int", function(name, target, hp)
+ -- subcommand function
+end)
+```
+
+## Installing ChatCmdBuilder
+
+The source code can be found and downloaded on
+[Github](https://github.com/rubenwardy/ChatCmdBuilder/).
+
+There are two ways to install:
+
+1. Install ChatCmdBuilder as a mod and depend on it.
+2. Include the init.lua file in ChatCmdBuilder as chatcmdbuilder.lua in your mod,
+ and dofile it.
+
+## Admin complex command
+
+Here is an example that creates a chat command that allows us to do this:
+
+* `/admin kill ` - kill user
+* `/admin move to ` - teleport user
+* `/admin log ` - show report log
+* `/admin log ` - log to report log
+
+```lua
+local admin_log
+local function load()
+ admin_log = {}
+end
+local function save()
+ -- todo
+end
+load()
+
+ChatCmdBuilder.new("admin", function(cmd)
+ cmd:sub("kill :name", function(name, target)
+ local player = minetest.get_player_by_name(target)
+ if player then
+ player:set_hp(0)
+ return true, "Killed " .. target
+ else
+ return false, "Unable to find " .. target
+ end
+ end)
+
+ cmd:sub("move :name to :pos:pos", function(name, target, pos)
+ local player = minetest.get_player_by_name(target)
+ if player then
+ player:setpos(pos)
+ return true, "Moved " .. target .. " to " ..
+ minetest.pos_to_string(pos)
+ else
+ return false, "Unable to find " .. target
+ end
+ end)
+
+ cmd:sub("log :username", function(name, target)
+ local log = admin_log[target]
+ if log then
+ return true, table.concat(log, "\n")
+ else
+ return false, "No entries for " .. target
+ end
+ end)
+
+ cmd:sub("log :username :message", function(name, target, message)
+ local log = admin_log[target] or {}
+ table.insert(log, message)
+ admin_log[target] = log
+ save()
+ return true, "Logged"
+ end)
+end, {
+ description = "Admin tools",
+ privs = {
+ kick = true,
+ ban = true
+ }
+})
+```
diff --git a/_it/players/formspecs.md b/_it/players/formspecs.md
new file mode 100644
index 0000000..cce823a
--- /dev/null
+++ b/_it/players/formspecs.md
@@ -0,0 +1,385 @@
+---
+title: Formspecs
+layout: default
+root: ../..
+idx: 4.5
+redirect_from: /en/chapters/formspecs.html
+minetest510:
+ level: warning
+ title: Real coordinates will be in 5.1.0
+ classes: web-only
+ message: This chapter describes the use of a feature that hasn't been released yet.
+ You can still use this chapter and the code in Minetest 5.0, but elements will
+ be positioned differently to what is shown.
+submit_vuln:
+ level: warning
+ title: Malicious clients can submit anything at anytime
+ message: You should never trust a formspec submission. A malicious client
+ can submit anything they like at any time - even if you never showed
+ them the formspec. This means that you should check privileges
+ and make sure that they should be allowed to perform the action.
+---
+
+## Introduction
+
+
+
+In this chapter we will learn how to create a formspec and display it to the user.
+A formspec is the specification code for a form.
+In Minetest, forms are windows such as the player inventory and can contain a
+variety of elements, such as labels, buttons and fields.
+
+Note that if you do not need to get user input, for example when you only need
+to provide information to the player, you should consider using
+[Heads Up Display (HUD)](hud.html) elements instead of forms, because
+unexpected windows tend to disrupt gameplay.
+
+- [Real or Legacy Coordinates](#real-or-legacy-coordinates)
+- [Anatomy of a Formspec](#anatomy-of-a-formspec)
+ - [Elements](#elements)
+ - [Header](#header)
+- [Guessing Game](#guessing-game)
+ - [Padding and Spacing](#padding-and-spacing)
+ - [Receiving Formspec Submissions](#receiving-formspec-submissions)
+ - [Contexts](#contexts)
+- [Formspec Sources](#formspec-sources)
+ - [Node Meta Formspecs](#node-meta-formspecs)
+ - [Player Inventory Formspecs](#player-inventory-formspecs)
+ - [Your Turn](#your-turn)
+
+
+## Real or Legacy Coordinates
+
+In older versions of Minetest, formspecs were inconsistent. The way that different
+elements were positioned varied in unexpected ways; it was hard to predict the
+placement of elements and align them. Minetest 5.1.0 contains a feature
+called real coordinates which aims to rectify this by introducing a consistent
+coordinate system. The use of real coordinates is highly recommended, and so
+this chapter will use them exclusively.
+
+{% include notice.html notice=page.minetest510 %}
+
+
+## Anatomy of a Formspec
+
+### Elements
+
+Formspec is a domain-specific language with an unusual format.
+It consists of a number of elements with the following form:
+
+ type[param1;param2]
+
+The element type is declared and then any parameters are given
+in square brackets. Multiple elements can be joined together, or placed
+on multiple lines, like so:
+
+ foo[param1]bar[param1]
+ bo[param1]
+
+
+Elements are items such as text boxes or buttons, or can be metadata such
+as size or background. You should refer to
+[lua_api.txt](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt#L1019)
+for a list of all possible elements. Search for "Formspec" to locate the correct
+part of the document.
+
+
+### Header
+
+The header of a formspec contains information which must appear first. This
+includes the size of the formspec, the position, the anchor, and whether the
+game-wide theme should be applied.
+
+The elements in the header must be defined in a specific order, otherwise you
+will see an error. This order is given in the above paragraph, and, as always,
+documented in [lua_api.txt](../../lua_api.html#sizewhfixed_size)
+
+The size is in formspec slots - a unit of measurement which is roughly
+around 64 pixels, but varies based on the screen density and scaling
+settings of the client. Here's a formspec which is `2,2` in size:
+
+ size[2,2]
+ real_coordinates[true]
+
+Notice how we explicitly need to enable the use of the real coordinate system.
+Without this, the legacy system will instead be used to size the formspec, which will
+result in a larger size. This element is a special case, as it is the only element
+which may appear both in the header and the body of a formspec. When in the header,
+it must appear immediately after the size.
+
+The position and anchor elements are used to place the formspec on the screen.
+The position sets where on the screen the formspec will be, and defaults to
+the center (`0.5,0.5`). The anchor sets where on the formspec the position is,
+allowing you to line the formspec up with the edge of the screen. The formspec
+can be placed to the left of the screen like so:
+
+ size[2,2]
+ real_coordinates[true]
+ position[0,0.5]
+ anchor[0,0.5]
+
+This sets the anchor to the left middle edge of the formspec box, and then the
+position of that anchor to the left of the screen.
+
+
+## Guessing Game
+
+
+
+The best way to learn is to make something, so let's make a guessing game.
+The principle is simple: the mod decides on a number, then the player makes
+guesses on the number. The mod then says if the guess is higher or lower then
+the actual number.
+
+First, let's make a function to create the formspec code. It's good practice to
+do this, as it makes it easier to reuse elsewhere.
+
+
+
+```lua
+guessing = {}
+
+function guessing.get_formspec(name)
+ -- TODO: display whether the last guess was higher or lower
+ local text = "I'm thinking of a number... Make a guess!"
+
+ local formspec = {
+ "size[6,3.476]",
+ "real_coordinates[true]",
+ "label[0.375,0.5;", minetest.formspec_escape(text), "]",
+ "field[0.375,1.25;5.25,0.8;number;Number;]",
+ "button[1.5,2.3;3,0.8;guess;Guess]"
+ }
+
+ -- table.concat is faster than string concatenation - `..`
+ return table.concat(formspec, "")
+end
+```
+
+In the above code, we place a field, a label, and a button. A field allows text
+entry, and a button is used to submit the form. You'll notice that the elements
+are positioned carefully in order to add padding and spacing, this will be explained
+later.
+
+Next, we want to allow the player to show the formspec. The main way to do this
+is using `show_formspec`:
+
+```lua
+function guessing.show_to(name)
+ minetest.show_formspec(name, "guessing:game", guessing.get_formspec(name))
+end
+
+minetest.register_chatcommand("game", {
+ func = function(name)
+ guessing.show_to(name)
+ end,
+})
+```
+
+The show_formspec function accepts a player name, the formspec name, and the
+formspec itself. The formspec name should be a valid itemname, ie: in the format
+`modname:itemname`.
+
+
+### Padding and Spacing
+
+
+
+Padding is the gap between the edge of the formspec and its contents, or between unrelated
+elements, shown in red. Spacing is the gap between related elements, shown in blue.
+
+It is fairly standard to have a padding of `0.375` and a spacing of `0.25`.
+
+
+
+
+### Receiving Formspec Submissions
+
+When `show_formspec` is called, the formspec is sent to the client to be displayed.
+For formspecs to be useful, information needs to be returned from the client to server.
+The method for this is called formspec field submission, and for `show_formspec`, that
+submission is received using a global callback:
+
+```lua
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+ if formname ~= "guessing:game" then
+ return
+ end
+
+ if fields.guess then
+ local pname = player:get_player_name()
+ minetest.chat_send_all(pname .. " guessed " .. fields.number)
+ end
+end)
+```
+
+The function given in minetest.register_on_player_receive_fields is called
+every time a user submits a form. Most callbacks will need to check the formname given
+to the function, and exit if it is not the right form; however, some callbacks
+may need to work on multiple forms, or on all forms.
+
+The `fields` parameter to the function is a table of the values submitted by the
+user, indexed by strings. Named elements will appear in the field under their own
+name, but only if they are relevent for the event that caused the submission.
+For example, a button element will only appear in fields if that particular button
+was pressed.
+
+{% include notice.html notice=page.submit_vuln %}
+
+So, now the formspec is sent to the client and the client sends information back.
+The next step is to somehow generate and remember the target value, and to update
+the formspec based on guesses. The way to do this is using a concept called
+"contexts".
+
+
+### Contexts
+
+In many cases you want minetest.show_formspec to give information
+to the callback which you don't want to send to the client. This might include
+what a chat command was called with, or what the dialog is about. In this case,
+the target value that needs to be remembered.
+
+A context is a per-player table to store information, and the contexts for all
+online players are stored in a file-local variable:
+
+```lua
+local _contexts = {}
+local function get_context(name)
+ local context = _contexts[name] or {}
+ _contexts[name] = context
+ return context
+end
+
+minetest.register_on_leaveplayer(function(player)
+ _contexts[player:get_player_name()] = nil
+end)
+```
+
+Next, we need to modify the show code to update the context
+before showing the formspec:
+
+```lua
+function guessing.show_to(name)
+ local context = get_context(name)
+ context.target = context.target or math.random(1, 10)
+
+ local fs = guessing.get_formspec(name, context)
+ minetest.show_formspec(name, "guessing:game", fs)
+end
+```
+
+We also need to modify the formspec generation code to use the context:
+
+```lua
+function guessing.get_formspec(name, context)
+ local text
+ if not context.guess then
+ text = "I'm thinking of a number... Make a guess!"
+ elseif context.guess == context.target then
+ text = "Hurray, you got it!"
+ elseif context.guess > context.target then
+ text = "To high!"
+ else
+ text = "To low!"
+ end
+```
+
+Note that it's good practice for get_formspec to only read the context, and not
+update it at all. This can make the function simpler, and also easier to test.
+
+And finally, we need to update the handler to update the context with the guess:
+
+```lua
+if fields.guess then
+ local name = player:get_player_name()
+ local context = get_context(name)
+ context.guess = tonumber(fields.number)
+ guessing.show_to(name)
+end
+```
+
+
+## Formspec Sources
+
+There are three different ways that a formspec can be delivered to the client:
+
+* [show_formspec](#guessing-game): the method used above, fields are received by register_on_player_receive_fields.
+* [Node Meta Formspecs](#node-meta-formspecs): the node contains a formspec in its meta data, and the client
+ shows it *immediately* when the player rightclicks. Fields are received by a
+ method in the node definition called `on_receive_fields`.
+* [Player Inventory Formspecs](#player-inventory-formspecs): the formspec is sent to the client at some point, and then
+ shown immediately when the player presses `i`. Fields are received by
+ register_on_player_receive_fields.
+
+### Node Meta Formspecs
+
+minetest.show_formspec is not the only way to show a formspec; you can also
+add formspecs to a [node's metadata](node_metadata.html). For example,
+this is used with chests to allow for faster opening times -
+you don't need to wait for the server to send the player the chest formspec.
+
+```lua
+minetest.register_node("mymod:rightclick", {
+ description = "Rightclick me!",
+ tiles = {"mymod_rightclick.png"},
+ groups = {cracky = 1},
+ after_place_node = function(pos, placer)
+ -- This function is run when the chest node is placed.
+ -- The following code sets the formspec for chest.
+ -- Meta is a way of storing data onto a node.
+
+ local meta = minetest.get_meta(pos)
+ meta:set_string("formspec",
+ "size[5,5]"..
+ "label[1,1;This is shown on right click]"..
+ "field[1,2;2,1;x;x;]")
+ end,
+ on_receive_fields = function(pos, formname, fields, player)
+ if(fields.quit) then return end
+ print(fields.x)
+ end
+})
+```
+
+Formspecs set this way do not trigger the same callback. In order to
+receive form input for meta formspecs, you must include an
+`on_receive_fields` entry when registering the node.
+
+This style of callback triggers when you press enter
+in a field, which is impossible with `minetest.show_formspec`;
+however, this kind of form can only be shown by right-clicking on a
+node. It cannot be triggered programmatically.
+
+### Player Inventory Formspecs
+
+The player inventory formspec is the one shown when the player presses i.
+The global callback is used to receive events from this formspec, and the
+formname is `""`.
+
+There are a number of different mods which allow multiple mods to customise
+the player inventory. The officially recommended mod is
+[Simple Fast Inventory (sfinv)](sfinv.html), and is included in Minetest Game.
+
+
+### Your Turn
+
+* Extend the Guessing Game to keep track of each player's top score, where the
+ top score is how many guesses it took.
+* Make a node called "Inbox" where users can open up a formspec and leave messages.
+ This node should store the placers' name as `owner` in the meta, and should use
+ `show_formspec` to show different formspecs to different players.
diff --git a/_it/players/hud.md b/_it/players/hud.md
new file mode 100644
index 0000000..c17dfe9
--- /dev/null
+++ b/_it/players/hud.md
@@ -0,0 +1,293 @@
+---
+title: HUD
+layout: default
+root: ../..
+idx: 4.6
+redirect_from: /en/chapters/hud.html
+---
+
+## Introduction
+
+Heads Up Display (HUD) elements allow you to show text, images, and other graphical elements.
+
+The HUD doesn't accept user input; for that, you should use a [formspec](formspecs.html).
+
+- [Positioning](#positioning)
+ - [Position and Offset](#position-and-offset)
+ - [Alignment](#alignment)
+ - [Scoreboard](#scoreboard)
+- [Text Elements](#text-elements)
+ - [Parameters](#parameters)
+ - [Our Example](#our-example)
+- [Image Elements](#image-elements)
+ - [Parameters](#parameters-1)
+ - [Scale](#scale)
+- [Changing an Element](#changing-an-element)
+- [Storing IDs](#storing-ids)
+- [Other Elements](#other-elements)
+
+## Positioning
+
+### Position and Offset
+
+
+
+Screens come in a variety of different physical sizes and resolutions, and
+the HUD needs to work well on all screen types.
+
+Minetest's solution to this is to specify the location of an element using both
+a percentage position and an offset.
+The percentage position is relative to the screen size, so to place an element
+in the centre of the screen, you would need to provide a percentage position of half
+the screen, e.g. (50%, 50%), and an offset of (0, 0).
+
+The offset is then used to move an element relative to the percentage position.
+
+
+
+### Alignment
+
+Alignment is where the result of position and offset is on the element -
+for example, `{x = -1.0, y = 0.0}` will make the result of position and offset point
+to the left of the element's bounds. This is particularly useful when you want to
+make a text element aligned to the left, centre, or right.
+
+
+
+The above diagram shows 3 windows (blue), each with a single HUD element (yellow)
+and a different alignment each time. The arrow is the result of the position
+and offset calculation.
+
+### Scoreboard
+
+For the purposes of this chapter, you will learn how to position and update a
+score panel like so:
+
+
+
+In the above screenshot, all the elements have the same percentage position
+(100%, 50%) - but different offsets. This allows the whole thing to be anchored
+to the right of the window, but to resize without breaking.
+
+## Text Elements
+
+You can create a HUD element once you have a copy of the player object:
+
+```lua
+local player = minetest.get_player_by_name("username")
+local idx = player:hud_add({
+ hud_elem_type = "text",
+ position = {x = 0.5, y = 0.5},
+ offset = {x = 0, y = 0},
+ text = "Hello world!",
+ alignment = {x = 0, y = 0}, -- center aligned
+ scale = {x = 100, y = 100}, -- covered later
+})
+```
+
+The `hud_add` function returns an element ID - this can be used later to modify
+or remove a HUD element.
+
+### Parameters
+
+The element's type is given using the `hud_elem_type` property in the definition
+table. The meaning of other properties varies based on this type.
+
+`scale` is the maximum bounds of text; text outside these bounds is cropped, e.g.: `{x=100, y=100}`.
+
+`number` is the text's colour, and is in [hexadecimal form](http://www.colorpicker.com/), e.g.: `0xFF0000`.
+
+
+### Our Example
+
+Let's go ahead and place all the text in our score panel:
+
+```lua
+-- Get the dig and place count from storage, or default to 0
+local meta = player:get_meta()
+local digs_text = "Digs: " .. meta:get_int("score:digs")
+local places_text = "Places: " .. meta:get_int("score:places")
+
+player:hud_add({
+ hud_elem_type = "text",
+ position = {x = 1, y = 0.5},
+ offset = {x = -120, y = -25},
+ text = "Stats",
+ alignment = 0,
+ scale = { x = 100, y = 30},
+ number = 0xFFFFFF,
+})
+
+player:hud_add({
+ hud_elem_type = "text",
+ position = {x = 1, y = 0.5},
+ offset = {x = -180, y = 0},
+ text = digs_text,
+ alignment = -1,
+ scale = { x = 50, y = 10},
+ number = 0xFFFFFF,
+})
+
+player:hud_add({
+ hud_elem_type = "text",
+ position = {x = 1, y = 0.5},
+ offset = {x = -70, y = 0},
+ text = places_text,
+ alignment = -1,
+ scale = { x = 50, y = 10},
+ number = 0xFFFFFF,
+})
+```
+
+This results in the following:
+
+
+
+
+## Image Elements
+
+Image elements are created in a very similar way to text elements:
+
+```lua
+player:hud_add({
+ hud_elem_type = "image",
+ position = {x = 1, y = 0.5},
+ offset = {x = -220, y = 0},
+ text = "score_background.png",
+ scale = { x = 1, y = 1},
+ alignment = { x = 1, y = 0 },
+})
+```
+
+You will now have this:
+
+
+
+### Parameters
+
+The `text` field is used to provide the image name.
+
+If a co-ordinate is positive, then it is a scale factor with 1 being the
+original image size, 2 being double the size, and so on.
+However, if a co-ordinate is negative, it is a percentage of the screen size.
+For example, `x=-100` is 100% of the width.
+
+### Scale
+
+Let's make the progress bar for our score panel as an example of scale:
+
+```lua
+local percent = tonumber(meta:get("score:score") or 0.2)
+
+player:hud_add({
+ hud_elem_type = "image",
+ position = {x = 1, y = 0.5},
+ offset = {x = -215, y = 23},
+ text = "score_bar_empty.png",
+ scale = { x = 1, y = 1},
+ alignment = { x = 1, y = 0 },
+})
+
+player:hud_add({
+ hud_elem_type = "image",
+ position = {x = 1, y = 0.5},
+ offset = {x = -215, y = 23},
+ text = "score_bar_full.png",
+ scale = { x = percent, y = 1},
+ alignment = { x = 1, y = 0 },
+})
+```
+
+We now have a HUD that looks like the one in the first post!
+There is one problem however, it won't update when the stats change.
+
+## Changing an Element
+
+You can use the ID returned by the hud_add method to update it or remove it later.
+
+```lua
+local idx = player:hud_add({
+ hud_elem_type = "text",
+ text = "Hello world!",
+ -- parameters removed for brevity
+})
+
+player:hud_change(idx, "text", "New Text")
+player:hud_remove(idx)
+```
+
+The `hud_change` method takes the element ID, the property to change, and the new
+value. The above call changes the `text` property from "Hello World" to "Test".
+
+This means that doing the `hud_change` immediately after the `hud_add` is
+functionally equivalent to the following, in a rather inefficient way:
+
+```lua
+local idx = player:hud_add({
+ hud_elem_type = "text",
+ text = "New Text",
+})
+```
+
+## Storing IDs
+
+```lua
+score = {}
+local saved_huds = {}
+
+function score.update_hud(player)
+ local player_name = player:get_player_name()
+
+ -- Get the dig and place count from storage, or default to 0
+ local meta = player:get_meta()
+ local digs_text = "Digs: " .. meta:get_int("score:digs")
+ local places_text = "Places: " .. meta:get_int("score:places")
+ local percent = tonumber(meta:get("score:score") or 0.2)
+
+ local ids = saved_huds[player_name]
+ if ids then
+ player:hud_change(ids["places"], "text", places_text)
+ player:hud_change(ids["digs"], "text", digs_text)
+ player:hud_change(ids["bar_foreground"],
+ "scale", { x = percent, y = 1 })
+ else
+ ids = {}
+ saved_huds[player_name] = ids
+
+ -- create HUD elements and set ids into `ids`
+ end
+end
+
+minetest.register_on_joinplayer(score.update_hud)
+
+minetest.register_on_leaveplayer(function(player)
+ saved_huds[player:get_player_name()] = nil
+end)
+```
+
+
+## Other Elements
+
+Read [lua_api.txt]({{ page.root }}/lua_api.html#hud-element-types) for a complete list of HUD elements.
diff --git a/_it/players/player_physics.md b/_it/players/player_physics.md
new file mode 100644
index 0000000..b84ed8c
--- /dev/null
+++ b/_it/players/player_physics.md
@@ -0,0 +1,76 @@
+---
+title: Player Physics
+layout: default
+root: ../..
+idx: 4.4
+redirect_from: /en/chapters/player_physics.html
+---
+
+## Introduction
+
+Player physics can be modified using physics overrides.
+Physics overrides can set the walking speed, jump speed,
+and gravity constants.
+Physics overrides are set on a player-by-player basis
+and are multipliers.
+For example, a value of 2 for gravity would make gravity twice as strong.
+
+- [Basic Example](#basic-example)
+- [Available Overrides](#available-overrides)
+ - [Old Movement Behaviour](#old-movement-behaviour)
+- [Mod Incompatibility](#mod-incompatibility)
+- [Your Turn](#your-turn)
+
+## Basic Example
+
+Here is an example of how to add an antigravity command, which
+puts the caller in low G:
+
+```lua
+minetest.register_chatcommand("antigravity", {
+ func = function(name, param)
+ local player = minetest.get_player_by_name(name)
+ player:set_physics_override({
+ gravity = 0.1, -- set gravity to 10% of its original value
+ -- (0.1 * 9.81)
+ })
+ end,
+})
+```
+
+## Available Overrides
+
+`player:set_physics_override()` is given a table of overrides.\\
+According to [lua_api.txt]({{ page.root }}/lua_api.html#player-only-no-op-for-other-objects),
+these can be:
+
+* speed: multiplier to default walking speed value (default: 1)
+* jump: multiplier to default jump value (default: 1)
+* gravity: multiplier to default gravity value (default: 1)
+* sneak: whether the player can sneak (default: true)
+
+### Old Movement Behaviour
+
+Player movement prior to the 0.4.16 release included the sneak glitch, which
+allows various movement glitches, including the ability
+to climb an 'elevator' made from a certain placement of nodes by sneaking
+(pressing shift) and pressing space to ascend. Though the behaviour was
+unintended, it has been preserved in overrides due to its use on many servers.
+
+Two overrides are needed to fully restore old movement behaviour:
+
+* new_move: whether the player uses new movement (default: true)
+* sneak_glitch: whether the player can use 'sneak elevators' (default: false)
+
+## Mod Incompatibility
+
+Please be warned that mods which override the same physics value of a player tend
+to be incompatible with each other. When setting an override, it overwrites
+any overrides that have been set before. This means that if multiple overrides set a
+player's speed, only the last one to run will be in effect.
+
+## Your Turn
+
+* **Sonic**: Set the speed multiplier to a high value (at least 6) when a player joins the game.
+* **Super bounce**: Increase the jump value so that the player can jump 20 metres (1 metre is 1 node).
+* **Space**: Make gravity decrease as the player gets higher.
diff --git a/_it/players/privileges.md b/_it/players/privileges.md
new file mode 100644
index 0000000..cacc68f
--- /dev/null
+++ b/_it/players/privileges.md
@@ -0,0 +1,138 @@
+---
+title: Privileges
+layout: default
+root: ../..
+idx: 4.1
+description: Registering privs.
+redirect_from: /en/chapters/privileges.html
+---
+
+## Introduction
+
+Privileges, often called privs for short, give players the ability to perform
+certain actions. Server owners can grant and revoke privileges to control
+which abilities each player has.
+
+- [When to use Privileges](#when-to-use-privileges)
+- [Declaring Privileges](#declaring-privileges)
+- [Checking for Privileges](#checking-for-privileges)
+- [Getting and Setting Privileges](#getting-and-setting-privileges)
+- [Adding Privileges to basic_privs](#adding-privileges-to-basicprivs)
+
+## When to use Privileges
+
+A privilege should give a player the ability to do something.
+Privileges are **not** for indicating class or status.
+
+**Good Privileges:**
+
+* interact
+* shout
+* noclip
+* fly
+* kick
+* ban
+* vote
+* worldedit
+* area_admin - admin functions of one mod is ok
+
+**Bad Privileges:**
+
+* moderator
+* admin
+* elf
+* dwarf
+
+## Declaring Privileges
+
+Use `register_privilege` to declare a new privilege:
+
+```lua
+minetest.register_privilege("vote", {
+ description = "Can vote on issues",
+ give_to_singleplayer = true
+})
+```
+
+`give_to_singleplayer` defaults to true when not specified, so it isn't
+actually needed in the above definition.
+
+## Checking for Privileges
+
+To quickly check whether a player has all the required privileges:
+
+```lua
+local has, missing = minetest.check_player_privs(player_or_name, {
+ interact = true,
+ vote = true })
+```
+
+In this example, `has` is true if the player has all the privileges needed.
+If `has` is false, then `missing` will contain a key-value table
+of the missing privileges.
+
+```lua
+local has, missing = minetest.check_player_privs(name, {
+ interact = true,
+ vote = true })
+
+if has then
+ print("Player has all privs!")
+else
+ print("Player is missing privs: " .. dump(missing))
+end
+```
+
+If you don't need to check the missing privileges, you can put
+`check_player_privs` directly into the if statement.
+
+```lua
+if not minetest.check_player_privs(name, { interact=true }) then
+ return false, "You need interact for this!"
+end
+```
+
+## Getting and Setting Privileges
+
+Player privileges can be accessed or modified regardless of the player
+being online.
+
+
+```lua
+local privs = minetest.get_player_privs(name)
+print(dump(privs))
+
+privs.vote = true
+minetest.set_player_privs(name, privs)
+```
+
+Privileges are always specified as a key-value table with the key being
+the privilege name and the value being a boolean.
+
+```lua
+{
+ fly = true,
+ interact = true,
+ shout = true
+}
+```
+
+## Adding Privileges to basic_privs
+
+Players with the `basic_privs` privilege are able to grant and revoke a limited
+set of privileges. It's common to give this privilege to moderators so that
+they can grant and revoke `interact` and `shout`, but can't grant themselves or other
+players privileges with greater potential for abuse such as `give` and `server`.
+
+To add a privilege to `basic_privs`, and adjust which privileges your moderators can
+grant and revoke from other players, you must change the `basic_privs` setting.
+
+By default, `basic_privs` has the following value:
+
+ basic_privs = interact, shout
+
+To add `vote`, update this to:
+
+ basic_privs = interact, shout, vote
+
+This will allow players with `basic_privs` to grant and revoke the `vote` privilege.
diff --git a/_it/players/sfinv.md b/_it/players/sfinv.md
new file mode 100644
index 0000000..19c908e
--- /dev/null
+++ b/_it/players/sfinv.md
@@ -0,0 +1,242 @@
+---
+title: "SFINV: Inventory Formspec"
+layout: default
+root: ../..
+idx: 4.7
+redirect_from: /en/chapters/sfinv.html
+---
+
+## Introduction
+
+Simple Fast Inventory (SFINV) is a mod found in Minetest Game that is used to
+create the player's inventory [formspec](formspecs.html). SFINV comes with
+an API that allows you to add and otherwise manage the pages shown.
+
+Whilst SFINV by default shows pages as tabs, pages are called pages
+because it is entirely possible that a mod or game decides to show them in
+some other format instead.
+For example, multiple pages could be shown in one formspec.
+
+- [Registering a Page](#registering-a-page)
+- [Receiving events](#receiving-events)
+- [Conditionally showing to players](#conditionally-showing-to-players)
+- [on_enter and on_leave callbacks](#onenter-and-onleave-callbacks)
+- [Adding to an existing page](#adding-to-an-existing-page)
+
+## Registering a Page
+
+SFINV provides the aptly named `sfinv.register_page` function to create pages.
+Simply call the function with the page's name and its definition:
+
+```lua
+sfinv.register_page("mymod:hello", {
+ title = "Hello!",
+ get = function(self, player, context)
+ return sfinv.make_formspec(player, context,
+ "label[0.1,0.1;Hello world!]", true)
+ end
+})
+```
+
+The `make_formspec` function surrounds your formspec with SFINV's formspec code.
+The fourth parameter, currently set as `true`, determines whether the
+player's inventory is shown.
+
+Let's make things more exciting; here is the code for the formspec generation
+part of a player admin tab. This tab will allow admins to kick or ban players by
+selecting them in a list and clicking a button.
+
+```lua
+sfinv.register_page("myadmin:myadmin", {
+ title = "Tab",
+ get = function(self, player, context)
+ local players = {}
+ context.myadmin_players = players
+
+ -- Using an array to build a formspec is considerably faster
+ local formspec = {
+ "textlist[0.1,0.1;7.8,3;playerlist;"
+ }
+
+ -- Add all players to the text list, and to the players list
+ local is_first = true
+ for _ , player in pairs(minetest.get_connected_players()) do
+ local player_name = player:get_player_name()
+ players[#players + 1] = player_name
+ if not is_first then
+ formspec[#formspec + 1] = ","
+ end
+ formspec[#formspec + 1] =
+ minetest.formspec_escape(player_name)
+ is_first = false
+ end
+ formspec[#formspec + 1] = "]"
+
+ -- Add buttons
+ formspec[#formspec + 1] = "button[0.1,3.3;2,1;kick;Kick]"
+ formspec[#formspec + 1] = "button[2.1,3.3;2,1;ban;Kick + Ban]"
+
+ -- Wrap the formspec in sfinv's layout
+ -- (ie: adds the tabs and background)
+ return sfinv.make_formspec(player, context,
+ table.concat(formspec, ""), false)
+ end,
+})
+```
+
+There's nothing new about the above code; all the concepts are
+covered above and in previous chapters.
+
+
+
+## Receiving events
+
+You can receive formspec events by adding a `on_player_receive_fields` function
+to a sfinv definition.
+
+```lua
+on_player_receive_fields = function(self, player, context, fields)
+ -- TODO: implement this
+end,
+```
+
+`on_player_receive_fields` works the same as
+`minetest.register_on_player_receive_fields`, except that `context` is
+given instead of `formname`.
+Please note that SFINV will consume events relevant to itself, such as
+navigation tab events, so you won't receive them in this callback.
+
+Now let's implement the `on_player_receive_fields` for our admin mod:
+
+```lua
+on_player_receive_fields = function(self, player, context, fields)
+ -- text list event, check event type and set index if selection changed
+ if fields.playerlist then
+ local event = minetest.explode_textlist_event(fields.playerlist)
+ if event.type == "CHG" then
+ context.myadmin_selected_idx = event.index
+ end
+
+ -- Kick button was pressed
+ elseif fields.kick then
+ local player_name =
+ context.myadmin_players[context.myadmin_selected_idx]
+ if player_name then
+ minetest.chat_send_player(player:get_player_name(),
+ "Kicked " .. player_name)
+ minetest.kick_player(player_name)
+ end
+
+ -- Ban button was pressed
+ elseif fields.ban then
+ local player_name =
+ context.myadmin_players[context.myadmin_selected_idx]
+ if player_name then
+ minetest.chat_send_player(player:get_player_name(),
+ "Banned " .. player_name)
+ minetest.ban_player(player_name)
+ minetest.kick_player(player_name, "Banned")
+ end
+ end
+end,
+```
+
+There's a rather large problem with this, however. Anyone can kick or ban players! You
+need a way to only show this to players with the kick or ban privileges.
+Luckily SFINV allows you to do this!
+
+## Conditionally showing to players
+
+You can add an `is_in_nav` function to your page's definition if you'd like to
+control when the page is shown:
+
+```lua
+is_in_nav = function(self, player, context)
+ local privs = minetest.get_player_privs(player:get_player_name())
+ return privs.kick or privs.ban
+end,
+```
+
+If you only need to check one priv or want to perform an 'and', you should use
+`minetest.check_player_privs()` instead of `get_player_privs`.
+
+Note that the `is_in_nav` is only called when the player's inventory formspec is
+generated. This happens when a player joins the game, switches tabs, or a mod
+requests for SFINV to regenerate.
+
+This means that you need to manually request that SFINV regenerates the inventory
+formspec on any events that may change `is_in_nav`'s result. In our case,
+we need to do that whenever kick or ban is granted or revoked to a player:
+
+```lua
+local function on_grant_revoke(grantee, granter, priv)
+ if priv ~= "kick" and priv ~= "ban" then
+ return
+ end
+
+ local player = minetest.get_player_by_name(grantee)
+ if not player then
+ return
+ end
+
+ local context = sfinv.get_or_create_context(player)
+ if context.page ~= "myadmin:myadmin" then
+ return
+ end
+
+ sfinv.set_player_inventory_formspec(player, context)
+end
+
+minetest.register_on_priv_grant(on_grant_revoke)
+minetest.register_on_priv_revoke(on_grant_revoke)
+```
+
+## on_enter and on_leave callbacks
+
+A player *enters* a tab when the tab is selected and *leaves* a
+tab when another tab is about to be selected.
+It's possible for multiple pages to be selected if a custom theme is
+used.
+
+Note that these events may not be triggered by the player.
+The player may not even have the formspec open at that time.
+For example, on_enter is called for the home page when a player
+joins the game even before they open their inventory.
+
+It's not possible to cancel a page change, as that would potentially
+confuse the player.
+
+```lua
+on_enter = function(self, player, context)
+
+end,
+
+on_leave = function(self, player, context)
+
+end,
+```
+
+## Adding to an existing page
+
+To add content to an existing page, you will need to override the page
+and modify the returned formspec.
+
+```lua
+local old_func = sfinv.registered_pages["sfinv:crafting"].get
+sfinv.override_page("sfinv:crafting", {
+ get = function(self, player, context, ...)
+ local ret = old_func(self, player, context, ...)
+
+ if type(ret) == "table" then
+ ret.formspec = ret.formspec .. "label[0,0;Hello]"
+ else
+ -- Backwards compatibility
+ ret = ret .. "label[0,0;Hello]"
+ end
+
+ return ret
+ end
+})
+```
diff --git a/_it/quality/clean_arch.md b/_it/quality/clean_arch.md
new file mode 100644
index 0000000..c3a6b2c
--- /dev/null
+++ b/_it/quality/clean_arch.md
@@ -0,0 +1,253 @@
+---
+title: Intro to Clean Architectures
+layout: default
+root: ../..
+idx: 8.4
+---
+
+## Introduction
+
+Once your mod reaches a respectable size, you'll find it harder and harder to
+keep the code clean and free of bugs. This is an especially big problem when using
+a dynamically typed language like Lua, given that the compiler gives you very little
+compiler-time help when it comes to things like making sure that types are used correctly.
+
+This chapter covers important concepts needed to keep your code clean,
+and common design patterns to achieve that. Please note that this chapter isn't
+meant to be prescriptive, but to instead give you an idea of the possibilities.
+There is no one good way of designing a mod, and good mod design is very subjective.
+
+- [Cohesion, Coupling, and Separation of Concerns](#cohesion-coupling-and-separation-of-concerns)
+- [Observer](#observer)
+- [Model-View-Controller](#model-view-controller)
+ - [API-View](#api-view)
+- [Conclusion](#conclusion)
+
+
+## Cohesion, Coupling, and Separation of Concerns
+
+Without any planning, a programming project will tend to gradually descend into
+spaghetti code. Spaghetti code is characterised by a lack of structure - all the
+code is thrown in together with no clear boundaries. This ultimately makes a
+project completely unmaintainable, ending in its abandonment.
+
+The opposite of this is to design your project as a collection of interacting
+smaller programs or areas of code.
+
+> Inside every large program, there is a small program trying to get out.
+>
+> --C.A.R. Hoare
+
+This should be done in such a way that you achieve Separation of Concerns -
+each area should be distinct and address a separate need or concern.
+
+These programs/areas should have the following two properties:
+
+* **High Cohesion** - the area should be closely/tightly related.
+* **Low Coupling** - keep dependencies between areas as low as possible, and avoid
+relying on internal implementations. It's a very good idea to make sure you have
+a low amount of coupling, as this means that changing the APIs of certain areas
+will be more feasible.
+
+Note that these apply both when thinking about the relationship between mods,
+and the relationship between areas inside a mod.
+
+
+## Observer
+
+A simple way to separate different areas of code is to use the Observer pattern.
+
+Let's take the example of unlocking an achievement when a player first kills a
+rare animal. The naïve approach would be to have achievement code in the mob
+kill function, checking the mob name and unlocking the award if it matches.
+This is a bad idea, however, as it makes the mobs mod coupled to the achievements
+code. If you kept on doing this - for example, adding XP to the mob death code -
+you could end up with a lot of messy dependencies.
+
+Enter the Observer pattern. Instead of the mymobs mod caring about awards,
+the mymobs mod exposes a way for other areas of code to register their
+interest in an event and receive data about the event.
+
+```lua
+mymobs.registered_on_death = {}
+function mymobs.register_on_death(func)
+ table.insert(mymobs.registered_on_death, func)
+end
+
+-- in mob death code
+for i=1, #mymobs.registered_on_death do
+ mymobs.registered_on_death[i](entity, reason)
+end
+```
+
+Then the other code registers its interest:
+
+```lua
+mymobs.register_on_death(function(mob, reason)
+ if reason.type == "punch" and reason.object and
+ reason.object:is_player() then
+ awards.notify_mob_kill(reason.object, mob.name)
+ end
+end)
+```
+
+You may be thinking - wait a second, this looks awfully familiar. And you're right!
+The Minetest API is heavily Observer-based to stop the engine having to care about
+what is listening to something.
+
+
+## Model-View-Controller
+
+In the next chapter, we will discuss how to automatically test your
+code and one of the problems we will have is how to separate your logic
+(calculations, what should be done) from API calls (`minetest.*`, other mods)
+as much as possible.
+
+One way to do this is to think about:
+
+* What **data** you have.
+* What **actions** you can take with this data.
+* How **events** (ie: formspec, punches, etc) trigger these actions, and how
+ these actions cause things to happen in the engine.
+
+Let's take an example of a land protection mod. The data you have is the areas
+and any associated metadata. Actions you can take are `create`, `edit`, or
+`delete`. The events that trigger these actions are chat commands and formspec
+receive fields. These are 3 areas that can usually be separated pretty well.
+
+In your tests, you will be able to make sure that an action when triggered does
+the right thing to the data. You won't need to test that an event calls an
+action (as this would require using the Minetest API, and this area of code
+should be made as small as possible anyway.)
+
+You should write your data representation using Pure Lua. "Pure" in this context
+means that the functions could run outside of Minetest - none of the engine's
+functions are called.
+
+```lua
+-- Data
+function land.create(name, area_name)
+ land.lands[area_name] = {
+ name = area_name,
+ owner = name,
+ -- more stuff
+ }
+end
+
+function land.get_by_name(area_name)
+ return land.lands[area_name]
+end
+```
+
+Your actions should also be pure, but calling other functions is more
+acceptable than in the above.
+
+```lua
+-- Controller
+function land.handle_create_submit(name, area_name)
+ -- process stuff
+ -- (ie: check for overlaps, check quotas, check permissions)
+
+ land.create(name, area_name)
+end
+
+function land.handle_creation_request(name)
+ -- This is a bad example, as explained later
+ land.show_create_formspec(name)
+end
+```
+
+Your event handlers will have to interact with the Minetest API. You should keep
+the number of calculations to a minimum, as you won't be able to test this area
+very easily.
+
+```lua
+-- View
+function land.show_create_formspec(name)
+ -- Note how there's no complex calculations here!
+ return [[
+ size[4,3]
+ label[1,0;This is an example]
+ field[0,1;3,1;area_name;]
+ button_exit[0,2;1,1;exit;Exit]
+ ]]
+end
+
+minetest.register_chatcommand("/land", {
+ privs = { land = true },
+ func = function(name)
+ land.handle_creation_request(name)
+ end,
+})
+
+minetest.register_on_player_receive_fields(function(player,
+ formname, fields)
+ land.handle_create_submit(player:get_player_name(),
+ fields.area_name)
+end)
+```
+
+The above is the Model-View-Controller pattern. The model is a collection of data
+with minimal functions. The view is a collection of functions which listen to
+events and pass it to the controller, and also receives calls from the controller to
+do something with the Minetest API. The controller is where the decisions and
+most of the calculations are made.
+
+The controller should have no knowledge about the Minetest API - notice how
+there are no Minetest calls or any view functions that resemble them.
+You should *NOT* have a function like `view.hud_add(player, def)`.
+Instead, the view defines some actions that the controller can tell the view to do,
+like `view.add_hud(info)` where info is a value or table which doesn't relate
+to the Minetest API at all.
+
+
+
+It is important that each area only communicates with its direct neighbours,
+as shown above, in order to reduce how much you need to change if you modify
+an area's internals or externals. For example, to change the formspec you
+would only need to edit the view. To change the view API, you would only need to
+change the view and the controller, but not the model at all.
+
+In practice, this design is rarely used because of the increased complexity
+and because it doesn't give many benefits for most types of mods. Instead,
+you will commonly see a less formal and strict kind of design -
+variants of the API-View.
+
+
+### API-View
+
+In an ideal world, you'd have the above 3 areas perfectly separated with all
+events going into the controller before going back to the normal view. But
+this isn't the real world. A good compromise is to reduce the mod into two
+parts:
+
+* **API** - This was the model and controller above. There should be no uses of
+ `minetest.` here.
+* **View** - This was also the view above. It's a good idea to structure this into separate
+ files for each type of event.
+
+rubenwardy's [crafting mod](https://github.com/rubenwardy/crafting) roughly
+follows this design. `api.lua` is almost all pure Lua functions handling the data
+storage and controller-style calculations. `gui.lua` is the view for formspecs
+and formspec submission, and `async_crafter.lua` is the view and controller for
+a node formspec and node timers.
+
+Separating the mod like this means that you can very easily test the API part,
+as it doesn't use any Minetest APIs - as shown in the
+[next chapter](unit_testing.html) and seen in the crafting mod.
+
+
+## Conclusion
+
+Good code design is subjective, and highly depends on the project you're making. As a
+general rule, try to keep cohesion high and coupling low. Phrased differently,
+keep related code together and unrelated code apart, and keep dependencies simple.
+
+I highly recommend reading the [Game Programming Patterns](http://gameprogrammingpatterns.com/)
+book. It's freely available to [read online](http://gameprogrammingpatterns.com/contents.html)
+and goes into much more detail on common programming patterns relevant to games.
diff --git a/_it/quality/common_mistakes.md b/_it/quality/common_mistakes.md
new file mode 100644
index 0000000..293a5aa
--- /dev/null
+++ b/_it/quality/common_mistakes.md
@@ -0,0 +1,167 @@
+---
+title: Common Mistakes
+layout: default
+root: ../..
+idx: 8.1
+redirect_from: /en/chapters/common_mistakes.html
+---
+
+## Introduction
+
+This chapter details common mistakes, and how to avoid them.
+
+- [Never Store ObjectRefs (ie: players or entities)](#never-store-objectrefs-ie-players-or-entities)
+- [Don't Trust Formspec Submissions](#dont-trust-formspec-submissions)
+- [Set ItemStacks After Changing Them](#set-itemstacks-after-changing-them)
+
+## Never Store ObjectRefs (ie: players or entities)
+
+If the object an ObjectRef represents is deleted - for example, if the player goes
+offline or the entity is unloaded - then calling methods on that object
+will result in a crash.
+
+For example, don't do this:
+
+```lua
+minetest.register_on_joinplayer(function(player)
+ local function func()
+ local pos = player:get_pos() -- BAD!
+ -- `player` is stored then accessed later.
+ -- If the player leaves in that second, the server *will* crash.
+ end
+
+ minetest.after(1, func)
+
+ foobar[player:get_player_name()] = player
+ -- RISKY
+ -- It's not recommended to do this.
+ -- Use minetest.get_connected_players() and
+ -- minetest.get_player_by_name() instead.
+end)
+```
+
+Do this instead:
+
+```lua
+minetest.register_on_joinplayer(function(player)
+ local function func(name)
+ -- Attempt to get the ref again
+ local player = minetest.get_player_by_name(name)
+
+ -- Check that the player is still online
+ if player then
+ -- Yay! This is fine
+ local pos = player:get_pos()
+ end
+ end
+
+ -- Pass the name into the function
+ minetest.after(1, func, player:get_player_name())
+end)
+```
+
+## Don't Trust Formspec Submissions
+
+Malicious clients can submit formspecs whenever they like, with
+whatever content they like.
+
+For example, the following code has a vulnerability which allows players to
+give themselves moderator privileges:
+
+```lua
+local function show_formspec(name)
+ if not minetest.check_player_privs(name, { privs = true }) then
+ return false
+ end
+
+ minetest.show_formspec(name, "modman:modman", [[
+ size[3,2]
+ field[0,0;3,1;target;Name;]
+ button_exit[0,1;3,1;sub;Promote]
+ ]])
+ return true
+})
+
+minetest.register_on_player_receive_fields(function(player,
+ formname, fields)
+ -- BAD! Missing privilege check here!
+
+ local privs = minetest.get_player_privs(fields.target)
+ privs.kick = true
+ privs.ban = true
+ minetest.set_player_privs(fields.target, privs)
+ return true
+end)
+```
+
+Add a privilege check to solve this:
+
+```lua
+minetest.register_on_player_receive_fields(function(player,
+ formname, fields)
+ if not minetest.check_player_privs(name, { privs = true }) then
+ return false
+ end
+
+ -- code
+end)
+```
+
+## Set ItemStacks After Changing Them
+
+Have you noticed that it's simply called an `ItemStack` in the API, not an `ItemStackRef`,
+similar to `InvRef`? This is because an `ItemStack` isn't a reference - it's a
+copy. Stacks work on a copy of the data rather than the stack in the inventory.
+This means that modifying a stack won't actually modify that stack in the inventory.
+
+For example, don't do this:
+
+```lua
+local inv = player:get_inventory()
+local stack = inv:get_stack("main", 1)
+stack:get_meta():set_string("description", "Partially eaten")
+-- BAD! Modification will be lost
+```
+
+Do this instead:
+
+```lua
+local inv = player:get_inventory()
+local stack = inv:get_stack("main", 1)
+stack:get_meta():set_string("description", "Partially eaten")
+inv:set_stack("main", 1, stack)
+-- Correct! Item stack is set
+```
+
+The behaviour of callbacks is slightly more complicated. Modifying an `ItemStack` you
+are given will change it for the caller too, and any subsequent callbacks. However,
+it will only be saved in the engine if the callback caller sets it.
+
+```lua
+minetest.register_on_item_eat(function(hp_change, replace_with_item,
+ itemstack, user, pointed_thing)
+ itemstack:get_meta():set_string("description", "Partially eaten")
+ -- Almost correct! Data will be lost if another
+ -- callback cancels the behaviour
+end)
+```
+
+If no callbacks cancel this, the stack will be set and the description will be updated,
+but if a callback does cancel this, then the update may be lost.
+
+It's better to do this instead:
+
+```lua
+minetest.register_on_item_eat(function(hp_change, replace_with_item,
+ itemstack, user, pointed_thing)
+ itemstack:get_meta():set_string("description", "Partially eaten")
+ user:get_inventory():set_stack("main", user:get_wield_index(),
+ itemstack)
+ -- Correct, description will always be set!
+end)
+```
+
+If the callbacks cancel or the callback runner doesn't set the stack,
+then the update will still be set.
+If the callbacks or the callback runner set the stack, then the use of
+set_stack doesn't matter.
diff --git a/_it/quality/luacheck.md b/_it/quality/luacheck.md
new file mode 100644
index 0000000..d9b4410
--- /dev/null
+++ b/_it/quality/luacheck.md
@@ -0,0 +1,152 @@
+---
+title: Automatic Error Checking
+layout: default
+root: ../..
+idx: 8.2
+description: Use LuaCheck to find errors
+redirect_from: /en/chapters/luacheck.html
+---
+
+## Introduction
+
+In this chapter, you will learn how to use a tool called LuaCheck to automatically
+scan your mod for any mistakes. This tool can be used in combination with your
+editor to provide alerts to any mistakes.
+
+- [Installing LuaCheck](#installing-luacheck)
+ - [Windows](#windows)
+ - [Linux](#linux)
+- [Running LuaCheck](#running-luacheck)
+- [Configuring LuaCheck](#configuring-luacheck)
+ - [Troubleshooting](#troubleshooting)
+- [Using with editor](#using-with-editor)
+- [Checking Commits with Travis](#checking-commits-with-travis)
+
+## Installing LuaCheck
+
+### Windows
+
+Simply download luacheck.exe from
+[the Github Releases page](https://github.com/mpeterv/luacheck/releases).
+
+### Linux
+
+First, you'll need to install LuaRocks:
+
+ sudo apt install luarocks
+
+You can then install LuaCheck globally:
+
+ sudo luarocks install luacheck
+
+Check that it's installed with the following command:
+
+ luacheck -v
+
+## Running LuaCheck
+
+The first time you run LuaCheck, it will probably pick up a lot of false
+errors. This is because it still needs to be configured.
+
+On Windows, open powershell or bash in the root folder of your project
+and run `path\to\luacheck.exe .`
+
+On Linux, run `luacheck .` whilst in the root folder of your project.
+
+## Configuring LuaCheck
+
+Create a file called .luacheckrc in the root of your project. This could be the
+root of your game, modpack, or mod.
+
+Put the following contents in it:
+
+```lua
+unused_args = false
+allow_defined_top = true
+
+globals = {
+ "minetest",
+}
+
+read_globals = {
+ string = {fields = {"split"}},
+ table = {fields = {"copy", "getn"}},
+
+ -- Builtin
+ "vector", "ItemStack",
+ "dump", "DIR_DELIM", "VoxelArea", "Settings",
+
+ -- MTG
+ "default", "sfinv", "creative",
+}
+```
+
+Next, you'll need to test that it works by running LuaCheck. You should get a lot
+fewer errors this time. Starting at the first error you get, modify the code to
+remove the issue, or modify the configuration if the code is correct. See the list
+below.
+
+### Troubleshooting
+
+* **accessing undefined variable foobar** - If `foobar` is meant to be a global,
+ add it to `read_globals`. Otherwise, add any missing `local`s to the mod.
+* **setting non-standard global variable foobar** - If `foobar` is meant to be a global,
+ add it to `globals`. Remove from `read_globals` if present.
+ Otherwise, add any missing `local`s to the mod.
+* **mutating read-only global variable 'foobar'** - Move `foobar` from `read_globals` to
+ `globals`, or stop writing to foobar.
+
+## Using with editor
+
+It is highly recommended that you find and install a plugin for your editor of choice
+to show you errors without running a command. Most editors will likely have a plugin
+available.
+
+* **Atom** - `linter-luacheck`.
+* **VSCode** - Ctrl+P, then paste: `ext install dwenegar.vscode-luacheck`
+* **Sublime** - Install using package-control:
+ [SublimeLinter](https://github.com/SublimeLinter/SublimeLinter),
+ [SublimeLinter-luacheck](https://github.com/SublimeLinter/SublimeLinter-luacheck).
+
+## Checking Commits with Travis
+
+If your project is public and is on Github, you can use TravisCI - a free service
+to run jobs on commits to check them. This means that every commit you push will
+be checked against LuaCheck, and a green tick or red cross will be displayed next to them
+depending on whether LuaCheck finds any mistakes. This is especially helpful for
+when your project receives a pull request - you'll be able to see the LuaCheck output
+without downloading the code.
+
+First, you should visit [travis-ci.org](https://travis-ci.org/) and sign in with
+your Github account. Then find your project's repo in your Travis profile,
+and enable Travis by flipping the switch.
+
+Next, create a file called .travis.yml with the following content:
+
+```yml
+language: generic
+sudo: false
+addons:
+ apt:
+ packages:
+ - luarocks
+before_install:
+ - luarocks install --local luacheck
+script:
+- $HOME/.luarocks/bin/luacheck .
+notifications:
+ email: false
+```
+
+If your project is a game rather than a mod or mod pack,
+change the line after `script:` to:
+
+```yml
+- $HOME/.luarocks/bin/luacheck mods/
+```
+
+Now commit and push to Github. Go to your project's page on Github, and click
+'commits'. You should see an orange disc next to the commit you just made.
+After awhile it should change either into a green tick or a red cross depending on the
+outcome of LuaCheck. In either case, you can click the icon to see the build logs
+and the output of LuaCheck.
diff --git a/_it/quality/readmore.md b/_it/quality/readmore.md
new file mode 100644
index 0000000..8dc1218
--- /dev/null
+++ b/_it/quality/readmore.md
@@ -0,0 +1,28 @@
+---
+title: Read More
+layout: default
+root: ../..
+idx: 8.7
+redirect_from: /en/chapters/readmore.html
+---
+
+## List of Resources
+
+After you've read this book, take a look at the following.
+
+### Minetest Modding
+
+* Minetest's Lua API Reference - [HTML version]({{ page.root }}/lua_api.html) |
+ [Text version](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt).
+* Explore the [Developer Wiki](http://dev.minetest.net/Main_Page).
+* Look at [existing mods](https://forum.minetest.net/viewforum.php?f=11).
+
+### Lua Programming
+
+* [Programming in Lua (PIL)](http://www.lua.org/pil/).
+* [Lua Crash Course](http://luatut.com/crash_course.html).
+
+### 3D Modelling
+
+* [Blender 3D: Noob to pro](https://en.wikibooks.org/wiki/Blender_3D:_Noob_to_Pro).
+* [Using Blender with Minetest](http://wiki.minetest.net/Using_Blender).
diff --git a/_it/quality/releasing.md b/_it/quality/releasing.md
new file mode 100644
index 0000000..8d31957
--- /dev/null
+++ b/_it/quality/releasing.md
@@ -0,0 +1,214 @@
+---
+title: Releasing a Mod
+layout: default
+root: ../..
+idx: 8.6
+redirect_from: /en/chapters/releasing.html
+---
+
+## Introduction
+
+Releasing, or publishing, a mod allows other people to make use of it. Once a mod has been
+released it might be used in singleplayer games or on servers, including public servers.
+
+- [License Choices](#license-choices)
+ - [LGPL and CC-BY-SA](#lgpl-and-cc-by-sa)
+ - [CC0](#cc0)
+ - [MIT](#mit)
+- [Packaging](#packaging)
+ - [README.txt](#readmetxt)
+ - [description.txt](#descriptiontxt)
+ - [screenshot.png](#screenshotpng)
+- [Uploading](#uploading)
+ - [Version Control Systems](#version-control-systems)
+ - [Forum Attachments](#forum-attachments)
+- [Forum Topic](#forum-topic)
+ - [Subject](#subject)
+
+## License Choices
+
+You need to specify a license for your mod. This is important because it tells other
+people the ways in which they are allowed to use your work. If your mod doesn't have
+a license, people won't know whether they are allowed to modify, distribute or use your
+mod on a public server.
+
+Your code and your art need different things from the licenses they use. For example,
+Creative Commons licenses shouldn't be used with source code,
+but can be suitable choices for artistic works such as images, text and meshes.
+
+You are allowed any license; however, mods which disallow derivatives are banned from the
+official Minetest forum. (For a mod to be allowed on the forum, other developers must be
+able to modify it and release the modified version.)
+
+Please note that **public domain is not a valid licence**, because the definition varies
+in different countries.
+
+### LGPL and CC-BY-SA
+
+This is a common license combination in the Minetest community, and is what
+Minetest and Minetest Game use.
+You license your code under LGPL 2.1 and your art under CC-BY-SA.
+This means that:
+
+* Anyone can modify, redistribute and sell modified or unmodified versions.
+* If someone modifies your mod, they must give their version the same license.
+* Your copyright notice must be kept.
+
+### CC0
+
+These licenses allow anyone to do what they want with your mod,
+which means they can modify, redistribute, sell, or leave-out attribution.
+These licenses can be used for both code and art.
+
+It is important to note that WTFPL is strongly discouraged and people may
+choose not to use your mod if it has this license.
+
+### MIT
+
+This is a common license for mod code. The only restriction it places on users
+of your mod is that they must include the same copyright notice and license
+in any copies of the mod or of substantial parts of the mod.
+
+## Packaging
+
+There are some files that are recommended to include in your mod
+before you release it.
+
+### README.txt
+
+The README file should state:
+
+* What the mod does.
+* What the license is.
+* What dependencies there are.
+* How to install the mod.
+* Current version of the mod.
+* Optionally, the where to report problems or get help.
+
+### description.txt
+
+This should explain what your mod does. Be concise without being vague.
+It should be short because it will be displayed in the content installer which has
+limited space.
+
+Good example:
+
+ Adds soup, cakes, bakes and juices.
+
+Avoid this:
+
+ (BAD) The food mod for Minetest.
+
+### screenshot.png
+
+Screenshots should be 3:2 (3 pixels of width for every 2 pixels of height)
+and have a minimum size of 300 x 200px.
+
+The screenshot is displayed in the mod store.
+
+## Uploading
+
+So that a potential user can download your mod, you need to upload it somewhere
+publicly accessible. There are several ways to do this, but you should use the
+approach that works best for you, as long as it meets these requirements, and any
+others which may be added by forum moderators:
+
+* **Stable** - The hosting website should be unlikely to shut down without warning.
+* **Direct link** - You should be able to click a link on the forum and download the file
+ without having to view another page.
+* **Virus Free** - Mods with malicious content will be removed from the forum.
+
+### Version Control Systems
+
+It is recommended that you use a version control system which:
+
+* Allows other developers to easily submit changes.
+* Allows the code to be previewed before downloading.
+* Allows users to submit bug reports.
+
+The majority of Minetest modders use GitHub as a website to host their code,
+but alternatives are possible.
+
+Using a GitHub can be difficult at first. If you need help with this, for
+information on using GitHub, please see:
+
+* [Pro Git book](http://git-scm.com/book/en/v1/Getting-Started) - Free to read online.
+* [GitHub for Windows app](https://help.github.com/articles/getting-started-with-github-for-windows/) -
+Using a graphical interface on Windows to upload your code.
+
+### Forum Attachments
+
+As an alternative to using a version management system, you can use forum attachments to share
+your mods. This can be done when creating a mod's forum topic (covered below).
+
+You need to zip the files for the mod into a single file. How to do this varies from
+operating system to operating system.
+This is nearly always done using the right click menu after selecting all files.
+
+When making a forum topic, on the "Create a Topic" page (see below), go to the
+"Upload Attachment" tab at the bottom.
+Click "Browse" and select the zipped file. It is recommended that you
+enter the version of your mod in the comment field.
+
+
+
+## Forum Topic
+
+You can now create a forum topic. You should create it in
+the ["WIP Mods"](https://forum.minetest.net/viewforum.php?f=9) (Work In Progress)
+forum.\\
+When you no longer consider your mod a work in progress, you can
+[request that it be moved](https://forum.minetest.net/viewtopic.php?f=11&t=10418)
+to "Mod Releases."
+
+The forum topic should contain similar content to the README, but should
+be more promotional and also include a link to download the mod.
+It's a good idea to include screenshots of your mod in action, if possible.
+
+The Minetest forum uses bbcode for formatting. Here is an example for a
+mod named superspecial:
+
+
+ Adds magic, rainbows and other special things.
+
+ See download attached.
+
+ [b]Version:[/b] 1.1
+ [b]License:[/b] LGPL 2.1 or later
+
+ Dependencies: default mod (found in minetest_game)
+
+ Report bugs or request help on the forum topic.
+
+ [h]Installation[/h]
+
+ Unzip the archive, rename the folder to superspecial and
+ place it in minetest/mods/
+
+ ( GNU/Linux: If you use a system-wide installation place
+ it in ~/.minetest/mods/. )
+
+ ( If you only want this to be used in a single world, place
+ the folder in worldmods/ in your world directory. )
+
+ For further information or help see:
+ [url]https://wiki.minetest.net/Installing_Mods[/url]
+
+If you modify the above example for your mod topic, remember to
+change "superspecial" to the name of your mod.
+
+### Subject
+
+The subject of topic must be in one of these formats:
+
+* [Mod] Mod Title [modname]
+* [Mod] Mod Title [version number] [modname]
+
+For example:
+
+* [Mod] More Blox [0.1] [moreblox]
diff --git a/_it/quality/security.md b/_it/quality/security.md
new file mode 100644
index 0000000..c37eba5
--- /dev/null
+++ b/_it/quality/security.md
@@ -0,0 +1,110 @@
+---
+title: Security
+layout: default
+root: ../..
+idx: 8.3
+---
+
+## Introduction
+
+Security is very important in making sure that your mod doesn't cause the server
+owner to lose data or control.
+
+- [Core Concepts](#core-concepts)
+- [Formspecs](#formspecs)
+ - [Never Trust Submissions](#never-trust-submissions)
+ - [Time of Check isn't Time of Use](#time-of-check-isnt-time-of-use)
+- [(Insecure) Environments](#insecure-environments)
+
+## Core Concepts
+
+The most important concept in security is to **never trust the user**.
+Anything the user submits should be treated as malicious.
+This means that you should always check that the information they
+enter is valid, that the user has the correct permissions,
+and that they are otherwise allowed to do that action
+(ie: in range or an owner).
+
+A malicious action isn't necessarily the modification or destruction of data,
+but can be accessing sensitive data, such as password hashes or
+private messages.
+This is especially bad if the server stores information such as emails or ages,
+which some may do for verification purposes.
+
+## Formspecs
+
+### Never Trust Submissions
+
+Any users can submit almost any formspec with any values at any time.
+
+Here's some real code found in a mod:
+
+```lua
+minetest.register_on_player_receive_fields(function(player,
+ formname, fields)
+ for key, field in pairs(fields) do
+ local x,y,z = string.match(key,
+ "goto_([%d-]+)_([%d-]+)_([%d-]+)")
+ if x and y and z then
+ player:set_pos({ x=tonumber(x), y=tonumber(y),
+ z=tonumber(z) })
+ return true
+ end
+ end
+end
+```
+
+Can you spot the problem? A malicious user could submit a formspec containing
+their own position values, allowing them to teleport to anywhere they wish to.
+This could even be automated using client modifications to essentially replicate
+the `/teleport` command with no need for a privilege.
+
+The solution for this kind of issue is to use a
+[Context](../players/formspecs.html#contexts), as shown previously in
+the Formspecs chapter.
+
+### Time of Check isn't Time of Use
+
+Any users can submit any formspec with any values at any time, except where the
+engine forbids it:
+
+* A node formspec submission will be blocked if the user is too far away.
+* From 5.0 onward, named formspecs will be blocked if they haven't been shown yet.
+
+This means that you should check in the handler that the user meets the
+conditions for showing the formspec in the first place, as well as any
+corresponding actions.
+
+The vulnerability caused by checking for permissions in the show formspec but not
+in the handle formspec is called Time Of Check is not Time Of Use (TOCTOU).
+
+
+## (Insecure) Environments
+
+Minetest allows mods to request an unsandboxed environment, giving them access
+to the full Lua API.
+
+Can you spot the vulnerability in the following?
+
+```lua
+local ie = minetest.request_insecure_environment()
+ie.os.execute(("path/to/prog %d"):format(3))
+```
+
+`string.format` is a function in the global shared table `string`.
+A malicious mod could override this function and pass stuff to os.execute:
+
+```lua
+string.format = function()
+ return "xdg-open 'http://example.com'"
+end
+```
+
+The mod could pass something much more malicious than opening a website, such
+as giving a remote user control over the machine.
+
+Some rules for using an insecure environment:
+
+* Always store it in a local and never pass it into a function.
+* Make sure you can trust any input given to an insecure function, to avoid the
+ issue above. This means avoiding globally redefinable functions.
diff --git a/_it/quality/unit_testing.md b/_it/quality/unit_testing.md
new file mode 100644
index 0000000..643380a
--- /dev/null
+++ b/_it/quality/unit_testing.md
@@ -0,0 +1,195 @@
+---
+title: Automatic Unit Testing
+layout: default
+root: ../..
+idx: 8.5
+---
+
+## Introduction
+
+Unit tests are an essential tool in proving and reassuring yourself that your code
+is correct. This chapter will show you how to write tests for Minetest mods and
+games using Busted. Writing unit tests for functions where you call Minetest
+functions is quite difficult, but luckily [in the previous chapter](clean_arch.html),
+we discussed how to structure your code avoid this.
+
+- [Installing Busted](#installing-busted)
+- [Your First Test](#your-first-test)
+ - [init.lua](#initlua)
+ - [api.lua](#apilua)
+ - [tests/api_spec.lua](#testsapispeclua)
+- [Mocking: Using External Functions](#mocking-using-external-functions)
+- [Checking Commits with Travis](#checking-commits-with-travis)
+- [Conclusion](#conclusion)
+
+## Installing Busted
+
+First, you'll need to install LuaRocks.
+
+* Windows: Follow the [installation instructions on LuaRock's wiki](https://github.com/luarocks/luarocks/wiki/Installation-instructions-for-Windows).
+* Debian/Ubuntu Linux: `sudo apt install luarocks`
+
+Next, you should install Busted globally:
+
+ sudo luarocks install busted
+
+Finally, check that it is installed:
+
+ busted --version
+
+
+## Your First Test
+
+Busted is Lua's leading unit test framework. Busted looks for Lua files with
+names ending in `_spec`, and then executes them in a standalone Lua environment.
+
+ mymod/
+ ├── init.lua
+ ├── api.lua
+ └── tests
+ └── api_spec.lua
+
+
+### init.lua
+
+```lua
+mymod = {}
+
+dofile(minetest.get_modpath("mymod") .. "/api.lua")
+```
+
+
+
+### api.lua
+
+```lua
+function mymod.add(x, y)
+ return x + y
+end
+```
+
+### tests/api_spec.lua
+
+```lua
+-- Look for required things in
+package.path = "../?.lua;" .. package.path
+
+-- Set mymod global for API to write into
+_G.mymod = {} --_
+-- Run api.lua file
+require("api")
+
+-- Tests
+describe("add", function()
+ it("adds", function()
+ assert.equals(2, mymod.add(1, 1))
+ end)
+
+ it("supports negatives", function()
+ assert.equals(0, mymod.add(-1, 1))
+ assert.equals(-2, mymod.add(-1, -1))
+ end)
+end)
+```
+
+You can now run the tests by opening a terminal in the mod's directory and
+running `busted .`
+
+It's important that the API file doesn't create the table itself, as globals in
+Busted work differently. Any variable which would be global in Minetest is instead
+a file local in busted. This would have been a better way for Minetest to do things,
+but it's too late for that now.
+
+Another thing to note is that any files you're testing should avoid calls to any
+functions not inside of it. You tend to only write tests for a single file at once.
+
+
+## Mocking: Using External Functions
+
+Mocking is the practice of replacing functions that the thing you're testing depends
+on. This can have two purposes; one, the function may not be available in the
+test environment, and two, you may want to capture calls to the function and any
+passed arguments.
+
+If you follow the advice in the [Clean Architectures](clean_arch.html) chapter,
+you'll already have a pretty clean file to test. You will still have to mock
+things not in your area, however - for example, you'll have to mock the view when
+testing the controller/API. If you didn't follow the advice, then things are a
+little harder as you may have to mock the Minetest API.
+
+```lua
+-- As above, make a table
+_G.minetest = {}
+
+-- Define the mock function
+local chat_send_all_calls = {}
+function minetest.chat_send_all(name, message)
+ table.insert(chat_send_all_calls, { name = name, message = message })
+end
+
+-- Tests
+describe("list_areas", function()
+ it("returns a line for each area", function()
+ chat_send_all_calls = {} -- reset table
+
+ mymod.list_areas_to_chat("singleplayer", "singleplayer")
+
+ assert.equals(2, #chat_send_all_calls)
+ end)
+
+ it("sends to right player", function()
+ chat_send_all_calls = {} -- reset table
+
+ mymod.list_areas_to_chat("singleplayer", "singleplayer")
+
+ for _, call in pairs(chat_send_all_calls) do --_
+ assert.equals("singleplayer", call.name)
+ end
+ end)
+
+ -- The above two tests are actually pointless,
+ -- as this one tests both things
+ it("returns correct thing", function()
+ chat_send_all_calls = {} -- reset table
+
+ mymod.list_areas_to_chat("singleplayer", "singleplayer")
+
+ local expected = {
+ { name = "singleplayer", message = "Town Hall (2,43,63)" },
+ { name = "singleplayer", message = "Airport (43,45,63)" },
+ }
+ assert.same(expected, chat_send_all_calls)
+ end)
+end)
+```
+
+
+## Checking Commits with Travis
+
+The Travis script from the [Automatic Error Checking](luacheck.html)
+chapter can be modified to also run Busted.
+
+```yml
+language: generic
+sudo: false
+addons:
+ apt:
+ packages:
+ - luarocks
+before_install:
+ - luarocks install --local luacheck && luarocks install --local busted
+script:
+- $HOME/.luarocks/bin/luacheck .
+- $HOME/.luarocks/bin/busted .
+notifications:
+ email: false
+```
+
+
+## Conclusion
+
+Unit tests will greatly increase the quality and reliability of your project if used
+well, but they require you to structure your code in a different way than usual.
+
+For an example of a mod with lots of unit tests, see
+[crafting by rubenwardy](https://github.com/rubenwardy/crafting).
diff --git a/_layouts/default.html b/_layouts/default.html
index 4b8249f..217b93e 100644
--- a/_layouts/default.html
+++ b/_layouts/default.html
@@ -22,6 +22,8 @@ layout: compress
{% if language == "en" %}
{% assign links = site.en | sort: "idx" %}
+ {% else if language == "it" %}
+ {% assign links = site.it | sort: "idx" %}
{% else %}
{% assign language = "en" %}
{% assign links = site.en | sort: "idx" %}