diff --git a/builtin/game/chat.lua b/builtin/game/chat.lua
index a7517bffe9..c8ecd95d14 100644
--- a/builtin/game/chat.lua
+++ b/builtin/game/chat.lua
@@ -43,18 +43,27 @@ end
-- Chat command handler
--
--- Unsure how to handle pairs()
-core.chatcommands = setmetatable({}, {
- __index=function (_, k)
- core.log("warn", "core.chatcommands is deprecated, use core.registered_chatcommands instead")
+--- Deprecated core.chatcommands
+core.chatcommands = setmetatable(table.copy(core.registered_chatcommands), {
+ __index = function (_, k)
+ core.log("warning", "core.chatcommands is deprecated, use core.registered_chatcommands instead.")
return core.registered_chatcommands[k]
end,
- __newindex=function (_, k, v)
- core.log("warn", "core.chatcommands is deprecated, use core.registered_chatcommands instead")
+ __newindex = function (_, k, v)
+ core.log("warning", "core.chatcommands is deprecated, use core.registered_chatcommands instead.")
+ rawset(core.chatcommands, k, v)
core.registered_chatcommands[k] = v
end,
})
+--- For support pairs() with core.chatcommands
+setmetatable(core.registered_chatcommands, {
+ __newindex = function (t, k, v)
+ rawset(t, k, v)
+ rawset(core.chatcommands, k, v)
+ end
+})
+
local msg_time_threshold =
tonumber(core.settings:get("chatcommand_msg_time_threshold")) or 0.1
core.register_on_chat_message(function(name, message)
diff --git a/doc/' b/doc/'
new file mode 100644
index 0000000000..aee3552b7a
--- /dev/null
+++ b/doc/'
@@ -0,0 +1,12073 @@
+Luanti Lua Modding API Reference
+================================
+
+**WARNING**: if you're looking for the `minetest` namespace (e.g. `minetest.something`),
+it's now called `core` due to the renaming of Luanti (formerly Minetest).
+`minetest` will keep existing as an alias, so that old code won't break.
+
+Note that `core` has already existed since version 0.4.10, so you can use it
+safely without breaking backwards compatibility.
+
+* More information at
+* Additional documentation:
+* (Unofficial) Luanti Modding Book by rubenwardy:
+* Modding tools:
+
+Introduction
+------------
+
+Content and functionality can be added to Luanti using Lua scripting
+in run-time loaded mods.
+
+A mod is a self-contained bunch of scripts, textures and other related
+things, which is loaded by and interfaces with Luanti.
+
+Mods are contained and ran solely on the server side. Definitions and media
+files are automatically transferred to the client.
+
+If you see a deficiency in the API, feel free to attempt to add the
+functionality in the engine and API, and to document it here.
+
+Programming in Lua
+------------------
+
+If you have any difficulty in understanding this, please read
+[Programming in Lua](http://www.lua.org/pil/).
+
+Startup
+-------
+
+Mods are loaded during server startup from the mod load paths by running
+the `init.lua` scripts in a shared environment.
+
+Paths
+-----
+
+Luanti keeps and looks for files mostly in two paths. `path_share` or `path_user`.
+
+`path_share` contains possibly read-only content for the engine (incl. games and mods).
+`path_user` contains mods or games installed by the user but also the users
+worlds or settings.
+
+With a local build (`RUN_IN_PLACE=1`) `path_share` and `path_user` both point to
+the build directory. For system-wide builds on Linux the share path is usually at
+`/usr/share/minetest` while the user path resides in `.minetest` in the home directory.
+Paths on other operating systems will differ.
+
+Games
+=====
+
+Games are looked up from:
+
+* `$path_share/games//`
+* `$path_user/games//`
+
+Where `` is unique to each game.
+
+The game directory can contain the following files:
+
+* `game.conf`, with the following keys:
+ * `title`: Required, a human-readable title to address the game, e.g. `title = Minetest Game`.
+ * `name`: (Deprecated) same as title.
+ * `description`: Short description to be shown in the content tab.
+ See [Translating content meta](#translating-content-meta).
+ * `first_mod`: Use this to specify the mod that must be loaded before any other mod.
+ * `last_mod`: Use this to specify the mod that must be loaded after all other mods
+ * `allowed_mapgens = `
+ e.g. `allowed_mapgens = v5,v6,flat`
+ Mapgens not in this list are removed from the list of mapgens for the
+ game.
+ If not specified, all mapgens are allowed.
+ * `disallowed_mapgens = `
+ e.g. `disallowed_mapgens = v5,v6,flat`
+ These mapgens are removed from the list of mapgens for the game.
+ When both `allowed_mapgens` and `disallowed_mapgens` are
+ specified, `allowed_mapgens` is applied before
+ `disallowed_mapgens`.
+ * `disallowed_mapgen_settings= `
+ e.g. `disallowed_mapgen_settings = mgv5_spflags`
+ These mapgen settings are hidden for this game in the world creation
+ dialog and game start menu. Add `seed` to hide the seed input field.
+ * `disabled_settings = `
+ e.g. `disabled_settings = enable_damage, creative_mode`
+ These settings are hidden for this game in the "Start game" tab
+ and will be initialized as `false` when the game is started.
+ Prepend a setting name with an exclamation mark to initialize it to `true`
+ (this does not work for `enable_server`).
+ Only these settings are supported:
+ `enable_damage`, `creative_mode`, `enable_server`.
+ * `map_persistent`: Specifies whether newly created worlds should use
+ a persistent map backend. Defaults to `true` (= "sqlite3")
+ * `author`: The author's ContentDB username.
+ * `release`: Ignore this: Should only ever be set by ContentDB, as it is
+ an internal ID used to track versions.
+ * `textdomain`: Textdomain used to translate description. Defaults to game id.
+ See [Translating content meta](#translating-content-meta).
+* `minetest.conf`:
+ Used to set default settings when running this game.
+* `settingtypes.txt`:
+ In the same format as the one in builtin.
+ This settingtypes.txt will be parsed by the menu and the settings will be
+ displayed in the "Games" category in the advanced settings tab.
+* If the game contains a folder called `textures` the server will load it as a
+ texturepack, overriding mod textures.
+ Any server texturepack will override mod textures and the game texturepack.
+
+Menu images
+-----------
+
+Games can provide custom main menu images. They are put inside a `menu`
+directory inside the game directory.
+
+The images are named `$identifier.png`, where `$identifier` is one of
+`overlay`, `background`, `footer`, `header`.
+If you want to specify multiple images for one identifier, add additional
+images named like `$identifier.$n.png`, with an ascending number $n starting
+with 1, and a random image will be chosen from the provided ones.
+
+Menu music
+-----------
+
+Games can provide custom main menu music. They are put inside a `menu`
+directory inside the game directory.
+
+The music files are named `theme.ogg`.
+If you want to specify multiple music files for one game, add additional
+images named like `theme.$n.ogg`, with an ascending number $n starting
+with 1 (max 10), and a random music file will be chosen from the provided ones.
+
+Mods
+====
+
+Mod load path
+-------------
+
+Paths are relative to the directories listed in the [Paths](#paths) section above.
+
+* `games//mods/`
+* `mods/`
+* `worlds//worldmods/`
+
+World-specific games
+--------------------
+
+It is possible to include a game in a world; in this case, no mods or
+games are loaded or checked from anywhere else.
+
+This is useful for e.g. adventure worlds and happens if the `/game/`
+directory exists.
+
+Mods should then be placed in `/game/mods/`.
+
+Modpacks
+--------
+
+Mods can be put in a subdirectory, if the parent directory, which otherwise
+should be a mod, contains a file named `modpack.conf`.
+The file is a key-value store of modpack details.
+
+* `name`: The modpack name. Allows Luanti to determine the modpack name even
+ if the folder is wrongly named.
+* `title`: A human-readable title to address the modpack. See [Translating content meta](#translating-content-meta).
+* `description`: Description of mod to be shown in the Mods tab of the main
+ menu. See [Translating content meta](#translating-content-meta).
+* `author`: The author's ContentDB username.
+* `release`: Ignore this: Should only ever be set by ContentDB, as it is an
+ internal ID used to track versions.
+* `textdomain`: Textdomain used to translate title and description. Defaults to modpack name.
+ See [Translating content meta](#translating-content-meta).
+
+Note: to support 0.4.x, please also create an empty modpack.txt file.
+
+Mod directory structure
+-----------------------
+
+ mods
+ ├── modname
+ │ ├── mod.conf
+ │ ├── screenshot.png
+ │ ├── settingtypes.txt
+ │ ├── init.lua
+ │ ├── models
+ │ ├── textures
+ │ │ ├── modname_stuff.png
+ │ │ ├── modname_something_else.png
+ │ │ ├── subfolder_foo
+ │ │ │ ├── modname_more_stuff.png
+ │ │ │ └── another_subfolder
+ │ │ └── bar_subfolder
+ │ ├── sounds
+ │ ├── fonts
+ │ ├── media
+ │ ├── locale
+ │ └──
+ └── another
+
+### modname
+
+The location of this directory can be fetched by using
+`core.get_modpath(modname)`.
+
+### mod.conf
+
+A `Settings` file that provides meta information about the mod.
+
+* `name`: The mod name. Allows Luanti to determine the mod name even if the
+ folder is wrongly named.
+* `title`: A human-readable title to address the mod. See [Translating content meta](#translating-content-meta).
+* `description`: Description of mod to be shown in the Mods tab of the main
+ menu. See [Translating content meta](#translating-content-meta).
+* `depends`: A comma separated list of dependencies. These are mods that must be
+ loaded before this mod.
+* `optional_depends`: A comma separated list of optional dependencies.
+ Like a dependency, but no error if the mod doesn't exist.
+* `author`: The author's ContentDB username.
+* `release`: Ignore this: Should only ever be set by ContentDB, as it is an
+ internal ID used to track versions.
+* `textdomain`: Textdomain used to translate title and description. Defaults to modname.
+ See [Translating content meta](#translating-content-meta).
+
+### `screenshot.png`
+
+A screenshot shown in the mod manager within the main menu. It should
+have an aspect ratio of 3:2 and a minimum size of 300×200 pixels.
+
+### `depends.txt`
+
+**Deprecated:** you should use mod.conf instead.
+
+This file is used if there are no dependencies in mod.conf.
+
+List of mods that have to be loaded before loading this mod.
+
+A single line contains a single modname.
+
+Optional dependencies can be defined by appending a question mark
+to a single modname. This means that if the specified mod
+is missing, it does not prevent this mod from being loaded.
+
+### `description.txt`
+
+**Deprecated:** you should use mod.conf instead.
+
+This file is used if there is no description in mod.conf.
+
+A file containing a description to be shown in the Mods tab of the main menu.
+
+### `settingtypes.txt`
+
+The format is documented in `builtin/settingtypes.txt`.
+It is parsed by the main menu settings dialogue to list mod-specific
+settings in the "Mods" category.
+
+`core.settings` can be used to read custom or engine settings.
+See [Settings](#settings).
+
+### `init.lua`
+
+The main Lua script. Running this script should register everything it
+wants to register. Subsequent execution depends on Luanti calling the
+registered callbacks.
+
+### `textures`, `sounds`, `media`, `models`, `locale`, `fonts`
+
+Media files (textures, sounds, whatever) that will be transferred to the
+client and will be available for use by the mod and translation files for
+the clients (see [Translations](#translations)). Accepted characters for names are:
+
+ a-zA-Z0-9_.-
+
+Accepted formats are:
+
+ images: .png, .jpg, .tga
+ sounds: .ogg vorbis
+ models: .x, .b3d, .obj, (since version 5.10:) .gltf, .glb
+ fonts: .ttf, .woff (both since version 5.11, see notes below)
+
+Currently the engine is unable to handle files over ~16MB in size. For best
+performance you should keep your media files as small as reasonably possible.
+
+Other formats won't be sent to the client (e.g. you can store .blend files
+in a folder for convenience, without the risk that such files are transferred)
+
+It is suggested to use the folders for the purpose they are thought for,
+eg. put textures into `textures`, translation files into `locale`,
+models for entities or meshnodes into `models` et cetera.
+
+These folders and subfolders can contain subfolders.
+Subfolders with names starting with `_` or `.` are ignored.
+If a subfolder contains a media file with the same name as a media file
+in one of its parents, the parent's file is used.
+
+Although it is discouraged, a mod can overwrite a media file of any mod that it
+depends on by supplying a file with an equal name.
+
+Only a subset of model file format features is supported:
+
+Simple textured meshes (with multiple textures), optionally with normals.
+The .x, .b3d and .gltf formats additionally support (a single) animation.
+
+#### glTF
+
+Binary glTF (`.glb`) files are supported and recommended over `.gltf` files
+due to their space savings.
+
+Bone weights should be normalized, e.g. using ["normalize all" in Blender](https://docs.blender.org/manual/en/4.2/grease_pencil/modes/weight_paint/weights_menu.html#normalize-all).
+
+Note that nodes using matrix transforms must not be animated.
+This also extends to bone overrides, which must not be applied to them.
+
+You can use the [Khronos glTF validator](https://github.com/KhronosGroup/glTF-Validator)
+to check whether a model is a valid glTF file.
+
+Many glTF features are not supported *yet*, including:
+
+* Animations
+ * Only a single animation is supported, use frame ranges within this animation.
+ * `CUBICSPLINE` interpolation is not supported.
+* Cameras
+* Materials
+ * Only base color textures are supported
+ * Backface culling is overridden
+ * Double-sided materials don't work
+* Alternative means of supplying data
+ * Embedded images. You can use `gltfutil.py` from the
+ [modding tools](https://github.com/luanti-org/modtools) to strip or extract embedded images.
+ * References to files via URIs
+
+Textures are supplied solely via the same means as for the other model file formats:
+The `textures` object property, the `tiles` node definition field and
+the list of textures used in the `model[]` formspec element.
+
+The order in which textures are to be supplied
+is that in which they appear in the `textures` array in the glTF file.
+
+Do not rely on glTF features not being supported; they may be supported in the future.
+The backwards compatibility guarantee does not extend to ignoring unsupported features.
+
+For example, if your model used an emissive material,
+you should expect that a future version of Luanti may respect this,
+and thus cause your model to render differently there.
+
+#### Custom fonts
+
+You can supply custom fonts in TrueType Font (`.ttf`) or Web Open Font Format (`.woff`) format.
+The former is supported primarily for convenience. The latter is preferred due to its compression.
+
+In the future, having multiple custom fonts and the ability to switch between them is planned,
+but for now this feature is limited to the ability to override Luanti's default fonts via mods.
+It is recommended that this only be used by game mods to set a look and feel.
+
+The stems (file names without extension) are self-explanatory:
+
+* Regular variants:
+ * `regular`
+ * `bold`
+ * `italic`
+ * `bold_italic`
+* Monospaced variants:
+ * `mono`
+ * `mono_bold`
+ * `mono_italic`
+ * `mono_bold_italic`
+
+Naming conventions
+------------------
+
+Registered names should generally be in this format:
+
+ modname:
+
+`` can have these characters:
+
+ a-zA-Z0-9_
+
+This is to prevent conflicting names from corrupting maps and is
+enforced by the mod loader.
+
+Registered names can be overridden by prefixing the name with `:`. This can
+be used for overriding the registrations of some other mod.
+
+The `:` prefix can also be used for maintaining backwards compatibility.
+
+### Example
+
+In the mod `experimental`, there is the ideal item/node/entity name `tnt`.
+So the name should be `experimental:tnt`.
+
+Any mod can redefine `experimental:tnt` by using the name
+
+ :experimental:tnt
+
+when registering it. For this to work correctly, that mod must have
+`experimental` as a dependency.
+
+
+
+
+Aliases
+=======
+
+Aliases of itemnames can be added by using
+`core.register_alias(alias, original_name)` or
+`core.register_alias_force(alias, original_name)`.
+
+This adds an alias `alias` for the item called `original_name`.
+From now on, you can use `alias` to refer to the item `original_name`.
+
+The only difference between `core.register_alias` and
+`core.register_alias_force` is that if an item named `alias` already exists,
+`core.register_alias` will do nothing while
+`core.register_alias_force` will unregister it.
+
+This can be used for maintaining backwards compatibility.
+
+This can also set quick access names for things, e.g. if
+you have an item called `epiclylongmodname:stuff`, you could do
+
+ core.register_alias("stuff", "epiclylongmodname:stuff")
+
+and be able to use `/giveme stuff`.
+
+Mapgen aliases
+--------------
+
+In a game, a certain number of these must be set to tell core mapgens which
+of the game's nodes are to be used for core mapgen generation. For example:
+
+ core.register_alias("mapgen_stone", "default:stone")
+
+### Aliases for non-V6 mapgens
+
+#### Essential aliases
+
+* `mapgen_stone`
+* `mapgen_water_source`
+* `mapgen_river_water_source`
+
+`mapgen_river_water_source` is required for mapgens with sloping rivers where
+it is necessary to have a river liquid node with a short `liquid_range` and
+`liquid_renewable = false` to avoid flooding.
+
+#### Optional aliases
+
+* `mapgen_lava_source`
+
+Fallback lava node used if cave liquids are not defined in biome definitions.
+Deprecated, define cave liquids in biome definitions instead.
+
+* `mapgen_cobble`
+
+Fallback node used if dungeon nodes are not defined in biome definitions.
+Deprecated, define dungeon nodes in biome definitions instead.
+
+### Aliases for Mapgen V6
+
+#### Essential
+
+* `mapgen_stone`
+* `mapgen_water_source`
+* `mapgen_lava_source`
+* `mapgen_dirt`
+* `mapgen_dirt_with_grass`
+* `mapgen_sand`
+
+* `mapgen_tree`
+* `mapgen_leaves`
+* `mapgen_apple`
+
+* `mapgen_cobble`
+
+#### Optional
+
+* `mapgen_gravel` (falls back to stone)
+* `mapgen_desert_stone` (falls back to stone)
+* `mapgen_desert_sand` (falls back to sand)
+* `mapgen_dirt_with_snow` (falls back to dirt_with_grass)
+* `mapgen_snowblock` (falls back to dirt_with_grass)
+* `mapgen_snow` (not placed if missing)
+* `mapgen_ice` (falls back to water_source)
+
+* `mapgen_jungletree` (falls back to tree)
+* `mapgen_jungleleaves` (falls back to leaves)
+* `mapgen_junglegrass` (not placed if missing)
+* `mapgen_pine_tree` (falls back to tree)
+* `mapgen_pine_needles` (falls back to leaves)
+
+* `mapgen_stair_cobble` (falls back to cobble)
+* `mapgen_mossycobble` (falls back to cobble)
+* `mapgen_stair_desert_stone` (falls back to desert_stone)
+
+### Setting the node used in Mapgen Singlenode
+
+By default the world is filled with air nodes. To set a different node use e.g.:
+
+ core.register_alias("mapgen_singlenode", "default:stone")
+
+
+
+
+Textures
+========
+
+Mods should generally prefix their textures with `modname_`, e.g. given
+the mod name `foomod`, a texture could be called:
+
+ foomod_foothing.png
+
+Textures are referred to by their complete name, or alternatively by
+stripping out the file extension:
+
+* e.g. `foomod_foothing.png`
+* e.g. `foomod_foothing`
+
+Supported texture formats are PNG (`.png`), JPEG (`.jpg`) and Targa (`.tga`).
+
+Luanti generally uses nearest-neighbor upscaling for textures to preserve the crisp
+look of pixel art (low-res textures).
+Users can optionally enable bilinear and/or trilinear filtering. However, to avoid
+everything becoming blurry, textures smaller than 192px will either not be filtered,
+or will be upscaled to that minimum resolution first without filtering.
+
+This is subject to change to move more control to the Lua API, but you can rely on
+low-res textures not suddenly becoming filtered.
+
+Texture modifiers
+-----------------
+
+There are various texture modifiers that can be used
+to let the client generate textures on-the-fly.
+The modifiers are applied directly in sRGB colorspace,
+i.e. without gamma-correction.
+
+### Notes
+
+ * `TEXMOD_UPSCALE`: The texture with the lower resolution will be automatically
+ upscaled to the higher resolution texture.
+
+### Texture overlaying
+
+Textures can be overlaid by putting a `^` between them.
+
+Warning: If the lower and upper pixels are both semi-transparent, this operation
+does *not* do alpha blending, and it is *not* associative. Otherwise it does
+alpha blending in srgb color space.
+
+Example:
+
+ default_dirt.png^default_grass_side.png
+
+`default_grass_side.png` is overlaid over `default_dirt.png`.
+
+*See notes: `TEXMOD_UPSCALE`*
+
+
+### Texture grouping
+
+Textures can be grouped together by enclosing them in `(` and `)`.
+
+Example: `cobble.png^(thing1.png^thing2.png)`
+
+A texture for `thing1.png^thing2.png` is created and the resulting
+texture is overlaid on top of `cobble.png`.
+
+### Escaping
+
+Modifiers that accept texture names (e.g. `[combine`) accept escaping to allow
+passing complex texture names as arguments. Escaping is done with backslash and
+is required for `^`, `:` and `\`.
+
+Example: `cobble.png^[lowpart:50:color.png\^[mask\:trans.png`
+Or as a Lua string: `"cobble.png^[lowpart:50:color.png\\^[mask\\:trans.png"`
+
+The lower 50 percent of `color.png^[mask:trans.png` are overlaid
+on top of `cobble.png`.
+
+### Advanced texture modifiers
+
+#### Crack
+
+* `[crack::
`
+* `[cracko::
`
+* `[crack:::
`
+* `[cracko:::
`
+
+Parameters:
+
+* ``: tile count (in each direction)
+* ``: animation frame count
+* `
`: current animation frame
+
+Draw a step of the crack animation on the texture.
+`crack` draws it normally, while `cracko` lays it over, keeping transparent
+pixels intact.
+
+Example:
+
+ default_cobble.png^[crack:10:1
+
+#### `[combine:x:,=:,=:...`
+
+* ``: width
+* ``: height
+* ``: x position, negative numbers allowed
+* ``: y position, negative numbers allowed
+* ``: texture to combine
+
+Creates a texture of size `` times `` and blits the listed files to their
+specified coordinates.
+
+Example:
+
+ [combine:16x32:0,0=default_cobble.png:0,16=default_wood.png
+
+#### `[resize:x`
+
+Resizes the texture to the given dimensions.
+
+Example:
+
+ default_sandstone.png^[resize:16x16
+
+#### `[opacity:`
+
+Makes the base image transparent according to the given ratio.
+
+`r` must be between 0 (transparent) and 255 (opaque).
+
+Example:
+
+ default_sandstone.png^[opacity:127
+
+#### `[invert:`
+
+Inverts the given channels of the base image.
+Mode may contain the characters "r", "g", "b", "a".
+Only the channels that are mentioned in the mode string will be inverted.
+
+Example:
+
+ default_apple.png^[invert:rgb
+
+#### `[brighten`
+
+Brightens the texture.
+
+Example:
+
+ tnt_tnt_side.png^[brighten
+
+#### `[noalpha`
+
+Makes the texture completely opaque.
+
+Example:
+
+ default_leaves.png^[noalpha
+
+#### `[makealpha:,,`
+
+Convert one color to transparency.
+
+Example:
+
+ default_cobble.png^[makealpha:128,128,128
+
+#### `[transform`
+
+* ``: transformation(s) to apply
+
+Rotates and/or flips the image.
+
+`` can be a number (between 0 and 7) or a transform name.
+Rotations are counter-clockwise.
+
+ 0 I identity
+ 1 R90 rotate by 90 degrees
+ 2 R180 rotate by 180 degrees
+ 3 R270 rotate by 270 degrees
+ 4 FX flip X
+ 5 FXR90 flip X then rotate by 90 degrees
+ 6 FY flip Y
+ 7 FYR90 flip Y then rotate by 90 degrees
+
+Example:
+
+ default_stone.png^[transformFXR90
+
+#### `[inventorycube{{{`
+
+Escaping does not apply here and `^` is replaced by `&` in texture names
+instead.
+
+Create an inventory cube texture using the side textures.
+
+Example:
+
+ [inventorycube{grass.png{dirt.png&grass_side.png{dirt.png&grass_side.png
+
+Creates an inventorycube with `grass.png`, `dirt.png^grass_side.png` and
+`dirt.png^grass_side.png` textures
+
+#### `[fill:x:,:`
+
+* ``: width
+* ``: height
+* ``: x position
+* ``: y position
+* ``: a `ColorString`.
+
+Creates a texture of the given size and color, optionally with an `,`
+position. An alpha value may be specified in the `Colorstring`.
+
+The optional `,` position is only used if the `[fill` is being overlaid
+onto another texture with '^'.
+
+When `[fill` is overlaid onto another texture it will not upscale or change
+the resolution of the texture, the base texture will determine the output
+resolution.
+
+Examples:
+
+ [fill:16x16:#20F02080
+ texture.png^[fill:8x8:4,4:red
+
+#### `[lowpart::`
+
+Blit the lower ``% part of `` on the texture.
+
+Example:
+
+ base.png^[lowpart:25:overlay.png
+
+#### `[verticalframe::`
+
+* ``: animation frame count
+* ``: current animation frame
+
+Crops the texture to a frame of a vertical animation.
+
+Example:
+
+ default_torch_animated.png^[verticalframe:16:8
+
+#### `[mask:`
+
+Apply a mask to the base image.
+
+The mask is applied using binary AND.
+
+*See notes: `TEXMOD_UPSCALE`*
+
+#### `[sheet:x:,`
+
+Retrieves a tile at position x, y (in tiles, 0-indexed)
+from the base image, which it assumes to be a tilesheet
+with dimensions w, h (in tiles).
+
+#### `[colorize::`
+
+Colorize the textures with the given color.
+`` is specified as a `ColorString`.
+`` is an int ranging from 0 to 255 or the word "`alpha`". If
+it is an int, then it specifies how far to interpolate between the
+colors where 0 is only the texture color and 255 is only ``. If
+omitted, the alpha of `` will be used as the ratio. If it is
+the word "`alpha`", then each texture pixel will contain the RGB of
+`` and the alpha of `` multiplied by the alpha of the
+texture pixel.
+
+#### `[colorizehsl:::`
+
+Colorize the texture to the given hue. The texture will be converted into a
+greyscale image as seen through a colored glass, like "Colorize" in GIMP.
+Saturation and lightness can optionally be adjusted.
+
+`` should be from -180 to +180. The hue at 0° on an HSL color wheel is
+red, 60° is yellow, 120° is green, and 180° is cyan, while -60° is magenta
+and -120° is blue.
+
+`` and `` are optional adjustments.
+
+`` is from -100 to +100, with a default of 0
+
+`` is from 0 to 100, with a default of 50
+
+#### `[multiply:`
+
+Multiplies texture colors with the given color.
+`` is specified as a `ColorString`.
+Result is more like what you'd expect if you put a color on top of another
+color, meaning white surfaces get a lot of your new color while black parts
+don't change very much.
+
+A Multiply blend can be applied between two textures by using the overlay
+modifier with a brightness adjustment:
+
+ textureA.png^[contrast:0:-64^[overlay:textureB.png
+
+#### `[screen:`
+
+Apply a Screen blend with the given color. A Screen blend is the inverse of
+a Multiply blend, lightening images instead of darkening them.
+
+`` is specified as a `ColorString`.
+
+A Screen blend can be applied between two textures by using the overlay
+modifier with a brightness adjustment:
+
+ textureA.png^[contrast:0:64^[overlay:textureB.png
+
+#### `[hsl:::`
+
+Adjust the hue, saturation, and lightness of the texture. Like
+"Hue-Saturation" in GIMP, but with 0 as the mid-point.
+
+`` should be from -180 to +180
+
+`` and `` are optional, and both percentages.
+
+`` is from -100 to +100.
+
+`` goes down to -100 (fully desaturated) but may go above 100,
+allowing for even muted colors to become highly saturated.
+
+#### `[contrast::`
+
+Adjust the brightness and contrast of the texture. Conceptually like
+GIMP's "Brightness-Contrast" feature but allows brightness to be wound
+all the way up to white or down to black.
+
+`` is a value from -127 to +127.
+
+`` is an optional value, from -127 to +127.
+
+If only a boost in contrast is required, an alternative technique is to
+hardlight blend the texture with itself, this increases contrast in the same
+way as an S-shaped color-curve, which avoids dark colors clipping to black
+and light colors clipping to white:
+
+ texture.png^[hardlight:texture.png
+
+#### `[overlay:`
+
+Applies an Overlay blend with the two textures, like the Overlay layer mode
+in GIMP. Overlay is the same as Hard light but with the role of the two
+textures swapped, see the `[hardlight` modifier description for more detail
+about these blend modes.
+
+*See notes: `TEXMOD_UPSCALE`*
+
+#### `[hardlight:`
+
+Applies a Hard light blend with the two textures, like the Hard light layer
+mode in GIMP.
+
+Hard light combines Multiply and Screen blend modes. Light parts of the
+`` texture will lighten (screen) the base texture, and dark parts of the
+`` texture will darken (multiply) the base texture. This can be useful
+for applying embossing or chiselled effects to textures. A Hard light with the
+same texture acts like applying an S-shaped color-curve, and can be used to
+increase contrast without clipping.
+
+Hard light is the same as Overlay but with the roles of the two textures
+swapped, i.e. `A.png^[hardlight:B.png` is the same as `B.png^[overlay:A.png`
+
+*See notes: `TEXMOD_UPSCALE`*
+
+#### `[png:`
+
+Embed a base64 encoded PNG image in the texture string.
+You can produce a valid string for this by calling
+`core.encode_base64(core.encode_png(tex))`,
+where `tex` is pixel data. Refer to the documentation of these
+functions for details.
+You can use this to send disposable images such as captchas
+to individual clients, or render things that would be too
+expensive to compose with `[combine:`.
+
+IMPORTANT: Avoid sending large images this way.
+This is not a replacement for asset files, do not use it to do anything
+that you could instead achieve by just using a file.
+In particular consider `core.dynamic_add_media` and test whether
+using other texture modifiers could result in a shorter string than
+embedding a whole image, this may vary by use case.
+
+*See notes: `TEXMOD_UPSCALE`*
+
+Hardware coloring
+-----------------
+
+The goal of hardware coloring is to simplify the creation of
+colorful nodes. If your textures use the same pattern, and they only
+differ in their color (like colored wool blocks), you can use hardware
+coloring instead of creating and managing many texture files.
+All of these methods use color multiplication (so a white-black texture
+with red coloring will result in red-black color).
+
+### Static coloring
+
+This method is useful if you wish to create nodes/items with
+the same texture, in different colors, each in a new node/item definition.
+
+#### Global color
+
+When you register an item or node, set its `color` field (which accepts a
+`ColorSpec`) to the desired color.
+
+An `ItemStack`'s static color can be overwritten by the `color` metadata
+field. If you set that field to a `ColorString`, that color will be used.
+
+#### Tile color
+
+Each tile may have an individual static color, which overwrites every
+other coloring method. To disable the coloring of a face,
+set its color to white (because multiplying with white does nothing).
+You can set the `color` property of the tiles in the node's definition
+if the tile is in table format.
+
+### Palettes
+
+For nodes and items which can have many colors, a palette is more
+suitable. A palette is a texture, which can contain up to 256 pixels.
+Each pixel is one possible color for the node/item.
+You can register one node/item, which can have up to 256 colors.
+
+#### Palette indexing
+
+When using palettes, you always provide a pixel index for the given
+node or `ItemStack`. The palette is read from left to right and from
+top to bottom. If the palette has less than 256 pixels, then it is
+stretched to contain exactly 256 pixels (after arranging the pixels
+to one line). The indexing starts from 0.
+
+Examples:
+
+* 16x16 palette, index = 0: the top left corner
+* 16x16 palette, index = 4: the fifth pixel in the first row
+* 16x16 palette, index = 16: the pixel below the top left corner
+* 16x16 palette, index = 255: the bottom right corner
+* 2 (width) x 4 (height) palette, index = 31: the top left corner.
+ The palette has 8 pixels, so each pixel is stretched to 32 pixels,
+ to ensure the total 256 pixels.
+* 2x4 palette, index = 32: the top right corner
+* 2x4 palette, index = 63: the top right corner
+* 2x4 palette, index = 64: the pixel below the top left corner
+
+#### Using palettes with items
+
+When registering an item, set the item definition's `palette` field to
+a texture. You can also use texture modifiers.
+
+The `ItemStack`'s color depends on the `palette_index` field of the
+stack's metadata. `palette_index` is an integer, which specifies the
+index of the pixel to use.
+
+#### Linking palettes with nodes
+
+When registering a node, set the item definition's `palette` field to
+a texture. You can also use texture modifiers.
+The node's color depends on its `param2`, so you also must set an
+appropriate `paramtype2`:
+
+* `paramtype2 = "color"` for nodes which use their full `param2` for
+ palette indexing. These nodes can have 256 different colors.
+ The palette should contain 256 pixels.
+* `paramtype2 = "colorwallmounted"` for nodes which use the first
+ five bits (most significant) of `param2` for palette indexing.
+ The remaining three bits are describing rotation, as in `wallmounted`
+ paramtype2. Division by 8 yields the palette index (without stretching the
+ palette). These nodes can have 32 different colors, and the palette
+ should contain 32 pixels.
+ Examples:
+ * `param2 = 17` is 2 * 8 + 1, so the rotation is 1 and the third (= 2 + 1)
+ pixel will be picked from the palette.
+ * `param2 = 35` is 4 * 8 + 3, so the rotation is 3 and the fifth (= 4 + 1)
+ pixel will be picked from the palette.
+* `paramtype2 = "colorfacedir"` for nodes which use the first
+ three bits of `param2` for palette indexing. The remaining
+ five bits are describing rotation, as in `facedir` paramtype2.
+ Division by 32 yields the palette index (without stretching the
+ palette). These nodes can have 8 different colors, and the
+ palette should contain 8 pixels.
+ Examples:
+ * `param2 = 17` is 0 * 32 + 17, so the rotation is 17 and the
+ first (= 0 + 1) pixel will be picked from the palette.
+ * `param2 = 35` is 1 * 32 + 3, so the rotation is 3 and the
+ second (= 1 + 1) pixel will be picked from the palette.
+* `paramtype2 = "color4dir"` for nodes which use the first
+ six bits of `param2` for palette indexing. The remaining
+ two bits are describing rotation, as in `4dir` paramtype2.
+ Division by 4 yields the palette index (without stretching the
+ palette). These nodes can have 64 different colors, and the
+ palette should contain 64 pixels.
+ Examples:
+ * `param2 = 17` is 4 * 4 + 1, so the rotation is 1 and the
+ fifth (= 4 + 1) pixel will be picked from the palette.
+ * `param2 = 35` is 8 * 4 + 3, so the rotation is 3 and the
+ ninth (= 8 + 1) pixel will be picked from the palette.
+
+To colorize a node on the map, set its `param2` value (according
+to the node's paramtype2).
+
+### Conversion between nodes in the inventory and on the map
+
+Static coloring is the same for both cases, there is no need
+for conversion.
+
+If the `ItemStack`'s metadata contains the `color` field, it will be
+lost on placement, because nodes on the map can only use palettes.
+
+If the `ItemStack`'s metadata contains the `palette_index` field, it is
+automatically transferred between node and item forms by the engine,
+when a player digs or places a colored node.
+You can disable this feature by setting the `drop` field of the node
+to itself (without metadata).
+To transfer the color to a special drop, you need a drop table.
+
+Example:
+
+```lua
+core.register_node("mod:stone", {
+ description = "Stone",
+ tiles = {"default_stone.png"},
+ paramtype2 = "color",
+ palette = "palette.png",
+ drop = {
+ items = {
+ -- assume that mod:cobblestone also has the same palette
+ {items = {"mod:cobblestone"}, inherit_color = true },
+ }
+ }
+})
+```
+
+### Colored items in craft recipes
+
+Craft recipes only support item strings, but fortunately item strings
+can also contain metadata. Example craft recipe registration:
+
+```lua
+core.register_craft({
+ output = core.itemstring_with_palette("wool:block", 3),
+ type = "shapeless",
+ recipe = {
+ "wool:block",
+ "dye:red",
+ },
+})
+```
+
+To set the `color` field, you can use `core.itemstring_with_color`.
+
+Metadata field filtering in the `recipe` field are not supported yet,
+so the craft output is independent of the color of the ingredients.
+
+Soft texture overlay
+--------------------
+
+Sometimes hardware coloring is not enough, because it affects the
+whole tile. Soft texture overlays were added to Luanti to allow
+the dynamic coloring of only specific parts of the node's texture.
+For example a grass block may have colored grass, while keeping the
+dirt brown.
+
+These overlays are 'soft', because unlike texture modifiers, the layers
+are not merged in the memory, but they are simply drawn on top of each
+other. This allows different hardware coloring, but also means that
+tiles with overlays are drawn slower. Using too much overlays might
+cause FPS loss.
+
+For inventory and wield images you can specify overlays which
+hardware coloring does not modify. You have to set `inventory_overlay`
+and `wield_overlay` fields to an image name.
+
+To define a node overlay, simply set the `overlay_tiles` field of the node
+definition. These tiles are defined in the same way as plain tiles:
+they can have a texture name, color etc.
+To skip one face, set that overlay tile to an empty string.
+
+Example (colored grass block):
+
+```lua
+core.register_node("default:dirt_with_grass", {
+ description = "Dirt with Grass",
+ -- Regular tiles, as usual
+ -- The dirt tile disables palette coloring
+ tiles = {{name = "default_grass.png"},
+ {name = "default_dirt.png", color = "white"}},
+ -- Overlay tiles: define them in the same style
+ -- The top and bottom tile does not have overlay
+ overlay_tiles = {"", "",
+ {name = "default_grass_side.png"}},
+ -- Global color, used in inventory
+ color = "green",
+ -- Palette in the world
+ paramtype2 = "color",
+ palette = "default_foilage.png",
+})
+```
+
+
+
+Sounds
+======
+
+Only Ogg Vorbis files are supported.
+
+For positional playing of sounds, only single-channel (mono) files are
+supported. Otherwise OpenAL will play them non-positionally.
+
+Mods should generally prefix their sound files with `modname_`, e.g. given
+the mod name "`foomod`", a sound could be called:
+
+ foomod_foosound.ogg
+
+Sound group
+-----------
+
+A sound group is the set of all sound files, whose filenames are of the following
+format:
+`[.].ogg`
+When a sound-group is played, one the files in the group is chosen at random.
+Sound files can only be referred to by their sound-group name.
+
+Example: When playing the sound `foomod_foosound`, the sound is chosen randomly
+from the available ones of the following files:
+
+* `foomod_foosound.ogg`
+* `foomod_foosound.0.ogg`
+* `foomod_foosound.1.ogg`
+* (...)
+* `foomod_foosound.9.ogg`
+
+`SimpleSoundSpec`
+-----------------
+
+Specifies a sound name, gain (=volume), pitch and fade.
+This is either a string or a table.
+
+In string form, you just specify the sound name or
+the empty string for no sound.
+
+Table form has the following fields:
+
+* `name`:
+ Sound-group name.
+ If == `""`, no sound is played.
+* `gain`:
+ Volume (`1.0` = 100%), must be non-negative.
+ At the end, OpenAL clamps sound gain to a maximum of `1.0`. By setting gain for
+ a positional sound higher than `1.0`, one can increase the radius inside which
+ maximal gain is reached.
+ Furthermore, gain of positional sounds doesn't increase inside a 1 node radius.
+ The gain given here describes the gain at a distance of 3 nodes.
+* `pitch`:
+ Applies a pitch-shift to the sound.
+ Each factor of `2.0` results in a pitch-shift of +12 semitones.
+ Must be positive.
+* `fade`:
+ If > `0.0`, the sound is faded in, with this value in gain per second, until
+ `gain` is reached.
+
+`gain`, `pitch` and `fade` are optional and default to `1.0`, `1.0` and `0.0`.
+
+Examples:
+
+* `""`: No sound
+* `{}`: No sound
+* `"default_place_node"`: Play e.g. `default_place_node.ogg`
+* `{name = "default_place_node"}`: Same as above
+* `{name = "default_place_node", gain = 0.5}`: 50% volume
+* `{name = "default_place_node", gain = 0.9, pitch = 1.1}`: 90% volume, 110% pitch
+
+Sound parameter table
+---------------------
+
+Table used to specify how a sound is played:
+
+```lua
+{
+ gain = 1.0,
+ -- Scales the gain specified in `SimpleSoundSpec`.
+
+ pitch = 1.0,
+ -- Overwrites the pitch specified in `SimpleSoundSpec`.
+
+ fade = 0.0,
+ -- Overwrites the fade specified in `SimpleSoundSpec`.
+
+ start_time = 0.0,
+ -- Start with a time-offset into the sound.
+ -- The behavior is as if the sound was already playing for this many seconds.
+ -- Negative values are relative to the sound's length, so the sound reaches
+ -- its end in `-start_time` seconds.
+ -- It is unspecified what happens if `loop` is false and `start_time` is
+ -- smaller than minus the sound's length.
+ -- Available since feature `sound_params_start_time`.
+
+ loop = false,
+ -- If true, sound is played in a loop.
+
+ pos = {x = 1, y = 2, z = 3},
+ -- Play sound at a position.
+ -- Can't be used together with `object`.
+
+ object = ,
+ -- Attach the sound to an object.
+ -- Can't be used together with `pos`.
+
+ to_player = name,
+ -- Only play for this player.
+ -- Can't be used together with `exclude_player`.
+
+ exclude_player = name,
+ -- Don't play sound for this player.
+ -- Can't be used together with `to_player`.
+
+ max_hear_distance = 32,
+ -- Only play for players that are at most this far away when the sound
+ -- starts playing.
+ -- Needs `pos` or `object` to be set.
+ -- `32` is the default.
+}
+```
+
+Examples:
+
+```lua
+-- Play locationless on all clients
+{
+ gain = 1.0, -- default
+ fade = 0.0, -- default
+ pitch = 1.0, -- default
+}
+-- Play locationless to one player
+{
+ to_player = name,
+ gain = 1.0, -- default
+ fade = 0.0, -- default
+ pitch = 1.0, -- default
+}
+-- Play locationless to one player, looped
+{
+ to_player = name,
+ gain = 1.0, -- default
+ loop = true,
+}
+-- Play at a location, start the sound at offset 5 seconds
+{
+ pos = {x = 1, y = 2, z = 3},
+ gain = 1.0, -- default
+ max_hear_distance = 32, -- default
+ start_time = 5.0,
+}
+-- Play connected to an object, looped
+{
+ object = ,
+ gain = 1.0, -- default
+ max_hear_distance = 32, -- default
+ loop = true,
+}
+-- Play at a location, heard by anyone *but* the given player
+{
+ pos = {x = 32, y = 0, z = 100},
+ max_hear_distance = 40,
+ exclude_player = name,
+}
+```
+
+Special sound-groups
+--------------------
+
+These sound-groups are played back by the engine if provided.
+
+ * `player_damage`: Played when the local player takes damage (gain = 0.5)
+ * `player_falling_damage`: Played when the local player takes
+ damage by falling (gain = 0.5)
+ * `player_jump`: Played when the local player jumps
+ * `default_dig_`: Default node digging sound (gain = 0.5)
+ (see node sound definition for details)
+
+Registered definitions
+======================
+
+Anything added using certain [Registration functions](#registration-functions) gets added to one or more
+of the global [Registered definition tables](#registered-definition-tables)
+
+Note that in some cases you will stumble upon things that are not contained
+in these tables (e.g. when a mod has been removed). Always check for
+existence before trying to access the fields.
+
+Example:
+
+All nodes registered with `core.register_node` get added to the table
+`core.registered_nodes`.
+
+If you want to check the drawtype of a node, you could do it like this:
+
+```lua
+local def = core.registered_nodes[nodename]
+local drawtype = def and def.drawtype
+```
+
+
+
+Nodes
+=====
+
+Nodes are the bulk data of the world: cubes and other things that take the
+space of a cube. Huge amounts of them are handled efficiently, but they
+are quite static.
+
+The definition of a node is stored and can be accessed by using
+
+```lua
+core.registered_nodes[node.name]
+```
+
+See [Node definition](#node-definition)
+
+Nodes are passed by value between Lua and the engine.
+They are represented by a table:
+
+```lua
+{name="name", param1=num, param2=num}
+```
+
+`param1` and `param2` are 8-bit integers ranging from 0 to 255. The engine uses
+them for certain automated functions. If you don't use these functions, you can
+use them to store arbitrary values.
+
+Node paramtypes
+---------------
+
+The functions of `param1` and `param2` are determined by certain fields in the
+node definition.
+
+The function of `param1` is determined by `paramtype` in node definition.
+`param1` is reserved for the engine when `paramtype != "none"`.
+
+* `paramtype = "light"`
+ * The value stores light with and without sun in its lower and upper 4 bits
+ respectively.
+ * Required by a light source node to enable spreading its light.
+ * Required by the following drawtypes as they determine their visual
+ brightness from their internal light value:
+ * torchlike
+ * signlike
+ * firelike
+ * fencelike
+ * raillike
+ * nodebox
+ * mesh
+ * plantlike
+ * plantlike_rooted
+* `paramtype = "none"`
+ * `param1` will not be used by the engine and can be used to store
+ an arbitrary value
+
+The function of `param2` is determined by `paramtype2` in node definition.
+`param2` is reserved for the engine when `paramtype2 != "none"`.
+
+* `paramtype2 = "flowingliquid"`
+ * Used by `drawtype = "flowingliquid"` and `liquidtype = "flowing"`
+ * The liquid level and a flag of the liquid are stored in `param2`
+ * Bits 0-2: Liquid level (0-7). The higher, the more liquid is in this node;
+ see `core.get_node_level`, `core.set_node_level` and `core.add_node_level`
+ to access/manipulate the content of this field
+ * Bit 3: If set, liquid is flowing downwards (no graphical effect)
+* `paramtype2 = "wallmounted"`
+ * Supported drawtypes: "torchlike", "signlike", "plantlike",
+ "plantlike_rooted", "normal", "nodebox", "mesh"
+ * The rotation of the node is stored in `param2`
+ * Node is 'mounted'/facing towards one of 6 directions
+ * You can make this value by using `core.dir_to_wallmounted()`
+ * Values range 0 - 7
+ * The value denotes at which direction the node is "mounted":
+ 0 = y+, 1 = y-, 2 = x+, 3 = x-, 4 = z+, 5 = z-
+ 6 = y+, but rotated by 90°
+ 7 = y-, but rotated by -90°
+ * By default, on placement the param2 is automatically set to the
+ appropriate rotation (0 to 5), depending on which side was
+ pointed at. With the node field `wallmounted_rotate_vertical = true`,
+ the param2 values 6 and 7 might additionally be set
+* `paramtype2 = "facedir"`
+ * Supported drawtypes: "normal", "nodebox", "mesh"
+ * The rotation of the node is stored in `param2`.
+ * Node is rotated around face and axis; 24 rotations in total.
+ * Can be made by using `core.dir_to_facedir()`.
+ * Chests and furnaces can be rotated that way, and also 'flipped'
+ * Values range 0 - 23
+ * facedir / 4 = axis direction:
+ 0 = y+, 1 = z+, 2 = z-, 3 = x+, 4 = x-, 5 = y-
+ * The node is rotated 90 degrees around the X or Z axis so that its top face
+ points in the desired direction. For the y- direction, it's rotated 180
+ degrees around the Z axis.
+ * facedir modulo 4 = left-handed rotation around the specified axis, in 90° steps.
+ * By default, on placement the param2 is automatically set to the
+ horizontal direction the player was looking at (values 0-3)
+ * Special case: If the node is a connected nodebox, the nodebox
+ will NOT rotate, only the textures will.
+* `paramtype2 = "4dir"`
+ * Supported drawtypes: "normal", "nodebox", "mesh"
+ * The rotation of the node is stored in `param2`.
+ * Allows node to be rotated horizontally, 4 rotations in total
+ * Can be made by using `core.dir_to_fourdir()`.
+ * Chests and furnaces can be rotated that way, but not flipped
+ * Values range 0 - 3
+ * 4dir modulo 4 = rotation
+ * Otherwise, behavior is identical to facedir
+* `paramtype2 = "leveled"`
+ * Only valid for "nodebox" with 'type = "leveled"', and "plantlike_rooted".
+ * Leveled nodebox:
+ * The level of the top face of the nodebox is stored in `param2`.
+ * The other faces are defined by 'fixed = {}' like 'type = "fixed"'
+ nodeboxes.
+ * The nodebox height is (`param2` / 64) nodes.
+ * The maximum accepted value of `param2` is 127.
+ * Rooted plantlike:
+ * The height of the 'plantlike' section is stored in `param2`.
+ * The height is (`param2` / 16) nodes.
+* `paramtype2 = "degrotate"`
+ * Valid for `plantlike` and `mesh` drawtypes. The rotation of the node is
+ stored in `param2`.
+ * Values range 0–239. The value stored in `param2` is multiplied by 1.5 to
+ get the actual rotation in degrees of the node.
+* `paramtype2 = "meshoptions"`
+ * Only valid for "plantlike" drawtype. `param2` encodes the shape and
+ optional modifiers of the "plant". `param2` is a bitfield.
+ * Bits 0 to 2 select the shape.
+ Use only one of the values below:
+ * 0 = an "x" shaped plant (ordinary plant)
+ * 1 = a "+" shaped plant (just rotated 45 degrees)
+ * 2 = a "*" shaped plant with 3 faces instead of 2
+ * 3 = a "#" shaped plant with 4 faces instead of 2
+ * 4 = a "#" shaped plant with 4 faces that lean outwards
+ * 5-7 are unused and reserved for future meshes.
+ * Bits 3 to 7 are used to enable any number of optional modifiers.
+ Just add the corresponding value(s) below to `param2`:
+ * 8 - Makes the plant slightly vary placement horizontally
+ * 16 - Makes the plant mesh 1.4x larger
+ * 32 - Moves each face randomly a small bit down (1/8 max)
+ * values 64 and 128 (bits 6-7) are reserved for future use.
+ * Example: `param2 = 0` selects a normal "x" shaped plant
+ * Example: `param2 = 17` selects a "+" shaped plant, 1.4x larger (1+16)
+* `paramtype2 = "color"`
+ * `param2` tells which color is picked from the palette.
+ The palette should have 256 pixels.
+* `paramtype2 = "colorfacedir"`
+ * Same as `facedir`, but with colors.
+ * The three most significant bits of `param2` tells which color is picked from the
+ palette. The palette should have 8 pixels.
+ * The five least significant bits contain the `facedir` value.
+* `paramtype2 = "color4dir"`
+ * Same as `4dir`, but with colors.
+ * The six most significant bits of `param2` tells which color is picked from the
+ palette. The palette should have 64 pixels.
+ * The two least significant bits contain the `4dir` rotation.
+* `paramtype2 = "colorwallmounted"`
+ * Same as `wallmounted`, but with colors.
+ * The five most significant bits of `param2` tells which color is picked from the
+ palette. The palette should have 32 pixels.
+ * The three least significant bits contain the `wallmounted` value.
+* `paramtype2 = "glasslikeliquidlevel"`
+ * Only valid for "glasslike_framed" or "glasslike_framed_optional"
+ drawtypes. "glasslike_framed_optional" nodes are only affected if the
+ "Connected Glass" setting is enabled.
+ * Bits 0-5 define 64 levels of internal liquid, 0 being empty and 63 being
+ full.
+ * Bits 6 and 7 modify the appearance of the frame and node faces. One or
+ both of these values may be added to `param2`:
+ * 64 - Makes the node not connect with neighbors above or below it.
+ * 128 - Makes the node not connect with neighbors to its sides.
+ * Liquid texture is defined using `special_tiles = {"modname_tilename.png"}`
+* `paramtype2 = "colordegrotate"`
+ * Same as `degrotate`, but with colors.
+ * The three most significant bits of `param2` tells which color is picked
+ from the palette. The palette should have 8 pixels.
+ * The five least significant bits store rotation in range 0–23 (i.e. in 15° steps)
+* `paramtype2 = "none"`
+ * `param2` will not be used by the engine and can be used to store
+ an arbitrary value
+
+Nodes can also contain extra data. See [Node Metadata](#node-metadata)
+
+Node drawtypes
+--------------
+
+There are a bunch of different looking node types.
+
+* `normal`
+ * A node-sized cube.
+* `airlike`
+ * Invisible, uses no texture.
+* `liquid`
+ * The cubic source node for a liquid.
+ * Faces bordering to the same node are never rendered.
+ * Connects to node specified in `liquid_alternative_flowing` if specified.
+ * Use `backface_culling = false` for the tiles you want to make
+ visible when inside the node.
+* `flowingliquid`
+ * The flowing version of a liquid, appears with various heights and slopes.
+ * Faces bordering to the same node are never rendered.
+ * Connects to node specified in `liquid_alternative_source`.
+ * You *must* set `liquid_alternative_flowing` to the node's own name.
+ * Node textures are defined with `special_tiles` where the first tile
+ is for the top and bottom faces and the second tile is for the side
+ faces.
+ * `tiles` is used for the item/inventory/wield image rendering.
+ * Use `backface_culling = false` for the special tiles you want to make
+ visible when inside the node
+* `glasslike`
+ * Often used for partially-transparent nodes.
+ * Only external sides of textures are visible.
+* `glasslike_framed`
+ * All face-connected nodes are drawn as one volume within a surrounding
+ frame.
+ * The frame appearance is generated from the edges of the first texture
+ specified in `tiles`. The width of the edges used are 1/16th of texture
+ size: 1 pixel for 16x16, 2 pixels for 32x32 etc.
+ * The glass 'shine' (or other desired detail) on each node face is supplied
+ by the second texture specified in `tiles`.
+* `glasslike_framed_optional`
+ * This switches between the above 2 drawtypes according to the menu setting
+ 'Connected Glass'.
+* `allfaces`
+ * Often used for partially-transparent nodes.
+ * External sides of textures, and unlike other drawtypes, the external sides
+ of other nodes, are visible from the inside.
+* `allfaces_optional`
+ * Often used for leaves nodes.
+ * This switches between `normal`, `glasslike` and `allfaces` according to
+ the menu setting: Opaque Leaves / Simple Leaves / Fancy Leaves.
+ * With 'Simple Leaves' selected, the texture specified in `special_tiles`
+ is used instead, if present. This allows a visually thicker texture to be
+ used to compensate for how `glasslike` reduces visual thickness.
+* `torchlike`
+ * A single vertical texture.
+ * If `paramtype2="[color]wallmounted"`:
+ * If placed on top of a node, uses the first texture specified in `tiles`.
+ * If placed against the underside of a node, uses the second texture
+ specified in `tiles`.
+ * If placed on the side of a node, uses the third texture specified in
+ `tiles` and is perpendicular to that node.
+ * If `paramtype2="none"`:
+ * Will be rendered as if placed on top of a node (see
+ above) and only the first texture is used.
+* `signlike`
+ * A single texture parallel to, and mounted against, the top, underside or
+ side of a node.
+ * If `paramtype2="[color]wallmounted"`, it rotates according to `param2`
+ * If `paramtype2="none"`, it will always be on the floor.
+* `plantlike`
+ * Two vertical and diagonal textures at right-angles to each other.
+ * See `paramtype2 = "meshoptions"` above for other options.
+* `firelike`
+ * When above a flat surface, appears as 6 textures, the central 2 as
+ `plantlike` plus 4 more surrounding those.
+ * If not above a surface the central 2 do not appear, but the texture
+ appears against the faces of surrounding nodes if they are present.
+* `fencelike`
+ * A 3D model suitable for a wooden fence.
+ * One placed node appears as a single vertical post.
+ * Adjacently-placed nodes cause horizontal bars to appear between them.
+* `raillike`
+ * Often used for tracks for mining carts.
+ * Requires 4 textures to be specified in `tiles`, in order: Straight,
+ curved, t-junction, crossing.
+ * Each placed node automatically switches to a suitable rotated texture
+ determined by the adjacent `raillike` nodes, in order to create a
+ continuous track network.
+ * Becomes a sloping node if placed against stepped nodes.
+* `nodebox`
+ * Often used for stairs and slabs.
+ * Allows defining nodes consisting of an arbitrary number of boxes.
+ * See [Node boxes](#node-boxes) below for more information.
+* `mesh`
+ * Uses models for nodes.
+ * Tiles should hold model materials textures.
+ * Only static meshes are implemented.
+ * For supported model formats see Irrlicht engine documentation.
+* `plantlike_rooted`
+ * Enables underwater `plantlike` without air bubbles around the nodes.
+ * Consists of a base cube at the coordinates of the node plus a
+ `plantlike` extension above
+ * If `paramtype2="leveled", the `plantlike` extension has a height
+ of `param2 / 16` nodes, otherwise it's the height of 1 node
+ * If `paramtype2="wallmounted"`, the `plantlike` extension
+ will be at one of the corresponding 6 sides of the base cube.
+ Also, the base cube rotates like a `normal` cube would
+ * The `plantlike` extension visually passes through any nodes above the
+ base cube without affecting them.
+ * The base cube texture tiles are defined as normal, the `plantlike`
+ extension uses the defined special tile, for example:
+ `special_tiles = {{name = "default_papyrus.png"}},`
+
+`*_optional` drawtypes need less rendering time if deactivated
+(always client-side).
+
+Node boxes
+----------
+
+Node selection boxes and collision boxes, and the appearance of the `nodebox`
+drawtype, are defined using "node boxes".
+
+A nodebox is defined as any of:
+
+```lua
+{
+ -- A normal cube; the default in most things
+ type = "regular"
+}
+{
+ -- A fixed box (or boxes) (facedir param2 is used, if applicable)
+ type = "fixed",
+ fixed = box OR {box1, box2, ...}
+}
+{
+ -- A variable height box (or boxes) with the top face position defined
+ -- by the node parameter 'leveled = ', or if 'paramtype2 == "leveled"'
+ -- by param2.
+ -- Other faces are defined by 'fixed = {}' as with 'type = "fixed"'.
+ type = "leveled",
+ fixed = box OR {box1, box2, ...}
+}
+{
+ -- A box like the selection box for torches
+ -- (wallmounted param2 is used, if applicable)
+ type = "wallmounted",
+ wall_top = box,
+ wall_bottom = box,
+ wall_side = box
+}
+{
+ -- A node that has optional boxes depending on neighboring nodes'
+ -- presence and type. See also `connects_to`.
+ type = "connected",
+ fixed = box OR {box1, box2, ...}
+ connect_top = box OR {box1, box2, ...}
+ connect_bottom = box OR {box1, box2, ...}
+ connect_front = box OR {box1, box2, ...}
+ connect_left = box OR {box1, box2, ...}
+ connect_back = box OR {box1, box2, ...}
+ connect_right = box OR {box1, box2, ...}
+ -- The following `disconnected_*` boxes are the opposites of the
+ -- `connect_*` ones above, i.e. when a node has no suitable neighbor
+ -- on the respective side, the corresponding disconnected box is drawn.
+ disconnected_top = box OR {box1, box2, ...}
+ disconnected_bottom = box OR {box1, box2, ...}
+ disconnected_front = box OR {box1, box2, ...}
+ disconnected_left = box OR {box1, box2, ...}
+ disconnected_back = box OR {box1, box2, ...}
+ disconnected_right = box OR {box1, box2, ...}
+ disconnected = box OR {box1, box2, ...} -- when there is *no* neighbor
+ disconnected_sides = box OR {box1, box2, ...} -- when there are *no*
+ -- neighbors to the sides
+}
+```
+
+A `box` is defined as:
+
+```lua
+{x1, y1, z1, x2, y2, z2}
+```
+
+A box of a regular node would look like:
+
+```lua
+{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
+```
+
+To avoid collision issues, keep each value within the range of +/- 1.45.
+This also applies to leveled nodeboxes, where the final height shall not
+exceed this soft limit.
+
+
+
+Map terminology and coordinates
+===============================
+
+Nodes, mapblocks, mapchunks
+---------------------------
+
+A 'node' is the fundamental cubic unit of a world and appears to a player as
+roughly 1x1x1 meters in size.
+
+A 'mapblock' (often abbreviated to 'block') is 16x16x16 nodes and is the
+fundamental region of a world that is stored in the world database, sent to
+clients and handled by many parts of the engine. This size is available as the
+constant `core.MAP_BLOCKSIZE` (=16).
+
+'mapblock' is preferred terminology to 'block' to help avoid confusion with
+'node', however 'block' often appears in the API.
+
+A 'mapchunk' (sometimes abbreviated to 'chunk') is usually 5x5x5 mapblocks
+(80x80x80 nodes) and is the volume of world generated in one operation by
+the map generator.
+The size in mapblocks has been chosen to optimize map generation.
+
+### Mapblock status
+
+A mapblock being "loaded" means that is in memory. These are the mapblocks that
+API functions like `core.get_node` or `core.set_node` can operate on. To reach
+this state, the mapblock must first go through the process of being "emerged".
+This means that it is loaded from disk, and/or, if it isn't yet generated,
+generated by the map generator.
+
+Mapblocks are loaded in a broad area around each player. They become "unloaded"
+again if no player is close enough. The engine commonly represents the contents
+of unloaded mapblocks as `"ignore"` nodes.
+
+A mapblock being "active" means that it is not only in memory, but also affected
+by world simulation:
+
+* Entities are active
+ * They are in memory as `ServerActiveObject`, exposed to Lua as `ObjectRef`
+ * They exist in Lua as luaentity tables
+* ABMs are executed
+* Node timers are executed
+
+Also, when a mapblock is "activated", LBMs are executed. Mapblocks are active
+in a smaller area around each player, and are "deactivated" again if no player
+is close enough.
+
+Related API functions:
+
+* `core.compare_block_status`
+* `core.forceload_block`
+* `core.load_area`
+* `core.emerge_area`
+
+Coordinates
+-----------
+
+### Orientation of axes
+
+For node and mapblock coordinates, +X is East, +Y is up, +Z is North.
+
+### Node coordinates
+
+Almost all positions used in the API use node coordinates.
+
+### Mapblock coordinates
+
+Occasionally the API uses 'blockpos' which refers to mapblock coordinates that
+specify a particular mapblock.
+For example blockpos (0,0,0) specifies the mapblock that extends from
+node position (0,0,0) to node position (15,15,15).
+
+#### Converting node position to the containing blockpos
+
+To calculate the blockpos of the mapblock that contains the node at 'nodepos',
+for each axis:
+
+* blockpos = math.floor(nodepos / core.MAP_BLOCKSIZE)
+
+#### Converting blockpos to min/max node positions
+
+To calculate the min/max node positions contained in the mapblock at 'blockpos',
+for each axis:
+
+* Minimum:
+ nodepos = blockpos * core.MAP_BLOCKSIZE
+* Maximum:
+ nodepos = (blockpos + 1) * core.MAP_BLOCKSIZE - 1
+
+
+
+
+HUD
+===
+
+HUD element types
+-----------------
+
+The `position` field is used for all element types.
+To account for differing resolutions, the position coordinates are the
+percentage of the screen, ranging in value from `0` to `1`.
+
+The `name` field is not yet used, but should contain a description of what the
+HUD element represents.
+
+The `direction` field is the direction in which something is drawn.
+`0` draws from left to right, `1` draws from right to left, `2` draws from
+top to bottom, and `3` draws from bottom to top.
+
+The `alignment` field specifies how the item will be aligned. It is a table
+where `x` and `y` range from `-1` to `1`, with `0` being central. `-1` is
+moved to the left/up, and `1` is to the right/down. Fractional values can be
+used.
+
+The `offset` field specifies a pixel offset from the position. Contrary to
+position, the offset is not scaled to screen size. This allows for some
+precisely positioned items in the HUD.
+
+**Note**: `offset` _will_ adapt to screen DPI as well as user defined scaling
+factor!
+
+The `z_index` field specifies the order of HUD elements from back to front.
+Lower z-index elements are displayed behind higher z-index elements. Elements
+with same z-index are displayed in an arbitrary order. Default 0.
+Supports negative values. By convention, the following values are recommended:
+
+* -400: Graphical effects, such as vignette
+* -300: Name tags, waypoints
+* -200: Wieldhand
+* -100: Things that block the player's view, e.g. masks
+* 0: Default. For standard in-game HUD elements like crosshair, hotbar,
+ minimap, builtin statbars, etc.
+* 100: Temporary text messages or notification icons
+* 1000: Full-screen effects such as full-black screen or credits.
+ This includes effects that cover the entire screen
+
+If your HUD element doesn't fit into any category, pick a number
+between the suggested values
+
+Below are the specific uses for fields in each type; fields not listed for that
+type are ignored.
+
+### `image`
+
+Displays an image on the HUD.
+
+* `scale`: The scale of the image, with `{x = 1, y = 1}` being the original texture size.
+ The `x` and `y` fields apply to the respective axes.
+ Positive values scale the source image.
+ Negative values represent percentages relative to screen dimensions.
+ Example: `{x = -20, y = 3}` means the image will be drawn 20% of screen width wide,
+ and 3 times as high as the source image is.
+* `text`: The name of the texture that is displayed.
+* `alignment`: The alignment of the image.
+* `offset`: offset in pixels from position.
+
+### `text`
+
+Displays text on the HUD.
+
+* `scale`: Defines the bounding rectangle of the text.
+ A value such as `{x=100, y=100}` should work.
+* `text`: The text to be displayed in the HUD element.
+ Supports `core.translate` (always)
+ and `core.colorize` (since protocol version 44)
+* `number`: An integer containing the RGB value of the color used to draw the
+ text. Specify `0xFFFFFF` for white text, `0xFF0000` for red, and so on.
+* `alignment`: The alignment of the text.
+* `offset`: offset in pixels from position.
+* `size`: size of the text.
+ The player-set font size is multiplied by size.x (y value isn't used).
+* `style`: determines font style
+ Bitfield with 1 = bold, 2 = italic, 4 = monospace
+
+### `statbar`
+
+Displays a horizontal bar made up of half-images with an optional background.
+
+* `text`: The name of the texture to use.
+* `text2`: Optional texture name to enable a background / "off state"
+ texture (useful to visualize the maximal value). Both textures
+ must have the same size.
+* `number`: The number of half-textures that are displayed.
+ If odd, will end with a vertically center-split texture.
+* `item`: Same as `number` but for the "off state" texture
+* `direction`: To which direction the images will extend to
+* `offset`: offset in pixels from position.
+* `size`: If used, will force full-image size to this value (override texture
+ pack image size)
+
+### `inventory`
+
+* `text`: The name of the inventory list to be displayed.
+* `number`: Number of items in the inventory to be displayed.
+* `item`: Position of item that is selected.
+* `direction`: Direction the list will be displayed in
+* `offset`: offset in pixels from position.
+* `alignment`: The alignment of the inventory. Aligned at the top left corner if not specified.
+
+### `hotbar`
+
+* `direction`: Direction the list will be displayed in
+* `offset`: offset in pixels from position.
+* `alignment`: The alignment of the inventory.
+
+### `waypoint`
+
+Displays distance to selected world position.
+
+* `name`: The name of the waypoint.
+* `text`: Distance suffix. Can be blank.
+* `precision`: Waypoint precision, integer >= 0. Defaults to 10.
+ If set to 0, distance is not shown. Shown value is `floor(distance*precision)/precision`.
+ When the precision is an integer multiple of 10, there will be `log_10(precision)` digits after the decimal point.
+ `precision = 1000`, for example, will show 3 decimal places (eg: `0.999`).
+ `precision = 2` will show multiples of `0.5`; precision = 5 will show multiples of `0.2` and so on:
+ `precision = n` will show multiples of `1/n`
+* `number:` An integer containing the RGB value of the color used to draw the
+ text.
+* `world_pos`: World position of the waypoint.
+* `offset`: offset in pixels from position.
+* `alignment`: The alignment of the waypoint.
+
+### `image_waypoint`
+
+Same as `image`, but does not accept a `position`; the position is instead determined by `world_pos`, the world position of the waypoint.
+
+* `scale`: The scale of the image, with `{x = 1, y = 1}` being the original texture size.
+ The `x` and `y` fields apply to the respective axes.
+ Positive values scale the source image.
+ Negative values represent percentages relative to screen dimensions.
+ Example: `{x = -20, y = 3}` means the image will be drawn 20% of screen width wide,
+ and 3 times as high as the source image is.
+* `text`: The name of the texture that is displayed.
+* `alignment`: The alignment of the image.
+* `world_pos`: World position of the waypoint.
+* `offset`: offset in pixels from position.
+
+### `compass`
+
+Displays an image oriented or translated according to current heading direction.
+
+* `size`: The size of this element. Negative values represent percentage
+ of the screen; e.g. `x=-100` means 100% (width).
+* `scale`: Scale of the translated image (used only for dir = 2 or dir = 3).
+* `text`: The name of the texture to use.
+* `alignment`: The alignment of the image.
+* `offset`: Offset in pixels from position.
+* `direction`: How the image is rotated/translated:
+ * 0 - Rotate as heading direction
+ * 1 - Rotate in reverse direction
+ * 2 - Translate as landscape direction
+ * 3 - Translate in reverse direction
+
+If translation is chosen, texture is repeated horizontally to fill the whole element.
+
+### `minimap`
+
+Displays a minimap on the HUD.
+
+* `size`: Size of the minimap to display. Minimap should be a square to avoid
+ distortion.
+ * Negative values represent percentages of the screen. If either `x` or `y`
+ is specified as a percentage, the resulting pixel size will be used for
+ both `x` and `y`. Example: On a 1920x1080 screen, `{x = 0, y = -25}` will
+ result in a 270x270 minimap.
+ * Negative values are supported starting with protocol version 45.
+* `alignment`: The alignment of the minimap.
+* `offset`: offset in pixels from position.
+
+Representations of simple things
+================================
+
+Vector (ie. a position)
+-----------------------
+
+```lua
+vector.new(x, y, z)
+```
+
+See [Spatial Vectors](#spatial-vectors) for details.
+
+`pointed_thing`
+---------------
+
+* `{type="nothing"}`
+* `{type="node", under=pos, above=pos}`
+ * Indicates a pointed node selection box.
+ * `under` refers to the node position behind the pointed face.
+ * `above` refers to the node position in front of the pointed face.
+* `{type="object", ref=ObjectRef}`
+
+Exact pointing location (currently only `Raycast` supports these fields):
+
+* `pointed_thing.intersection_point`: The absolute world coordinates of the
+ point on the selection box which is pointed at. May be in the selection box
+ if the pointer is in the box too.
+* `pointed_thing.box_id`: The ID of the pointed selection box (counting starts
+ from 1).
+* `pointed_thing.intersection_normal`: Unit vector, points outwards of the
+ selected selection box. This specifies which face is pointed at.
+ Is a null vector `vector.zero()` when the pointer is inside the selection box.
+ For entities with rotated selection boxes, this will be rotated properly
+ by the entity's rotation - it will always be in absolute world space.
+
+
+
+
+Flag Specifier Format
+=====================
+
+Flags using the standardized flag specifier format can be specified in either
+of two ways, by string or table.
+
+The string format is a comma-delimited set of flag names; whitespace and
+unrecognized flag fields are ignored. Specifying a flag in the string sets the
+flag, and specifying a flag prefixed by the string `"no"` explicitly
+clears the flag from whatever the default may be.
+
+In addition to the standard string flag format, the schematic flags field can
+also be a table of flag names to boolean values representing whether or not the
+flag is set. Additionally, if a field with the flag name prefixed with `"no"`
+is present, mapped to a boolean of any value, the specified flag is unset.
+
+E.g. A flag field of value
+
+```lua
+{place_center_x = true, place_center_y=false, place_center_z=true}
+```
+
+is equivalent to
+
+```lua
+{place_center_x = true, noplace_center_y=true, place_center_z=true}
+```
+
+which is equivalent to
+
+```lua
+"place_center_x, noplace_center_y, place_center_z"
+```
+
+or even
+
+```lua
+"place_center_x, place_center_z"
+```
+
+since, by default, no schematic attributes are set.
+
+
+
+
+Items
+=====
+
+Items are things that can be held by players, dropped in the map and
+stored in inventories.
+Items come in the form of item stacks, which are collections of equal
+items that occupy a single inventory slot.
+
+Item types
+----------
+
+There are three kinds of items: nodes, tools and craftitems.
+
+* Node: Placeable item form of a node in the world's voxel grid
+* Tool: Has a changeable wear property but cannot be stacked
+* Craftitem: Has no special properties
+
+Every registered node (the voxel in the world) has a corresponding
+item form (the thing in your inventory) that comes along with it.
+This item form can be placed which will create a node in the
+world (by default).
+Both the 'actual' node and its item form share the same identifier.
+For all practical purposes, you can treat the node and its item form
+interchangeably. We usually just say 'node' to the item form of
+the node as well.
+
+Note the definition of tools is purely technical. The only really
+unique thing about tools is their wear, and that's basically it.
+Beyond that, you can't make any gameplay-relevant assumptions
+about tools or non-tools. It is perfectly valid to register something
+that acts as tool in a gameplay sense as a craftitem, and vice-versa.
+
+Craftitems can be used for items that neither need to be a node
+nor a tool.
+
+Special Items
+-------------
+The following items are predefined and have special properties.
+
+* `"unknown"`: An item that represents every item which has not been registered
+* `"air"`: The node which appears everywhere where no other node is
+* `"ignore"`: Mapblocks that are not loaded are represented using this node.
+ * Also used for nodes that have not yet been set by the map generator.
+ * This is also what appears outside of the map boundary.
+* `""`: The player's hand, which is in use whenever the player wields no item.
+ * Its range and tool capabilities are also used as a fallback for the wielded item.
+ * It can be overridden to change those properties:
+ * globally using `core.override_item`
+ * per-player using the special `"hand"` inventory list
+
+Amount and wear
+---------------
+
+All item stacks have an amount between 0 and 65535. It is 1 by
+default. Tool item stacks cannot have an amount greater than 1.
+
+Tools use a wear (damage) value ranging from 0 to 65535. The
+value 0 is the default and is used for unworn tools. The values
+1 to 65535 are used for worn tools, where a higher value stands for
+a higher wear. Non-tools technically also have a wear property,
+but it is always 0. There is also a special 'toolrepair' crafting
+recipe that is only available to tools.
+
+Item formats
+------------
+
+Items and item stacks can exist in three formats: Serializes, table format
+and `ItemStack`.
+
+When an item must be passed to a function, it can usually be in any of
+these formats.
+
+### Serialized
+
+This is called "stackstring" or "itemstring". It is a simple string with
+1-4 components:
+
+1. Full item identifier ("item name")
+2. Optional amount
+3. Optional wear value
+4. Optional item metadata
+
+Syntax:
+
+ [[ [ ]]]
+
+Examples:
+
+* `"default:apple"`: 1 apple
+* `"default:dirt 5"`: 5 dirt
+* `"default:pick_stone"`: a new stone pickaxe
+* `"default:pick_wood 1 21323"`: a wooden pickaxe, ca. 1/3 worn out
+* `[[default:pick_wood 1 21323 "\u0001description\u0002My worn out pick\u0003"]]`:
+ * a wooden pickaxe from the `default` mod,
+ * amount must be 1 (pickaxe is a tool), ca. 1/3 worn out (it's a tool),
+ * with the `description` field set to `"My worn out pick"` in its metadata
+* `[[default:dirt 5 0 "\u0001description\u0002Special dirt\u0003"]]`:
+ * analogous to the above example
+ * note how the wear is set to `0` as dirt is not a tool
+
+You should ideally use the `ItemStack` format to build complex item strings
+(especially if they use item metadata)
+without relying on the serialization format. Example:
+
+ local stack = ItemStack("default:pick_wood")
+ stack:set_wear(21323)
+ stack:get_meta():set_string("description", "My worn out pick")
+ local itemstring = stack:to_string()
+
+Additionally the methods `core.itemstring_with_palette(item, palette_index)`
+and `core.itemstring_with_color(item, colorstring)` may be used to create
+item strings encoding color information in their metadata.
+
+### Table format
+
+Examples:
+
+5 dirt nodes:
+
+```lua
+{name="default:dirt", count=5, wear=0, metadata=""}
+```
+
+A wooden pick about 1/3 worn out:
+
+```lua
+{name="default:pick_wood", count=1, wear=21323, metadata=""}
+```
+
+An apple:
+
+```lua
+{name="default:apple", count=1, wear=0, metadata=""}
+```
+
+### `ItemStack` format
+
+A native C++ format with many helper methods. Useful for converting
+between formats. See the [Class Reference](#class-reference) section for details.
+
+
+
+
+Groups
+======
+
+In a number of places, there is a group table. Groups define the
+properties of a thing (item, node, armor of entity, tool capabilities)
+in such a way that the engine and other mods can can interact with
+the thing without actually knowing what the thing is.
+
+Usage
+-----
+
+Groups are stored in a table, having the group names with keys and the
+group ratings as values. Group ratings are integer values within the
+range [-32767, 32767]. For example:
+
+```lua
+-- Default dirt
+groups = {crumbly=3, soil=1}
+
+-- A more special dirt-kind of thing
+groups = {crumbly=2, soil=1, level=2, outerspace=1}
+```
+
+Groups always have a rating associated with them. If there is no
+useful meaning for a rating for an enabled group, it shall be `1`.
+
+When not defined, the rating of a group defaults to `0`. Thus when you
+read groups, you must interpret `nil` and `0` as the same value, `0`.
+
+You can read the rating of a group for an item or a node by using
+
+```lua
+core.get_item_group(itemname, groupname)
+```
+
+Groups of items
+---------------
+
+Groups of items can define what kind of an item it is (e.g. wool).
+
+Groups of nodes
+---------------
+
+In addition to the general item things, groups are used to define whether
+a node is destroyable and how long it takes to destroy by a tool.
+
+Groups of entities
+------------------
+
+For entities, groups are, as of now, used only for calculating damage.
+The rating is the percentage of damage caused by items with this damage group.
+See [Entity damage mechanism](#entity-damage-mechanism).
+
+```lua
+object:get_armor_groups() --> a group-rating table (e.g. {fleshy=100})
+object:set_armor_groups({fleshy=30, cracky=80})
+```
+
+Groups of tool capabilities
+---------------------------
+
+Groups in tool capabilities define which groups of nodes and entities they
+are effective towards.
+
+Groups in crafting recipes
+--------------------------
+
+In crafting recipes, you can specify a group as an input item.
+This means that any item in that group will be accepted as input.
+
+The basic syntax is:
+
+```lua
+"group:"
+```
+
+For example, `"group:meat"` will accept any item in the `meat` group.
+
+It is also possible to require an input item to be in
+multiple groups at once. The syntax for that is:
+
+```lua
+"group:,,(...),"
+```
+
+For example, `"group:leaves,birch,trimmed"` accepts any item which is member
+of *all* the groups `leaves` *and* `birch` *and* `trimmed`.
+
+An example recipe: Craft a raw meat soup from any meat, any water and any bowl:
+
+```lua
+{
+ output = "food:meat_soup_raw",
+ recipe = {
+ {"group:meat"},
+ {"group:water"},
+ {"group:bowl"},
+ },
+}
+```
+
+Another example: Craft red wool from white wool and red dye
+(here, "red dye" is defined as any item which is member of
+*both* the groups `dye` and `basecolor_red`).
+
+```lua
+{
+ type = "shapeless",
+ output = "wool:red",
+ recipe = {"wool:white", "group:dye,basecolor_red"},
+}
+```
+
+Special groups
+--------------
+
+The asterisk `(*)` after a group name describes that there is no engine
+functionality bound to it, and implementation is left up as a suggestion
+to games.
+
+### Node and item groups
+
+* `not_in_creative_inventory`: (*) Special group for inventory mods to indicate
+ that the item should be hidden in item lists.
+
+
+### Node-only groups
+
+* `attached_node`: the node is 'attached' to a neighboring node. It checks
+ whether the node it is attached to is walkable. If it
+ isn't, the node will drop as an item.
+ * `1`: if the node is wallmounted, the node is attached in the wallmounted
+ direction. Otherwise, the node is attached to the node below.
+ * `2`: if the node is facedir or 4dir, the facedir or 4dir direction is checked.
+ No effect for other nodes.
+ Note: The "attaching face" of this node is tile no. 5 (back face).
+ * `3`: the node is always attached to the node below.
+ * `4`: the node is always attached to the node above.
+* `bouncy`: value is bounce speed in percent.
+ If positive, jump/sneak on floor impact will increase/decrease bounce height.
+ Negative value is the same bounciness, but non-controllable.
+* `connect_to_raillike`: makes nodes of raillike drawtype with same group value
+ connect to each other
+* `dig_immediate`: Player can always pick up node without reducing tool wear
+ * `2`: the node always gets the digging time 0.5 seconds (rail, sign)
+ * `3`: the node always gets the digging time 0 seconds (torch)
+* `disable_jump`: Player (and possibly other things) cannot jump from node
+ or if their feet are in the node. Note: not supported for `new_move = false`
+* `disable_descend`: Player (and possibly other things) cannot *actively*
+ descend in node using Sneak or Aux1 key (for liquids and climbable nodes
+ only). Note: not supported for `new_move = false`
+* `fall_damage_add_percent`: modifies the fall damage suffered when hitting
+ the top of this node. There's also an armor group with the same name.
+ The final player damage is determined by the following formula:
+ ```lua
+ damage =
+ collision speed
+ * ((node_fall_damage_add_percent + 100) / 100) -- node group
+ * ((player_fall_damage_add_percent + 100) / 100) -- player armor group
+ - (14) -- constant tolerance
+ ```
+ Negative damage values are discarded as no damage.
+* `falling_node`: if there is no walkable block under the node it will fall
+* `float`: the node will not fall through liquids (`liquidtype ~= "none"`)
+ * A liquid source with `groups = {falling_node = 1, float = 1}`
+ will fall through flowing liquids.
+* `level`: Can be used to give an additional sense of progression in the game.
+ * A larger level will cause e.g. a weapon of a lower level make much less
+ damage, and get worn out much faster, or not be able to get drops
+ from destroyed nodes.
+ * `0` is something that is directly accessible at the start of gameplay
+ * There is no upper limit
+ * See also: `leveldiff` in [Tool Capabilities](#tool-capabilities)
+* `slippery`: Players and items will slide on the node.
+ Slipperiness rises steadily with `slippery` value, starting at 1.
+
+
+### Tool-only groups
+
+* `disable_repair`: If set to 1 for a tool, it cannot be repaired using the
+ `"toolrepair"` crafting recipe
+
+
+### `ObjectRef` armor groups
+
+* `immortal`: Skips all damage and breath handling for an object. This group
+ will also hide the integrated HUD status bars for players. It is
+ automatically set to all players when damage is disabled on the server and
+ cannot be reset (subject to change).
+* `fall_damage_add_percent`: Modifies the fall damage suffered by players
+ when they hit the ground. It is analog to the node group with the same
+ name. See the node group above for the exact calculation.
+* `punch_operable`: For entities; disables the regular damage mechanism for
+ players punching it by hand or a non-tool item, so that it can do something
+ else than take damage.
+
+
+
+Known damage and digging time defining groups
+---------------------------------------------
+
+* `crumbly`: dirt, sand
+* `cracky`: tough but crackable stuff like stone.
+* `snappy`: something that can be cut using things like scissors, shears,
+ bolt cutters and the like, e.g. leaves, small plants, wire, sheets of metal
+* `choppy`: something that can be cut using force; e.g. trees, wooden planks
+* `fleshy`: Living things like animals and the player. This could imply
+ some blood effects when hitting.
+* `explody`: Especially prone to explosions
+* `oddly_breakable_by_hand`:
+ Can be added to nodes that shouldn't logically be breakable by the
+ hand but are. Somewhat similar to `dig_immediate`, but times are more
+ like `{[1]=3.50,[2]=2.00,[3]=0.70}` and this does not override the
+ digging speed of an item if it can dig at a faster speed than this
+ suggests for the hand.
+
+Examples of custom groups
+-------------------------
+
+Item groups are often used for defining, well, _groups of items_.
+
+* `meat`: any meat-kind of a thing (rating might define the size or healing
+ ability or be irrelevant -- it is not defined as of yet)
+* `eatable`: anything that can be eaten. Rating might define HP gain in half
+ hearts.
+* `flammable`: can be set on fire. Rating might define the intensity of the
+ fire, affecting e.g. the speed of the spreading of an open fire.
+* `wool`: any wool (any origin, any color)
+* `metal`: any metal
+* `weapon`: any weapon
+* `heavy`: anything considerably heavy
+
+Digging time calculation specifics
+----------------------------------
+
+Groups such as `crumbly`, `cracky` and `snappy` are used for this
+purpose. Rating is `1`, `2` or `3`. A higher rating for such a group implies
+faster digging time.
+
+The `level` group is used to limit the toughness of nodes an item capable
+of digging can dig and to scale the digging times / damage to a greater extent.
+
+**Please do understand this**, otherwise you cannot use the system to it's
+full potential.
+
+Items define their properties by a list of parameters for groups. They
+cannot dig other groups; thus it is important to use a standard bunch of
+groups to enable interaction with items.
+
+
+
+
+Tool Capabilities
+=================
+
+'Tool capabilities' is a property of items that defines two things:
+
+1) Which nodes it can dig and how fast
+2) Which objects it can hurt by punching and by how much
+
+Tool capabilities are available for all items, not just tools.
+But only tools can receive wear from digging and punching.
+
+Missing or incomplete tool capabilities will default to the
+player's hand.
+
+Tool capabilities definition
+----------------------------
+
+Tool capabilities define:
+
+* Full punch interval
+* Maximum drop level
+* For an arbitrary list of node groups:
+ * Uses (until the tool breaks)
+ * Maximum level (usually `0`, `1`, `2` or `3`)
+ * Digging times
+* Damage groups
+* Punch attack uses (until the tool breaks)
+
+### Full punch interval `full_punch_interval`
+
+When used as a weapon, the item will do full damage if this time is spent
+between punches. If e.g. half the time is spent, the item will do half
+damage.
+
+### Maximum drop level `max_drop_level`
+
+Suggests the maximum level of node, when dug with the item, that will drop
+its useful item. (e.g. iron ore to drop a lump of iron).
+
+This value is not used in the engine; it is the responsibility of the game/mod
+code to implement this.
+
+### Uses `uses` (tools only)
+
+Determines how many uses the tool has when it is used for digging a node,
+of this group, of the maximum level. The maximum supported number of
+uses is 65535. The special number 0 is used for infinite uses.
+For lower leveled nodes, the use count is multiplied by `3^leveldiff`.
+`leveldiff` is the difference of the tool's `maxlevel` `groupcaps` and the
+node's `level` group. The node cannot be dug if `leveldiff` is less than zero.
+
+* `uses=10, leveldiff=0`: actual uses: 10
+* `uses=10, leveldiff=1`: actual uses: 30
+* `uses=10, leveldiff=2`: actual uses: 90
+
+For non-tools, this has no effect.
+
+### Maximum level `maxlevel`
+
+Tells what is the maximum level of a node of this group that the item will
+be able to dig.
+
+### Digging times `times`
+
+List of digging times for different ratings of the group, for nodes of the
+maximum level.
+
+For example, as a Lua table, `times={[2]=2.00, [3]=0.70}`. This would
+result in the item to be able to dig nodes that have a rating of `2` or `3`
+for this group, and unable to dig the rating `1`, which is the toughest.
+Unless there is a matching group that enables digging otherwise.
+
+If the result digging time is 0, a delay of 0.15 seconds is added between
+digging nodes. If the player releases LMB after digging, this delay is set to 0,
+i.e. players can more quickly click the nodes away instead of holding LMB.
+
+This extra delay is not applied in case of a digging time between 0 and 0.15,
+so a digging time of 0.01 is actually faster than a digging time of 0.
+
+### Damage groups
+
+List of damage for groups of entities. See [Entity damage mechanism](#entity-damage-mechanism).
+
+### Punch attack uses (tools only)
+
+Determines how many uses (before breaking) the tool has when dealing damage
+to an object, when the full punch interval (see above) was always
+waited out fully.
+
+Wear received by the tool is proportional to the time spent, scaled by
+the full punch interval.
+
+For non-tools, this has no effect.
+
+Example definition of the capabilities of an item
+-------------------------------------------------
+
+```lua
+tool_capabilities = {
+ groupcaps={
+ crumbly={maxlevel=2, uses=20, times={[1]=1.60, [2]=1.20, [3]=0.80}}
+ },
+}
+```
+
+This makes the item capable of digging nodes that fulfill both of these:
+
+* Have the `crumbly` group
+* Have a `level` group less or equal to `2`
+
+Table of resulting digging times:
+
+ crumbly 0 1 2 3 4 <- level
+ -> 0 - - - - -
+ 1 0.80 1.60 1.60 - -
+ 2 0.60 1.20 1.20 - -
+ 3 0.40 0.80 0.80 - -
+
+ level diff: 2 1 0 -1 -2
+
+Table of resulting tool uses:
+
+ -> 0 - - - - -
+ 1 180 60 20 - -
+ 2 180 60 20 - -
+ 3 180 60 20 - -
+
+**Notes**:
+
+* At `crumbly==0`, the node is not diggable.
+* At `crumbly==3`, the level difference digging time divider kicks in and makes
+ easy nodes to be quickly breakable.
+* At `level > 2`, the node is not diggable, because it's `level > maxlevel`
+
+
+
+
+Entity damage mechanism
+=======================
+
+Damage calculation:
+
+ damage = 0
+ foreach group in cap.damage_groups:
+ damage += cap.damage_groups[group]
+ * limit(actual_interval / cap.full_punch_interval, 0.0, 1.0)
+ * (object.armor_groups[group] / 100.0)
+ -- Where object.armor_groups[group] is 0 for inexistent values
+ return damage
+
+Client predicts damage based on damage groups. Because of this, it is able to
+give an immediate response when an entity is damaged or dies; the response is
+pre-defined somehow (e.g. by defining a sprite animation) (not implemented;
+TODO).
+Currently a smoke puff will appear when an entity dies.
+
+The group `immortal` completely disables normal damage.
+
+Entities can define a special armor group, which is `punch_operable`. This
+group disables the regular damage mechanism for players punching it by hand or
+a non-tool item, so that it can do something else than take damage.
+
+On the Lua side, every punch calls:
+
+```lua
+entity:on_punch(puncher, time_from_last_punch, tool_capabilities, direction,
+ damage)
+```
+
+This should never be called directly, because damage is usually not handled by
+the entity itself.
+
+* `puncher` is the object performing the punch. Can be `nil`. Should never be
+ accessed unless absolutely required, to encourage interoperability.
+* `time_from_last_punch` is time from last punch (by `puncher`) or `nil`.
+* `tool_capabilities` can be `nil`.
+* `direction` is a unit vector, pointing from the source of the punch to
+ the punched object.
+* `damage` damage that will be done to entity
+Return value of this function will determine if damage is done by this function
+(retval true) or shall be done by engine (retval false)
+
+To punch an entity/object in Lua, call:
+
+```lua
+object:punch(puncher, time_from_last_punch, tool_capabilities, direction)
+```
+
+* Return value is tool wear.
+* Parameters are equal to the above callback.
+* If `direction` equals `nil` and `puncher` does not equal `nil`, `direction`
+ will be automatically filled in based on the location of `puncher`.
+
+
+
+
+Metadata
+========
+
+Node Metadata
+-------------
+
+The instance of a node in the world normally only contains the three values
+mentioned in [Nodes](#nodes). However, it is possible to insert extra data into a node.
+It is called "node metadata"; See `NodeMetaRef`.
+
+Node metadata contains two things:
+
+* A key-value store
+* An inventory
+
+Some of the values in the key-value store are handled specially:
+
+* `formspec`: Defines an inventory menu that is opened with the
+ 'place/use' key. Only works if no `on_rightclick` was
+ defined for the node. See also [Formspec](#formspec).
+* `infotext`: Text shown on the screen when the node is pointed at.
+ Line-breaks will be applied automatically.
+ If the infotext is very long, it will be truncated.
+
+Example:
+
+```lua
+local meta = core.get_meta(pos)
+
+-- Set node formspec and infotext
+meta:set_string("formspec",
+ "size[8,9]"..
+ "list[context;main;0,0;8,4;]"..
+ "list[current_player;main;0,5;8,4;]")
+meta:set_string("infotext", "Chest");
+
+-- Set inventory list size of `"main"` list to 32
+local inv = meta:get_inventory()
+inv:set_size("main", 32)
+
+-- Dump node metadata
+print(dump(meta:to_table()))
+
+-- Set node metadata from a metadata table
+meta:from_table({
+ inventory = {
+ -- Set items of inventory in all 32 slots of the `"main"` list
+ main = {[1] = "default:dirt", [2] = "", [3] = "", [4] = "",
+ [5] = "", [6] = "", [7] = "", [8] = "", [9] = "",
+ [10] = "", [11] = "", [12] = "", [13] = "",
+ [14] = "default:cobble", [15] = "", [16] = "", [17] = "",
+ [18] = "", [19] = "", [20] = "default:cobble", [21] = "",
+ [22] = "", [23] = "", [24] = "", [25] = "", [26] = "",
+ [27] = "", [28] = "", [29] = "", [30] = "", [31] = "",
+ [32] = ""}
+ },
+ -- metadata fields
+ fields = {
+ formspec = "size[8,9]list[context;main;0,0;8,4;]list[current_player;main;0,5;8,4;]",
+ infotext = "Chest"
+ }
+})
+```
+
+Item Metadata
+-------------
+
+Item stacks can store metadata too. See [`ItemStackMetaRef`](#itemstackmetaref)
+Note: They are not able to store the character `"\1"`, be very careful when storing binary data in them
+
+Item metadata only contains a key-value store.
+
+Some of the values in the key-value store are handled specially:
+
+* `description`: Set the item stack's description.
+ See also: `get_description` in [`ItemStack`](#itemstack)
+* `short_description`: Set the item stack's short description.
+ See also: `get_short_description` in [`ItemStack`](#itemstack)
+* `inventory_image`: Override inventory_image
+* `inventory_overlay`: Override inventory_overlay
+* `wield_image`: Override wield_image
+* `wield_overlay`: Override wield_overlay
+* `wield_scale`: Override wield_scale, use vector.to_string
+* `color`: A `ColorString`, which sets the stack's color.
+* `palette_index`: If the item has a palette, this is used to get the
+ current color from the palette.
+* `count_meta`: Replace the displayed count with any string.
+* `count_alignment`: Set the alignment of the displayed count value. This is an
+ int value. The lowest 2 bits specify the alignment in x-direction, the 3rd and
+ 4th bit specify the alignment in y-direction:
+ 0 = default, 1 = left / up, 2 = middle, 3 = right / down
+ The default currently is the same as right/down.
+ Example: 6 = 2 + 1*4 = middle,up
+* `range`: Overrides the pointing range
+ Example: `meta:set_float("range", 4.2)`
+
+Example:
+
+```lua
+local meta = stack:get_meta()
+meta:set_string("key", "value")
+print(dump(meta:to_table()))
+```
+
+Example manipulations of "description" and expected output behaviors:
+
+```lua
+print(ItemStack("default:pick_steel"):get_description()) --> Steel Pickaxe
+print(ItemStack("foobar"):get_description()) --> Unknown Item
+
+local stack = ItemStack("default:stone")
+stack:get_meta():set_string("description", "Custom description\nAnother line")
+print(stack:get_description()) --> Custom description\nAnother line
+print(stack:get_short_description()) --> Custom description
+
+stack:get_meta():set_string("short_description", "Short")
+print(stack:get_description()) --> Custom description\nAnother line
+print(stack:get_short_description()) --> Short
+
+print(ItemStack("mod:item_with_no_desc"):get_description()) --> mod:item_with_no_desc
+```
+
+
+Formspec
+========
+
+Formspec defines a menu. This supports inventories and some of the
+typical widgets like buttons, checkboxes, text input fields, etc.
+It is a string, with a somewhat strange format.
+
+A formspec is made out of formspec elements, which includes widgets
+like buttons but also can be used to set stuff like background color.
+
+Many formspec elements have a `name`, which is a unique identifier which
+is used when the server receives user input. You must not use the name
+"quit" for formspec elements.
+
+Spaces and newlines can be inserted between the blocks, as is used in the
+examples.
+
+Position and size units are inventory slots unless the new coordinate system
+is enabled. `X` and `Y` position the formspec element relative to the top left
+of the menu or container. `W` and `H` are its width and height values.
+
+If the new system is enabled, all elements have unified coordinates for all
+elements with no padding or spacing in between. This is highly recommended
+for new forms. See `real_coordinates[]` and `Migrating to Real
+Coordinates`.
+
+Inventories with a `player:` inventory location are only sent to the
+player named ``.
+
+When displaying text which can contain formspec code, e.g. text set by a player,
+use `core.formspec_escape`.
+For colored text you can use `core.colorize`.
+
+Since formspec version 3, elements drawn in the order they are defined. All
+background elements are drawn before all other elements.
+
+**WARNING**: do _not_ use an element name starting with `key_`; those names are
+reserved to pass key press events to formspec!
+
+**WARNING**: names and values of elements cannot contain binary data such as ASCII
+control characters. For values, escape sequences used by the engine are an exception to this.
+
+**WARNING**: Luanti allows you to add elements to every single formspec instance
+using `player:set_formspec_prepend()`, which may be the reason backgrounds are
+appearing when you don't expect them to, or why things are styled differently
+to normal. See [`no_prepend[]`] and [Styling Formspecs](#styling-formspecs).
+
+Examples
+--------
+
+### Chest
+
+ size[8,9]
+ list[context;main;0,0;8,4;]
+ list[current_player;main;0,5;8,4;]
+
+### Furnace
+
+ size[8,9]
+ list[context;fuel;2,3;1,1;]
+ list[context;src;2,1;1,1;]
+ list[context;dst;5,1;2,2;]
+ list[current_player;main;0,5;8,4;]
+
+### Minecraft-like player inventory
+
+ size[8,7.5]
+ image[1,0.6;1,2;player.png]
+ list[current_player;main;0,3.5;8,4;]
+ list[current_player;craft;3,0;3,3;]
+ list[current_player;craftpreview;7,1;1,1;]
+
+Version History
+---------------
+
+* Formspec version 1 (pre-5.1.0):
+ * (too much)
+* Formspec version 2 (5.1.0):
+ * Forced real coordinates
+ * background9[]: 9-slice scaling parameters
+* Formspec version 3 (5.2.0):
+ * Formspec elements are drawn in the order of definition
+ * bgcolor[]: use 3 parameters (bgcolor, formspec (now an enum), fbgcolor)
+ * box[] and image[] elements enable clipping by default
+ * new element: scroll_container[]
+* Formspec version 4 (5.4.0):
+ * Allow dropdown indexing events
+* Formspec version 5 (5.5.0):
+ * Added padding[] element
+* Formspec version 6 (5.6.0):
+ * Add nine-slice images, animated_image, and fgimg_middle
+* Formspec version 7 (5.8.0):
+ * style[]: Add focused state for buttons
+ * Add field_enter_after_edit[] (experimental)
+* Formspec version 8 (5.10.0)
+ * scroll_container[]: content padding parameter
+* Formspec version 9 (5.12.0)
+ * Add allow_close[]
+ * label[]: Add "area label" variant
+* Formspec version 10 (5.13.0)
+ * model[]: Support floating-point frames
+
+Elements
+--------
+
+### `formspec_version[]`
+
+* Set the formspec version to a certain number. If not specified,
+ version 1 is assumed.
+* Must be specified before `size` element.
+* Clients older than this version can neither show newer elements nor display
+ elements with new arguments correctly.
+* Available since feature `formspec_version_element`.
+* See also: [Version History](#version-history).
+
+### `size[,,]`
+
+* Define the size of the menu in inventory slots
+* `fixed_size`: `true`/`false` (optional)
+* deprecated: `invsize[,;]`
+
+### `position[,]`
+
+* Must be used after `size` element.
+* Defines the position on the game window of the formspec's `anchor` point.
+* For X and Y, 0.0 and 1.0 represent opposite edges of the game window,
+ for example:
+ * [0.0, 0.0] sets the position to the top left corner of the game window.
+ * [1.0, 1.0] sets the position to the bottom right of the game window.
+* Defaults to the center of the game window [0.5, 0.5].
+
+### `anchor[,]`
+
+* Must be used after both `size` and `position` (if present) elements.
+* Defines the location of the anchor point within the formspec.
+* For X and Y, 0.0 and 1.0 represent opposite edges of the formspec,
+ for example:
+ * [0.0, 1.0] sets the anchor to the bottom left corner of the formspec.
+ * [1.0, 0.0] sets the anchor to the top right of the formspec.
+* Defaults to the center of the formspec [0.5, 0.5].
+
+* `position` and `anchor` elements need suitable values to avoid a formspec
+ extending off the game window due to particular game window sizes.
+
+### `padding[,]`
+
+* Must be used after the `size`, `position`, and `anchor` elements (if present).
+* Defines how much space is padded around the formspec if the formspec tries to
+ increase past the size of the screen and coordinates have to be shrunk.
+* For X and Y, 0.0 represents no padding (the formspec can touch the edge of the
+ screen), and 0.5 represents half the screen (which forces the coordinate size
+ to 0). If negative, the formspec can extend off the edge of the screen.
+* Defaults to [0.05, 0.05].
+
+### `no_prepend[]`
+
+* Must be used after the `size`, `position`, `anchor`, and `padding` elements
+ (if present).
+* Disables player:set_formspec_prepend() from applying to this formspec.
+
+### `real_coordinates[]`
+
+* INFORMATION: Enable it automatically using `formspec_version` version 2 or newer.
+* When set to true, all following formspec elements will use the new coordinate system.
+* If used immediately after `size`, `position`, `anchor`, and `no_prepend` elements
+ (if present), the form size will use the new coordinate system.
+* **Note**: Formspec prepends are not affected by the coordinates in the main form.
+ They must enable it explicitly.
+* For information on converting forms to the new coordinate system, see `Migrating
+ to Real Coordinates`.
+
+### `allow_close[]`
+
+* When set to false, the formspec will not close when the user tries to close
+ it with the Escape key or similar. Default true.
+* The formspec can still be closed with `*_exit[]` elements and
+ `core.close_formspec()`, regardless of this setting.
+
+### `container[,]`
+
+* Start of a container block, moves all physical elements in the container by
+ (X, Y).
+* Must have matching `container_end`
+* Containers can be nested, in which case the offsets are added
+ (child containers are relative to parent containers)
+
+### `container_end[]`
+
+* End of a container, following elements are no longer relative to this
+ container.
+
+### `scroll_container[,;,;;;;]`
+
+* Start of a scroll_container block. All contained elements will ...
+ * take the scroll_container coordinate as position origin,
+ * be additionally moved by the current value of the scrollbar with the name
+ `scrollbar name` times `scroll factor` along the orientation `orientation` and
+ * be clipped to the rectangle defined by `X`, `Y`, `W` and `H`.
+* `orientation`: possible values are `vertical` and `horizontal`.
+* `scroll factor`: optional, defaults to `0.1`.
+* `content padding`: (optional), in formspec coordinate units
+ * If specified, the scrollbar properties `max` and `thumbsize` are calculated automatically
+ based on the content size plus `content padding` at the end of the container. `min` is set to 0.
+ * Negative `scroll factor` is not supported.
+ * When active, `scrollbaroptions[]` has no effect on the affected properties.
+ * Defaults to empty value (= disabled).
+* Nesting is possible.
+* Some elements might work a little different if they are in a scroll_container.
+* Note: If you want the scroll_container to actually work, you also need to add a
+ scrollbar element with the specified name. Furthermore, it is highly recommended
+ to use a scrollbaroptions element on this scrollbar.
+
+### `scroll_container_end[]`
+
+* End of a scroll_container, following elements are no longer bound to this
+ container.
+
+### `list[;;,;,;]`
+
+* Show an inventory list if it has been sent to the client.
+* If the inventory list changes (eg. it didn't exist before, it's resized, or its items
+ are moved) while the formspec is open, the formspec element may (but is not guaranteed
+ to) adapt to the new inventory list.
+* Item slots are drawn in a grid from left to right, then up to down, ordered
+ according to the slot index.
+* `W` and `H` are in inventory slots, not in coordinates.
+* `starting item index` (Optional): The index of the first (upper-left) item to draw.
+ Indices start at `0`. Default is `0`.
+* The number of shown slots is the minimum of `W*H` and the inventory list's size minus
+ `starting item index`.
+* **Note**: With the new coordinate system, the spacing between inventory
+ slots is one-fourth the size of an inventory slot by default. Also see
+ [Styling Formspecs](#styling-formspecs) for changing the size of slots and spacing.
+
+### `listring[;]`
+
+* Appends to an internal ring of inventory lists.
+* Shift-clicking on items in one element of the ring
+ will send them to the next inventory list inside the ring
+* The first occurrence of an element inside the ring will
+ determine the inventory where items will be sent to
+
+### `listring[]`
+
+* Shorthand for doing `listring[;]`
+ for the last two inventory lists added by list[...]
+
+### `listcolors[;]`
+
+* Sets background color of slots as `ColorString`
+* Sets background color of slots on mouse hovering
+
+### `listcolors[;;]`
+
+* Sets background color of slots as `ColorString`
+* Sets background color of slots on mouse hovering
+* Sets color of slots border
+
+### `listcolors[;;;;]`
+
+* Sets background color of slots as `ColorString`
+* Sets background color of slots on mouse hovering
+* Sets color of slots border
+* Sets default background color of tooltips
+* Sets default font color of tooltips
+
+### `tooltip[;;;]`
+
+* Adds tooltip for an element
+* `bgcolor` tooltip background color as `ColorString` (optional)
+* `fontcolor` tooltip font color as `ColorString` (optional)
+
+### `tooltip[,;,;;;]`
+
+* Adds tooltip for an area. Other tooltips will take priority when present.
+* `bgcolor` tooltip background color as `ColorString` (optional)
+* `fontcolor` tooltip font color as `ColorString` (optional)
+
+### `image[,;,;;]`
+
+* Show an image.
+* `middle` (optional): Makes the image render in 9-sliced mode and defines the middle rect.
+ * Requires formspec version >= 6.
+ * See `background9[]` documentation for more information.
+
+### `animated_image[,;,;;;;;;]`
+
+* Show an animated image. The image is drawn like a "vertical_frames" tile
+ animation (See [Tile animation definition](#tile-animation-definition)), but uses a frame count/duration for simplicity
+* `name`: Element name to send when an event occurs. The event value is the index of the current frame.
+* `texture name`: The image to use.
+* `frame count`: The number of frames animating the image.
+* `frame duration`: Milliseconds between each frame. `0` means the frames don't advance.
+* `frame start` (optional): The index of the frame to start on. Default `1`.
+* `middle` (optional): Makes the image render in 9-sliced mode and defines the middle rect.
+ * Requires formspec version >= 6.
+ * See `background9[]` documentation for more information.
+
+### `model[,;,;;;;;;;;]`
+
+* Show a mesh model.
+* `name`: Element name that can be used for styling
+* `mesh`: The mesh model to use.
+* `textures`: The mesh textures to use according to the mesh materials.
+ Texture names must be separated by commas.
+* `rotation` (Optional): Initial rotation of the camera, format `x,y`.
+ The axes are euler angles in degrees.
+* `continuous` (Optional): Whether the rotation is continuous. Default `false`.
+* `mouse control` (Optional): Whether the model can be controlled with the mouse. Default `true`.
+* `frame loop range` (Optional): Range of the animation frames.
+ * Defaults to the full range of all available frames.
+ * Syntax: `,`
+* `animation speed` (Optional): Sets the animation speed. Default 0 FPS.
+
+### `item_image[,;,;]`
+
+* Show an inventory image of registered item/node
+
+### `bgcolor[;;]`
+
+* Sets background color of formspec.
+* `bgcolor` and `fbgcolor` (optional) are `ColorString`s, they define the color
+ of the non-fullscreen and the fullscreen background.
+* `fullscreen` (optional) can be one of the following:
+ * `false`: Only the non-fullscreen background color is drawn. (default)
+ * `true`: Only the fullscreen background color is drawn.
+ * `both`: The non-fullscreen and the fullscreen background color are drawn.
+ * `neither`: No background color is drawn.
+* Note: Leave a parameter empty to not modify the value.
+* Note: `fbgcolor`, leaving parameters empty and values for `fullscreen` that
+ are not bools are only available since formspec version 3.
+
+### `background[,;,;]`
+
+* Example for formspec 8x4 in 16x resolution: image shall be sized
+ 8 times 16px times 4 times 16px.
+
+### `background[,;,;;]`
+
+* Example for formspec 8x4 in 16x resolution:
+ image shall be sized 8 times 16px times 4 times 16px
+* If `auto_clip` is `true`, the background is clipped to the formspec size
+ (`x` and `y` are used as offset values, `w` and `h` are ignored)
+
+### `background9[,;,;;;]`
+
+* 9-sliced background. See https://en.wikipedia.org/wiki/9-slice_scaling
+* Middle is a rect which defines the middle of the 9-slice.
+ * `x` - The middle will be x pixels from all sides.
+ * `x,y` - The middle will be x pixels from the horizontal and y from the vertical.
+ * `x,y,x2,y2` - The middle will start at x,y, and end at x2, y2. Negative x2 and y2 values
+ will be added to the width and height of the texture, allowing it to be used as the
+ distance from the far end.
+ * All numbers in middle are integers.
+* If `auto_clip` is `true`, the background is clipped to the formspec size
+ (`x` and `y` are used as offset values, `w` and `h` are ignored)
+* Available since formspec version 2
+
+### `pwdfield[,;,;;