diff --git a/doc/' b/doc/' deleted file mode 100644 index aee3552b7a..0000000000 --- a/doc/' +++ /dev/null @@ -1,12073 +0,0 @@ -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[,;,;;

...
`: Centered text - -`...`: Left-aligned text - -`...`: Right-aligned text - -`...`: Justified text - -`...`: Monospaced font - -`...`, `...`, `...`: Bold, italic, underline styles. - -`...` - -Make that text a clickable text triggering an action. - -* `name`: Name of the action (mandatory). -* `url`: URL to open when the action is triggered (optional). - -When clicked, the formspec is send to the server. The value of the text field -sent to `on_player_receive_fields` will be "action:" concatenated to the action -name. - -`` - -Draws an image which is present in the client media cache. - -* `name`: Name of the texture (mandatory). -* `float`: If present, makes the image floating (`left` or `right`). -* `width`: Force image width instead of taking texture width. -* `height`: Force image height instead of taking texture height. - -If only width or height given, texture aspect is kept. - -`` - -Draws an item image. - -* `name`: Item string of the item to draw (mandatory). -* `float`: If present, makes the image floating (`left` or `right`). -* `width`: Item image width. -* `height`: Item image height. -* `rotate`: Rotate item image if set to `yes` or `X,Y,Z`. X, Y and Z being -rotation speeds in percent of standard speed (-1000 to 1000). Works only if -`inventory_items_animations` is set to true. -* `angle`: Angle in which the item image is shown. Value has `X,Y,Z` form. -X, Y and Z being angles around each three axes. Works only if -`inventory_items_animations` is set to true. - -Inventory -========= - -Inventory locations -------------------- - -* `"context"`: Selected node metadata (deprecated: `"current_name"`) -* `"current_player"`: Player to whom the menu is shown -* `"player:"`: Any player -* `"nodemeta:,,"`: Any node metadata -* `"detached:"`: A detached inventory - -Player Inventory lists ----------------------- - -* `main`: list containing the default inventory -* `craft`: list containing the craft input -* `craftpreview`: list containing the craft prediction -* `craftresult`: list containing the crafted output -* `hand`: list containing an override for the empty hand - * Is not created automatically, use `InvRef:set_size` - * Players use the first item in this list as their hand - * It behaves as if the default hand `""` has been overridden for this specific player - -Custom lists can be added and deleted with `InvRef:set_size(name, size)` like -any other inventory. - -ItemStack transaction order ---------------------------- - -This list describes the situation for non-empty ItemStacks in both slots -that cannot be stacked at all, hence triggering an ItemStack swap operation. -Put/take callbacks on empty ItemStack are not executed. - -1. The "allow take" and "allow put" callbacks are each run once for the source - and destination inventory. -2. The allowed ItemStacks are exchanged. -3. The "on take" callbacks are run for the source and destination inventories -4. The "on put" callbacks are run for the source and destination inventories - -Colors -====== - -`ColorString` -------------- - -`#RGB` defines a color in hexadecimal format. - -`#RGBA` defines a color in hexadecimal format and alpha channel. - -`#RRGGBB` defines a color in hexadecimal format. - -`#RRGGBBAA` defines a color in hexadecimal format and alpha channel. - -Named colors are also supported and are equivalent to -[CSS Color Module Level 4](https://www.w3.org/TR/css-color-4/#named-color). -To specify the value of the alpha channel, append `#A` or `#AA` to the end of -the color name (e.g. `colorname#08`). - -`ColorSpec` ------------ - -A ColorSpec specifies a 32-bit color. It can be written in any of the following -forms: - -* table form: Each element ranging from 0..255 (a, if absent, defaults to 255): - * `colorspec = {a=255, r=0, g=255, b=0}` -* numerical form: The raw integer value of an ARGB8 quad: - * `colorspec = 0xFF00FF00` -* string form: A ColorString (defined above): - * `colorspec = "green"` - - - - -Escape sequences -================ - -Most text can contain escape sequences, that can for example color the text. -There are a few exceptions: tab headers, dropdowns and vertical labels can't. -The following functions provide escape sequences: - -* `core.get_color_escape_sequence(color)`: - * `color` is a ColorString - * The escape sequence sets the text color to `color` -* `core.colorize(color, message)`: - * Equivalent to: - `core.get_color_escape_sequence(color) .. - message .. - core.get_color_escape_sequence("#ffffff")` -* `core.get_background_escape_sequence(color)` - * `color` is a ColorString - * The escape sequence sets the background of the whole text element to - `color`. Only defined for item descriptions and tooltips. -* `core.strip_foreground_colors(str)` - * Removes foreground colors added by `get_color_escape_sequence`. -* `core.strip_background_colors(str)` - * Removes background colors added by `get_background_escape_sequence`. -* `core.strip_colors(str)` - * Removes all color escape sequences. - - -Coordinate System -================= - -Luanti uses a **left-handed** coordinate system: Y is "up", X is "right", Z is "forward". -This is the convention used by Unity, DirectX and Irrlicht. -It means that when you're pointing in +Z direction in-game ("forward"), +X is to your right; +Y is up. - -Consistently, rotation is [**left-handed**](https://en.wikipedia.org/w/index.php?title=Right-hand_rule) as well. -Luanti uses [Tait-Bryan angles](https://en.wikipedia.org/wiki/Euler_angles#Tait%E2%80%93Bryan_angles) for rotations, -often referred to simply as "euler angles" (even though they are not "proper" euler angles). -The rotation order is extrinsic X-Y-Z: -First rotation around the (unrotated) X-axis is applied, -then rotation around the (unrotated) Y-axis follows, -and finally rotation around the (unrotated) Z-axis is applied. -(Note: As a product of rotation matrices, this will be written in reverse, so `Z*Y*X`.) - -Attachment and bone override rotations both use these conventions. - -There is an exception, however: Object rotation (`ObjectRef:set_rotation`, `ObjectRef:get_rotation`, `automatic_rotate`) -**does not** use left-handed (extrinsic) X-Y-Z rotations. -Instead, it uses **right-handed (extrinsic) Z-X-Y** rotations: -First roll (Z) is applied, then pitch (X); yaw (Y) is applied last. - -See [Scratchapixel](https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/geometry/coordinate-systems.html) -or [Wikipedia](https://en.wikipedia.org/wiki/Cartesian_coordinate_system#Orientation_and_handedness) -for a more detailed and pictorial explanation of these terms. - - -Spatial Vectors -=============== - -Luanti stores 3-dimensional spatial vectors in Lua as tables of 3 coordinates, -and has a class to represent them (`vector.*`), which this chapter is about. -For details on what a spatial vectors is, please refer to Wikipedia: -https://en.wikipedia.org/wiki/Euclidean_vector. - -Spatial vectors are used for various things, including, but not limited to: - -* any 3D spatial vector (x/y/z-directions) -* Euler angles (pitch/yaw/roll in radians) (Spatial vectors have no real semantic - meaning here. Therefore, most vector operations make no sense in this use case.) - -Note that they are *not* used for: - -* n-dimensional vectors where n is not 3 (ie. n=2) -* arrays of the form `{num, num, num}` - -The API documentation may refer to spatial vectors, as produced by `vector.new`, -by any of the following notations: - -* `(x, y, z)` (Used rarely, and only if it's clear that it's a vector.) -* `vector.new(x, y, z)` -* `{x=num, y=num, z=num}` (Even here you are still supposed to use `vector.new`.) - -Compatibility notes -------------------- - -Vectors used to be defined as tables of the form `{x = num, y = num, z = num}`. -Since version 5.5.0, vectors additionally have a metatable to enable easier use. -Note: Those old-style vectors can still be found in old mod code. Hence, mod and -engine APIs still need to be able to cope with them in many places. - -Manually constructed tables are deprecated and highly discouraged. This interface -should be used to ensure seamless compatibility between mods and the Luanti API. -This is especially important to callback function parameters and functions overwritten -by mods. -Also, though not likely, the internal implementation of a vector might change in -the future. -In your own code, or if you define your own API, you can, of course, still use -other representations of vectors. - -Vectors provided by API functions will provide an instance of this class if not -stated otherwise. Mods should adapt this for convenience reasons. - -Special properties of the class -------------------------------- - -Vectors can be indexed with numbers and allow method and operator syntax. - -All these forms of addressing a vector `v` are valid: -`v[1]`, `v[3]`, `v.x`, `v[1] = 42`, `v.y = 13` -Note: Prefer letter over number indexing for performance and compatibility reasons. - -Where `v` is a vector and `foo` stands for any function name, `v:foo(...)` does -the same as `vector.foo(v, ...)`, apart from deprecated functionality. - -`tostring` is defined for vectors, see `vector.to_string`. - -The metatable that is used for vectors can be accessed via `vector.metatable`. -Do not modify it! - -All `vector.*` functions allow vectors `{x = X, y = Y, z = Z}` without metatables. -Returned vectors always have a metatable set. - -Common functions and methods ----------------------------- - -For the following functions (and subchapters), -`v`, `v1`, `v2` are vectors, -`p1`, `p2` are position vectors, -`s` is a scalar (a number), -vectors are written like this: `(x, y, z)`: - -* `vector.new([a[, b, c]])`: - * Returns a new vector `(a, b, c)`. - * Deprecated: `vector.new()` does the same as `vector.zero()` and - `vector.new(v)` does the same as `vector.copy(v)` -* `vector.zero()`: - * Returns a new vector `(0, 0, 0)`. -* `vector.random_direction()`: - * Returns a new vector of length 1, pointing into a direction chosen uniformly at random. -* `vector.copy(v)`: - * Returns a copy of the vector `v`. -* `vector.from_string(s[, init])`: - * Returns `v, np`, where `v` is a vector read from the given string `s` and - `np` is the next position in the string after the vector. - * Returns `nil` on failure. - * `s`: Has to begin with a substring of the form `"(x, y, z)"`. Additional - spaces, leaving away commas and adding an additional comma to the end - is allowed. - * `init`: If given starts looking for the vector at this string index. -* `vector.to_string(v)`: - * Returns a string of the form `"(x, y, z)"`. - * `tostring(v)` does the same. -* `vector.direction(p1, p2)`: - * Returns a vector of length 1 with direction `p1` to `p2`. - * If `p1` and `p2` are identical, returns `(0, 0, 0)`. -* `vector.distance(p1, p2)`: - * Returns zero or a positive number, the distance between `p1` and `p2`. -* `vector.length(v)`: - * Returns zero or a positive number, the length of vector `v`. -* `vector.normalize(v)`: - * Returns a vector of length 1 with direction of vector `v`. - * If `v` has zero length, returns `(0, 0, 0)`. -* `vector.floor(v)`: - * Returns a vector, each dimension rounded down. -* `vector.ceil(v)`: - * Returns a vector, each dimension rounded up. -* `vector.round(v)`: - * Returns a vector, each dimension rounded to nearest integer. - * At a multiple of 0.5, rounds away from zero. -* `vector.sign(v, tolerance)`: - * Returns a vector where `math.sign` was called for each component. - * See [Helper functions](#helper-functions) for details. -* `vector.abs(v)`: - * Returns a vector with absolute values for each component. -* `vector.apply(v, func, ...)`: - * Returns a vector where the function `func` has been applied to each - component. - * `...` are optional arguments passed to `func`. -* `vector.combine(v, w, func)`: - * Returns a vector where the function `func` has combined both components of `v` and `w` - for each component -* `vector.equals(v1, v2)`: - * Returns a boolean, `true` if the vectors are identical. -* `vector.sort(v1, v2)`: - * Returns in order minp, maxp vectors of the cuboid defined by `v1`, `v2`. -* `vector.angle(v1, v2)`: - * Returns the angle between `v1` and `v2` in radians. -* `vector.dot(v1, v2)`: - * Returns the dot product of `v1` and `v2`. -* `vector.cross(v1, v2)`: - * Returns the cross product of `v1` and `v2`. -* `vector.offset(v, x, y, z)`: - * Returns the sum of the vectors `v` and `(x, y, z)`. -* `vector.check(v)`: - * Returns a boolean value indicating whether `v` is a real vector, eg. created - by a `vector.*` function. - * Returns `false` for anything else, including tables like `{x=3,y=1,z=4}`. -* `vector.in_area(pos, min, max)`: - * Returns a boolean value indicating if `pos` is inside area formed by `min` and `max`. - * `min` and `max` are inclusive. - * If `min` is bigger than `max` on some axis, function always returns false. - * You can use `vector.sort` if you have two vectors and don't know which are the minimum and the maximum. -* `vector.random_in_area(min, max)`: - * Returns a random integer position in area formed by `min` and `max` - * `min` and `max` are inclusive. - * You can use `vector.sort` if you have two vectors and don't know which are the minimum and the maximum. - -For the following functions `x` can be either a vector or a number: - -* `vector.add(v, x)`: - * Returns a vector. - * If `x` is a vector: Returns the sum of `v` and `x`. - * If `x` is a number: Adds `x` to each component of `v`. -* `vector.subtract(v, x)`: - * Returns a vector. - * If `x` is a vector: Returns the difference of `v` subtracted by `x`. - * If `x` is a number: Subtracts `x` from each component of `v`. -* `vector.multiply(v, s)`: - * Returns a scaled vector. - * Deprecated: If `s` is a vector: Returns the Schur product. -* `vector.divide(v, s)`: - * Returns a scaled vector. - * Deprecated: If `s` is a vector: Returns the Schur quotient. - -Operators ---------- - -Operators can be used if all of the involved vectors have metatables: - -* `v1 == v2`: - * Returns whether `v1` and `v2` are identical. -* `-v`: - * Returns the additive inverse of v. -* `v1 + v2`: - * Returns the sum of both vectors. - * Note: `+` cannot be used together with scalars. -* `v1 - v2`: - * Returns the difference of `v1` subtracted by `v2`. - * Note: `-` cannot be used together with scalars. -* `v * s` or `s * v`: - * Returns `v` scaled by `s`. -* `v / s`: - * Returns `v` scaled by `1 / s`. - -Rotation-related functions --------------------------- - -For the following functions `a` is an angle in radians and `r` is a rotation -vector (`{x = , y = , z = }`) where pitch, yaw and roll are -angles in radians. - -* `vector.rotate(v, r)`: - * Applies the rotation `r` to `v` and returns the result. - * Uses (extrinsic) Z-X-Y rotation order and is right-handed, consistent with `ObjectRef:set_rotation`. - * `vector.rotate(vector.new(0, 0, 1), r)` and - `vector.rotate(vector.new(0, 1, 0), r)` return vectors pointing - forward and up relative to an entity's rotation `r`. -* `vector.rotate_around_axis(v1, v2, a)`: - * Returns `v1` rotated around axis `v2` by `a` radians according to - the right hand rule. -* `vector.dir_to_rotation(direction[, up])`: - * Returns a rotation vector for `direction` pointing forward using `up` - as the up vector. - * If `up` is omitted, the roll of the returned vector defaults to zero. - * Otherwise `direction` and `up` need to be vectors in a 90 degree angle to each other. - -Further helpers ---------------- - -There are more helper functions involving vectors, but they are listed elsewhere -because they only work on specific sorts of vectors or involve things that are not -vectors. - -For example: - -* `core.hash_node_position` (Only works on node positions.) -* `core.dir_to_wallmounted` (Involves wallmounted param2 values.) - - - - -Helper functions -================ - -* `dump2(obj, name, dumped)`: returns a string which makes `obj` - human-readable, handles reference loops. - * `obj`: arbitrary variable - * `name`: string, default: `"_"` - * `dumped`: table, default: `{}` -* `dump(value, indent)`: returns a string which makes `value` human-readable - * `value`: arbitrary value - * Circular references are supported. Every table is dumped only once. - * `indent`: string to use for indentation, default: `"\t"` - * `""` disables indentation & line breaks (compact output) -* `math.hypot(x, y)` - * Get the hypotenuse of a triangle with legs x and y. - Useful for distance calculation. -* `math.sign(x, tolerance)`: returns `-1`, `0` or `1` - * Get the sign of a number. - * tolerance: number, default: `0.0` - * If the absolute value of `x` is within the `tolerance` or `x` is NaN, - `0` is returned. -* `math.factorial(x)`: returns the factorial of `x` -* `math.round(x)`: Returns `x` rounded to the nearest integer. - * At a multiple of 0.5, rounds away from zero. -* `string.split(str, separator, include_empty, max_splits, sep_is_pattern)` - * `separator`: string, cannot be empty, default: `","` - * `include_empty`: boolean, default: `false` - * `max_splits`: number, if it's negative, splits aren't limited, - default: `-1` - * `sep_is_pattern`: boolean, it specifies whether separator is a plain - string or a pattern (regex), default: `false` - * e.g. `"a,b":split","` returns `{"a","b"}` -* `string:trim()`: returns the string without whitespace pre- and suffixes - * e.g. `"\n \t\tfoo bar\t ":trim()` returns `"foo bar"` -* `core.wrap_text(str, limit, as_table)`: returns a string or table - * Adds newlines to the string to keep it within the specified character - limit - * Note that the returned lines may be longer than the limit since it only - splits at word borders. - * `limit`: number, maximal amount of characters in one line - * `as_table`: boolean, if set to true, a table of lines instead of a string - is returned, default: `false` -* `core.pos_to_string(pos, decimal_places)`: returns string `"(X,Y,Z)"` - * `pos`: table {x=X, y=Y, z=Z} - * Converts the position `pos` to a human-readable, printable string - * `decimal_places`: number, if specified, the x, y and z values of - the position are rounded to the given decimal place. -* `core.string_to_pos(string)`: returns a position or `nil` - * Same but in reverse. - * If the string can't be parsed to a position, nothing is returned. -* `core.string_to_area("(X1, Y1, Z1) (X2, Y2, Z2)", relative_to)`: - * returns two positions - * Converts a string representing an area box into two positions - * X1, Y1, ... Z2 are coordinates - * `relative_to`: Optional. If set to a position, each coordinate - can use the tilde notation for relative positions - * Tilde notation - * `"~"`: Relative coordinate - * `"~"`: Relative coordinate plus `` - * Example: `core.string_to_area("(1,2,3) (~5,~-5,~)", {x=10,y=10,z=10})` - returns `{x=1,y=2,z=3}, {x=15,y=5,z=10}` -* `core.formspec_escape(string)`: returns a string - * escapes the characters "[", "]", "\", "," and ";", which cannot be used - in formspecs. -* `core.is_yes(arg)` - * returns true if passed 'y', 'yes', 'true' or a number that isn't zero. -* `core.is_nan(arg)` - * returns true when the passed number represents NaN. -* `core.get_us_time()` - * returns time with microsecond precision. May not return wall time. -* `table.copy(table)`: returns a table - * returns a deep copy of `table` - * strips metatables, but this may change in the future -* `table.copy_with_metatables(table)` - * since 5.12 - * `table` can also be non-table value, which will be returned as-is - * preserves metatables as they are -* `table.indexof(list, val)`: returns the smallest numerical index containing - the value `val` in the table `list`. Non-numerical indices are ignored. - If `val` could not be found, `-1` is returned. `list` must not have - negative indices. -* `table.keyof(table, val)`: returns the key containing - the value `val` in the table `table`. If multiple keys contain `val`, - it is unspecified which key will be returned. - If `val` could not be found, `nil` is returned. -* `table.insert_all(table, other_table)`: - * Appends all values in `other_table` to `table` - uses `#table + 1` to - find new indices. -* `table.key_value_swap(t)`: returns a table with keys and values swapped - * If multiple keys in `t` map to the same value, it is unspecified which - value maps to that key. -* `table.shuffle(table, [from], [to], [random_func])`: - * Shuffles elements `from` to `to` in `table` in place - * `from` defaults to `1` - * `to` defaults to `#table` - * `random_func` defaults to `math.random`. This function receives two - integers as arguments and should return a random integer inclusively - between them. -* `core.pointed_thing_to_face_pos(placer, pointed_thing)`: returns a - position. - * returns the exact position on the surface of a pointed node -* `core.get_tool_wear_after_use(uses [, initial_wear])` - * Simulates a tool being used once and returns the added wear, - such that, if only this function is used to calculate wear, - the tool will break exactly after `uses` times of uses - * `uses`: Number of times the tool can be used - * `initial_wear`: The initial wear the tool starts with (default: 0) -* `core.get_dig_params(groups, tool_capabilities [, wear])`: - Simulates an item that digs a node. - Returns a table with the following fields: - * `diggable`: `true` if node can be dug, `false` otherwise. - * `time`: Time it would take to dig the node. - * `wear`: How much wear would be added to the tool (ignored for non-tools). - `time` and `wear` are meaningless if node's not diggable - Parameters: - * `groups`: Table of the node groups of the node that would be dug - * `tool_capabilities`: Tool capabilities table of the item - * `wear`: Amount of wear the tool starts with (default: 0) -* `core.get_hit_params(groups, tool_capabilities [, time_from_last_punch [, wear]])`: - Simulates an item that punches an object. - Returns a table with the following fields: - * `hp`: How much damage the punch would cause (between -65535 and 65535). - * `wear`: How much wear would be added to the tool (ignored for non-tools). - Parameters: - * `groups`: Damage groups of the object - * `tool_capabilities`: Tool capabilities table of the item - * `time_from_last_punch`: time in seconds since last punch action - * `wear`: Amount of wear the item starts with (default: 0) -* `core.file_exists(path)` - * Returns true if a file exists - * Use if you only want to check if a file exists, don't use to check if you can open it (example: you can check if a schematic exists before loading it) - - - - -Translations -============ - -Texts can be translated client-side with the help of `core.translate` and -translation files. - -Translating a string --------------------- - -Two functions are provided to translate strings: `core.translate` and -`core.get_translator`. - -* `core.get_translator(textdomain)` is a simple wrapper around - `core.translate` and `core.translate_n`. - After `local S, PS = core.get_translator(textdomain)`, we have - `S(str, ...)` equivalent to `core.translate(textdomain, str, ...)`, and - `PS(str, str_plural, n, ...)` to `core.translate_n(textdomain, str, str_plural, n, ...)`. - It is intended to be used in the following way, so that it avoids verbose - repetitions of `core.translate`: - - ```lua - local S, PS = core.get_translator(textdomain) - S(str, ...) - ``` - - As an extra commodity, if `textdomain` is nil, it is assumed to be "" instead. - -* `core.translate(textdomain, str, ...)` translates the string `str` with - the given `textdomain` for disambiguation. The textdomain must match the - textdomain specified in the translation file in order to get the string - translated. This can be used so that a string is translated differently in - different contexts. - It is advised to use the name of the mod as textdomain whenever possible, to - avoid clashes with other mods. - This function must be given a number of arguments equal to the number of - arguments the translated string expects. - Arguments are literal strings -- they will not be translated. - -* `core.translate_n(textdomain, str, str_plural, n, ...)` translates the - string `str` with the given `textdomain` for disambiguaion. The value of - `n`, which must be a nonnegative integer, is used to decide whether to use - the singular or the plural version of the string. Depending on the locale of - the client, the choice between singular and plural might be more complicated, - but the choice will be done automatically using the value of `n`. - - You can read https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html - for more details on the differences of plurals between languages. - - Also note that plurals are only handled in .po or .mo files, and not in .tr files. - -For instance, suppose we want to greet players when they join and provide a -command that shows the amount of time since the player joined. We can do the -following: - -```lua -local S, PS = core.get_translator("hello") -core.register_on_joinplayer(function(player) - local name = player:get_player_name() - core.chat_send_player(name, S("Hello @1, how are you today?", name)) -end) -core.register_chatcommand("playtime", { - func = function(name) - local last_login = core.get_auth_handler().get_auth(name).last_login - local playtime = math.floor((last_login-os.time())/60) - return true, PS( - "You have been playing for @1 minute.", - "You have been playing for @1 minutes.", - minutes, tostring(minutes)) - end, -}) -``` - -When someone called "CoolGuy" joins the game with an old client or a client -that does not have localization enabled, they will see `Hello CoolGuy, how are -you today?`. If they use the `/playtime` command, they will see `You have been -playing for 1 minute` or (for example) `You have been playing for 4 minutes.` - -However, if we have for instance a translation file named `hello.de.po` -containing the following: - -```po -msgid "" -msgstr "" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -msgid "Hello @1, how are you today?" -msgstr "Hallo @1, wie geht es dir heute?" - -msgid "You have been playing for @1 minute." -msgid_plural "You have been playing for @1 minutes." -msgstr[0] "Du spielst seit @1 Minute." -msgstr[1] "Du spielst seit @1 Minuten." -``` - -and CoolGuy has set a German locale, they will see `Hallo CoolGuy, wie geht es -dir heute?` when they join, and the `/playtime` command will show them `Du -spielst seit 1 Minute.` or (for example) `Du spielst seit 4 Minuten.` - -Creating and updating translation files ---------------------------------------- - -As an alternative to writing translation files by hand (as shown in the above -example), it is also possible to generate translation files based on the source -code. - -It is recommended to first generate a translation template. The translation -template includes translatable strings that translators can directly work on. -After creating the `locale` directory, a translation template for the above -example using the following command: - -```sh -xgettext -L lua -kS -kPS:1,2 -kcore.translate:1c,2 -kcore.translate_n:1c,2,3 \ - -d hello -o locale/hello.pot *.lua -``` - -The above command can also be used to update the translation template when new -translatable strings are added. - -The German translator can then create the translation file with - -```sh -msginit -l de -i locale/hello.pot -o locale/hello.de.po -``` - -and provide the translations by editing `locale/hello.de.po`. - -The translation file can be updated using - -```sh -msgmerge -U locale/hello.de.po locale/hello.pot -``` - -Refer to the [Gettext manual](https://www.gnu.org/software/gettext/manual/) for -further information on creating and updating translation files. - -Operations on translated strings --------------------------------- - -The output of `core.translate` is a string, with escape sequences adding -additional information to that string so that it can be translated on the -different clients. In particular, you can't expect operations like string.length -to work on them like you would expect them to, or string.gsub to work in the -expected manner. However, string concatenation will still work as expected -(note that you should only use this for things like formspecs; do not translate -sentences by breaking them into parts; arguments should be used instead), and -operations such as `core.colorize` which are also concatenation. - -Old translation file format ---------------------------- - -A translation file has the suffix `.[lang].tr`, where `[lang]` is the language -it corresponds to. It must be put into the `locale` subdirectory of the mod. -The file should be a text file, with the following format: - -* Lines beginning with `# textdomain:` (the space is significant) can be used - to specify the text domain of all following translations in the file. -* All other empty lines or lines beginning with `#` are ignored. -* Other lines should be in the format `original=translated`. Both `original` - and `translated` can contain escape sequences beginning with `@` to insert - arguments, literal `@`, `=` or newline (See [Escapes](#escapes) below). - There must be no extraneous whitespace around the `=` or at the beginning or - the end of the line. - -Using the earlier example of greeting the player, the translation file would be - -``` -# textdomain: hello -Hello @1, how are you today?=Hallo @1, wie geht es dir heute? -``` - -For old translation files, consider using the script `mod_translation_updater.py` -in the Luanti [modtools](https://github.com/luanti-org/modtools) repository to -generate and update translation files automatically from the Lua sources. - -Gettext translation file format -------------------------------- - -Gettext files can also be used as translations. A translation file has the suffix -`.[lang].po` or `.[lang].mo`, depending on whether it is compiled or not, and must -also be placed in the `locale` subdirectory of the mod. The value of `textdomain` -is `msgctxt` in the gettext files. If `msgctxt` is not provided, the name of the -translation file is used instead. - -A typical entry in a `.po` file would look like: - -```po -msgctxt "textdomain" -msgid "Hello world!" -msgstr "Bonjour le monde!" -``` - -Escapes -------- - -Strings that need to be translated can contain several escapes, preceded by `@`. - -* `@@` acts as a literal `@`. -* `@n`, where `n` is a digit between 1 and 9, is an argument for the translated - string that will be inlined when translated. Due to how translations are - implemented, the original translation string **must** have its arguments in - increasing order, without gaps or repetitions, starting from 1. -* `@=` acts as a literal `=`. It is not required in strings given to - `core.translate`, but is in translation files to avoid being confused - with the `=` separating the original from the translation. -* `@\n` (where the `\n` is a literal newline) acts as a literal newline. - As with `@=`, this escape is not required in strings given to - `core.translate`, but is in translation files. -* `@n` acts as a literal newline as well. - -Server side translations ------------------------- - -On some specific cases, server translation could be useful. For example, filter -a list on labels and send results to client. A method is supplied to achieve -that: - -`core.get_translated_string(lang_code, string)`: resolves translations in -the given string just like the client would, using the translation files for -`lang_code`. For this to have any effect, the string needs to contain translation -markup, e.g. `core.get_translated_string("fr", S("Hello"))`. - -The `lang_code` to use for a given player can be retrieved from -the table returned by `core.get_player_information(name)`. - -IMPORTANT: This functionality should only be used for sorting, filtering or similar purposes. -You do not need to use this to get translated strings to show up on the client. - -Translating content meta ------------------------- - -You can translate content meta, such as `title` and `description`, by placing -translations in a `locale/DOMAIN.LANG.tr` file. The textdomain defaults to the -content name, but can be customised using `textdomain` in the content's .conf. - -### Mods and Texture Packs - -Say you have a mod called `mymod` with a short description in mod.conf: - -``` -description = This is the short description -``` - -Luanti will look for translations in the `mymod` textdomain as there's no -textdomain specified in mod.conf. For example, `mymod/locale/mymod.fr.tr`: - -``` -# textdomain:mymod -This is the short description=Voici la description succincte -``` - -### Games and Modpacks - -For games and modpacks, Luanti will look for the textdomain in all mods. - -Say you have a game called `mygame` with the following game.conf: - -``` -description = This is the game's short description -textdomain = mygame -``` - -Luanti will then look for the textdomain `mygame` in all mods, for example, -`mygame/mods/anymod/locale/mygame.fr.tr`. Note that it is still recommended that your -textdomain match the mod name, but this isn't required. - - - -Fractal value noise -=================== - -Value noise creates a continuously-varying value depending on the input values. -It is similar to Perlin noise, but may exhibit more geometric artifacts, -as it interpolates between values and not between gradients as in Perlin noise. - -Usually in Luanti the input values are either 2D or 3D coordinates in nodes. -The result is used during map generation to create the terrain shape, vary heat -and humidity to distribute biomes, vary the density of decorations or vary the -structure of ores. - -Structure of fractal value noise --------------------------------- - -An 'octave' is a simple noise generator that outputs a value between -1 and 1. -The smooth wavy noise it generates has a single characteristic scale, almost -like a 'wavelength', so on its own does not create fine detail. -Due to this fractal value noise combines several octaves to create variation on -multiple scales. Each additional octave has a smaller 'wavelength' than the -previous. - -This combination results in noise varying very roughly between -2.0 and 2.0 and -with an average value of 0.0, so `scale` and `offset` are then used to multiply -and offset the noise variation. - -The final fractal value noise variation is created as follows: - -``` -noise = offset + scale * (octave1 + - octave2 * persistence + - octave3 * persistence ^ 2 + - octave4 * persistence ^ 3 + - ...) -``` - -Noise Parameters ----------------- - -Noise Parameters are commonly called `NoiseParams`. - -### `offset` - -After the multiplication by `scale` this is added to the result and is the final -step in creating the noise value. -Can be positive or negative. - -### `scale` - -Once all octaves have been combined, the result is multiplied by this. -Can be positive or negative. - -### `spread` - -For octave1, this is roughly the change of input value needed for a very large -variation in the noise value generated by octave1. It is almost like a -'wavelength' for the wavy noise variation. -Each additional octave has a 'wavelength' that is smaller than the previous -octave, to create finer detail. `spread` will therefore roughly be the typical -size of the largest structures in the final noise variation. - -`spread` is a vector with values for x, y, z to allow the noise variation to be -stretched or compressed in the desired axes. -Values are positive numbers. - -### `seed` - -This is a whole number that determines the entire pattern of the noise -variation. Altering it enables different noise patterns to be created. -With other parameters equal, different seeds produce different noise patterns -and identical seeds produce identical noise patterns. - -For this parameter you can randomly choose any whole number. Usually it is -preferable for this to be different from other seeds, but sometimes it is useful -to be able to create identical noise patterns. - -In some noise APIs the world seed is added to the seed specified in noise -parameters. This is done to make the resulting noise pattern vary in different -worlds, and be 'world-specific'. - -### `octaves` - -The number of simple noise generators that are combined. -A whole number, 1 or more. -Each additional octave adds finer detail to the noise but also increases the -noise calculation load. -3 is a typical minimum for a high quality, complex and natural-looking noise -variation. 1 octave has a slight 'gridlike' appearance. - -Choose the number of octaves according to the `spread` and `lacunarity`, and the -size of the finest detail you require. For example: -if `spread` is 512 nodes, `lacunarity` is 2.0 and finest detail required is 16 -nodes, octaves will be 6 because the 'wavelengths' of the octaves will be -512, 256, 128, 64, 32, 16 nodes. -Warning: If the 'wavelength' of any octave falls below 1 an error will occur. - -### `persistence` - -Each additional octave has an amplitude that is the amplitude of the previous -octave multiplied by `persistence`, to reduce the amplitude of finer details, -as is often helpful and natural to do so. -Since this controls the balance of fine detail to large-scale detail -`persistence` can be thought of as the 'roughness' of the noise. - -A positive or negative non-zero number, often between 0.3 and 1.0. -A common medium value is 0.5, such that each octave has half the amplitude of -the previous octave. -This may need to be tuned when altering `lacunarity`; when doing so consider -that a common medium value is 1 / lacunarity. - -Instead of `persistence`, the key `persist` may be used to the same effect. - -### `lacunarity` - -Each additional octave has a 'wavelength' that is the 'wavelength' of the -previous octave multiplied by 1 / lacunarity, to create finer detail. -'lacunarity' is often 2.0 so 'wavelength' often halves per octave. - -A positive number no smaller than 1.0. -Values below 2.0 create higher quality noise at the expense of requiring more -octaves to cover a particular range of 'wavelengths'. - -### `flags` - -Leave this field unset for no special handling. -Currently supported are `defaults`, `eased` and `absvalue`: - -#### `defaults` - -Specify this if you would like to keep auto-selection of eased/not-eased while -specifying some other flags. - -#### `eased` - -Maps noise gradient values onto a quintic S-curve before performing -interpolation. This results in smooth, rolling noise. -Disable this (`noeased`) for sharp-looking noise with a slightly gridded -appearance. -If no flags are specified (or defaults is), 2D noise is eased and 3D noise is -not eased. -Easing a 3D noise significantly increases the noise calculation load, so use -with restraint. - -#### `absvalue` - -The absolute value of each octave's noise variation is used when combining the -octaves. The final value noise variation is created as follows: - -``` -noise = offset + scale * (abs(octave1) + - abs(octave2) * persistence + - abs(octave3) * persistence ^ 2 + - abs(octave4) * persistence ^ 3 + - ...) -``` - -### Format example - -For 2D or 3D value noise or value noise maps: - -```lua -np_terrain = { - offset = 0, - scale = 1, - spread = {x = 500, y = 500, z = 500}, - seed = 571347, - octaves = 5, - persistence = 0.63, - lacunarity = 2.0, - flags = "defaults, absvalue", -} -``` - -For 2D noise the Z component of `spread` is still defined but is ignored. -A single noise parameter table can be used for 2D or 3D noise. - - - - -Ores -==== - -Ore types ---------- - -These tell in what manner the ore is generated. - -All default ores are of the uniformly-distributed scatter type. - -### `scatter` - -Randomly chooses a location and generates a cluster of ore. - -If `noise_params` is specified, the ore will be placed if the 3D value noise -at that point is greater than the `noise_threshold`, giving the ability to -create a non-equal distribution of ore. - -### `sheet` - -Creates a sheet of ore in a blob shape according to the 2D value noise -described by `noise_params` and `noise_threshold`. This is essentially an -improved version of the so-called "stratus" ore seen in some unofficial mods. - -This sheet consists of vertical columns of uniform randomly distributed height, -varying between the inclusive range `column_height_min` and `column_height_max`. -If `column_height_min` is not specified, this parameter defaults to 1. -If `column_height_max` is not specified, this parameter defaults to `clust_size` -for reverse compatibility. New code should prefer `column_height_max`. - -The `column_midpoint_factor` parameter controls the position of the column at -which ore emanates from. -If 1, columns grow upward. If 0, columns grow downward. If 0.5, columns grow -equally starting from each direction. -`column_midpoint_factor` is a decimal number ranging in value from 0 to 1. If -this parameter is not specified, the default is 0.5. - -The ore parameters `clust_scarcity` and `clust_num_ores` are ignored for this -ore type. - -### `puff` - -Creates a sheet of ore in a cloud-like puff shape. - -As with the `sheet` ore type, the size and shape of puffs are described by -`noise_params` and `noise_threshold` and are placed at random vertical -positions within the currently generated chunk. - -The vertical top and bottom displacement of each puff are determined by the -noise parameters `np_puff_top` and `np_puff_bottom`, respectively. - -### `blob` - -Creates a deformed sphere of ore according to 3d value noise described by -`noise_params`. The maximum size of the blob is `clust_size`, and -`clust_scarcity` has the same meaning as with the `scatter` type. - -### `vein` - -Creates veins of ore varying in density by according to the intersection of two -instances of 3d value noise with different seeds, both described by -`noise_params`. - -`random_factor` varies the influence random chance has on placement of an ore -inside the vein, which is `1` by default. Note that modifying this parameter -may require adjusting `noise_threshold`. - -The parameters `clust_scarcity`, `clust_num_ores`, and `clust_size` are ignored -by this ore type. - -This ore type is difficult to control since it is sensitive to small changes. -The following is a decent set of parameters to work from: - -```lua -noise_params = { - offset = 0, - scale = 3, - spread = {x=200, y=200, z=200}, - seed = 5390, - octaves = 4, - persistence = 0.5, - lacunarity = 2.0, - flags = "eased", -}, -noise_threshold = 1.6 -``` - -**WARNING**: Use this ore type *very* sparingly since it is ~200x more -computationally expensive than any other ore. - -### `stratum` - -Creates a single undulating ore stratum that is continuous across mapchunk -borders and horizontally spans the world. - -The 2D value noise described by `noise_params` defines the Y coordinate of -the stratum midpoint. The 2D value noise described by `np_stratum_thickness` -defines the stratum's vertical thickness (in units of nodes). Due to being -continuous across mapchunk borders the stratum's vertical thickness is -unlimited. - -If the noise parameter `noise_params` is omitted the ore will occur from y_min -to y_max in a simple horizontal stratum. - -A parameter `stratum_thickness` can be provided instead of the noise parameter -`np_stratum_thickness`, to create a constant thickness. - -Leaving out one or both noise parameters makes the ore generation less -intensive, useful when adding multiple strata. - -`y_min` and `y_max` define the limits of the ore generation and for performance -reasons should be set as close together as possible but without clipping the -stratum's Y variation. - -Each node in the stratum has a 1-in-`clust_scarcity` chance of being ore, so a -solid-ore stratum would require a `clust_scarcity` of 1. - -The parameters `clust_num_ores`, `clust_size`, `noise_threshold` and -`random_factor` are ignored by this ore type. - -Ore attributes --------------- - -See section [Flag Specifier Format](#flag-specifier-format). - -Currently supported flags: -`puff_cliffs`, `puff_additive_composition`. - -### `puff_cliffs` - -If set, puff ore generation will not taper down large differences in -displacement when approaching the edge of a puff. This flag has no effect for -ore types other than `puff`. - -### `puff_additive_composition` - -By default, when noise described by `np_puff_top` or `np_puff_bottom` results -in a negative displacement, the sub-column at that point is not generated. With -this attribute set, puff ore generation will instead generate the absolute -difference in noise displacement values. This flag has no effect for ore types -other than `puff`. - - - - -Decoration types -================ - -The varying types of decorations that can be placed. - -`simple` --------- - -Creates a 1 times `H` times 1 column of a specified node (or a random node from -a list, if a decoration list is specified). Can specify a certain node it must -spawn next to, such as water or lava, for example. Can also generate a -decoration of random height between a specified lower and upper bound. -This type of decoration is intended for placement of grass, flowers, cacti, -papyri, waterlilies and so on. - -`schematic` ------------ - -Copies a box of `MapNodes` from a specified schematic file (or raw description). -Can specify a probability of a node randomly appearing when placed. -This decoration type is intended to be used for multi-node sized discrete -structures, such as trees, cave spikes, rocks, and so on. - -`lsystem` ------------ - -Generates a L-system tree at the position where the decoration is placed. -Uses the same L-system as `core.spawn_tree`, but is faster than using it manually. -The `treedef` field in the decoration definition is used for the tree definition. - - - -Schematics -========== - -Schematic specifier --------------------- - -A schematic specifier identifies a schematic by either a filename to a -Luanti Schematic file (`.mts`) or through raw data supplied through Lua, -in the form of a table. This table specifies the following fields: - -* The `size` field is a 3D vector containing the dimensions of the provided - schematic. (required field) -* The `yslice_prob` field is a table of {ypos, prob} slice tables. A slice table - sets the probability of a particular horizontal slice of the schematic being - placed. (optional field) - `ypos` = 0 for the lowest horizontal slice of a schematic. - The default of `prob` is 255. -* The `data` field is a flat table of MapNode tables making up the schematic, - in the order of `[z [y [x]]]`. (required field) - Each MapNode table contains: - * `name`: the name of the map node to place (required) - * `prob` (alias `param1`): the probability of this node being placed - (default: 255) - * `param2`: the raw param2 value of the node being placed onto the map - (default: 0) - * `force_place`: boolean representing if the node should forcibly overwrite - any previous contents (default: false) - -About probability values: - -* A probability value of `0` or `1` means that node will never appear - (0% chance). -* A probability value of `254` or `255` means the node will always appear - (100% chance). -* If the probability value `p` is greater than `1`, then there is a - `(p / 256 * 100)` percent chance that node will appear when the schematic is - placed on the map. - -Schematic attributes --------------------- - -See section [Flag Specifier Format](#flag-specifier-format). - -Currently supported flags: `place_center_x`, `place_center_y`, `place_center_z`, - `force_placement`. - -* `place_center_x`: Placement of this decoration is centered along the X axis. -* `place_center_y`: Placement of this decoration is centered along the Y axis. -* `place_center_z`: Placement of this decoration is centered along the Z axis. -* `force_placement`: Schematic nodes other than "ignore" will replace existing - nodes. - - - - -Lua Voxel Manipulator -===================== - -About VoxelManip ----------------- - -VoxelManip is a scripting interface to the internal 'Map Voxel Manipulator' -facility. The purpose of this object is for fast, low-level, bulk access to -reading and writing Map content. As such, setting map nodes through VoxelManip -will lack many of the higher level features and concepts you may be used to -with other methods of setting nodes. For example, nodes will not have their -construction and destruction callbacks run, and no rollback information is -logged. - -It is important to note that VoxelManip is designed for speed, and *not* ease -of use or flexibility. If your mod requires a map manipulation facility that -will handle 100% of all edge cases, or the use of high level node placement -features, perhaps `core.set_node()` is better suited for the job. - -In addition, VoxelManip might not be faster, or could even be slower, for your -specific use case. VoxelManip is most effective when setting large areas of map -at once - for example, if only setting a 3x3x3 node area, a -`core.set_node()` loop may be more optimal. Always profile code using both -methods of map manipulation to determine which is most appropriate for your -usage. - -A recent simple test of setting cubic areas showed that `core.set_node()` -is faster than a VoxelManip for a 3x3x3 node cube or smaller. - -Using VoxelManip ----------------- - -A VoxelManip object can be created any time using either: -`VoxelManip([p1, p2])`, or `core.get_voxel_manip([p1, p2])`. - -If the optional position parameters are present for either of these routines, -the specified region will be pre-loaded into the VoxelManip object on creation. -Otherwise, the area of map you wish to manipulate must first be loaded into the -VoxelManip object using `VoxelManip:read_from_map()`, or an empty one created -with `VoxelManip:initialize()`. - -Note that `VoxelManip:read_from_map()` returns two position vectors. The region -formed by these positions indicate the minimum and maximum (respectively) -positions of the area actually loaded in the VoxelManip, which may be larger -than the area requested. For convenience, the loaded area coordinates can also -be queried any time after loading map data with `VoxelManip:get_emerged_area()`. - -Now that the VoxelManip object is populated with map data, your mod can fetch a -copy of this data using either of two methods. `VoxelManip:get_node_at()`, -which retrieves an individual node in a MapNode formatted table at the position -requested. This is the simplest method to use, but also the slowest. - -Nodes in a VoxelManip object may also be read in bulk to a flat array table -using: - -* `VoxelManip:get_data()` for node content (in Content ID form, see section - [Content IDs](#content-ids), -* `VoxelManip:get_light_data()` for node param (usually light levels), and -* `VoxelManip:get_param2_data()` for the node type-dependent "param2" values. - -See section [Flat array format](#flat-array-format) for more details. - -It is very important to understand that the tables returned by any of the above -three functions represent a snapshot of the VoxelManip's internal state at the -time of the call. This copy of the data will not magically update itself if -another function modifies the internal VoxelManip state. -Any functions that modify a VoxelManip's contents work on the VoxelManip's -internal state unless otherwise explicitly stated. - -Once the bulk data has been edited to your liking, the internal VoxelManip -state can be set using: - -* `VoxelManip:set_data()` or -* `VoxelManip:set_light_data()` or -* `VoxelManip:set_param2_data()` - -The parameter to each of the above three functions can use any table at all in -the same flat array format as produced by `get_data()` etc. and is not required -to be a table retrieved from `get_data()`. - -Once the internal VoxelManip state has been modified to your liking, the -changes can be committed back to the map by calling `VoxelManip:write_to_map()`. - -### Flat array format - -Let - `Nx = p2.X - p1.X + 1`, - `Ny = p2.Y - p1.Y + 1`, and - `Nz = p2.Z - p1.Z + 1`. - -Then, for a loaded region of p1..p2, this array ranges from `1` up to and -including the value of the expression `Nx * Ny * Nz`. - -Positions offset from p1 are present in the array with the format of: - - [ - (0, 0, 0), (1, 0, 0), (2, 0, 0), ... (Nx, 0, 0), - (0, 1, 0), (1, 1, 0), (2, 1, 0), ... (Nx, 1, 0), - ... - (0, Ny, 0), (1, Ny, 0), (2, Ny, 0), ... (Nx, Ny, 0), - (0, 0, 1), (1, 0, 1), (2, 0, 1), ... (Nx, 0, 1), - ... - (0, Ny, 2), (1, Ny, 2), (2, Ny, 2), ... (Nx, Ny, 2), - ... - (0, Ny, Nz), (1, Ny, Nz), (2, Ny, Nz), ... (Nx, Ny, Nz) - ] - -and the array index for a position p contained completely in p1..p2 is: - -`(p.Z - p1.Z) * Ny * Nx + (p.Y - p1.Y) * Nx + (p.X - p1.X) + 1` - -Note that this is the same "flat 3D array" format as -`ValueNoiseMap:get3dMap_flat()`. -VoxelArea objects (see section [`VoxelArea`](#voxelarea)) can be used to simplify calculation -of the index for a single point in a flat VoxelManip array. - -### Content IDs - -A Content ID is a unique integer identifier for a specific node type. -These IDs are used by VoxelManip in place of the node name string for -`VoxelManip:get_data()` and `VoxelManip:set_data()`. You can use -`core.get_content_id()` to look up the Content ID for the specified node -name, and `core.get_name_from_content_id()` to look up the node name string -for a given Content ID. -After registration of a node, its Content ID will remain the same throughout -execution of the mod. -Note that the node being queried needs to have already been been registered. - -The following builtin node types have their Content IDs defined as constants: - -* `core.CONTENT_UNKNOWN`: ID for "unknown" nodes -* `core.CONTENT_AIR`: ID for "air" nodes -* `core.CONTENT_IGNORE`: ID for "ignore" nodes - -### Mapgen VoxelManip objects - -Inside of `on_generated()` callbacks, it is possible to retrieve the same -VoxelManip object used by the core's Map Generator (commonly abbreviated -Mapgen). Most of the rules previously described still apply but with a few -differences: - -* The Mapgen VoxelManip object is retrieved using: - `core.get_mapgen_object("voxelmanip")` - -* This VoxelManip object already has the region of map just generated loaded - into it; it's not necessary to call `VoxelManip:read_from_map()`. - Note that the region of map it has loaded is NOT THE SAME as the `minp`, `maxp` - parameters of `on_generated()`. Refer to `core.get_mapgen_object` docs. - Once you're done you still need to call `VoxelManip:write_to_map()` - -* The `on_generated()` callbacks of some mods may place individual nodes in the - generated area using non-VoxelManip map modification methods. Because the - same Mapgen VoxelManip object is passed through each `on_generated()` - callback, it becomes necessary for the Mapgen VoxelManip object to maintain - consistency with the current map state. For this reason, calling any of - `core.add_node()`, `core.set_node()` or `core.swap_node()` - will also update the Mapgen VoxelManip object's internal state active on the - current thread. - -* After modifying the Mapgen VoxelManip object's internal buffer, it may be - necessary to update lighting information using either: - `VoxelManip:calc_lighting()` or `VoxelManip:set_lighting()`. - -### Other API functions operating on a VoxelManip - -If any VoxelManip contents were set to a liquid node (`liquidtype ~= "none"`), -`VoxelManip:update_liquids()` must be called for these liquid nodes to begin -flowing. It is recommended to call this function only after having written all -buffered data back to the VoxelManip object, save for special situations where -the modder desires to only have certain liquid nodes begin flowing. - -The functions `core.generate_ores()` and `core.generate_decorations()` -will generate all registered decorations and ores throughout the full area -inside of the specified VoxelManip object. - -`core.place_schematic_on_vmanip()` is otherwise identical to -`core.place_schematic()`, except instead of placing the specified schematic -directly on the map at the specified position, it will place the schematic -inside the VoxelManip. - -### Notes - -* Attempting to read data from a VoxelManip object before map is read will - result in a zero-length array table for `VoxelManip:get_data()`, and an - "ignore" node at any position for `VoxelManip:get_node_at()`. - -* If you attempt to use a VoxelManip to read a region of the map that has - already been generated, but is not currently loaded, that region will be - loaded from disk. This means that reading a region of the map with a - VoxelManip has a similar effect as calling `core.load_area` on that - region. - -* If a region of the map has either not yet been generated or is outside the - map boundaries, it is filled with "ignore" nodes. Writing to regions of the - map that are not yet generated may result in unexpected behavior. You - can use `core.emerge_area` to make sure that the area you want to - read/write is already generated. - -* Other mods, or the engine itself, could possibly modify the area of the map - currently loaded into a VoxelManip object. With the exception of Mapgen - VoxelManips (see above section), the internal buffers are not updated. For - this reason, it is strongly encouraged to complete the usage of a particular - VoxelManip object in the same callback it had been created. - -* If a VoxelManip object will be used often, such as in an `on_generated()` - callback, consider passing a file-scoped table as the optional parameter to - `VoxelManip:get_data()`, which serves as a static buffer the function can use - to write map data to instead of returning a new table each call. This greatly - enhances performance by avoiding unnecessary memory allocations. - -Methods -------- - -* `read_from_map(p1, p2)`: Loads a part of the map into the VoxelManip object - containing the region formed by `p1` and `p2`. - * returns actual emerged `pmin`, actual emerged `pmax` (MapBlock-aligned) - * Note that calling this multiple times will *add* to the area loaded in the - VoxelManip, and not reset it. -* `initialize(p1, p2, [node])`: Clears and resizes the VoxelManip object to - comprise the region formed by `p1` and `p2`. - * **No data** is read from the map, so you can use this to treat `VoxelManip` - objects as general containers of node data. - * `node`: if present the data will be filled with this node; if not it will - be uninitialized - * returns actual emerged `pmin`, actual emerged `pmax` (MapBlock-aligned) - * (introduced in 5.13.0) -* `write_to_map([light])`: Writes the data loaded from the `VoxelManip` back to - the map. - * **important**: you should call `set_data()` before this, or nothing will change. - * if `light` is true, then lighting is automatically recalculated. - The default value is true. - If `light` is false, no light calculations happen, and you should correct - all modified blocks with `core.fix_light()` as soon as possible. - Keep in mind that modifying the map where light is incorrect can cause - more lighting bugs. -* `get_node_at(pos)`: Returns a `MapNode` table of the node currently loaded in - the `VoxelManip` at that position -* `set_node_at(pos, node)`: Sets a specific `MapNode` in the `VoxelManip` at - that position. -* `get_data([buffer])`: Retrieves the node content data loaded into the - `VoxelManip` object. - * returns raw node data in the form of an array of node content IDs - * if the param `buffer` is present, this table will be used to store the - result instead. -* `set_data(data)`: Sets the data contents of the `VoxelManip` object -* `update_map()`: Does nothing, kept for compatibility. -* `set_lighting(light, [p1, p2])`: Set the lighting within the `VoxelManip` to - a uniform value. - * `light` is a table, `{day=<0...15>, night=<0...15>}` - * To be used only by a `VoxelManip` object from - `core.get_mapgen_object`. - * (`p1`, `p2`) is the area in which lighting is set, defaults to the whole - area if left out. -* `get_light_data([buffer])`: Gets the light data read into the - `VoxelManip` object - * Returns an array (indices 1 to volume) of integers ranging from `0` to - `255`. - * Each value is the bitwise combination of day and night light values - (`0` to `15` each). - * `light = day + (night * 16)` - * If the param `buffer` is present, this table will be used to store the - result instead. -* `set_light_data(light_data)`: Sets the `param1` (light) contents of each node - in the `VoxelManip`. - * expects lighting data in the same format that `get_light_data()` returns -* `get_param2_data([buffer])`: Gets the raw `param2` data read into the - `VoxelManip` object. - * Returns an array (indices 1 to volume) of integers ranging from `0` to - `255`. - * If the param `buffer` is present, this table will be used to store the - result instead. -* `set_param2_data(param2_data)`: Sets the `param2` contents of each node in - the `VoxelManip`. -* `calc_lighting([p1, p2], [propagate_shadow])`: Calculate lighting within the - `VoxelManip`. - * To be used only with a `VoxelManip` object from `core.get_mapgen_object`. - * (`p1`, `p2`) is the area in which lighting is set, defaults to the whole - area if left out or nil. For almost all uses these should be left out - or nil to use the default. - * `propagate_shadow` is an optional boolean deciding whether shadows in a - generated mapchunk above are propagated down into the mapchunk, defaults - to `true` if left out. -* `update_liquids()`: Update liquid flow -* `was_modified()`: Returns `true` if the data in the VoxelManip has been modified - since it was last read from the map. This means you have to call `get_data()` again. - This only applies to a `VoxelManip` object from `core.get_mapgen_object`, - where the engine will keep the map and the VM in sync automatically. - * Note: this doesn't do what you think it does and is subject to removal. Don't use it! -* `get_emerged_area()`: Returns actual emerged minimum and maximum positions. - * "Emerged" does not imply that this region was actually loaded from the map, - if `initialize()` has been used. -* `close()`: Frees the data buffers associated with the VoxelManip object. - It will become empty. - * Since Lua's garbage collector is not aware of the potentially significant - memory behind a VoxelManip, frequent VoxelManip usage can cause the server to - run out of RAM. Therefore it's recommend to call this method once you're done - with the VoxelManip. - * (introduced in 5.13.0) - -`VoxelArea` ------------ - -A helper class for voxel areas. -It can be created via `VoxelArea(pmin, pmax)` or -`VoxelArea:new({MinEdge = pmin, MaxEdge = pmax})`. -The coordinates are *inclusive*, like most other things in Luanti. - -### Methods - -* `getExtent()`: returns a 3D vector containing the size of the area formed by - `MinEdge` and `MaxEdge`. -* `getVolume()`: returns the volume of the area formed by `MinEdge` and - `MaxEdge`. -* `index(x, y, z)`: returns the index of an absolute position in a flat array - starting at `1`. - * `x`, `y` and `z` must be integers to avoid an incorrect index result. - * The position (x, y, z) is not checked for being inside the area volume, - being outside can cause an incorrect index result. - * Useful for things like `VoxelManip`, raw Schematic specifiers, - `ValueNoiseMap:get2d`/`3dMap`, and so on. -* `indexp(p)`: same functionality as `index(x, y, z)` but takes a vector. - * As with `index(x, y, z)`, the components of `p` must be integers, and `p` - is not checked for being inside the area volume. -* `position(i)`: returns the absolute position vector corresponding to index - `i`. -* `contains(x, y, z)`: check if (`x`,`y`,`z`) is inside area formed by - `MinEdge` and `MaxEdge`. -* `containsp(p)`: same as above, except takes a vector -* `containsi(i)`: same as above, except takes an index `i` -* `iter(minx, miny, minz, maxx, maxy, maxz)`: returns an iterator that returns - indices. - * from (`minx`,`miny`,`minz`) to (`maxx`,`maxy`,`maxz`) in the order of - `[z [y [x]]]`. -* `iterp(minp, maxp)`: same as above, except takes a vector - -### Y stride and z stride of a flat array - -For a particular position in a voxel area, whose flat array index is known, -it is often useful to know the index of a neighboring or nearby position. -The table below shows the changes of index required for 1 node movements along -the axes in a voxel area: - - Movement Change of index - +x +1 - -x -1 - +y +ystride - -y -ystride - +z +zstride - -z -zstride - -If, for example: - - local area = VoxelArea(emin, emax) - -The values of `ystride` and `zstride` can be obtained using `area.ystride` and -`area.zstride`. - - - - -Mapgen objects -============== - -A mapgen object is a construct used in map generation. Mapgen objects can be -used by an `on_generated` callback to speed up operations by avoiding -unnecessary recalculations, these can be retrieved using the -`core.get_mapgen_object()` function. If the requested Mapgen object is -unavailable, or `get_mapgen_object()` was called outside of an `on_generated` -callback, `nil` is returned. - -The following Mapgen objects are currently available: - -### `voxelmanip` - -This returns three values; the `VoxelManip` object to be used, minimum and -maximum emerged position, in that order. All mapgens support this object. - -### `heightmap` - -Returns an array containing the y coordinates of the ground levels of nodes in -the most recently generated chunk by the current mapgen. - -### `biomemap` - -Returns an array containing the biome IDs of nodes in the most recently -generated chunk by the current mapgen. - -### `heatmap` - -Returns an array containing the temperature values of nodes in the most -recently generated chunk by the current mapgen. - -### `humiditymap` - -Returns an array containing the humidity values of nodes in the most recently -generated chunk by the current mapgen. - -### `gennotify` - -Returns a table. You need to announce your interest in a specific -field by calling `core.set_gen_notify()` *before* map generation happens. - -* key = string: generation notification type -* value = list of positions (usually) - * Exceptions are denoted in the listing below. - -Available generation notification types: - -* `dungeon`: bottom center position of dungeon rooms -* `temple`: as above but for desert temples (mgv6 only) -* `cave_begin` -* `cave_end` -* `large_cave_begin` -* `large_cave_end` -* `custom`: data originating from [Mapgen environment](#mapgen-environment) (Lua API) - * This is a table. - * key = user-defined ID (string) - * value = arbitrary Lua value -* `decoration#id`: decorations - * (see below) - -Decorations have a key in the format of `"decoration#id"`, where `id` is the -numeric unique decoration ID as returned by `core.get_decoration_id()`. -For example, `decoration#123`. - -The returned positions are the ground surface 'place_on' nodes, -not the decorations themselves. A 'simple' type decoration is often 1 -node above the returned position and possibly displaced by 'place_offset_y'. - - -Registered entities -=================== - -Functions receive a "luaentity" table as `self`: - -* It has the member `name`, which is the registered name `("mod:thing")` -* It has the member `object`, which is an `ObjectRef` pointing to the object -* The original prototype is visible directly via a metatable - -Callbacks: - -* `on_activate(self, staticdata, dtime_s)` - * Called when the object is instantiated. - * `dtime_s` is the time passed since the object was unloaded, which can be - used for updating the entity state. -* `on_deactivate(self, removal)` - * Called when the object is about to get removed or unloaded. - * `removal`: boolean indicating whether the object is about to get removed. - Calling `object:remove()` on an active object will call this with `removal=true`. - The mapblock the entity resides in being unloaded will call this with `removal=false`. - * Note that this won't be called if the object hasn't been activated in the first place. - In particular, `core.clear_objects({mode = "full"})` won't call this, - whereas `core.clear_objects({mode = "quick"})` might call this. -* `on_step(self, dtime, moveresult)` - * Called on every server tick, after movement and collision processing. - * `dtime`: elapsed time since last call - * `moveresult`: table with collision info (only available if physical=true) -* `on_punch(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)` - * Called when somebody punches the object. - * Note that you probably want to handle most punches using the automatic - armor group system. - * `puncher`: an `ObjectRef` (can be `nil`) - * `time_from_last_punch`: Meant for disallowing spamming of clicks - (can be `nil`). - * `tool_capabilities`: capability table of used item (can be `nil`) - * `dir`: unit vector of direction of punch. Always defined. Points from the - puncher to the punched. - * `damage`: damage that will be done to entity. - * Can return `true` to prevent the default damage mechanism. -* `on_death(self, killer)` - * Called when the object dies. - * `killer`: an `ObjectRef` (can be `nil`) -* `on_rightclick(self, clicker)` - * Called when `clicker` pressed the 'place/use' key while pointing - to the object (not necessarily an actual rightclick) - * `clicker`: an `ObjectRef` (may or may not be a player) -* `on_attach_child(self, child)` - * Called after another object is attached to this object. - * `child`: an `ObjectRef` of the child -* `on_detach_child(self, child)` - * Called after another object has detached from this object. - * `child`: an `ObjectRef` of the child -* `on_detach(self, parent)` - * Called after detaching from another object. - * `parent`: an `ObjectRef` from where it got detached - * Note: this is also called before removal from the world. -* `get_staticdata(self)` - * Should return a string that will be passed to `on_activate` when the - object is instantiated the next time. - -Collision info passed to `on_step` (`moveresult` argument): - -```lua -{ - touching_ground = boolean, - -- Note that touching_ground is only true if the entity was moving and - -- collided with ground. - - collides = boolean, - standing_on_object = boolean, - - collisions = { - { - type = string, -- "node" or "object", - axis = string, -- "x", "y" or "z" - node_pos = vector, -- if type is "node" - object = ObjectRef, -- if type is "object" - -- The position of the entity when the collision occurred. - -- Available since feature "moveresult_new_pos". - new_pos = vector, - old_velocity = vector, - new_velocity = vector, - }, - ... - } - -- `collisions` does not contain data of unloaded mapblock collisions - -- or when the velocity changes are negligibly small -} -``` - - - -L-system trees -============== - -Tree definition ---------------- - -```lua -treedef={ - axiom, --string initial tree axiom - rules_a, --string rules set A - rules_b, --string rules set B - rules_c, --string rules set C - rules_d, --string rules set D - trunk, --string trunk node name - leaves, --string leaves node name - leaves2, --string secondary leaves node name - leaves2_chance,--num chance (0-100) to replace leaves with leaves2 - angle, --num angle in deg - iterations, --num max # of iterations, usually 2 -5 - random_level, --num factor to lower number of iterations, usually 0 - 3 - trunk_type, --string single/double/crossed) type of trunk: 1 node, - -- 2x2 nodes or 3x3 in cross shape - thin_branches, --boolean true -> use thin (1 node) branches - fruit, --string fruit node name - fruit_chance, --num chance (0-100) to replace leaves with fruit node - seed, --num random seed, if no seed is provided, the engine will create one. -} -``` - -Key for special L-System symbols used in axioms ------------------------------------------------ - -* `G`: move forward one unit with the pen up -* `F`: move forward one unit with the pen down drawing trunks and branches -* `f`: move forward one unit with the pen down drawing leaves (100% chance) -* `T`: move forward one unit with the pen down drawing trunks only -* `R`: move forward one unit with the pen down placing fruit -* `A`: replace with rules set A -* `B`: replace with rules set B -* `C`: replace with rules set C -* `D`: replace with rules set D -* `a`: replace with rules set A, chance 90% -* `b`: replace with rules set B, chance 80% -* `c`: replace with rules set C, chance 70% -* `d`: replace with rules set D, chance 60% -* `+`: yaw the turtle right by `angle` parameter -* `-`: yaw the turtle left by `angle` parameter -* `&`: pitch the turtle down by `angle` parameter -* `^`: pitch the turtle up by `angle` parameter -* `/`: roll the turtle to the right by `angle` parameter -* `*`: roll the turtle to the left by `angle` parameter -* `[`: save in stack current state info -* `]`: recover from stack state info - -Example -------- - -Spawn a small apple tree: - -```lua -pos = {x=230,y=20,z=4} -apple_tree={ - axiom="FFFFFAFFBF", - rules_a="[&&&FFFFF&&FFFF][&&&++++FFFFF&&FFFF][&&&----FFFFF&&FFFF]", - rules_b="[&&&++FFFFF&&FFFF][&&&--FFFFF&&FFFF][&&&------FFFFF&&FFFF]", - trunk="default:tree", - leaves="default:leaves", - angle=30, - iterations=2, - random_level=0, - trunk_type="single", - thin_branches=true, - fruit_chance=10, - fruit="default:apple" -} -core.spawn_tree(pos,apple_tree) -``` - -Privileges -========== - -Privileges provide a means for server administrators to give certain players -access to special abilities in the engine, games or mods. -For example, game moderators may need to travel instantly to any place in the world, -this ability is implemented in `/teleport` command which requires `teleport` privilege. - -Registering privileges ----------------------- - -A mod can register a custom privilege using `core.register_privilege` function -to give server administrators fine-grained access control over mod functionality. - -For consistency and practical reasons, privileges should strictly increase the abilities of the user. -Do not register custom privileges that e.g. restrict the player from certain in-game actions. - -Checking privileges -------------------- - -A mod can call `core.check_player_privs` to test whether a player has privileges -to perform an operation. -Also, when registering a chat command with `core.register_chatcommand` a mod can -declare privileges that the command requires using the `privs` field of the command -definition. - -Managing player privileges --------------------------- - -A mod can update player privileges using `core.set_player_privs` function. -Players holding the `privs` privilege can see and manage privileges for all -players on the server. - -A mod can subscribe to changes in player privileges using `core.register_on_priv_grant` -and `core.register_on_priv_revoke` functions. - -Built-in privileges -------------------- - -Luanti includes a set of built-in privileges that control capabilities -provided by the Luanti engine and can be used by mods: - - * Basic privileges are normally granted to all players: - * `shout`: can communicate using the in-game chat. - * `interact`: can modify the world by digging, building and interacting - with the nodes, entities and other players. Players without the `interact` - privilege can only travel and observe the world. - - * Advanced privileges allow bypassing certain aspects of the gameplay: - * `fast`: can use "fast mode" to move with maximum speed. - * `fly`: can use "fly mode" to move freely above the ground without falling. - * `noclip`: can use "noclip mode" to fly through solid nodes (e.g. walls). - * `teleport`: can use `/teleport` command to move to any point in the world. - * `bring`: can teleport other players to oneself. - * `give`: can use `/give` and `/giveme` commands to give any item - in the game to oneself or others. - * `settime`: can use `/time` command to change current in-game time. - * `debug`: can enable wireframe rendering mode. - - * Security-related privileges: - * `privs`: can modify privileges of the players using `/grant[me]` and - `/revoke[me]` commands. - * `basic_privs`: can grant and revoke basic privileges as defined by - the `basic_privs` setting. - * `kick`: can kick other players from the server using `/kick` command. - * `ban`: can ban other players using `/ban` command. - * `password`: can use `/setpassword` and `/clearpassword` commands - to manage players' passwords. - * `protection_bypass`: can bypass node protection. Note that the engine does not act upon this privilege, - it is only an implementation suggestion for games. - - * Administrative privileges: - * `server`: can use `/fixlight`, `/deleteblocks` and `/deleteobjects` - commands. Can clear inventory of other players using `/clearinv` command. - * `rollback`: can use `/rollback_check` and `/rollback` commands. - -Related settings ----------------- - -Luanti includes the following settings to control behavior of privileges: - - * `default_privs`: defines privileges granted to new players. - * `basic_privs`: defines privileges that can be granted/revoked by players having - the `basic_privs` privilege. This can be used, for example, to give - limited moderation powers to selected users. - -'core' namespace reference -========================== - -Utilities ---------- - -* `core.get_current_modname()`: returns the currently loading mod's name, - when loading a mod. -* `core.get_modpath(modname)`: returns the directory path for a mod, - e.g. `"/home/user/.minetest/usermods/modname"`. - * Returns nil if the mod is not enabled or does not exist (not installed). - * Works regardless of whether the mod has been loaded yet. - * Useful for loading additional `.lua` modules or static data from a mod, - or checking if a mod is enabled. -* `core.get_modnames()`: returns a list of enabled mods, sorted alphabetically. - * Does not include disabled mods, even if they are installed. -* `core.get_game_info()`: returns a table containing information about the - current game. Note that other meta information (e.g. version/release number) - can be manually read from `game.conf` in the game's root directory. - - ```lua - { - id = string, - title = string, - author = string, - -- The root directory of the game - path = string, - } - ``` - -* `core.get_worldpath()`: returns e.g. `"/home/user/.minetest/world"` - * Useful for storing custom data -* `core.get_mod_data_path()`: returns e.g. `"/home/user/.minetest/mod_data/mymod"` - * Useful for storing custom data *independently of worlds*. - * Must be called during mod load time. - * Can read or write to this directory at any time. - * It's possible that multiple Luanti instances are running at the same - time, which may lead to corruption if you are not careful. -* `core.is_singleplayer()` -* `core.features`: Table containing *server-side* API feature flags - - ```lua - { - glasslike_framed = true, -- 0.4.7 - nodebox_as_selectionbox = true, -- 0.4.7 - get_all_craft_recipes_works = true, -- 0.4.7 - -- The transparency channel of textures can optionally be used on - -- nodes (0.4.7) - use_texture_alpha = true, - -- Tree and grass ABMs are no longer done from C++ (0.4.8) - no_legacy_abms = true, - -- Texture grouping is possible using parentheses (0.4.11) - texture_names_parens = true, - -- Unique Area ID for AreaStore:insert_area (0.4.14) - area_store_custom_ids = true, - -- add_entity supports passing initial staticdata to on_activate - -- (0.4.16) - add_entity_with_staticdata = true, - -- Chat messages are no longer predicted (0.4.16) - no_chat_message_prediction = true, - -- The transparency channel of textures can optionally be used on - -- objects (ie: players and lua entities) (5.0.0) - object_use_texture_alpha = true, - -- Object selectionbox is settable independently from collisionbox - -- (5.0.0) - object_independent_selectionbox = true, - -- Specifies whether binary data can be uploaded or downloaded using - -- the HTTP API (5.1.0) - httpfetch_binary_data = true, - -- Whether formspec_version[] may be used (5.1.0) - formspec_version_element = true, - -- Whether AreaStore's IDs are kept on save/load (5.1.0) - area_store_persistent_ids = true, - -- Whether core.find_path is functional (5.2.0) - pathfinder_works = true, - -- Whether Collision info is available to an objects' on_step (5.3.0) - object_step_has_moveresult = true, - -- Whether get_velocity() and add_velocity() can be used on players (5.4.0) - direct_velocity_on_players = true, - -- nodedef's use_texture_alpha accepts new string modes (5.4.0) - use_texture_alpha_string_modes = true, - -- degrotate param2 rotates in units of 1.5° instead of 2° - -- thus changing the range of values from 0-179 to 0-240 (5.5.0) - degrotate_240_steps = true, - -- ABM supports min_y and max_y fields in definition (5.5.0) - abm_min_max_y = true, - -- dynamic_add_media supports passing a table with options (5.5.0) - dynamic_add_media_table = true, - -- particlespawners support texpools and animation of properties, - -- particle textures support smooth fade and scale animations, and - -- sprite-sheet particle animations can by synced to the lifetime - -- of individual particles (5.6.0) - particlespawner_tweenable = true, - -- allows get_sky to return a table instead of separate values (5.6.0) - get_sky_as_table = true, - -- VoxelManip:get_light_data accepts an optional buffer argument (5.7.0) - get_light_data_buffer = true, - -- When using a mod storage backend that is not "files" or "dummy", - -- the amount of data in mod storage is not constrained by - -- the amount of RAM available. (5.7.0) - mod_storage_on_disk = true, - -- "zstd" method for compress/decompress (5.7.0) - compress_zstd = true, - -- Sound parameter tables support start_time (5.8.0) - sound_params_start_time = true, - -- New fields for set_physics_override: speed_climb, speed_crouch, - -- liquid_fluidity, liquid_fluidity_smooth, liquid_sink, - -- acceleration_default, acceleration_air (5.8.0) - physics_overrides_v2 = true, - -- In HUD definitions the field `type` is used and `hud_elem_type` is deprecated (5.9.0) - hud_def_type_field = true, - -- PseudoRandom and PcgRandom state is restorable - -- PseudoRandom has get_state method - -- PcgRandom has get_state and set_state methods (5.9.0) - random_state_restore = true, - -- core.after guarantees that coexisting jobs are executed primarily - -- in order of expiry and secondarily in order of registration (5.9.0) - after_order_expiry_registration = true, - -- wallmounted nodes mounted at floor or ceiling may additionally - -- be rotated by 90° with special param2 values (5.9.0) - wallmounted_rotate = true, - -- Availability of the `pointabilities` property in the item definition (5.9.0) - item_specific_pointabilities = true, - -- Nodes `pointable` property can be `"blocking"` (5.9.0) - blocking_pointability_type = true, - -- dynamic_add_media can be called at startup when leaving callback as `nil` (5.9.0) - dynamic_add_media_startup = true, - -- dynamic_add_media supports `filename` and `filedata` parameters (5.9.0) - dynamic_add_media_filepath = true, - -- L-system decoration type (5.9.0) - lsystem_decoration_type = true, - -- Overridable pointing range using the itemstack meta key `"range"` (5.9.0) - item_meta_range = true, - -- Allow passing an optional "actor" ObjectRef to the following functions: - -- core.place_node, core.dig_node, core.punch_node (5.9.0) - node_interaction_actor = true, - -- "new_pos" field in entity moveresult (5.9.0) - moveresult_new_pos = true, - -- Allow removing definition fields in `core.override_item` (5.9.0) - override_item_remove_fields = true, - -- The predefined hotbar is a Lua HUD element of type `hotbar` (5.10.0) - hotbar_hud_element = true, - -- Bulk LBM support (5.10.0) - bulk_lbms = true, - -- ABM supports field without_neighbors (5.10.0) - abm_without_neighbors = true, - -- biomes have a weight parameter (5.11.0) - biome_weights = true, - -- Particles can specify a "clip" blend mode (5.11.0) - particle_blend_clip = true, - -- The `match_meta` optional parameter is available for `InvRef:remove_item()` (5.12.0) - remove_item_match_meta = true, - -- The HTTP API supports the HEAD and PATCH methods (5.12.0) - httpfetch_additional_methods = true, - -- objects have get_guid method (5.13.0) - object_guids = true, - } - ``` - -* `core.has_feature(arg)`: returns `boolean, missing_features` - * checks for *server-side* feature availability - * `arg`: string or table in format `{foo=true, bar=true}` - * `missing_features`: `{foo=true, bar=true}` -* `core.get_player_information(player_name)`: Table containing information - about a player. Example return value: - - ```lua - { - address = "127.0.0.1", -- IP address of client - ip_version = 4, -- IPv4 / IPv6 - connection_uptime = 200, -- seconds since client connected - protocol_version = 32, -- protocol version used by client - formspec_version = 2, -- supported formspec version - lang_code = "fr", -- Language code used for translation - - -- the following keys can be missing if no stats have been collected yet - min_rtt = 0.01, -- minimum round trip time - max_rtt = 0.2, -- maximum round trip time - avg_rtt = 0.02, -- average round trip time - min_jitter = 0.01, -- minimum packet time jitter - max_jitter = 0.5, -- maximum packet time jitter - avg_jitter = 0.03, -- average packet time jitter - - -- The version information is provided by the client and may be spoofed - -- or inconsistent in engine forks. You must not use this for checking - -- feature availability of clients. Instead, do use the fields - -- `protocol_version` and `formspec_version` where it matters. - -- Use `core.protocol_versions` to map Luanti versions to protocol versions. - -- This version string is only suitable for analysis purposes. - version_string = "0.4.9-git", -- full version string - - -- the following information is available in a debug build only!!! - -- DO NOT USE IN MODS - --serialization_version = 26, -- serialization version used by client - --major = 0, -- major version number - --minor = 4, -- minor version number - --patch = 10, -- patch version number - --state = "Active" -- current client state - } - ``` - -* `core.protocol_versions`: - * Table mapping Luanti versions to corresponding protocol versions for modder convenience. - * For example, to check whether a client has at least the feature set - of Luanti 5.8.0 or newer, you could do: - `core.get_player_information(player_name).protocol_version >= core.protocol_versions["5.8.0"]` - * (available since 5.11) - - ```lua - { - [version string] = protocol version at time of release - -- every major and minor version has an entry - -- patch versions only for the first release whose protocol version is not already present in the table - } - ``` - -* `core.get_player_window_information(player_name)`: - - ```lua - -- Will only be present if the client sent this information (requires v5.7+) - -- - -- Note that none of these things are constant, they are likely to change during a client - -- connection as the player resizes the window and moves it between monitors - -- - -- real_gui_scaling and real_hud_scaling can be used instead of DPI. - -- OSes don't necessarily give the physical DPI, as they may allow user configuration. - -- real_*_scaling is just OS DPI / 96 but with another level of user configuration. - { - -- Current size of the in-game render target (pixels). - -- - -- This is usually the window size, but may be smaller in certain situations, - -- such as side-by-side mode. - size = { - x = 1308, - y = 577, - }, - - -- Estimated maximum formspec size before Luanti will start shrinking the - -- formspec to fit. For a fullscreen formspec, use the size returned by - -- this table and `padding[0,0]`. `bgcolor[;true]` is also recommended. - max_formspec_size = { - x = 20, - y = 11.25 - }, - - -- GUI Scaling multiplier - -- Equal to the setting `gui_scaling` multiplied by `dpi / 96` - real_gui_scaling = 1, - - -- HUD Scaling multiplier - -- Equal to the setting `hud_scaling` multiplied by `dpi / 96` - real_hud_scaling = 1, - - -- Whether the touchscreen controls are enabled. - -- Usually (but not always) `true` on Android. - -- Requires at least version 5.9.0 on the client. For older clients, it - -- is always set to `false`. - touch_controls = false, - } - ``` - -* `core.mkdir(path)`: returns success. - * Creates a directory specified by `path`, creating parent directories - if they don't exist. -* `core.rmdir(path, recursive)`: returns success. - * Removes a directory specified by `path`. - * If `recursive` is set to `true`, the directory is recursively removed. - Otherwise, the directory will only be removed if it is empty. - * Returns true on success, false on failure. -* `core.cpdir(source, destination)`: returns success. - * Copies a directory specified by `path` to `destination` - * Any files in `destination` will be overwritten if they already exist. - * Returns true on success, false on failure. -* `core.mvdir(source, destination)`: returns success. - * Moves a directory specified by `path` to `destination`. - * If the `destination` is a non-empty directory, then the move will fail. - * Returns true on success, false on failure. -* `core.get_dir_list(path, [is_dir])`: returns list of entry names - * is_dir is one of: - * nil: return all entries, - * true: return only subdirectory names, or - * false: return only file names. -* `core.safe_file_write(path, content)`: returns boolean indicating success - * Replaces contents of file at path with new contents in a safe (atomic) - way. Use this instead of below code when writing e.g. database files: - `local f = io.open(path, "wb"); f:write(content); f:close()` -* `core.get_version()`: returns a table containing components of the - engine version. Components: - * `project`: Name of the project, eg, "Luanti" - * `string`: Simple version, eg, "1.2.3-dev" - * `proto_min`: The minimum supported protocol version - * `proto_max`: The maximum supported protocol version - * `hash`: Full git version (only set if available), - eg, "1.2.3-dev-01234567-dirty". - * `is_dev`: Boolean value indicating whether it's a development build - Use this for informational purposes only. The information in the returned - table does not represent the capabilities of the engine, nor is it - reliable or verifiable. Compatible forks will have a different name and - version entirely. To check for the presence of engine features, test - whether the functions exported by the wanted features exist. For example: - `if core.check_for_falling then ... end`. -* `core.sha1(data, [raw])`: returns the sha1 hash of data - * `data`: string of data to hash - * `raw`: return raw bytes instead of hex digits, default: false -* `core.sha256(data, [raw])`: returns the sha256 hash of data - * `data`: string of data to hash - * `raw`: return raw bytes instead of hex digits, default: false -* `core.colorspec_to_colorstring(colorspec)`: Converts a ColorSpec to a - ColorString. If the ColorSpec is invalid, returns `nil`. - * `colorspec`: The ColorSpec to convert -* `core.colorspec_to_bytes(colorspec)`: Converts a ColorSpec to a raw - string of four bytes in an RGBA layout, returned as a string. - * `colorspec`: The ColorSpec to convert -* `core.colorspec_to_table(colorspec)`: Converts a ColorSpec into RGBA table - form. If the ColorSpec is invalid, returns `nil`. You can use this to parse - ColorStrings. - * `colorspec`: The ColorSpec to convert -* `core.time_to_day_night_ratio(time_of_day)`: Returns a "day-night ratio" value - (as accepted by `ObjectRef:override_day_night_ratio`) that is equivalent to - the given "time of day" value (as returned by `core.get_timeofday`). -* `core.encode_png(width, height, data, [compression])`: Encode a PNG - image and return it in string form. - * `width`: Width of the image - * `height`: Height of the image - * `data`: Image data, one of: - * array table of ColorSpec, length must be width*height - * string with raw RGBA pixels, length must be width*height*4 - * `compression`: Optional zlib compression level, number in range 0 to 9. - The data is one-dimensional, starting in the upper left corner of the image - and laid out in scanlines going from left to right, then top to bottom. - You can use `colorspec_to_bytes` to generate raw RGBA values. - Palettes are not supported at the moment. - You may use this to procedurally generate textures during server init. -* `core.urlencode(str)`: Encodes reserved URI characters by a - percent sign followed by two hex digits. See - [RFC 3986, section 2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3). - -Logging -------- - -* `core.debug(...)` - * Equivalent to `core.log(table.concat({...}, "\t"))` -* `core.log([level,] text)` - * `level` is one of `"none"`, `"error"`, `"warning"`, `"action"`, - `"info"`, or `"verbose"`. Default is `"none"`. - -Registration functions ----------------------- - -Call these functions only at load time! - -### Environment - -* `core.register_node(name, nodedef)` - * register a node with its definition - * Note: you must pass a clean table that hasn't already been used for - another registration to this function, as it will be modified. -* `core.register_craftitem(name, itemdef)` - * register an item with its definition - * Note: (as above) -* `core.register_tool(name, tooldef)` - * register a tool item with its definition - * Note: (as above) -* `core.override_item(name, redefinition, del_fields)` - * `redefinition` is a table of fields `[name] = new_value`, - overwriting fields of or adding fields to the existing definition. - * `del_fields` is a list of field names to be set - to `nil` ("deleted from") the original definition. - * Overrides fields of an item registered with register_node/tool/craftitem. - * Note: Item must already be defined. - * Example: `core.override_item("default:mese", - {light_source=core.LIGHT_MAX}, {"sounds"})`: - Overwrites the `light_source` field, - removes the sounds from the definition of the mese block. -* `core.unregister_item(name)` - * Unregisters the item from the engine, and deletes the entry with key - `name` from `core.registered_items` and from the associated item table - according to its nature (e.g. `core.registered_nodes`) -* `core.register_entity(name, entity definition)` -* `core.register_abm(abm definition)` -* `core.register_lbm(lbm definition)` -* `core.register_alias(alias, original_name)` - * Also use this to set the 'mapgen aliases' needed in a game for the core - mapgens. See [Mapgen aliases](#mapgen-aliases) section above. -* `core.register_alias_force(alias, original_name)` -* `core.register_ore(ore definition)` - * Returns an integer object handle uniquely identifying the registered - ore on success. - * The order of ore registrations determines the order of ore generation. -* `core.register_biome(biome definition)` - * Returns an integer object handle uniquely identifying the registered - biome on success. To get the biome ID, use `core.get_biome_id`. -* `core.unregister_biome(name)` - * Unregisters the biome from the engine, and deletes the entry with key - `name` from `core.registered_biomes`. - * Warning: This alters the biome to biome ID correspondences, so any - decorations or ores using the 'biomes' field must afterwards be cleared - and re-registered. -* `core.register_decoration(decoration definition)` - * Returns an integer object handle uniquely identifying the registered - decoration on success. To get the decoration ID, use - `core.get_decoration_id`. - * The order of decoration registrations determines the order of decoration - generation. -* `core.register_schematic(schematic definition)` - * Returns an integer object handle uniquely identifying the registered - schematic on success. - * If the schematic is loaded from a file, the `name` field is set to the - filename. - * If the function is called when loading the mod, and `name` is a relative - path, then the current mod path will be prepended to the schematic - filename. -* `core.clear_registered_biomes()` - * Clears all biomes currently registered. - * Warning: Clearing and re-registering biomes alters the biome to biome ID - correspondences, so any decorations or ores using the 'biomes' field must - afterwards be cleared and re-registered. -* `core.clear_registered_decorations()` - * Clears all decorations currently registered. -* `core.clear_registered_ores()` - * Clears all ores currently registered. -* `core.clear_registered_schematics()` - * Clears all schematics currently registered. - -### Gameplay - -* `core.register_craft(recipe)` - * Check recipe table syntax for different types below. -* `core.clear_craft(recipe)` - * Will erase existing craft based either on output item or on input recipe. - * Specify either output or input only. If you specify both, input will be - ignored. For input use the same recipe table syntax as for - `core.register_craft(recipe)`. For output specify only the item, - without a quantity. - * Returns false if no erase candidate could be found, otherwise returns true. - * **Warning**! The type field ("shaped", "cooking" or any other) will be - ignored if the recipe contains output. Erasing is then done independently - from the crafting method. -* `core.register_chatcommand(cmd, chatcommand definition)` -* `core.override_chatcommand(name, redefinition)` - * Overrides fields of a chatcommand registered with `register_chatcommand`. -* `core.unregister_chatcommand(name)` - * Unregisters a chatcommands registered with `register_chatcommand`. -* `core.register_privilege(name, definition)` - * `definition` can be a description or a definition table (see [Privilege - definition](#privilege-definition)). - * If it is a description, the priv will be granted to singleplayer and admin - by default. - * To allow players with `basic_privs` to grant, see the `basic_privs` - minetest.conf setting. -* `core.register_authentication_handler(authentication handler definition)` - * Registers an auth handler that overrides the builtin one. - * This function can be called by a single mod once only. - -Global callback registration functions --------------------------------------- - -Call these functions only at load time! - -* `core.register_globalstep(function(dtime))` - * Called every server step, usually interval of 0.1s. - * `dtime` is the time since last execution in seconds. -* `core.register_on_mods_loaded(function())` - * Called after mods have finished loading and before the media is cached or the - aliases handled. -* `core.register_on_shutdown(function())` - * Called before server shutdown - * Players that were kicked by the shutdown procedure are still fully accessible - in `core.get_connected_players()`. - * **Warning**: If the server terminates abnormally (i.e. crashes), the - registered callbacks **will likely not be run**. Data should be saved at - semi-frequent intervals as well as on server shutdown. -* `core.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing))` - * Called when a node has been placed - * If return `true` no item is taken from `itemstack` - * `placer` may be any valid ObjectRef or nil. - * **Not recommended**; use `on_construct` or `after_place_node` in node - definition whenever possible. -* `core.register_on_dignode(function(pos, oldnode, digger))` - * Called when a node has been dug. - * **Not recommended**; Use `on_destruct` or `after_dig_node` in node - definition whenever possible. -* `core.register_on_punchnode(function(pos, node, puncher, pointed_thing))` - * Called when a node is punched -* `core.register_on_generated(function(minp, maxp, blockseed))` - * Called after generating a piece of world between `minp` and `maxp`. - * **Avoid using this** whenever possible. As with other callbacks this blocks - the main thread and introduces noticeable latency. - Consider [Mapgen environment](#mapgen-environment) for an alternative. -* `core.register_on_newplayer(function(ObjectRef))` - * Called when a new player enters the world for the first time -* `core.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage))` - * Called when a player is punched - * Note: This callback is invoked even if the punched player is dead. - * `player`: ObjectRef - Player that was punched - * `hitter`: ObjectRef - Player that hit. Can be nil. - * `time_from_last_punch`: Meant for disallowing spamming of clicks - (can be nil). - * `tool_capabilities`: Capability table of used item (can be nil) - * `dir`: Unit vector of direction of punch. Always defined. Points from - the puncher to the punched. - * `damage`: Number that represents the damage calculated by the engine - * should return `true` to prevent the default damage mechanism -* `core.register_on_rightclickplayer(function(player, clicker))` - * Called when the 'place/use' key was used while pointing a player - (not necessarily an actual rightclick) - * `player`: ObjectRef - Player that is acted upon - * `clicker`: ObjectRef - Object that acted upon `player`, may or may not be a player -* `core.register_on_player_hpchange(function(player, hp_change, reason), modifier)` - * Called when the player gets damaged or healed - * When `hp == 0`, damage doesn't trigger this callback. - * When `hp == hp_max`, healing does still trigger this callback. - * `player`: ObjectRef of the player - * `hp_change`: the amount of change. Negative when it is damage. - * Historically, the new HP value was clamped to [0, 65535] before - calculating the HP change. This clamping has been removed as of - version 5.10.0 - * `reason`: a PlayerHPChangeReason table. - * The `type` field will have one of the following values: - * `set_hp`: A mod or the engine called `set_hp` without - giving a type - use this for custom damage types. - * `punch`: Was punched. `reason.object` will hold the puncher, or nil if none. - * `fall` - * `node_damage`: `damage_per_second` from a neighboring node. - `reason.node` will hold the node name or nil. - `reason.node_pos` will hold the position of the node - * `drown` - * `respawn` - * Any of the above types may have additional fields from mods. - * `reason.from` will be `mod` or `engine`. - * `modifier`: when true, the function should return the actual `hp_change`. - Note: modifiers only get a temporary `hp_change` that can be modified by later modifiers. - Modifiers can return true as a second argument to stop the execution of further functions. - Non-modifiers receive the final HP change calculated by the modifiers. -* `core.register_on_dieplayer(function(ObjectRef, reason))` - * Called when a player dies - * `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange - * For customizing the death screen, see `core.show_death_screen`. -* `core.register_on_respawnplayer(function(ObjectRef))` - * Called when player is to be respawned - * Called _before_ repositioning of player occurs - * return true in func to disable regular player placement -* `core.register_on_prejoinplayer(function(name, ip))` - * Called when a client connects to the server, prior to authentication - * If it returns a string, the client is disconnected with that string as - reason. -* `core.register_on_joinplayer(function(ObjectRef, last_login))` - * Called when a player joins the game - * `last_login`: The timestamp of the previous login, or nil if player is new -* `core.register_on_leaveplayer(function(ObjectRef, timed_out))` - * Called when a player leaves the game - * Does not get executed for connected players on shutdown. - * `timed_out`: True for timeout, false for other reasons. -* `core.register_on_authplayer(function(name, ip, is_success))` - * Called when a client attempts to log into an account. - * `name`: The name of the account being authenticated. - * `ip`: The IP address of the client - * `is_success`: Whether the client was successfully authenticated - * For newly registered accounts, `is_success` will always be true -* `core.register_on_auth_fail(function(name, ip))` - * Deprecated: use `core.register_on_authplayer(name, ip, is_success)` instead. -* `core.register_on_cheat(function(ObjectRef, cheat))` - * Called when a player cheats - * `cheat`: `{type=}`, where `` is one of: - * `moved_too_fast` - * `interacted_too_far` - * `interacted_with_self` - * `interacted_while_dead` - * `finished_unknown_dig` - * `dug_unbreakable` - * `dug_too_fast` -* `core.register_on_chat_message(function(name, message))` - * Called always when a player says something - * Return `true` to mark the message as handled, which means that it will - not be sent to other players. -* `core.register_on_chatcommand(function(name, command, params))` - * Called always when a chatcommand is triggered, before `core.registered_chatcommands` - is checked to see if the command exists, but after the input is parsed. - * Return `true` to mark the command as handled, which means that the default - handlers will be prevented. -* `core.register_on_player_receive_fields(function(player, formname, fields))` - * Called when the server received input from `player`. - Specifically, this is called on any of the - following events: - * a button was pressed, - * Enter was pressed while the focus was on a text field - * a checkbox was toggled, - * something was selected in a dropdown list, - * a different tab was selected, - * selection was changed in a textlist or table, - * an entry was double-clicked in a textlist or table, - * a scrollbar was moved, or - * the form was actively closed by the player. - * `formname` is the name passed to `core.show_formspec`. - Special case: The empty string refers to the player inventory - (the formspec set by the `set_inventory_formspec` player method). - * Fields are sent for formspec elements which define a field. `fields` - is a table containing each formspecs element value (as string), with - the `name` parameter as index for each. The value depends on the - formspec element type: - * `animated_image`: Returns the index of the current frame. - * `button` and variants: If pressed, contains the user-facing button - text as value. If not pressed, is `nil` - * `field`, `textarea` and variants: Text in the field - * `dropdown`: Either the index or value, depending on the `index event` - dropdown argument. - * `tabheader`: Tab index, starting with `"1"` (only if tab changed) - * `checkbox`: `"true"` if checked, `"false"` if unchecked - * `textlist`: See `core.explode_textlist_event` - * `table`: See `core.explode_table_event` - * `scrollbar`: See `core.explode_scrollbar_event` - * Special case: `["quit"]="true"` is sent when the user actively - closed the form by mouse click, keypress or through a `button_exit[]` - element. - * Special case: `["try_quit"]="true"` is sent when the user tries to - close the formspec, but the formspec used `allow_close[false]`. - * Special case: `["key_enter"]="true"` is sent when the user pressed - the Enter key and the focus was either nowhere (causing the formspec - to be closed) or on a button. If the focus was on a text field, - additionally, the index `key_enter_field` contains the name of the - text field. See also: `field_close_on_enter`. - * Newest functions are called first - * If function returns `true`, remaining functions are not called -* `core.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv))` - * Called when `player` crafts something - * `itemstack` is the output - * `old_craft_grid` contains the recipe, is a list of `ItemStack`s (Note: the one in the inventory is - cleared). - * `craft_inv` is the inventory with the crafting grid - * Return either an `ItemStack`, to replace the output, or `nil`, to not - modify it. -* `core.register_craft_predict(function(itemstack, player, old_craft_grid, craft_inv))` - * The same as before, except that it is called before the player crafts, to - make craft prediction, and it should not change anything. -* `core.register_allow_player_inventory_action(function(player, action, inventory, inventory_info))` - * Determines how much of a stack may be taken, put or moved to a - player inventory. - * Function arguments: see `core.register_on_player_inventory_action` - * Return a numeric value to limit the amount of items to be taken, put or - moved. A value of `-1` for `take` will make the source stack infinite. -* `core.register_on_player_inventory_action(function(player, action, inventory, inventory_info))` - * Called after an item take, put or move event from/to/in a player inventory - * These inventory actions are recognized: - * move: Item was moved within the player inventory - * put: Item was put into player inventory from another inventory - * take: Item was taken from player inventory and put into another inventory - * `player` (type `ObjectRef`) is the player who modified the inventory - `inventory` (type `InvRef`). - * List of possible `action` (string) values and their - `inventory_info` (table) contents: - * `move`: `{from_list=string, to_list=string, from_index=number, to_index=number, count=number}` - * `put`: `{listname=string, index=number, stack=ItemStack}` - * `take`: Same as `put` - * Does not accept or handle any return value. -* `core.register_on_protection_violation(function(pos, name))` - * Called by `builtin` and mods when a player violates protection at a - position (eg, digs a node or punches a protected entity). - * The registered functions can be called using - `core.record_protection_violation`. - * The provided function should check that the position is protected by the - mod calling this function before it prints a message, if it does, to - allow for multiple protection mods. -* `core.register_on_item_eat(function(hp_change, replace_with_item, itemstack, user, pointed_thing))` - * Called when an item is eaten, by `core.item_eat` - * Return `itemstack` to cancel the default item eat response (i.e.: hp increase). -* `core.register_on_item_pickup(function(itemstack, picker, pointed_thing, time_from_last_punch, ...))` - * Called by `core.item_pickup` before an item is picked up. - * Function is added to `core.registered_on_item_pickups`. - * Oldest functions are called first. - * Parameters are the same as in the `on_pickup` callback. - * Return an itemstack to cancel the default item pick-up response (i.e.: adding - the item into inventory). -* `core.register_on_priv_grant(function(name, granter, priv))` - * Called when `granter` grants the priv `priv` to `name`. - * Note that the callback will be called twice if it's done by a player, - once with granter being the player name, and again with granter being nil. -* `core.register_on_priv_revoke(function(name, revoker, priv))` - * Called when `revoker` revokes the priv `priv` from `name`. - * Note that the callback will be called twice if it's done by a player, - once with revoker being the player name, and again with revoker being nil. -* `core.register_can_bypass_userlimit(function(name, ip))` - * Called when `name` user connects with `ip`. - * Return `true` to by pass the player limit -* `core.register_on_modchannel_message(function(channel_name, sender, message))` - * Called when an incoming mod channel message is received - * You should have joined some channels to receive events. - * If message comes from a server mod, `sender` field is an empty string. -* `core.register_on_liquid_transformed(function(pos_list, node_list))` - * Called after liquid nodes (`liquidtype ~= "none"`) are modified by the - engine's liquid transformation process. - * `pos_list` is an array of all modified positions. - * `node_list` is an array of the old node that was previously at the position - with the corresponding index in pos_list. -* `core.register_on_mapblocks_changed(function(modified_blocks, modified_block_count))` - * Called soon after any nodes or node metadata have been modified. No - modifications will be missed, but there may be false positives. - * Will never be called more than once per server step. - * `modified_blocks` is the set of modified mapblock position hashes. These - are in the same format as those produced by `core.hash_node_position`, - and can be converted to positions with `core.get_position_from_hash`. - The set is a table where the keys are hashes and the values are `true`. - * `modified_block_count` is the number of entries in the set. - * Note: callbacks must be registered at mod load time. - -Setting-related ---------------- - -* `core.settings`: Settings object containing all of the settings from the - main config file (`minetest.conf`). See [`Settings`](#settings). -* `core.setting_get_pos(name)`: Loads a setting from the main settings and - parses it as a position (in the format `(1,2,3)`). Returns a position or nil. **Deprecated: use `core.settings:get_pos()` instead** - -Authentication --------------- - -* `core.string_to_privs(str[, delim])`: - * Converts string representation of privs into table form - * `delim`: String separating the privs. Defaults to `","`. - * Returns `{ priv1 = true, ... }` -* `core.privs_to_string(privs[, delim])`: - * Returns the string representation of `privs` - * `delim`: String to delimit privs. Defaults to `","`. -* `core.get_player_privs(name) -> {priv1=true,...}` -* `core.check_player_privs(player_or_name, ...)`: - returns `bool, missing_privs` - * A quickhand for checking privileges. - * `player_or_name`: Either a Player object or the name of a player. - * `...` is either a list of strings, e.g. `"priva", "privb"` or - a table, e.g. `{ priva = true, privb = true }`. - -* `core.check_password_entry(name, entry, password)` - * Returns true if the "password entry" for a player with name matches given - password, false otherwise. - * The "password entry" is the password representation generated by the - engine as returned as part of a `get_auth()` call on the auth handler. - * Only use this function for making it possible to log in via password from - external protocols such as IRC, other uses are frowned upon. -* `core.get_password_hash(name, raw_password)` - * Convert a name-password pair to a password hash that Luanti can use. - * The returned value alone is not a good basis for password checks based - on comparing the password hash in the database with the password hash - from the function, with an externally provided password, as the hash - in the db might use the new SRP verifier format. - * For this purpose, use `core.check_password_entry` instead. -* `core.get_player_ip(name)`: returns an IP address string for the player - `name`. - * The player needs to be online for this to be successful. - -* `core.get_auth_handler()`: Return the currently active auth handler - * Must be called *after* load time, to ensure that any custom auth handler was - already registered. - * See the [Authentication handler definition](#authentication-handler-definition) - * Use this to e.g. get the authentication data for a player: - `local auth_data = core.get_auth_handler().get_auth(playername)` -* `core.notify_authentication_modified(name)` - * Must be called by the authentication handler for privilege changes. - * `name`: string; if omitted, all auth data should be considered modified -* `core.set_player_password(name, password_hash)`: Set password hash of - player `name`. -* `core.set_player_privs(name, privs)`: Set privileges of player `name`. - * `privs` is a **set** of privileges: - A table where the keys are names of privileges and the values are `true`. - * Example: `core.set_player_privs("singleplayer", {interact = true, fly = true})`. - This **sets** the player privileges to `interact` and `fly`; - `singleplayer` will only have these two privileges afterwards. -* `core.change_player_privs(name, changes)`: Helper to grant or revoke privileges. - * `changes`: Table of changes to make. - A field `[privname] = true` grants a privilege, - whereas `[privname] = false` revokes a privilege. - * Example: `core.change_player_privs("singleplayer", {interact = true, fly = false})` - will grant singleplayer the `interact` privilege - and revoke singleplayer's `fly` privilege. - All other privileges will remain unchanged. -* `core.auth_reload()` - * See `reload()` in authentication handler definition - -`core.set_player_password`, `core.set_player_privs`, -`core.get_player_privs` and `core.auth_reload` call the authentication -handler. - -Chat ----- - -* `core.chat_send_all(text)`: send chat message to all players -* `core.chat_send_player(name, text)`: send chat message to specific player - * `name`: Name of the player -* `core.format_chat_message(name, message)` - * Used by the server to format a chat message, based on the setting `chat_message_format`. - Refer to the documentation of the setting for a list of valid placeholders. - * Takes player name and message, and returns the formatted string to be sent to players. - * Can be redefined by mods if required, for things like colored names or messages. - * **Only** the first occurrence of each placeholder will be replaced. - -Environment access ------------------- - -* `core.set_node(pos, node)` - * Set node at position `pos`. - * Any existing metadata is deleted. - * `node`: table `{name=string, param1=number, param2=number}` - If param1 or param2 is omitted, it's set to `0`. - * e.g. `core.set_node({x=0, y=10, z=0}, {name="default:wood"})` -* `core.add_node(pos, node)`: alias to `core.set_node` -* `core.bulk_set_node({pos1, pos2, pos3, ...}, node)` - * Set the same node at all positions in the first argument. - * e.g. `core.bulk_set_node({{x=0, y=1, z=1}, {x=1, y=2, z=2}}, {name="default:stone"})` - * For node specification or position syntax see `core.set_node` call - * Faster than set_node due to single call, but still considerably slower - than Lua Voxel Manipulators (LVM) for large numbers of nodes. - Unlike LVMs, this will call node callbacks. It also allows setting nodes - in spread out positions which would cause LVMs to waste memory. - For setting a cube, this is 1.3x faster than set_node whereas LVM is 20 - times faster. -* `core.swap_node(pos, node)` - * Swap node at position with another. - * This keeps the metadata intact and will not run con-/destructor callbacks. -* `core.bulk_swap_node({pos1, pos2, pos3, ...}, node)` - * Equivalent to `core.swap_node` but in bulk. -* `core.remove_node(pos)`: Remove a node - * Equivalent to `core.set_node(pos, {name="air"})`, but a bit faster. -* `core.get_node(pos)` - * Returns the node at the given position as table in the same format as `set_node`. - * This function never returns `nil` and instead returns - `{name="ignore", param1=0, param2=0}` for unloaded areas. -* `core.get_node_or_nil(pos)` - * Same as `get_node` but returns `nil` for unloaded areas. - * Note that even loaded areas can contain "ignore" nodes. -* `core.get_node_raw(x, y, z)` - * Same as `get_node` but a faster low-level API - * Returns `content_id`, `param1`, `param2`, and `pos_ok` - * The `content_id` can be mapped to a name using `core.get_name_from_content_id()` - * If `pos_ok` is false, the area is unloaded and `content_id == core.CONTENT_IGNORE` -* `core.get_node_light(pos[, timeofday])` - * Gets the light value at the given position. Note that the light value - "inside" the node at the given position is returned, so you usually want - to get the light value of a neighbor. - * `pos`: The position where to measure the light. - * `timeofday`: `nil` for current time, `0` for night, `0.5` for day - * Returns a number between `0` and `15` or `nil` - * `nil` is returned e.g. when the map isn't loaded at `pos` -* `core.get_natural_light(pos[, timeofday])` - * Figures out the sunlight (or moonlight) value at pos at the given time of - day. - * `pos`: The position of the node - * `timeofday`: `nil` for current time, `0` for night, `0.5` for day - * Returns a number between `0` and `15` or `nil` - * This function tests 203 nodes in the worst case, which happens very - unlikely -* `core.get_artificial_light(param1)` - * Calculates the artificial light (light from e.g. torches) value from the - `param1` value. - * `param1`: The param1 value of a `paramtype = "light"` node. - * Returns a number between `0` and `15` - * Currently it's the same as `math.floor(param1 / 16)`, except that it - ensures compatibility. -* `core.place_node(pos, node[, placer])` - * Place node with the same effects that a player would cause - * `placer`: The ObjectRef that places the node (optional) -* `core.dig_node(pos[, digger])` - * Dig node with the same effects that a player would cause - * `digger`: The ObjectRef that digs the node (optional) - * Returns `true` if successful, `false` on failure (e.g. protected location) -* `core.punch_node(pos[, puncher])` - * Punch node with the same effects that a player would cause - * `puncher`: The ObjectRef that punches the node (optional) -* `core.spawn_falling_node(pos)` - * Change node into falling node - * Returns `true` and the ObjectRef of the spawned entity if successful, `false` on failure - -* `core.find_nodes_with_meta(pos1, pos2)` - * Get a table of positions of nodes that have metadata within a region - {pos1, pos2}. -* `core.get_meta(pos)` - * Get a `NodeMetaRef` at that position -* `core.get_node_timer(pos)` - * Get `NodeTimerRef` - -* `core.add_entity(pos, name, [staticdata])`: Spawn Lua-defined entity at - position. - * Returns `ObjectRef`, or `nil` if failed - * Entities with `static_save = true` can be added also - to unloaded and non-generated blocks. -* `core.add_item(pos, item)`: Spawn item - * Returns `ObjectRef`, or `nil` if failed - * Items can be added also to unloaded and non-generated blocks. -* `core.get_player_by_name(name)`: Get an `ObjectRef` to a player - * Returns nothing in case of error (player offline, doesn't exist, ...). -* `core.get_objects_inside_radius(center, radius)` - * returns a list of ObjectRefs - * `radius`: using a Euclidean metric - * **Warning**: Any kind of interaction with the environment or other APIs - can cause later objects in the list to become invalid while you're iterating it. - (e.g. punching an entity removes its children) - It is recommended to use `core.objects_inside_radius` instead, which - transparently takes care of this possibility. -* `core.objects_inside_radius(center, radius)` - * returns an iterator of valid objects - * example: `for obj in core.objects_inside_radius(center, radius) do obj:punch(...) end` -* `core.get_objects_in_area(min_pos, max_pos)` - * returns a list of ObjectRefs - * `min_pos` and `max_pos` are the min and max positions of the area to search - * **Warning**: The same warning as for `core.get_objects_inside_radius` applies. - Use `core.objects_in_area` instead to iterate only valid objects. -* `core.objects_in_area(min_pos, max_pos)` - * returns an iterator of valid objects -* `core.set_timeofday(val)`: set time of day - * `val` is between `0` and `1`; `0` for midnight, `0.5` for midday -* `core.get_timeofday()`: get time of day -* `core.get_gametime()`: returns the time, in seconds, since the world was - created. The time is not available (`nil`) before the first server step. -* `core.get_day_count()`: returns number days elapsed since world was - created. - * Time changes are accounted for. -* `core.find_node_near(pos, radius, nodenames, [search_center])`: returns - pos or `nil`. - * `radius`: using a maximum metric - * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` - * `search_center` is an optional boolean (default: `false`) - If true `pos` is also checked for the nodes -* `core.find_nodes_in_area(pos1, pos2, nodenames, [grouped])` - * `pos1` and `pos2` are the min and max positions of the area to search. - * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` - * If `grouped` is true the return value is a table indexed by node name - which contains lists of positions. - * If `grouped` is false or absent the return values are as follows: - first value: Table with all node positions - second value: Table with the count of each node with the node name - as index - * Area volume is limited to 150,000,000 nodes -* `core.find_nodes_in_area_under_air(pos1, pos2, nodenames)`: returns a - list of positions. - * `nodenames`: e.g. `{"ignore", "group:tree"}` or `"default:dirt"` - * Return value: Table with all node positions with a node air above - * Area volume is limited to 150,000,000 nodes -* `core.get_value_noise(noiseparams)` - * Return world-specific value noise. - * The actual seed used is the noiseparams seed plus the world seed. - * **Important**: Requires the mapgen environment to be initalized, do not use at load time. -* `core.get_value_noise(seeddiff, octaves, persistence, spread)` - * Deprecated: use `core.get_value_noise(noiseparams)` instead. -* `core.get_perlin(noiseparams)` - * Deprecated: renamed to `core.get_value_noise` in version 5.12.0. -* `core.get_perlin(seeddiff, octaves, persistence, spread)` - * Deprecated: renamed to `core.get_value_noise` in version 5.12.0. -* `core.get_voxel_manip([pos1, pos2])` - * Return voxel manipulator object. - * Loads the manipulator from the map if positions are passed. -* `core.set_gen_notify(flags, [deco_ids], [custom_ids])` - * Set the types of on-generate notifications that should be collected. - * `flags`: flag field, see [`gennotify`](#gennotify) for available generation notification types. - * The following parameters are optional: - * `deco_ids` is a list of IDs of decorations which notification - is requested for. - * `custom_ids` is a list of user-defined IDs (strings) which are - requested. By convention these should be the mod name with an optional - colon and specifier added, e.g. `"default"` or `"default:dungeon_loot"` -* `core.get_gen_notify()` - * Returns a flagstring, a table with the `deco_id`s and a table with - user-defined IDs. -* `core.get_decoration_id(decoration_name)` - * Returns the decoration ID number for the provided decoration name string, - or `nil` on failure. -* `core.get_mapgen_object(objectname)` - * Return requested mapgen object if available (see [Mapgen objects](#mapgen-objects)) -* `core.get_heat(pos)` - * Returns the heat at the position, or `nil` on failure. -* `core.get_humidity(pos)` - * Returns the humidity at the position, or `nil` on failure. -* `core.get_biome_data(pos)` - * Returns a table containing: - * `biome` the biome id of the biome at that position - * `heat` the heat at the position - * `humidity` the humidity at the position - * Or returns `nil` on failure. -* `core.get_biome_id(biome_name)` - * Returns the biome id, as used in the biomemap Mapgen object and returned - by `core.get_biome_data(pos)`, for a given biome_name string. -* `core.get_biome_name(biome_id)` - * Returns the biome name string for the provided biome id, or `nil` on - failure. - * If no biomes have been registered, such as in mgv6, returns `default`. -* `core.get_mapgen_params()` - * Deprecated: use `core.get_mapgen_setting(name)` instead. - * Returns a table containing: - * `mgname` - * `seed` - * `chunksize` - * `water_level` - * `flags` -* `core.set_mapgen_params(MapgenParams)` - * Deprecated: use `core.set_mapgen_setting(name, value, override)` - instead. - * Set map generation parameters. - * Function cannot be called after the registration period. - * Takes a table as an argument with the fields: - * `mgname` - * `seed` - * `chunksize` - * `water_level` - * `flags` - * Leave field unset to leave that parameter unchanged. - * `flags` contains a comma-delimited string of flags to set, or if the - prefix `"no"` is attached, clears instead. - * `flags` is in the same format and has the same options as `mg_flags` in - `minetest.conf`. -* `core.get_mapgen_edges([mapgen_limit[, chunksize]])` - * Returns the minimum and maximum possible generated node positions - in that order. - * `mapgen_limit` is an optional number. If it is absent, its value is that - of the *active* mapgen setting `"mapgen_limit"`. - * `chunksize` is an optional number. If it is absent, its value is that - of the *active* mapgen setting `"chunksize"`. -* `core.get_mapgen_chunksize()` - * Returns the currently active chunksize of the mapgen, as a vector. - The size is specified in blocks. -* `core.get_mapgen_setting(name)` - * Gets the *active* mapgen setting (or nil if none exists) in string - format with the following order of precedence: - 1) Settings loaded from map_meta.txt or overrides set during mod - execution. - 2) Settings set by mods without a metafile override - 3) Settings explicitly set in the user config file, minetest.conf - 4) Settings set as the user config default -* `core.get_mapgen_setting_noiseparams(name)` - * Same as above, but returns the value as a NoiseParams table if the - setting `name` exists and is a valid NoiseParams. -* `core.set_mapgen_setting(name, value, [override_meta])` - * Sets a mapgen param to `value`, and will take effect if the corresponding - mapgen setting is not already present in map_meta.txt. - * `override_meta` is an optional boolean (default: `false`). If this is set - to true, the setting will become the active setting regardless of the map - metafile contents. - * Note: to set the seed, use `"seed"`, not `"fixed_map_seed"`. -* `core.set_mapgen_setting_noiseparams(name, value, [override_meta])` - * Same as above, except value is a NoiseParams table. -* `core.set_noiseparams(name, noiseparams, set_default)` - * Sets the noiseparams setting of `name` to the noiseparams table specified - in `noiseparams`. - * `set_default` is an optional boolean (default: `true`) that specifies - whether the setting should be applied to the default config or current - active config. -* `core.get_noiseparams(name)` - * Returns a table of the noiseparams for name. -* `core.generate_ores(vm[, pos1, pos2])` - * Generate all registered ores within the VoxelManip `vm` and in the area - from `pos1` to `pos2`. - * `pos1` and `pos2` are optional and default to mapchunk minp and maxp. -* `core.generate_decorations(vm[, pos1, pos2])` - * Generate all registered decorations within the VoxelManip `vm` and in the - area from `pos1` to `pos2`. - * `pos1` and `pos2` are optional and default to mapchunk minp and maxp. -* `core.clear_objects([options])` - * Clear all objects in the environment - * Takes an optional table as an argument with the field `mode`. - * mode = `"full"`: Load and go through every mapblock, clearing - objects (default). - * mode = `"quick"`: Clear objects immediately in loaded mapblocks, - clear objects in unloaded mapblocks only when the - mapblocks are next activated. -* `core.load_area(pos1[, pos2])` - * Load the mapblocks containing the area from `pos1` to `pos2`. - `pos2` defaults to `pos1` if not specified. - * This function does not trigger map generation. -* `core.emerge_area(pos1, pos2, [callback], [param])` - * Queue all blocks in the area from `pos1` to `pos2`, inclusive, to be - asynchronously fetched from memory, loaded from disk, or if inexistent, - generates them. - * If `callback` is a valid Lua function, this will be called for each block - emerged. - * The function signature of callback is: - `function EmergeAreaCallback(blockpos, action, calls_remaining, param)` - * `blockpos` is the *block* coordinates of the block that had been - emerged. - * `action` could be one of the following constant values: - * `core.EMERGE_CANCELLED` - * `core.EMERGE_ERRORED` - * `core.EMERGE_FROM_MEMORY` - * `core.EMERGE_FROM_DISK` - * `core.EMERGE_GENERATED` - * `calls_remaining` is the number of callbacks to be expected after - this one. - * `param` is the user-defined parameter passed to emerge_area (or - nil if the parameter was absent). -* `core.delete_area(pos1, pos2)` - * delete all mapblocks in the area from pos1 to pos2, inclusive -* `core.line_of_sight(pos1, pos2)`: returns `boolean, pos` - * Checks if there is anything other than air between pos1 and pos2. - * Returns false if something is blocking the sight. - * Returns the position of the blocking node when `false` - * `pos1`: First position - * `pos2`: Second position -* `core.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast` - * Creates a `Raycast` object. - * `pos1`: start of the ray - * `pos2`: end of the ray - * `objects`: if false, only nodes will be returned. Default is `true`. - * `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be - returned. Default is `false`. - * `pointabilities`: Allows overriding the `pointable` property of - nodes and objects. Uses the same format as the `pointabilities` property - of item definitions. Default is `nil`. -* `core.find_path(pos1, pos2, searchdistance, max_jump, max_drop, algorithm)` - * returns table containing path that can be walked on - * returns a table of 3D points representing a path from `pos1` to `pos2` or - `nil` on failure. - * Reasons for failure: - * No path exists at all - * No path exists within `searchdistance` (see below) - * Start or end pos is buried in land - * `pos1`: start position - * `pos2`: end position - * `searchdistance`: maximum distance from the search positions to search in. - In detail: Path must be completely inside a cuboid. The minimum - `searchdistance` of 1 will confine search between `pos1` and `pos2`. - Larger values will increase the size of this cuboid in all directions - * `max_jump`: maximum height difference to consider walkable - * `max_drop`: maximum height difference to consider droppable - * `algorithm`: One of `"A*_noprefetch"` (default), `"A*"`, `"Dijkstra"`. - Difference between `"A*"` and `"A*_noprefetch"` is that - `"A*"` will pre-calculate the cost-data, the other will calculate it - on-the-fly -* `core.spawn_tree(pos, treedef)` - * spawns L-system tree at given `pos` with definition in `treedef` table -* `core.spawn_tree_on_vmanip(vmanip, pos, treedef)` - * analogous to `core.spawn_tree`, but spawns a L-system tree onto the specified - VoxelManip object `vmanip` instead of the map. -* `core.transforming_liquid_add(pos)` - * add node to liquid flow update queue -* `core.get_node_max_level(pos)` - * get max available level for leveled node -* `core.get_node_level(pos)` - * get level of leveled node (water, snow) -* `core.set_node_level(pos, level)` - * set level of leveled node, default `level` equals `1` - * if `totallevel > maxlevel`, returns rest (`total-max`). -* `core.add_node_level(pos, level)` - * increase level of leveled node by level, default `level` equals `1` - * if `totallevel > maxlevel`, returns rest (`total-max`) - * `level` must be between -127 and 127 -* `core.get_node_boxes(box_type, pos, [node])` - * `box_type` must be `"node_box"`, `"collision_box"` or `"selection_box"`. - * `pos` must be a node position. - * `node` can be a table in the form `{name=string, param1=number, param2=number}`. - If `node` is `nil`, the actual node at `pos` is used instead. - * Resolves any facedir-rotated boxes, connected boxes and the like into - actual boxes. - * Returns a list of boxes in the form - `{{x1, y1, z1, x2, y2, z2}, {x1, y1, z1, x2, y2, z2}, ...}`. Coordinates - are relative to `pos`. - * See also: [Node boxes](#node-boxes) -* `core.fix_light(pos1, pos2)`: returns `true`/`false` - * resets the light in a cuboid-shaped part of - the map and removes lighting bugs. - * Loads the area if it is not loaded. - * `pos1` is the corner of the cuboid with the least coordinates - (in node coordinates), inclusive. - * `pos2` is the opposite corner of the cuboid, inclusive. - * The actual updated cuboid might be larger than the specified one, - because only whole map blocks can be updated. - The actual updated area consists of those map blocks that intersect - with the given cuboid. - * However, the neighborhood of the updated area might change - as well, as light can spread out of the cuboid, also light - might be removed. - * returns `false` if the area is not fully generated, - `true` otherwise -* `core.check_single_for_falling(pos)` - * causes an unsupported `group:falling_node` node to fall and causes an - unattached `group:attached_node` node to fall. - * does not spread these updates to neighbors. -* `core.check_for_falling(pos)` - * causes an unsupported `group:falling_node` node to fall and causes an - unattached `group:attached_node` node to fall. - * spread these updates to neighbors and can cause a cascade - of nodes to fall. -* `core.get_spawn_level(x, z)` - * Returns a player spawn y coordinate for the provided (x, z) - coordinates, or `nil` for an unsuitable spawn point. - * For most mapgens a 'suitable spawn point' is one with y between - `water_level` and `water_level + 16`, and in mgv7 well away from rivers, - so `nil` will be returned for many (x, z) coordinates. - * The spawn level returned is for a player spawn in unmodified terrain. - * The spawn level is intentionally above terrain level to cope with - full-node biome 'dust' nodes. - -Mod channels ------------- - -You can find mod channels communication scheme in `doc/mod_channels.png`. - -* `core.mod_channel_join(channel_name)` - * Server joins channel `channel_name`, and creates it if necessary. You - should listen for incoming messages with - `core.register_on_modchannel_message` - * This returns a [ModChannel](#modchannel) object. - -Inventory ---------- - -`core.get_inventory(location)`: returns an `InvRef` - -* `location` = e.g. - * `{type="player", name="celeron55"}` - * `{type="node", pos={x=, y=, z=}}` - * `{type="detached", name="creative"}` -* `core.create_detached_inventory(name, callbacks, [player_name])`: returns - an `InvRef`. - * `callbacks`: See [Detached inventory callbacks](#detached-inventory-callbacks) - * `player_name`: Make detached inventory available to one player - exclusively, by default they will be sent to every player (even if not - used). - Note that this parameter is mostly just a workaround and will be removed - in future releases. - * Creates a detached inventory. If it already exists, it is cleared. -* `core.remove_detached_inventory(name)` - * Returns a `boolean` indicating whether the removal succeeded. -* `core.do_item_eat(hp_change, replace_with_item, itemstack, user, pointed_thing)`: - returns leftover ItemStack or nil to indicate no inventory change - * See `core.item_eat` and `core.register_on_item_eat` - -Formspec functions --------- - -* `core.show_formspec(playername, formname, formspec)` - * `playername`: name of player to show formspec - * `formname`: name passed to `on_player_receive_fields` callbacks. - * It should follow the `"modname:"` naming convention. - * If empty: Shows a custom, temporary inventory formspec. - * An inventory formspec shown this way will also be updated if - `ObjectRef:set_inventory_formspec` is called. - * Use `ObjectRef:set_inventory_formspec` to change the player's - inventory formspec for future opens. - * Supported if server AND client are both of version >= 5.13.0. - * `formspec`: formspec to display - * See also: `core.register_on_player_receive_fields` -* `core.close_formspec(playername, formname)` - * `playername`: name of player to close formspec - * `formname`: has to exactly match the one given in `show_formspec`, or the - formspec will not close. - * calling `show_formspec(playername, formname, "")` is equal to this - expression. - * to close a formspec regardless of the formname, call - `core.close_formspec(playername, "")`. - **USE THIS ONLY WHEN ABSOLUTELY NECESSARY!** -* `core.formspec_escape(string)`: returns a string - * escapes the characters "[", "]", "\", "," and ";", which cannot be used - in formspecs. -* `core.hypertext_escape(string)`: returns a string - * escapes the characters "\", "<", and ">" to show text in a hypertext element. - * not safe for use with tag attributes. - * this function does not do formspec escaping, you will likely need to do - `core.formspec_escape(core.hypertext_escape(string))` if the hypertext is - not already being formspec escaped. -* `core.explode_table_event(string)`: returns a table - * returns e.g. `{type="CHG", row=1, column=2}` - * `type` is one of: - * `"INV"`: no row selected - * `"CHG"`: selected - * `"DCL"`: double-click -* `core.explode_textlist_event(string)`: returns a table - * returns e.g. `{type="CHG", index=1}` - * `type` is one of: - * `"INV"`: no row selected - * `"CHG"`: selected - * `"DCL"`: double-click -* `core.explode_scrollbar_event(string)`: returns a table - * returns e.g. `{type="CHG", value=500}` - * `type` is one of: - * `"INV"`: something failed - * `"CHG"`: has been changed - * `"VAL"`: not changed -* `core.show_death_screen(player, reason)` - * Called when the death screen should be shown. - * `player` is an ObjectRef, `reason` is a PlayerHPChangeReason table or nil. - * By default, this shows a simple formspec with the option to respawn. - Respawning is done via `ObjectRef:respawn`. - * You can override this to show a custom death screen. - * For general death handling, use `core.register_on_dieplayer` instead. - -Item handling -------------- - -* `core.inventorycube(img1, img2, img3)` - * Returns a string for making an image of a cube (useful as an item image) -* `core.get_pointed_thing_position(pointed_thing, above)` - * Returns the position of a `pointed_thing` or `nil` if the `pointed_thing` - does not refer to a node or entity. - * If the optional `above` parameter is true and the `pointed_thing` refers - to a node, then it will return the `above` position of the `pointed_thing`. -* `core.dir_to_facedir(dir[, is6d])` - * Convert a vector to a facedir value, used in `param2` for - `paramtype2="facedir"`. - * passing something non-`nil`/`false` for the optional second parameter - causes it to take the y component into account. -* `core.facedir_to_dir(facedir)` - * Convert a facedir back into a vector aimed directly out the "back" of a - node. -* `core.dir_to_fourdir(dir)` - * Convert a vector to a 4dir value, used in `param2` for - `paramtype2="4dir"`. -* `core.fourdir_to_dir(fourdir)` - * Convert a 4dir back into a vector aimed directly out the "back" of a - node. -* `core.dir_to_wallmounted(dir)` - * Convert a vector to a wallmounted value, used for - `paramtype2="wallmounted"`. -* `core.wallmounted_to_dir(wallmounted)` - * Convert a wallmounted value back into a vector aimed directly out the - "back" of a node. -* `core.dir_to_yaw(dir)` - * Convert a vector into a yaw (angle) -* `core.yaw_to_dir(yaw)` - * Convert yaw (angle) to a vector -* `core.is_colored_paramtype(ptype)` - * Returns a boolean. Returns `true` if the given `paramtype2` contains - color information (`color`, `colorwallmounted`, `colorfacedir`, etc.). -* `core.strip_param2_color(param2, paramtype2)` - * Removes everything but the color information from the - given `param2` value. - * Returns `nil` if the given `paramtype2` does not contain color - information. -* `core.get_node_drops(node[, toolname, tool, digger, pos])` - * Returns list of itemstrings that are dropped by `node` when dug with the - item `toolname` (not limited to tools). The default implementation doesn't - use `tool`, `digger`, and `pos`, but these are provided by `core.node_dig` - since 5.12.0 for games/mods implementing customized drops. - * `node`: node as table or node name - * `toolname`: name of the item used to dig (can be `nil`) - * `tool`: `ItemStack` used to dig (can be `nil`) - * `digger`: the ObjectRef that digs the node (can be `nil`) - * `pos`: the pos of the dug node (can be `nil`) -* `core.get_craft_result(input)`: returns `output, decremented_input` - * `input.method` = `"normal"` or `"cooking"` or `"fuel"` - * `input.width` = for example `3` - * `input.items` = for example - `{stack1, stack2, stack3, stack4, stack 5, stack 6, stack 7, stack 8, stack 9}` - * `output.item` = `ItemStack`, if unsuccessful: empty `ItemStack` - * `output.time` = a number, if unsuccessful: `0` - * `output.replacements` = List of replacement `ItemStack`s that couldn't be - placed in `decremented_input.items`. Replacements can be placed in - `decremented_input` if the stack of the replaced item has a count of 1. - * `decremented_input` = like `input` -* `core.get_craft_recipe(output)`: returns input - * returns last registered recipe for output item (node) - * `output` is a node or item type such as `"default:torch"` - * `input.method` = `"normal"` or `"cooking"` or `"fuel"` - * `input.width` = for example `3` - * `input.items` = for example - `{stack1, stack2, stack3, stack4, stack 5, stack 6, stack 7, stack 8, stack 9}` - * `input.items` = `nil` if no recipe found -* `core.get_all_craft_recipes(query item)`: returns a table or `nil` - * returns indexed table with all registered recipes for query item (node) - or `nil` if no recipe was found. - * recipe entry table: - * `method`: 'normal' or 'cooking' or 'fuel' - * `width`: 0-3, 0 means shapeless recipe - * `items`: indexed [1-9] table with recipe items - * `output`: string with item name and quantity - * Example result for `"default:gold_ingot"` with two recipes: - ```lua - { - { - method = "cooking", width = 3, - output = "default:gold_ingot", items = {"default:gold_lump"} - }, - { - method = "normal", width = 1, - output = "default:gold_ingot 9", items = {"default:goldblock"} - } - } - ``` - -* `core.handle_node_drops(pos, drops, digger)` - * `drops`: list of itemstrings - * Handles drops from nodes after digging: Default action is to put them - into digger's inventory. - * Can be overridden to get different functionality (e.g. dropping items on - ground) -* `core.itemstring_with_palette(item, palette_index)`: returns an item - string. - * Creates an item string which contains palette index information - for hardware colorization. You can use the returned string - as an output in a craft recipe. - * `item`: the item stack which becomes colored. Can be in string, - table and native form. - * `palette_index`: this index is added to the item stack -* `core.itemstring_with_color(item, colorstring)`: returns an item string - * Creates an item string which contains static color information - for hardware colorization. Use this method if you wish to colorize - an item that does not own a palette. You can use the returned string - as an output in a craft recipe. - * `item`: the item stack which becomes colored. Can be in string, - table and native form. - * `colorstring`: the new color of the item stack - -Rollback --------- - -* `core.rollback_get_node_actions(pos, range, seconds, limit)`: - returns `{{actor, pos, time, oldnode, newnode}, ...}` - * Find who has done something to a node, or near a node - * `actor`: `"player:"`, also `"liquid"`. -* `core.rollback_revert_actions_by(actor, seconds)`: returns - `boolean, log_messages`. - * Revert latest actions of someone - * `actor`: `"player:"`, also `"liquid"`. - -Defaults for the `on_place` and `on_drop` item definition functions -------------------------------------------------------------------- - -* `core.item_place_node(itemstack, placer, pointed_thing[, param2, prevent_after_place])` - * Place item as a node - * `param2` overrides `facedir` and wallmounted `param2` - * `prevent_after_place`: if set to `true`, `after_place_node` is not called - for the newly placed node to prevent a callback and placement loop - * returns `itemstack, position` - * `position`: the location the node was placed to. `nil` if nothing was placed. -* `core.item_place_object(itemstack, placer, pointed_thing)` - * Place item as-is - * returns the leftover itemstack - * **Note**: This function is deprecated and will never be called. -* `core.item_place(itemstack, placer, pointed_thing[, param2])` - * Wrapper that calls `core.item_place_node` if appropriate - * Calls `on_rightclick` of `pointed_thing.under` if defined instead - * **Note**: is not called when wielded item overrides `on_place` - * `param2` overrides facedir and wallmounted `param2` - * returns `itemstack, position` - * `position`: the location the node was placed to. `nil` if nothing was placed. -* `core.item_pickup(itemstack, picker, pointed_thing, time_from_last_punch, ...)` - * Runs callbacks registered by `core.register_on_item_pickup` and adds - the item to the picker's `"main"` inventory list. - * Parameters are the same as in `on_pickup`. - * Returns the leftover itemstack. -* `core.item_drop(itemstack, dropper, pos)` - * Converts `itemstack` to an in-world Lua entity. - * `itemstack` (`ItemStack`) is modified (cleared) on success. - * In versions < 5.12.0, `itemstack` was cleared in all cases. - * `dropper` (`ObjectRef`) is optional. - * Returned values on success: - 1. leftover itemstack - 2. `ObjectRef` of the spawned object (provided since 5.12.0) -* `core.item_eat(hp_change[, replace_with_item])` - * Returns `function(itemstack, user, pointed_thing)` as a - function wrapper for `core.do_item_eat`. - * `replace_with_item` is the itemstring which is added to the inventory. - If the player is eating a stack and `replace_with_item` doesn't fit onto - the eaten stack, then the remainings go to a different spot, or are dropped. - -Defaults for the `on_punch` and `on_dig` node definition callbacks ------------------------------------------------------------------- - -* `core.node_punch(pos, node, puncher, pointed_thing)` - * Calls functions registered by `core.register_on_punchnode()` -* `core.node_dig(pos, node, digger)` - * Checks if node can be dug, puts item into inventory, removes node - * Calls functions registered by `core.registered_on_dignodes()` - -Sounds ------- - -* `core.sound_play(spec, parameters, [ephemeral])`: returns a handle - * `spec` is a `SimpleSoundSpec` - * `parameters` is a sound parameter table - * `ephemeral` is a boolean (default: false) - Ephemeral sounds will not return a handle and can't be stopped or faded. - It is recommend to use this for short sounds that happen in response to - player actions (e.g. door closing). -* `core.sound_stop(handle)` - * `handle` is a handle returned by `core.sound_play` -* `core.sound_fade(handle, step, gain)` - * `handle` is a handle returned by `core.sound_play` - * `step` determines how fast a sound will fade. - The gain will change by this much per second, - until it reaches the target gain. - Note: Older versions used a signed step. This is deprecated, but old - code will still work. (the client uses abs(step) to correct it) - * `gain` the target gain for the fade. - Fading to zero will delete the sound. - -Timing ------- - -* `core.after(time, func, ...)`: returns job table to use as below. - * Call the function `func` after `time` seconds, may be fractional - * Optional: Variable number of arguments that are passed to `func` - * Jobs set for earlier times are executed earlier. If multiple jobs expire - at exactly the same time, then they are executed in registration order. - * `time` is a lower bound. The job is executed in the first server-step that - started at least `time` seconds after the last time a server-step started, - measured with globalstep dtime. - * If `time` is `0`, the job is executed in the next step. - -* `job:cancel()` - * Cancels the job function from being called - -Async environment ------------------ - -The engine allows you to submit jobs to be ran in an isolated environment -concurrently with normal server operation. -A job consists of a function to be ran in the async environment, any amount of -arguments (will be serialized) and a callback that will be called with the return -value of the job function once it is finished. - -The async environment does *not* have access to the map, entities, players or any -globals defined in the 'usual' environment. Consequently, functions like -`core.get_node()` or `core.get_player_by_name()` simply do not exist in it. - -Arguments and return values passed through this can contain certain userdata -objects that will be seamlessly copied (not shared) to the async environment. -This allows you easy interoperability for delegating work to jobs. - -* `core.handle_async(func, callback, ...)`: - * Queue the function `func` to be ran in an async environment. - Note that there are multiple persistent workers and any of them may - end up running a given job. The engine will scale the amount of - worker threads automatically. - * When `func` returns the callback is called (in the normal environment) - with all of the return values as arguments. - * Optional: Variable number of arguments that are passed to `func` -* `core.register_async_dofile(path)`: - * Register a path to a Lua file to be imported when an async environment - is initialized. You can use this to preload code which you can then call - later using `core.handle_async()`. - - -### List of APIs available in an async environment - -Classes: - -* `AreaStore` -* `ItemStack` -* `ValueNoise` -* `ValueNoiseMap` -* `PseudoRandom` -* `PcgRandom` -* `SecureRandom` -* `VoxelArea` -* `VoxelManip` - * only if transferred into environment; can't read/write to map -* `Settings` - -Class instances that can be transferred between environments: - -* `ItemStack` -* `ValueNoise` -* `ValueNoiseMap` -* `VoxelManip` - -Functions: - -* Standalone helpers such as logging, filesystem, encoding, - hashing or compression APIs -* `core.register_portable_metatable` -* IPC - -Variables: - -* `core.settings` -* `core.registered_items`, `registered_nodes`, `registered_tools`, - `registered_craftitems` and `registered_aliases` - * with all functions and userdata values replaced by `true`, calling any - callbacks here is obviously not possible - -Mapgen environment ------------------- - -The engine runs the map generator on separate threads, each of these also has -a Lua environment. Its primary purpose is to allow mods to operate on newly -generated parts of the map to e.g. generate custom structures. -Internally it is referred to as "emerge environment". - -Refer to [Async environment](#async-environment) for the usual disclaimer on what environment isolation entails. - -The map generator threads, which also contain the above mentioned Lua environment, -are initialized after all mods have been loaded by the server. After that the -registered scripts (not all mods!) - see below - are run during initialization of -the mapgen environment. After that only callbacks happen. The mapgen env -does not have a global step or timer. - -* `core.register_mapgen_script(path)`: - * Register a path to a Lua file to be imported when a mapgen environment - is initialized. Run in order of registration. - -### List of APIs exclusive to the mapgen env - -* `core.register_on_generated(function(vmanip, minp, maxp, blockseed))` - * Called after the engine mapgen finishes a chunk but before it is written to - the map. - * Chunk data resides in `vmanip`. Other parts of the map are not accessible. - The area of the chunk if comprised of `minp` and `maxp`, note that is smaller - than the emerged area of the VoxelManip. - Note: calling `read_from_map()` or `write_to_map()` on the VoxelManipulator object - is not necessary and is disallowed. - * `blockseed`: 64-bit seed number used for this chunk -* `core.save_gen_notify(id, data)` - * Saves data for retrieval using the gennotify mechanism (see [Mapgen objects](#mapgen-objects)). - * Data is bound to the chunk that is currently being processed, so this function - only makes sense inside the `on_generated` callback. - * `id`: user-defined ID (a string) - By convention these should be the mod name with an optional - colon and specifier added, e.g. `"default"` or `"default:dungeon_loot"` - * `data`: any Lua object (will be serialized, no userdata allowed) - * returns `true` if the data was remembered. That is if `core.set_gen_notify` - was called with the same user-defined ID before. - -### List of APIs available in the mapgen env - -Classes: - -* `AreaStore` -* `ItemStack` -* `ValueNoise` -* `ValueNoiseMap` -* `PseudoRandom` -* `PcgRandom` -* `SecureRandom` -* `VoxelArea` -* `VoxelManip` - * only given by callbacks; cannot access rest of map -* `Settings` - -Functions: - -* Standalone helpers such as logging, filesystem, encoding, - hashing or compression APIs -* `core.get_biome_id`, `get_biome_name`, `get_heat`, `get_humidity`, - `get_biome_data`, `get_mapgen_object`, `get_mapgen_params`, `get_mapgen_edges`, - `get_mapgen_setting`, `get_noiseparams`, `get_decoration_id` and more -* `core.get_node`, `set_node`, `find_node_near`, `find_nodes_in_area`, - `spawn_tree` and similar - * these only operate on the current chunk (if inside a callback) -* IPC - -Variables: - -* `core.settings` -* `core.registered_items`, `registered_nodes`, `registered_tools`, - `registered_craftitems` and `registered_aliases` - * with all functions and userdata values replaced by `true`, calling any - callbacks here is obviously not possible -* `core.registered_biomes`, `registered_ores`, `registered_decorations` - -Note that node metadata does not exist in the mapgen env, we suggest deferring -setting any metadata you need to the `on_generated` callback in the regular env. -You can use the gennotify mechanism to transfer this information. - -Server ------- - -* `core.request_shutdown([message],[reconnect],[delay])`: request for - server shutdown. Will display `message` to clients. - * `reconnect` == true displays a reconnect button - * `delay` adds an optional delay (in seconds) before shutdown. - Negative delay cancels the current active shutdown. - Zero delay triggers an immediate shutdown. -* `core.cancel_shutdown_requests()`: cancel current delayed shutdown -* `core.get_server_status(name, joined)` - * Returns the server status string when a player joins or when the command - `/status` is called. Returns `nil` or an empty string when the message is - disabled. - * `joined`: Boolean value, indicates whether the function was called when - a player joined. - * This function may be overwritten by mods to customize the status message. -* `core.get_server_uptime()`: returns the server uptime in seconds -* `core.get_server_max_lag()`: returns the current maximum lag - of the server in seconds or nil if server is not fully loaded yet -* `core.remove_player(name)`: remove player from database (if they are not - connected). - * As auth data is not removed, `core.player_exists` will continue to - return true. Call the below method as well if you want to remove auth - data too. - * Returns a code (0: successful, 1: no such player, 2: player is connected) -* `core.remove_player_auth(name)`: remove player authentication data - * Returns boolean indicating success (false if player nonexistent) -* `core.dynamic_add_media(options, callback)` - * `options`: table containing the following parameters - * `filename`: name the media file will be usable as - (optional if `filepath` present) - * `filepath`: path to the file on the filesystem [*] - * `filedata`: the data of the file to be sent [*] - * `to_player`: name of the player the media should be sent to instead of - all players (optional) - * `ephemeral`: boolean that marks the media as ephemeral, - it will not be cached on the client (optional, default false) - * Exactly one of the parameters marked [*] must be specified. - * `callback`: function with arguments `name`, which is a player name - * Pushes the specified media file to client(s). (details below) - The file must be a supported image, sound or model format. - Dynamically added media is not persisted between server restarts. - * Returns false on error, true if the request was accepted - * The given callback will be called for every player as soon as the - media is available on the client. - * Details/Notes: - * If `ephemeral`=false and `to_player` is unset the file is added to the media - sent to clients on startup, this means the media will appear even on - old clients if they rejoin the server. - * If `ephemeral`=false the file must not be modified, deleted, moved or - renamed after calling this function. - * Regardless of any use of `ephemeral`, adding media files with the same - name twice is not possible/guaranteed to work. An exception to this is the - use of `to_player` to send the same, already existent file to multiple - chosen players. - * You can also call this at startup time. In that case `callback` MUST - be `nil` and you cannot use `ephemeral` or `to_player`, as these logically - do not make sense. - * Clients will attempt to fetch files added this way via remote media, - this can make transfer of bigger files painless (if set up). Nevertheless - it is advised not to use dynamic media for big media files. - -IPC ---- - -The engine provides a generalized mechanism to enable sharing data between the -different Lua environments (main, mapgen and async). -It is essentially a shared in-memory key-value store. - -* `core.ipc_get(key)`: - * Read a value from the shared data area. - * `key`: string, should use the `"modname:thing"` convention to avoid conflicts. - * returns an arbitrary Lua value, or `nil` if this key does not exist -* `core.ipc_set(key, value)`: - * Write a value to the shared data area. - * `key`: as above - * `value`: an arbitrary Lua value, cannot be or contain userdata. - -Interacting with the shared data will perform an operation comparable to -(de)serialization on each access. -For that reason modifying references will not have any effect, as in this example: -```lua -core.ipc_set("test:foo", {}) -core.ipc_get("test:foo").subkey = "value" -- WRONG! -core.ipc_get("test:foo") -- returns an empty table -``` - -**Advanced**: - -* `core.ipc_cas(key, old_value, new_value)`: - * Write a value to the shared data area, but only if the previous value - equals what was given. - This operation is called Compare-and-Swap and can be used to implement - synchronization between threads. - * `key`: as above - * `old_value`: value compared to using `==` (`nil` compares equal for non-existing keys) - * `new_value`: value that will be set - * returns: true on success, false otherwise -* `core.ipc_poll(key, timeout)`: - * Do a blocking wait until a value (other than `nil`) is present at the key. - * **IMPORTANT**: You usually don't need this function. Use this as a last resort - if nothing else can satisfy your use case! None of the Lua environments the - engine has are safe to block for extended periods, especially on the main - thread any delays directly translate to lag felt by players. - * `key`: as above - * `timeout`: maximum wait time, in milliseconds (positive values only) - * returns: true on success, false on timeout - -Bans ----- - -* `core.get_ban_list()`: returns a list of all bans formatted as string -* `core.get_ban_description(ip_or_name)`: returns list of bans matching - IP address or name formatted as string -* `core.ban_player(name)`: ban the IP of a currently connected player - * Returns boolean indicating success -* `core.unban_player_or_ip(ip_or_name)`: remove ban record matching - IP address or name -* `core.kick_player(name[, reason[, reconnect]])`: disconnect a player with an optional - reason. - * Returns boolean indicating success (false if player nonexistent) - * If `reconnect` is true, allow the user to reconnect. -* `core.disconnect_player(name[, reason[, reconnect]])`: disconnect a player with an - optional reason, this will not prefix with 'Kicked: ' like kick_player. - If no reason is given, it will default to 'Disconnected.' - * Returns boolean indicating success (false if player nonexistent) - -Particles ---------- - -* `core.add_particle(particle definition)` - * Deprecated: `core.add_particle(pos, velocity, acceleration, - expirationtime, size, collisiondetection, texture, playername)` - -* `core.add_particlespawner(particlespawner definition)` - * Add a `ParticleSpawner`, an object that spawns an amount of particles - over `time` seconds. - * Returns an `id`, and -1 if adding didn't succeed - * Deprecated: `core.add_particlespawner(amount, time, - minpos, maxpos, - minvel, maxvel, - minacc, maxacc, - minexptime, maxexptime, - minsize, maxsize, - collisiondetection, texture, playername)` - -* `core.delete_particlespawner(id, player)` - * Delete `ParticleSpawner` with `id` (return value from - `core.add_particlespawner`). - * If playername is specified, only deletes on the player's client, - otherwise on all clients. - -Schematics ----------- - -* `core.create_schematic(p1, p2, probability_list, filename, slice_prob_list)` - * Create a schematic from the volume of map specified by the box formed by - p1 and p2. - * Apply the specified probability and per-node force-place to the specified - nodes according to the `probability_list`. - * `probability_list` is an array of tables containing two fields, `pos` - and `prob`. - * `pos` is the 3D vector specifying the absolute coordinates of the - node being modified, - * `prob` is an integer value from `0` to `255` that encodes - probability and per-node force-place. Probability has levels - 0-127, then 128 may be added to encode per-node force-place. - For probability stated as 0-255, divide by 2 and round down to - get values 0-127, then add 128 to apply per-node force-place. - * If there are two or more entries with the same pos value, the - last entry is used. - * If `pos` is not inside the box formed by `p1` and `p2`, it is - ignored. - * If `probability_list` equals `nil`, no probabilities are applied. - * Apply the specified probability to the specified horizontal slices - according to the `slice_prob_list`. - * `slice_prob_list` is an array of tables containing two fields, `ypos` - and `prob`. - * `ypos` indicates the y position of the slice with a probability - applied, the lowest slice being `ypos = 0`. - * If slice probability list equals `nil`, no slice probabilities - are applied. - * Saves schematic in the Luanti Schematic format to filename. - -* `core.place_schematic(pos, schematic, rotation, replacements, force_placement, flags)` - * Place the schematic specified by schematic (see [Schematic specifier](#schematic-specifier)) at - `pos`. - * `rotation` can equal `"0"`, `"90"`, `"180"`, `"270"`, or `"random"`. - * If the `rotation` parameter is omitted, the schematic is not rotated. - * `replacements` = `{["old_name"] = "convert_to", ...}` - * `force_placement` is a boolean indicating whether nodes other than `air` - and `ignore` are replaced by the schematic. - * Returns nil if the schematic could not be loaded. - * **Warning**: Once you have loaded a schematic from a file, it will be - cached. Future calls will always use the cached version and the - replacement list defined for it, regardless of whether the file or the - replacement list parameter have changed. The only way to load the file - anew is to restart the server. - * `flags` is a flag field with the available flags: - * place_center_x - * place_center_y - * place_center_z - -* `core.place_schematic_on_vmanip(vmanip, pos, schematic, rotation, replacement, force_placement, flags)`: - * This function is analogous to core.place_schematic, but places a - schematic onto the specified VoxelManip object `vmanip` instead of the - map. - * Returns false if any part of the schematic was cut-off due to the - VoxelManip not containing the full area required, and true if the whole - schematic was able to fit. - * Returns nil if the schematic could not be loaded. - * After execution, any external copies of the VoxelManip contents are - invalidated. - * `flags` is a flag field with the available flags: - * place_center_x - * place_center_y - * place_center_z - -* `core.serialize_schematic(schematic, format, options)` - * Return the serialized schematic specified by schematic - (see [Schematic specifier](#schematic-specifier)) - * in the `format` of either "mts" or "lua". - * "mts" - a string containing the binary MTS data used in the MTS file - format. - * "lua" - a string containing Lua code representing the schematic in table - format. - * `options` is a table containing the following optional parameters: - * If `lua_use_comments` is true and `format` is "lua", the Lua code - generated will have (X, Z) position comments for every X row - generated in the schematic data for easier reading. - * If `lua_num_indent_spaces` is a nonzero number and `format` is "lua", - the Lua code generated will use that number of spaces as indentation - instead of a tab character. - -* `core.read_schematic(schematic, options)` - * Returns a Lua table representing the schematic (see: [Schematic specifier](#schematic-specifier)) - * `schematic` is the schematic to read (see: [Schematic specifier](#schematic-specifier)) - * `options` is a table containing the following optional parameters: - * `write_yslice_prob`: string value: - * `none`: no `write_yslice_prob` table is inserted, - * `low`: only probabilities that are not 254 or 255 are written in - the `write_ylisce_prob` table, - * `all`: write all probabilities to the `write_yslice_prob` table. - * The default for this option is `all`. - * Any invalid value will be interpreted as `all`. - -HTTP Requests -------------- - -* `core.request_http_api()`: - * returns `HTTPApiTable` containing http functions if the calling mod has - been granted access by being listed in the `secure.http_mods` or - `secure.trusted_mods` setting, otherwise returns `nil`. - * The returned table contains the functions `fetch`, `fetch_async` and - `fetch_async_get` described below. - * Only works at init time and must be called from the mod's main scope - (not from a function). - * Function only exists if Luanti server was built with cURL support. - * **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED TABLE, STORE IT IN - A LOCAL VARIABLE!** -* `HTTPApiTable.fetch(HTTPRequest req, callback)` - * Performs given request asynchronously and calls callback upon completion - * callback: `function(HTTPRequestResult res)` - * Use this HTTP function if you are unsure, the others are for advanced use -* `HTTPApiTable.fetch_async(HTTPRequest req)`: returns handle - * Performs given request asynchronously and returns handle for - `HTTPApiTable.fetch_async_get` -* `HTTPApiTable.fetch_async_get(handle)`: returns HTTPRequestResult - * Return response data for given asynchronous HTTP request - -Storage API ------------ - -* `core.get_mod_storage()`: - * returns reference to mod private `StorageRef` - * must be called during mod load time - -Misc. ------ - -* `core.get_connected_players()`: returns list of `ObjectRefs` -* `core.is_player(obj)`: boolean, whether `obj` is a player -* `core.player_exists(name)`: boolean, whether player exists - (regardless of online status) -* `core.is_valid_player_name(name)`: boolean, whether the given name - could be used as a player name (regardless of whether said player exists). -* `core.hud_replace_builtin(name, hud_definition)` - * Replaces definition of a builtin hud element - * `name`: `"breath"`, `"health"`, `"minimap"` or `"hotbar"` - * `hud_definition`: definition to replace builtin definition -* `core.parse_relative_number(arg, relative_to)`: returns number or nil - * Helper function for chat commands. - * For parsing an optionally relative number of a chat command - parameter, using the chat command tilde notation. - * `arg`: String snippet containing the number; possible values: - * `""`: return as number - * `"~"`: return `relative_to + ` - * `"~"`: return `relative_to` - * Anything else will return `nil` - * `relative_to`: Number to which the `arg` number might be relative to - * Examples: - * `core.parse_relative_number("5", 10)` returns 5 - * `core.parse_relative_number("~5", 10)` returns 15 - * `core.parse_relative_number("~", 10)` returns 10 -* `core.send_join_message(player_name)` - * This function can be overridden by mods to change the join message. -* `core.send_leave_message(player_name, timed_out)` - * This function can be overridden by mods to change the leave message. -* `core.hash_node_position(pos)`: returns a 48-bit integer - * `pos`: table {x=number, y=number, z=number}, - * Gives a unique numeric encoding for a node position (16+16+16=48bit) - * Despite the name, this is not a hash function (so it doesn't mix or produce collisions). -* `core.get_position_from_hash(hash)`: returns a position - * Inverse transform of `core.hash_node_position` -* `core.get_item_group(name, group)`: returns a rating - * Get rating of a group of an item. (`0` means: not in group) -* `core.get_node_group(name, group)`: returns a rating - * Deprecated: An alias for the former. -* `core.raillike_group(name)`: returns a rating - * Returns rating of the connect_to_raillike group corresponding to name - * If name is not yet the name of a connect_to_raillike group, a new group - id is created, with that name. -* `core.get_content_id(name)`: returns an integer - * Gets the internal content ID of `name` -* `core.get_name_from_content_id(content_id)`: returns a string - * Gets the name of the content with that content ID -* `core.parse_json(string[, nullvalue, return_error])`: returns something - * Convert a string containing JSON data into the Lua equivalent - * `nullvalue`: returned in place of the JSON null; defaults to `nil` - * On success returns a table, a string, a number, a boolean or `nullvalue` - * On failure: If `return_error` is not set or is `false`, - outputs an error message and returns `nil`. - Otherwise returns `nil, err` (error message). - * Example: `parse_json("[10, {\"a\":false}]")`, returns `{10, {a = false}}` -* `core.write_json(data[, styled])`: returns a string or `nil` and an error - message. - * Convert a Lua table into a JSON string - * styled: Outputs in a human-readable format if this is set, defaults to - false. - * Unserializable things like functions and userdata will cause an error. - * **Warning**: JSON is more strict than the Lua table format. - 1. You can only use strings and positive integers of at least one as - keys. - 2. You cannot mix string and integer keys. - This is due to the fact that JSON has two distinct array and object - values. - * Example: `write_json({10, {a = false}})`, - returns `'[10, {"a": false}]'` -* `core.serialize(table)`: returns a string - * Convert a value into string form readable by `core.deserialize`. - * Supports tables, strings, numbers, booleans and `nil`. - * Support for dumping function bytecode is **deprecated**. - * Note: To obtain a human-readable representation of a value, use `dump` instead. - * Example: `serialize({foo="bar"})`, returns `'return { ["foo"] = "bar" }'` -* `core.deserialize(string[, safe])`: returns a table - * Convert a string returned by `core.serialize` into a table - * `string` is loaded in an empty sandbox environment. - * Will load functions if `safe` is `false` or omitted. - Although these functions cannot directly access the global environment, - they could bypass this restriction with maliciously crafted Lua bytecode - if mod security is disabled. - * Will silently strip functions embedded via calls to `loadstring` - (typically bytecode dumped by `core.serialize`) if `safe` is `true`. - You should not rely on this if possible. - * Example: `core.deserialize("return loadstring('')", true)` will be `nil`. - * This function should not be used on untrusted data, regardless of the - value of `safe`. It is fine to serialize then deserialize user-provided - data, but directly providing user input to deserialize is always unsafe. - * Example: `deserialize('return { ["foo"] = "bar" }')`, - returns `{foo="bar"}` - * Example: `deserialize('print("foo")')`, returns `nil` - (function call fails), returns - `error:[string "print("foo")"]:1: attempt to call global 'print' (a nil value)` -* `core.compress(data, method, ...)`: returns `compressed_data` - * Compress a string of data. - * `method` is a string identifying the compression method to be used. - * Supported compression methods: - * Deflate (zlib): `"deflate"` - * Zstandard: `"zstd"` - * `...` indicates method-specific arguments. Currently defined arguments - are: - * Deflate: `level` - Compression level, `0`-`9` or `nil`. - * Zstandard: `level` - Compression level. Integer or `nil`. Default `3`. - Note any supported Zstandard compression level could be used here, - but these are subject to change between Zstandard versions. -* `core.decompress(compressed_data, method, ...)`: returns data - * Decompress a string of data using the algorithm specified by `method`. - * See documentation on `core.compress()` for supported compression - methods. - * `...` indicates method-specific arguments. Currently, no methods use this -* `core.rgba(red, green, blue[, alpha])`: returns a string - * Each argument is an 8 Bit unsigned integer - * Returns the ColorString from rgb or rgba values - * Example: `core.rgba(10, 20, 30, 40)`, returns `"#0A141E28"` -* `core.encode_base64(string)`: returns string encoded in base64 - * Encodes a string in base64. -* `core.decode_base64(string)`: returns string or nil on failure - * Padding characters are only supported starting at version 5.4.0, where - 5.5.0 and newer perform proper checks. - * Decodes a string encoded in base64. -* `core.is_protected(pos, name)`: returns boolean - * Returning `true` restricts the player `name` from modifying (i.e. digging, - placing) the node at position `pos`. - * `name` will be `""` for non-players or unknown players. - * This function should be overridden by protection mods. It is highly - recommended to grant access to players with the `protection_bypass` privilege. - * Cache and call the old version of this function if the position is - not protected by the mod. This will allow using multiple protection mods. - * Example: - ```lua - local old_is_protected = core.is_protected - function core.is_protected(pos, name) - if mymod:position_protected_from(pos, name) then - return true - end - return old_is_protected(pos, name) - end - ``` -* `core.record_protection_violation(pos, name)` - * This function calls functions registered with - `core.register_on_protection_violation`. -* `core.is_creative_enabled(name)`: returns boolean - * Returning `true` means that Creative Mode is enabled for player `name`. - * `name` will be `""` for non-players or if the player is unknown. - * This function should be overridden by Creative Mode-related mods to - implement a per-player Creative Mode. - * By default, this function returns `true` if the setting - `creative_mode` is `true` and `false` otherwise. -* `core.is_area_protected(pos1, pos2, player_name, interval)` - * Returns the position of the first node that `player_name` may not modify - in the specified cuboid between `pos1` and `pos2`. - * Returns `false` if no protections were found. - * Applies `is_protected()` to a 3D lattice of points in the defined volume. - The points are spaced evenly throughout the volume and have a spacing - similar to, but no larger than, `interval`. - * All corners and edges of the defined volume are checked. - * `interval` defaults to 4. - * `interval` should be carefully chosen and maximized to avoid an excessive - number of points being checked. - * Like `core.is_protected`, this function may be extended or - overwritten by mods to provide a faster implementation to check the - cuboid for intersections. -* `core.rotate_and_place(itemstack, placer, pointed_thing[, infinitestacks, - orient_flags, prevent_after_place])` - * Attempt to predict the desired orientation of the facedir-capable node - defined by `itemstack`, and place it accordingly (on-wall, on the floor, - or hanging from the ceiling). - * `infinitestacks`: if `true`, the itemstack is not changed. Otherwise the - stacks are handled normally. - * `orient_flags`: Optional table containing extra tweaks to the placement code: - * `invert_wall`: if `true`, place wall-orientation on the ground and - ground-orientation on the wall. - * `force_wall`: if `true`, always place the node in wall orientation. - * `force_ceiling`: if `true`, always place on the ceiling. - * `force_floor`: if `true`, always place the node on the floor. - * `force_facedir`: if `true`, forcefully reset the facedir to north - when placing on the floor or ceiling. - * The first four options are mutually-exclusive; the last in the list - takes precedence over the first. - * `prevent_after_place` is directly passed to `core.item_place_node` - * Returns the new itemstack after placement -* `core.rotate_node(itemstack, placer, pointed_thing)` - * calls `rotate_and_place()` with `infinitestacks` set according to the state - of the creative mode setting, checks for "sneak" to set the `invert_wall` - parameter and `prevent_after_place` set to `true`. - -* `core.calculate_knockback(player, hitter, time_from_last_punch, - tool_capabilities, dir, distance, damage)` - * Returns the amount of knockback applied on the punched player. - * Arguments are equivalent to `register_on_punchplayer`, except the following: - * `distance`: distance between puncher and punched player - * This function can be overridden by mods that wish to modify this behavior. - * You may want to cache and call the old function to allow multiple mods to - change knockback behavior. - -* `core.forceload_block(pos[, transient[, limit]])` - * forceloads the position `pos`. - * this means that the mapblock containing `pos` will always be kept in the - `"active"` state, regardless of nearby players or server settings. - * returns `true` if area could be forceloaded - * If `transient` is `false` or absent, the forceload will be persistent - (saved between server runs). If `true`, the forceload will be transient - (not saved between server runs). - * `limit` is an optional limit on the number of blocks that can be - forceloaded at once. If `limit` is negative, there is no limit. If it is - absent, the limit is the value of the setting `"max_forceloaded_blocks"`. - If the call would put the number of blocks over the limit, the call fails. - -* `core.forceload_free_block(pos[, transient])` - * stops forceloading the position `pos` - * If `transient` is `false` or absent, frees a persistent forceload. - If `true`, frees a transient forceload. - -* `core.compare_block_status(pos, condition)` - * Checks whether the mapblock at position `pos` is in the wanted condition. - * `condition` may be one of the following values: - * `"unknown"`: not in memory - * `"emerging"`: in the queue for loading from disk or generating - * `"loaded"`: in memory but inactive (no ABMs are executed) - * `"active"`: in memory and active - * Other values are reserved for future functionality extensions - * Return value, the comparison status: - * `false`: Mapblock does not fulfill the wanted condition - * `true`: Mapblock meets the requirement - * `nil`: Unsupported `condition` value - -* `core.request_insecure_environment()`: returns an environment containing - insecure functions if the calling mod has been listed as trusted in the - `secure.trusted_mods` setting or security is disabled, otherwise returns - `nil`. - * Only works at init time and must be called from the mod's main scope - (ie: the init.lua of the mod, not from another Lua file or within a function). - * **DO NOT ALLOW ANY OTHER MODS TO ACCESS THE RETURNED ENVIRONMENT, STORE - IT IN A LOCAL VARIABLE!** - -* `core.global_exists(name)` - * Checks if a global variable has been set, without triggering a warning. - -* `core.register_portable_metatable(name, mt)`: - * Register a metatable that should be preserved when Lua data is transferred - between environments (via IPC or `handle_async`). - * `name` is a string that identifies the metatable. It is recommended to - follow the `modname:name` convention for this identifier. - * `mt` is the metatable to register. - * Note that the same metatable can be registered under multiple names, - but multiple metatables must not be registered under the same name. - * You must register the metatable in both the main environment - and the async environment for this mechanism to work. - -Global objects --------------- - -* `core.env`: `EnvRef` of the server environment and world. - * Any function in the `core` namespace can be called using the syntax - `core.env:somefunction(somearguments)` - instead of `core.somefunction(somearguments)` - * Deprecated, but support is not to be dropped soon -* `minetest`: alias for the `core` namespace - * Deprecated, but support is not to be dropped soon - -Global tables -------------- - -### Registered definition tables - -* `core.registered_items` - * Map of registered items, indexed by name -* `core.registered_nodes` - * Map of registered node definitions, indexed by name -* `core.registered_craftitems` - * Map of registered craft item definitions, indexed by name -* `core.registered_tools` - * Map of registered tool definitions, indexed by name -* `core.registered_entities` - * Map of registered entity prototypes, indexed by name - * Values in this table may be modified directly. - Note: changes to initial properties will only affect entities spawned afterwards, - as they are only read when spawning. -* `core.objects_by_guid` - * Map of active object references, indexed by object GUID -* `core.object_refs` - * **Obsolete:** Use `core.objects_by_guid` instead. - GUIDs are strictly more useful than active object IDs. - * Map of active object references, indexed by active object id -* `core.luaentities` - * Map of Lua entities, indexed by active object id -* `core.registered_abms` - * List of ABM definitions -* `core.registered_lbms` - * List of LBM definitions -* `core.registered_aliases` - * Map of registered aliases, indexed by name -* `core.registered_ores` - * Map of registered ore definitions, indexed by the `name` field. - * If `name` is nil, the key is the object handle returned by - `core.register_ore`. -* `core.registered_biomes` - * Map of registered biome definitions, indexed by the `name` field. - * If `name` is nil, the key is the object handle returned by - `core.register_biome`. -* `core.registered_decorations` - * Map of registered decoration definitions, indexed by the `name` field. - * If `name` is nil, the key is the object handle returned by - `core.register_decoration`. -* `core.registered_chatcommands` - * Map of registered chat command definitions, indexed by name -* `core.registered_privileges` - * Map of registered privilege definitions, indexed by name - * Registered privileges can be modified directly in this table. - -### Registered callback tables - -All callbacks registered with [Global callback registration functions](#global-callback-registration-functions) are added -to corresponding `core.registered_*` tables. - -For historical reasons, the use of an -s suffix in these names is inconsistent. - -* `core.registered_on_chat_messages` -* `core.registered_on_chatcommands` -* `core.registered_globalsteps` -* `core.registered_on_punchnodes` -* `core.registered_on_placenodes` -* `core.registered_on_dignodes` -* `core.registered_on_generateds` -* `core.registered_on_newplayers` -* `core.registered_on_dieplayers` -* `core.registered_on_respawnplayers` -* `core.registered_on_prejoinplayers` -* `core.registered_on_joinplayers` -* `core.registered_on_leaveplayers` -* `core.registered_on_player_receive_fields` -* `core.registered_on_cheats` -* `core.registered_on_crafts` -* `core.registered_craft_predicts` -* `core.registered_on_item_eats` -* `core.registered_on_item_pickups` -* `core.registered_on_punchplayers` -* `core.registered_on_authplayers` -* `core.registered_on_player_inventory_actions` -* `core.registered_allow_player_inventory_actions` -* `core.registered_on_rightclickplayers` -* `core.registered_on_mods_loaded` -* `core.registered_on_shutdown` -* `core.registered_on_protection_violation` -* `core.registered_on_priv_grant` -* `core.registered_on_priv_revoke` -* `core.registered_can_bypass_userlimit` -* `core.registered_on_modchannel_message` -* `core.registered_on_liquid_transformed` -* `core.registered_on_mapblocks_changed` - -Class reference -=============== - -Sorted alphabetically. - -`AreaStore` ------------ - -AreaStore is a data structure to calculate intersections of 3D cuboid volumes -and points. The `data` field (string) may be used to store and retrieve any -mod-relevant information to the specified area. - -Despite its name, mods must take care of persisting AreaStore data. They may -use the provided load and write functions for this. - - -### Methods - -* `AreaStore(type_name)` - * Returns a new AreaStore instance - * `type_name`: optional, forces the internally used API. - * Possible values: `"LibSpatial"` (default). - * When other values are specified, or SpatialIndex is not available, - the custom Luanti functions are used. -* `get_area(id, include_corners, include_data)` - * Returns the area information about the specified ID. - * Returned values are either of these: - ```lua - nil -- Area not found - true -- Without `include_corners` and `include_data` - { - min = pos, max = pos -- `include_corners == true` - data = string -- `include_data == true` - } - ``` - -* `get_areas_for_pos(pos, include_corners, include_data)` - * Returns all areas as table, indexed by the area ID. - * Table values: see `get_area`. -* `get_areas_in_area(corner1, corner2, accept_overlap, include_corners, include_data)` - * Returns all areas that contain all nodes inside the area specified by` - `corner1 and `corner2` (inclusive). - * `accept_overlap`: if `true`, areas are returned that have nodes in - common (intersect) with the specified area. - * Returns the same values as `get_areas_for_pos`. -* `insert_area(corner1, corner2, data, [id])`: inserts an area into the store. - * Returns the new area's ID, or nil if the insertion failed. - * The (inclusive) positions `corner1` and `corner2` describe the area. - * `data` is a string stored with the area. - * `id` (optional): will be used as the internal area ID if it is a unique - number between 0 and 2^32-2. -* `reserve(count)` - * Requires SpatialIndex, no-op function otherwise. - * Reserves resources for `count` many contained areas to improve - efficiency when working with many area entries. Additional areas can still - be inserted afterwards at the usual complexity. -* `remove_area(id)`: removes the area with the given id from the store, returns - success. -* `set_cache_params(params)`: sets params for the included prefiltering cache. - Calling invalidates the cache, so that its elements have to be newly - generated. - * `params` is a table with the following fields: - ```lua - { - enabled = boolean, -- Whether to enable, default true - block_radius = int, -- The radius (in nodes) of the areas the cache - -- generates prefiltered lists for, minimum 16, - -- default 64 - limit = int, -- The cache size, minimum 20, default 1000 - } - ``` -* `to_string()`: Experimental. Returns area store serialized as a (binary) - string. -* `to_file(filename)`: Experimental. Like `to_string()`, but writes the data to - a file. -* `from_string(str)`: Experimental. Deserializes string and loads it into the - AreaStore. - Returns success and, optionally, an error message. -* `from_file(filename)`: Experimental. Like `from_string()`, but reads the data - from a file. - -`InvRef` --------- - -An `InvRef` is a reference to an inventory. - -### Methods - -* `is_empty(listname)`: return `true` if list is empty -* `get_size(listname)`: get size of a list -* `set_size(listname, size)`: set size of a list - * If `listname` is not known, a new list will be created - * Setting `size` to 0 deletes a list - * returns `false` on error (e.g. invalid `listname` or `size`) -* `get_width(listname)`: get width of a list -* `set_width(listname, width)`: set width of list; currently used for crafting - * returns `false` on error (e.g. invalid `listname` or `width`) -* `get_stack(listname, i)`: get a copy of stack index `i` in list -* `set_stack(listname, i, stack)`: copy `stack` to index `i` in list -* `get_list(listname)`: returns full list (list of `ItemStack`s) - or `nil` if list doesn't exist (size 0) -* `set_list(listname, list)`: set full list (size will not change) -* `get_lists()`: returns table that maps listnames to inventory lists -* `set_lists(lists)`: sets inventory lists (size will not change) -* `add_item(listname, stack)`: add item somewhere in list, returns leftover - `ItemStack`. -* `room_for_item(listname, stack):` returns `true` if the stack of items - can be fully added to the list -* `contains_item(listname, stack, [match_meta])`: returns `true` if - the stack of items can be fully taken from the list. - * If `match_meta` is `true`, item metadata is also considered when comparing - items. Otherwise, only the items names are compared. Default: `false` - * The method ignores wear. -* `remove_item(listname, stack, [match_meta])`: take as many items as specified from the - list, returns the items that were actually removed (as an `ItemStack`). - * If `match_meta` is `true` (available since feature `remove_item_match_meta`), - item metadata is also considered when comparing items. Otherwise, only the - items names are compared. Default: `false` - * The method ignores wear. -* `get_location()`: returns a location compatible to - `core.get_inventory(location)`. - * returns `{type="undefined"}` in case location is not known - -### Callbacks - -Detached & nodemeta inventories provide the following callbacks for move actions: - -#### Before - -The `allow_*` callbacks return how many items can be moved. - -* `allow_move`/`allow_metadata_inventory_move`: Moving items in the inventory -* `allow_take`/`allow_metadata_inventory_take`: Taking items from the inventory -* `allow_put`/`allow_metadata_inventory_put`: Putting items to the inventory - -#### After - -The `on_*` callbacks are called after the items have been placed in the inventories. - -* `on_move`/`on_metadata_inventory_move`: Moving items in the inventory -* `on_take`/`on_metadata_inventory_take`: Taking items from the inventory -* `on_put`/`on_metadata_inventory_put`: Putting items to the inventory - -#### Swapping - -When a player tries to put an item to a place where another item is, the items are *swapped*. -This means that all callbacks will be called twice (once for each action). - -`ItemStack` ------------ - -An `ItemStack` is a stack of items. - -It can be created via `ItemStack(x)`, where x is an `ItemStack`, -an itemstring, a table or `nil`. - -### Methods - -* `is_empty()`: returns `true` if stack is empty. -* `get_name()`: returns item name (e.g. `"default:stone"`). -* `set_name(item_name)`: returns a boolean indicating whether the item was - cleared. -* `get_count()`: Returns number of items on the stack. -* `set_count(count)`: returns a boolean indicating whether the item was cleared - * `count`: number, unsigned 16 bit integer -* `get_wear()`: returns tool wear (`0`-`65535`), `0` for non-tools. -* `set_wear(wear)`: returns boolean indicating whether item was cleared - * `wear`: number, unsigned 16 bit integer -* `get_meta()`: returns ItemStackMetaRef. See section for more details -* `get_metadata()`: **Deprecated.** Returns metadata (a string attached to an item stack). - * If you need to access this to maintain backwards compatibility, - use `stack:get_meta():get_string("")` instead. -* `set_metadata(metadata)`: **Deprecated.** Returns true. - * If you need to set this to maintain backwards compatibility, - use `stack:get_meta():set_string("", metadata)` instead. -* `get_description()`: returns the description shown in inventory list tooltips. - * The engine uses this when showing item descriptions in tooltips. - * Fields for finding the description, in order: - * `description` in item metadata (See [Item Metadata](#item-metadata).) - * `description` in item definition - * item name -* `get_short_description()`: returns the short description or nil. - * Unlike the description, this does not include new lines. - * Fields for finding the short description, in order: - * `short_description` in item metadata (See [Item Metadata](#item-metadata).) - * `short_description` in item definition - * first line of the description (From item meta or def, see `get_description()`.) - * Returns nil if none of the above are set -* `clear()`: removes all items from the stack, making it empty. -* `replace(item)`: replace the contents of this stack. - * `item` can also be an itemstring or table. -* `to_string()`: returns the stack in itemstring form. -* `to_table()`: returns the stack in Lua table form. -* `get_stack_max()`: returns the maximum size of the stack (depends on the - item). -* `get_free_space()`: returns `get_stack_max() - get_count()`. -* `is_known()`: returns `true` if the item name refers to a defined item type. -* `get_definition()`: returns the item definition table. -* `get_tool_capabilities()`: returns the digging properties of the item, - or those of the hand if none are defined for this item type -* `add_wear(amount)` - * Increases wear by `amount` if the item is a tool, otherwise does nothing - * Valid `amount` range is [0,65536] - * `amount`: number, integer -* `add_wear_by_uses(max_uses)` - * Increases wear in such a way that, if only this function is called, - the item breaks after `max_uses` times - * Valid `max_uses` range is [0,65536] - * Does nothing if item is not a tool or if `max_uses` is 0 -* `get_wear_bar_params()`: returns the wear bar parameters of the item, - or nil if none are defined for this item type or in the stack's meta -* `add_item(item)`: returns leftover `ItemStack` - * Put some item or stack onto this stack -* `item_fits(item)`: returns `true` if item or stack can be fully added to - this one. -* `take_item(n)`: returns taken `ItemStack` - * Take (and remove) up to `n` items from this stack - * `n`: number, default: `1` -* `peek_item(n)`: returns taken `ItemStack` - * Copy (don't remove) up to `n` items from this stack - * `n`: number, default: `1` -* `equals(other)`: - * returns `true` if this stack is identical to `other`. - * Note: `stack1:to_string() == stack2:to_string()` is not reliable, - as stack metadata can be serialized in arbitrary order. - * Note: if `other` is an itemstring or table representation of an - ItemStack, this will always return false, even if it is - "equivalent". - -### Operators - -* `stack1 == stack2`: - * Returns whether `stack1` and `stack2` are identical. - * Note: `stack1:to_string() == stack2:to_string()` is not reliable, - as stack metadata can be serialized in arbitrary order. - * Note: if `stack2` is an itemstring or table representation of an - ItemStack, this will always return false, even if it is - "equivalent". - -`ItemStackMetaRef` ------------------- - -ItemStack metadata: reference extra data and functionality stored in a stack. -Can be obtained via `item:get_meta()`. - -### Methods - -* All methods in MetaDataRef -* `set_tool_capabilities([tool_capabilities])` - * Overrides the item's tool capabilities - * A nil value will clear the override data and restore the original - behavior. -* `set_wear_bar_params([wear_bar_params])` - * Overrides the item's wear bar parameters (see "Wear Bar Color" section) - * A nil value will clear the override data and restore the original - behavior. - -`MetaDataRef` -------------- - -Base class used by [`StorageRef`](#storageref), [`NodeMetaRef`](#nodemetaref), [`ItemStackMetaRef`](#itemstackmetaref), -and [`PlayerMetaRef`](#playermetaref). - -Note: If a metadata value is in the format `${k}`, an attempt to get the value -will return the value associated with key `k`. There is a low recursion limit. -This behavior is **deprecated** and will be removed in a future version. Usage -of the `${k}` syntax in formspecs is not deprecated. - -### Methods - -* `contains(key)`: Returns true if key present, otherwise false. - * Returns `nil` when the MetaData is inexistent. -* `get(key)`: Returns `nil` if key not present, else the stored string. -* `set_string(key, value)`: Value of `""` will delete the key. -* `get_string(key)`: Returns `""` if key not present. -* `set_int(key, value)` - * The range for the value is system-dependent (usually 32 bits). - The value will be converted into a string when stored. -* `get_int(key)`: Returns `0` if key not present. -* `set_float(key, value)` - * Store a number (a 64-bit float) exactly. - * The value will be converted into a string when stored. -* `get_float(key)`: Returns `0` if key not present. -* `get_keys()`: returns a list of all keys in the metadata. -* `to_table()`: - * Returns a metadata table (see below) or `nil` on failure. -* `from_table(data)` - * Imports metadata from a metadata table - * If `data` is a metadata table (see below), the metadata it represents - will replace all metadata of this MetaDataRef object - * Any non-table value for `data` will clear all metadata - * Item table values the `inventory` field may also be itemstrings - * Returns `true` on success -* `equals(other)` - * returns `true` if this metadata has the same key-value pairs as `other` - -### Metadata tables - -Metadata tables represent MetaDataRef in a Lua table form (see `from_table`/`to_table`). - -A metadata table is a table that has the following keys: - -* `fields`: key-value storage of metadata fields - * all values are stored as strings - * numbers must be converted to strings first -* `inventory` (for NodeMetaRef only): A node inventory in table form - * inventory table keys are inventory list names - * inventory table values are item tables - * item table keys are slot IDs (starting with 1) - * item table values are ItemStacks - -Example: - -```lua -metadata_table = { - -- metadata fields (key/value store) - fields = { - infotext = "Container", - another_key = "Another Value", - }, - - -- inventory data (for nodes) - inventory = { - -- inventory list "main" with 4 slots - main = { - -- list of all item slots - [1] = ItemStack("example:dirt"), - [2] = ItemStack("example:stone 25"), - [3] = ItemStack(""), -- empty slot - [4] = ItemStack("example:pickaxe"), - }, - -- inventory list "hidden" with 1 slot - hidden = { - [1] = ItemStack("example:diamond"), - }, - }, -} -``` - -`ModChannel` ------------- - -An interface to use mod channels on client and server - -### Methods - -* `leave()`: leave the mod channel. - * Server leaves channel `channel_name`. - * No more incoming or outgoing messages can be sent to this channel from - server mods. - * This invalidate all future object usage. - * Ensure you set mod_channel to nil after that to free Lua resources. -* `is_writeable()`: returns true if channel is writeable and mod can send over - it. -* `send_all(message)`: Send `message` though the mod channel. - * If mod channel is not writeable or invalid, message will be dropped. - * Message size is limited to 65535 characters by protocol. - -`NodeMetaRef` -------------- - -Node metadata: reference extra data and functionality stored in a node. -Can be obtained via `core.get_meta(pos)`. - -### Methods - -* All methods in MetaDataRef -* `get_inventory()`: returns `InvRef` -* `mark_as_private(name or {name1, name2, ...})`: Mark specific vars as private - This will prevent them from being sent to the client. Note that the "private" - status will only be remembered if an associated key-value pair exists, - meaning it's best to call this when initializing all other meta (e.g. - `on_construct`). - -`NodeTimerRef` --------------- - -Node Timers: a high resolution persistent per-node timer. -Can be gotten via `core.get_node_timer(pos)`. - -### Methods - -* `set(timeout,elapsed)` - * set a timer's state - * `timeout` is in seconds, and supports fractional values (0.1 etc) - * `elapsed` is in seconds, and supports fractional values (0.1 etc) - * will trigger the node's `on_timer` function after `(timeout - elapsed)` - seconds. -* `start(timeout)` - * start a timer - * equivalent to `set(timeout,0)` -* `stop()` - * stops the timer -* `get_timeout()`: returns current timeout in seconds - * if `timeout` equals `0`, timer is inactive -* `get_elapsed()`: returns current elapsed time in seconds - * the node's `on_timer` function will be called after `(timeout - elapsed)` - seconds. -* `is_started()`: returns boolean state of timer - * returns `true` if timer is started, otherwise `false` - -`ObjectRef` ------------ - -Moving things in the game are generally these. -This is basically a reference to a C++ `ServerActiveObject`. - -### Advice on handling `ObjectRefs` - -When you receive an `ObjectRef` as a callback argument or from another API -function, it is possible to store the reference somewhere and keep it around. -It will keep functioning until the object is unloaded or removed. - -However, doing this is **NOT** recommended - `ObjectRefs` should be "let go" -of as soon as control is returned from Lua back to the engine. - -Doing so is much less error-prone and you will never need to wonder if the -object you are working with still exists. - -If this is not feasible, you can test whether an `ObjectRef` is still valid -via `object:is_valid()`. - -Getters may be called for invalid objects and will return nothing then. -All other methods should not be called on invalid objects. - -### Attachments - -It is possible to attach objects to other objects (`set_attach` method). - -When an object is attached, it is positioned relative to the parent's position -and rotation. `get_pos` and `get_rotation` will always return the parent's -values and changes via their setter counterparts are ignored. - -To change position or rotation call `set_attach` again with the new values. - -**Note**: Just like model dimensions, the relative position in `set_attach` -must be multiplied by 10 compared to world positions. - -It is also possible to attach to a bone of the parent object. In that case the -child will follow movement and rotation of that bone. - -### Methods - -* `is_valid()`: returns whether the object is valid. - * See "Advice on handling `ObjectRefs`" above. -* `get_pos()`: returns position as vector `{x=num, y=num, z=num}` -* `set_pos(pos)`: - * Sets the position of the object. - * No-op if object is attached. - * `pos` is a vector `{x=num, y=num, z=num}` -* `add_pos(pos)`: - * Changes position by adding to the current position. - * No-op if object is attached. - * `pos` is a vector `{x=num, y=num, z=num}`. - * In comparison to using `set_pos`, `add_pos` will avoid synchronization problems. -* `get_velocity()`: returns the velocity, a vector. -* `add_velocity(vel)` - * Changes velocity by adding to the current velocity. - * `vel` is a vector, e.g. `{x=0.0, y=2.3, z=1.0}` - * In comparison to using `get_velocity`, adding the velocity and then using - `set_velocity`, `add_velocity` is supposed to avoid synchronization problems. - Additionally, players also do not support `set_velocity`. - * If object is a player: - * Does not apply during `free_move`. - * Note that since the player speed is normalized at each move step, - increasing e.g. Y velocity beyond what would usually be achieved - (see: physics overrides) will cause existing X/Z velocity to be reduced. - * Example: `add_velocity({x=0, y=6.5, z=0})` is equivalent to - pressing the jump key (assuming default settings) -* `move_to(pos, continuous=false)` - * Does an interpolated move for Lua entities for visually smooth transitions. - * If `continuous` is true, the Lua entity will not be moved to the current - position before starting the interpolated move. - * For players this does the same as `set_pos`,`continuous` is ignored. - * no-op if object is attached -* `punch(puncher, time_from_last_punch, tool_capabilities, dir)` - * punches the object, triggering all consequences a normal punch would have - * `puncher`: another `ObjectRef` which punched the object or `nil` - * `dir`: direction vector of punch - * Other arguments: See `on_punch` for entities - * Arguments `time_from_last_punch`, `tool_capabilities`, and `dir` - will be replaced with a default value when the caller sets them to `nil`. -* `right_click(clicker)`: - * simulates using the 'place/use' key on the object - * triggers all consequences as if a real player had done this - * `clicker` is another `ObjectRef` which has clicked - * note: this is called `right_click` for historical reasons only -* `get_hp()`: returns number of health points -* `set_hp(hp, reason)`: set number of health points - * See reason in register_on_player_hpchange - * Is limited to the range of 0 ... 65535 (2^16 - 1) - * For players: HP are also limited by `hp_max` specified in object properties -* `get_inventory()`: returns an `InvRef` for players, otherwise returns `nil` -* `get_wield_list()`: returns the name of the inventory list the wielded item - is in. -* `get_wield_index()`: returns the wield list index of the wielded item (starting with 1) -* `get_wielded_item()`: returns a copy of the wielded item as an `ItemStack` -* `set_wielded_item(item)`: replaces the wielded item, returns `true` if - successful. -* `get_armor_groups()`: - * returns a table with all of the object's armor group ratings - * syntax: the table keys are the armor group names, - the table values are the corresponding group ratings - * see section '`ObjectRef` armor groups' for details -* `set_armor_groups({group1=rating, group2=rating, ...})` - * sets the object's full list of armor groups - * same table syntax as for `get_armor_groups` - * note: all armor groups not in the table will be removed -* `set_animation(frame_range, frame_speed, frame_blend, frame_loop)` - * Sets the object animation parameters and (re)starts the animation - * Animations only work with a `"mesh"` visual - * `frame_range`: Beginning and end frame (as specified in the mesh file). - * Syntax: `{x=start_frame, y=end_frame}` - * Animation interpolates towards the end frame but stops when it is reached - * If looped, there is no interpolation back to the start frame - * If looped, the model should look identical at start and end - * default: `{x=1.0, y=1.0}` - * `frame_speed`: How fast the animation plays, in frames per second (number) - * default: `15.0` - * `frame_blend`: number, default: `0.0` - * `frame_loop`: If `true`, animation will loop. If false, it will play once - * default: `true` -* `get_animation()`: returns current animation parameters set by `set_animation`: - * `frame_range`, `frame_speed`, `frame_blend`, `frame_loop`. -* `set_animation_frame_speed(frame_speed)` - * Sets the frame speed of the object's animation - * Unlike `set_animation`, this will not restart the animation - * `frame_speed`: See `set_animation` -* `set_attach(parent[, bone, position, rotation, forced_visible])` - * Attaches object to `parent` - * See 'Attachments' section for details - * `parent`: `ObjectRef` to attach to - * `bone`: Bone to attach to. Default is `""` (the root bone) - * `position`: relative position, default `{x=0, y=0, z=0}` - * `rotation`: relative rotation in degrees, default `{x=0, y=0, z=0}` - * `forced_visible`: Boolean to control whether the attached entity - should appear in first person, default `false`. - * This command may fail silently (do nothing) when it would result - in circular attachments. -* `get_attach()`: - * returns current attachment parameters or nil if it isn't attached - * If attached, returns `parent`, `bone`, `position`, `rotation`, `forced_visible` -* `get_children()`: returns a list of ObjectRefs that are attached to the - object. -* `set_detach()`: Detaches object. No-op if object was not attached. -* `set_bone_position([bone, position, rotation])` - * Sets absolute bone overrides, e.g. it is equivalent to - ```lua - obj:set_bone_override(bone, { - position = {vec = position, absolute = true}, - rotation = {vec = rotation:apply(math.rad), absolute = true} - }) - ``` - * **Note:** Rotation is in degrees, not radians. - * **Deprecated:** Use `set_bone_override` instead. -* `get_bone_position(bone)`: returns the previously set position and rotation of the bone - * Shorthand for `get_bone_override(bone).position.vec, get_bone_override(bone).rotation.vec:apply(math.deg)`. - * **Note:** Returned rotation is in degrees, not radians. - * **Deprecated:** Use `get_bone_override` instead. -* `set_bone_override(bone, override)` - * `bone`: string - * `override`: `{ position = property, rotation = property, scale = property }` or `nil` - * `override = nil` (including omission) is shorthand for `override = {}` which clears the override - * Each `property` is a table of the form - `{ vec = vector, interpolation = 0, absolute = false }` or `nil` - * `vec` is in the same coordinate system as the model, and in radians for rotation. - It defaults to `vector.zero()` for translation and rotation and `vector.new(1, 1, 1)` for scale. - * `interpolation`: The old and new overrides are interpolated over this timeframe (in seconds). - * `absolute`: If set to `false` (which is the default), - the override will be relative to the animated property: - * Translation in the case of `position`; - * Composition in the case of `rotation`; - * Per-axis multiplication in the case of `scale` - * `property = nil` is equivalent to no override on that property - * **Note:** Unlike `set_bone_position`, the rotation is in radians, not degrees. - * Compatibility note: Clients prior to 5.9.0 only support absolute position and rotation. - All values are treated as absolute and are set immediately (no interpolation). -* `get_bone_override(bone)`: returns `override` in the above format - * **Note:** Unlike `get_bone_position`, the returned rotation is in radians, not degrees. -* `get_bone_overrides()`: returns all bone overrides as table `{[bonename] = override, ...}` -* `set_properties(object property table)` -* `get_properties()`: returns a table of all object properties -* `set_observers(observers)`: sets observers (players this object is sent to) - * If `observers` is `nil`, the object's observers are "unmanaged": - The object is sent to all players as governed by server settings. This is the default. - * `observers` is a "set" of player names: `{name1 = true, name2 = true, ...}` - * A set is a table where the keys are the elements of the set - (in this case, *valid* player names) and the values are all `true`. - * Attachments: The *effective observers* of an object are made up of - all players who can observe the object *and* are also effective observers - of its parent object (if there is one). - * Players are automatically added to their own observer sets. - Players **must** effectively observe themselves. - * Object activation and deactivation are unaffected by observability. - * Attached sounds do not work correctly and thus should not be used - on objects with managed observers yet. -* `get_observers()`: - * throws an error if the object is invalid - * returns `nil` if the observers are unmanaged - * returns a table with all observer names as keys and `true` values (a "set") otherwise -* `get_effective_observers()`: - * Like `get_observers()`, but returns the "effective" observers, taking into account attachments - * Time complexity: O(nm) - * n: number of observers of the involved entities - * m: number of ancestors along the attachment chain -* `is_player()`: returns true for players, false otherwise -* `get_nametag_attributes()` - * returns a table with the attributes of the nametag of an object - * a nametag is a HUD text rendered above the object - * ```lua - { - text = "", - color = {a=0..255, r=0..255, g=0..255, b=0..255}, - bgcolor = {a=0..255, r=0..255, g=0..255, b=0..255}, - } - ``` -* `set_nametag_attributes(attributes)` - * sets the attributes of the nametag of an object - * `attributes`: - ```lua - { - text = "My Nametag", - color = ColorSpec, - -- ^ Text color - bgcolor = ColorSpec or false, - -- ^ Sets background color of nametag - -- `false` will cause the background to be set automatically based on user settings - -- Default: false - } - ``` -* `get_guid()`: returns a global unique identifier (a string) - * For players, this is a player name. - * For Lua entities, this is a uniquely generated string, guaranteed not to collide with player names. - * example: `@bGh3p2AbRE29Mb4biqX6OA` - * GUIDs only use printable ASCII characters. - * GUIDs persist between object reloads, and their format is guaranteed not to change. - Thus you can use the GUID to identify an object in a particular world online and offline. - - -#### Lua entity only (no-op for other objects) - -* `remove()`: remove object - * The object is removed after returning from Lua. However the `ObjectRef` - itself instantly becomes unusable with all further method calls having - no effect and returning `nil`. -* `set_velocity(vel)` - * Sets the velocity - * `vel` is a vector, e.g. `{x=0.0, y=2.3, z=1.0}` -* `set_acceleration(acc)` - * Sets the acceleration - * `acc` is a vector -* `get_acceleration()`: returns the acceleration, a vector -* `set_rotation(rot)` - * `rot` is a vector (radians). X is pitch (elevation), Y is yaw (heading) - and Z is roll (bank). - * Sets the **right-handed Z-X-Y** rotation: - First roll (Z) is applied, then pitch (X); yaw (Y) is applied last. - * Does not reset rotation incurred through `automatic_rotate`. - Remove & re-add your objects to force a certain rotation. -* `get_rotation()`: returns the rotation, a vector (radians) -* `set_yaw(yaw)`: sets the yaw in radians (heading). -* `get_yaw()`: returns number in radians -* `set_texture_mod(mod)` - * Set a texture modifier to the base texture, for sprites and meshes. - * When calling `set_texture_mod` again, the previous one is discarded. - * `mod` the texture modifier. See [Texture modifiers](#texture-modifiers). -* `get_texture_mod()` returns current texture modifier -* `set_sprite(start_frame, num_frames, framelength, select_x_by_camera)` - * Specifies and starts a sprite animation - * Only used by `sprite` and `upright_sprite` visuals - * Animations iterate along the frame `y` position. - * `start_frame`: {x=column number, y=row number}, the coordinate of the - first frame, default: `{x=0, y=0}` - * `num_frames`: Total frames in the texture, default: `1` - * `framelength`: Time per animated frame in seconds, default: `0.2` - * `select_x_by_camera`: Only for visual = `sprite`. Changes the frame `x` - position according to the view direction. default: `false`. - * First column: subject facing the camera - * Second column: subject looking to the left - * Third column: subject backing the camera - * Fourth column: subject looking to the right - * Fifth column: subject viewed from above - * Sixth column: subject viewed from below -* `get_luaentity()`: - * Returns the object's associated luaentity table, if there is one - * Otherwise returns `nil` (e.g. for players) -* `get_entity_name()`: - * **Deprecated**: Will be removed in a future version, - use `:get_luaentity().name` instead. - -#### Player only (no-op for other objects) - -* `get_player_name()`: Returns player name or `""` if is not a player -* `get_player_velocity()`: **DEPRECATED**, use get_velocity() instead. - table {x, y, z} representing the player's instantaneous velocity in nodes/s -* `add_player_velocity(vel)`: **DEPRECATED**, use add_velocity(vel) instead. -* `get_look_dir()`: get camera direction as a unit vector -* `get_look_vertical()`: pitch in radians - * Angle ranges between -pi/2 and pi/2, which are straight up and down - respectively. -* `get_look_horizontal()`: yaw in radians - * Angle is counter-clockwise from the +z direction. -* `set_look_vertical(radians)`: sets look pitch - * radians: Angle from looking forward, where positive is downwards. -* `set_look_horizontal(radians)`: sets look yaw - * radians: Angle from the +z direction, where positive is counter-clockwise. -* `get_look_pitch()`: pitch in radians - Deprecated as broken. Use - `get_look_vertical`. - * Angle ranges between -pi/2 and pi/2, which are straight down and up - respectively. -* `get_look_yaw()`: yaw in radians - Deprecated as broken. Use - `get_look_horizontal`. - * Angle is counter-clockwise from the +x direction. -* `set_look_pitch(radians)`: sets look pitch - Deprecated. Use - `set_look_vertical`. -* `set_look_yaw(radians)`: sets look yaw - Deprecated. Use - `set_look_horizontal`. -* `get_breath()`: returns player's breath -* `set_breath(value)`: sets player's breath - * values: - * `0`: player is drowning - * max: bubbles bar is not shown - * See [Object properties](#object-properties) for more information - * Is limited to range 0 ... 65535 (2^16 - 1) -* `set_fov(fov, is_multiplier, transition_time)`: Sets player's FOV - * `fov`: Field of View (FOV) value. - * `is_multiplier`: Set to `true` if the FOV value is a multiplier. - Defaults to `false`. - * `transition_time`: If defined, enables smooth FOV transition. - Interpreted as the time (in seconds) to reach target FOV. - If set to 0, FOV change is instantaneous. Defaults to 0. - * Set `fov` to 0 to clear FOV override. -* `get_fov()`: Returns the following: - * Server-sent FOV value. Returns 0 if an FOV override doesn't exist. - * Boolean indicating whether the FOV value is a multiplier. - * Time (in seconds) taken for the FOV transition. Set by `set_fov`. -* `set_attribute(attribute, value)`: DEPRECATED, use get_meta() instead - * Sets an extra attribute with value on player. - * `value` must be a string, or a number which will be converted to a - string. - * If `value` is `nil`, remove attribute from player. -* `get_attribute(attribute)`: DEPRECATED, use get_meta() instead - * Returns value (a string) for extra attribute. - * Returns `nil` if no attribute found. -* `get_meta()`: Returns metadata associated with the player (a PlayerMetaRef). -* `set_inventory_formspec(formspec)` - * Redefines the player's inventory formspec. - * Should usually be called at least once in the `on_joinplayer` callback. - * If `formspec` is `""`, the player's inventory is disabled. - * If the inventory formspec is currently open on the client, it is - updated immediately. - * See also: `core.register_on_player_receive_fields` -* `get_inventory_formspec()`: returns a formspec string -* `set_formspec_prepend(formspec)`: - * the formspec string will be added to every formspec shown to the user, - except for those with a no_prepend[] tag. - * This should be used to set style elements such as background[] and - bgcolor[], any non-style elements (eg: label) may result in weird behavior. - * Only affects formspecs shown after this is called. -* `get_formspec_prepend()`: returns a formspec string. -* `get_player_control()`: returns table with player input - * The table contains the following boolean fields representing the pressed - keys: `up`, `down`, `left`, `right`, `jump`, `aux1`, `sneak`, `dig`, - `place`, `LMB`, `RMB` and `zoom`. - * The fields `LMB` and `RMB` are equal to `dig` and `place` respectively, - and exist only to preserve backwards compatibility. - * The table also contains the fields `movement_x` and `movement_y`. - * They represent the movement of the player. Values are numbers in the - range [-1.0,+1.0]. - * They take both keyboard and joystick input into account. - * You should prefer them over `up`, `down`, `left` and `right` to - support different input methods correctly. - * Returns an empty table `{}` if the object is not a player. -* `get_player_control_bits()`: returns integer with bit packed player pressed - keys. - * Bits: - * 0 - up - * 1 - down - * 2 - left - * 3 - right - * 4 - jump - * 5 - aux1 - * 6 - sneak - * 7 - dig - * 8 - place - * 9 - zoom - * Returns `0` (no bits set) if the object is not a player. -* `set_physics_override(override_table)` - * Overrides the physics attributes of the player - * `override_table` is a table with the following fields: - * `speed`: multiplier to *all* movement speed (`speed_*`) and - acceleration (`acceleration_*`) values (default: `1`) - * `speed_walk`: multiplier to default walk speed value (default: `1`) - * Note: The actual walk speed is the product of `speed` and `speed_walk` - * `speed_climb`: multiplier to default climb speed value (default: `1`) - * Note: The actual climb speed is the product of `speed` and `speed_climb` - * `speed_crouch`: multiplier to default sneak speed value (default: `1`) - * Note: The actual sneak speed is the product of `speed` and `speed_crouch` - * `speed_fast`: multiplier to default speed value in Fast Mode (default: `1`) - * Note: The actual fast speed is the product of `speed` and `speed_fast` - * `jump`: multiplier to default jump value (default: `1`) - * `gravity`: multiplier to default gravity value (default: `1`) - * `liquid_fluidity`: multiplier to liquid movement resistance value - (for nodes with `liquid_move_physics`); the higher this value, the lower the - resistance to movement. At `math.huge`, the resistance is zero and you can - move through any liquid like air. (default: `1`) - * Warning: Values below 1 are currently unsupported. - * `liquid_fluidity_smooth`: multiplier to default maximum liquid resistance value - (for nodes with `liquid_move_physics`); controls deceleration when entering - node at high speed. At higher values you come to a halt more quickly - (default: `1`) - * `liquid_sink`: multiplier to default liquid sinking speed value; - (for nodes with `liquid_move_physics`) (default: `1`) - * `acceleration_default`: multiplier to horizontal and vertical acceleration - on ground or when climbing (default: `1`) - * Note: The actual acceleration is the product of `speed` and `acceleration_default` - * `acceleration_air`: multiplier to acceleration - when jumping or falling (default: `1`) - * Note: The actual acceleration is the product of `speed` and `acceleration_air` - * `acceleration_fast`: multiplier to acceleration in Fast Mode (default: `1`) - * Note: The actual acceleration is the product of `speed` and `acceleration_fast` - * `sneak`: whether player can sneak (default: `true`) - * `sneak_glitch`: whether player can use the new move code replications - of the old sneak side-effects: sneak ladders and 2 node sneak jump - (default: `false`) - * `new_move`: use new move/sneak code. When `false` the exact old code - is used for the specific old sneak behavior (default: `true`) - * Note: All numeric fields above modify a corresponding `movement_*` setting. - * For games, we recommend for simpler code to first modify the `movement_*` - settings (e.g. via the game's `minetest.conf`) to set a global base value - for all players and only use `set_physics_override` when you need to change - from the base value on a per-player basis - * Note: Some of the fields don't exist in old API versions, see feature - `physics_overrides_v2`. - -* `get_physics_override()`: returns the table given to `set_physics_override` -* `hud_add(hud definition)`: add a HUD element described by HUD def, returns ID - number on success -* `hud_remove(id)`: remove the HUD element of the specified id -* `hud_change(id, stat, value)`: change a value of a previously added HUD - element. - * `stat` supports the same keys as in the hud definition table except for - `"type"` (or the deprecated `"hud_elem_type"`). -* `hud_get(id)`: gets the HUD element definition structure of the specified ID -* `hud_get_all()`: - * Returns a table in the form `{ [id] = HUD definition, [id] = ... }`. - * A mod should keep track of its introduced IDs and only use this to access foreign elements. - * It is discouraged to change foreign HUD elements. -* `hud_set_flags(flags)`: sets specified HUD flags of player. - * `flags`: A table with the following fields set to boolean values - * `hotbar` - * `healthbar` - * `crosshair` - * `wielditem` - * `breathbar` - * `minimap`: Modifies the client's permission to view the minimap. - The client may locally elect to not view the minimap. - * `minimap_radar`: is only usable when `minimap` is true - * `basic_debug`: Allow showing basic debug info that might give a gameplay advantage. - This includes map seed, player position, look direction, the pointed node and block bounds. - Does not affect players with the `debug` privilege. - * `chat`: Modifies the client's permission to view chat on the HUD. - The client may locally elect to not view chat. Does not affect the console. - * If a flag equals `nil`, the flag is not modified -* `hud_get_flags()`: returns a table of player HUD flags with boolean values. - * See `hud_set_flags` for a list of flags that can be toggled. -* `hud_set_hotbar_itemcount(count)`: sets number of items in builtin hotbar - * `count`: number of items, must be between `1` and `32` - * If `count` exceeds the `"main"` list size, the list size will be used instead. -* `hud_get_hotbar_itemcount()`: returns number of visible items - * This value is also clamped by the `"main"` list size. -* `hud_set_hotbar_image(texturename)` - * sets background image for hotbar -* `hud_get_hotbar_image()`: returns texturename -* `hud_set_hotbar_selected_image(texturename)` - * sets image for selected item of hotbar -* `hud_get_hotbar_selected_image()`: returns texturename -* `set_minimap_modes({mode, mode, ...}, selected_mode)` - * Overrides the available minimap modes (and toggle order), and changes the - selected mode. - * `mode` is a table consisting of up to four fields: - * `type`: Available type: - * `off`: Minimap off - * `surface`: Minimap in surface mode - * `radar`: Minimap in radar mode - * `texture`: Texture to be displayed instead of terrain map - (texture is centered around 0,0 and can be scaled). - Texture size is limited to 512 x 512 pixel. - * `label`: Optional label to display on minimap mode toggle - The translation must be handled within the mod. - * `size`: Sidelength or diameter, in number of nodes, of the terrain - displayed in minimap - * `texture`: Only for texture type, name of the texture to display - * `scale`: Only for texture type, scale of the texture map in nodes per - pixel (for example a `scale` of 2 means each pixel represents a 2x2 - nodes square) - * `selected_mode` is the mode index to be selected after modes have been changed - (0 is the first mode). -* `set_sky(sky_parameters)` - * The presence of the function `set_sun`, `set_moon` or `set_stars` indicates - whether `set_sky` accepts this format. Check the legacy format otherwise. - * Passing no arguments resets the sky to its default values. - * `sky_parameters` is a table with the following optional fields: - * `base_color`: ColorSpec, meaning depends on `type` (default: `#ffffff`) - * `body_orbit_tilt`: Float, rotation angle of sun/moon orbit in degrees. - By default, orbit is controlled by a client-side setting, and this field is not set. - After a value is assigned, it can only be changed to another float value. - Valid range [-60.0,60.0] (default: not set) - * `type`: Available types: - * `"regular"`: Uses 0 textures, `base_color` ignored - * `"skybox"`: Uses 6 textures, `base_color` used as fog. - * `"plain"`: Uses 0 textures, `base_color` used as both fog and sky. - (default: `"regular"`) - * `textures`: A table containing up to six textures in the following - order: Y+ (top), Y- (bottom), X+ (east), X- (west), Z- (south), Z+ (north). - The top and bottom textures are oriented in-line with the east (X+) face (the top edge of the - bottom texture and the bottom edge of the top texture touch the east face). - Some top and bottom textures expect to be aligned with the north face and will need to be rotated - by -90 and 90 degrees, respectively, to fit the eastward orientation. - * `clouds`: Boolean for whether clouds appear. (default: `true`) - * `sky_color`: A table used in `"regular"` type only, containing the - following values (alpha is ignored): - * `day_sky`: ColorSpec, for the top half of the sky during the day. - (default: `#61b5f5`) - * `day_horizon`: ColorSpec, for the bottom half of the sky during the day. - (default: `#90d3f6`) - * `dawn_sky`: ColorSpec, for the top half of the sky during dawn/sunset. - (default: `#b4bafa`) - The resulting sky color will be a darkened version of the ColorSpec. - Warning: The darkening of the ColorSpec is subject to change. - * `dawn_horizon`: ColorSpec, for the bottom half of the sky during dawn/sunset. - (default: `#bac1f0`) - The resulting sky color will be a darkened version of the ColorSpec. - Warning: The darkening of the ColorSpec is subject to change. - * `night_sky`: ColorSpec, for the top half of the sky during the night. - (default: `#006bff`) - The resulting sky color will be a dark version of the ColorSpec. - Warning: The darkening of the ColorSpec is subject to change. - * `night_horizon`: ColorSpec, for the bottom half of the sky during the night. - (default: `#4090ff`) - The resulting sky color will be a dark version of the ColorSpec. - Warning: The darkening of the ColorSpec is subject to change. - * `indoors`: ColorSpec, for when you're either indoors or underground. - (default: `#646464`) - * `fog_sun_tint`: ColorSpec, changes the fog tinting for the sun - at sunrise and sunset. (default: `#f47d1d`) - * `fog_moon_tint`: ColorSpec, changes the fog tinting for the moon - at sunrise and sunset. (default: `#7f99cc`) - * `fog_tint_type`: string, changes which mode the directional fog - abides by, `"custom"` uses `sun_tint` and `moon_tint`, while - `"default"` uses the classic Luanti sun and moon tinting. - Will use tonemaps, if set to `"default"`. (default: `"default"`) - * `fog`: A table with following optional fields: - * `fog_distance`: integer, set an upper bound for the client's viewing_range. - Any value >= 0 sets the desired upper bound for viewing_range, - disables range_all and prevents disabling fog (F3 key by default). - Any value < 0 resets the behavior to being client-controlled. - (default: -1) - * `fog_start`: float, override the client's fog_start. - Fraction of the visible distance at which fog starts to be rendered. - Any value between [0.0, 0.99] set the fog_start as a fraction of the viewing_range. - Any value < 0, resets the behavior to being client-controlled. - (default: -1) - * `fog_color`: ColorSpec, override the color of the fog. - Unlike `base_color` above this will apply regardless of the skybox type. - (default: `"#00000000"`, which means no override) -* `set_sky(base_color, type, {texture names}, clouds)` - * Deprecated. Use `set_sky(sky_parameters)` - * `base_color`: ColorSpec, defaults to white - * `type`: Available types: - * `"regular"`: Uses 0 textures, `bgcolor` ignored - * `"skybox"`: Uses 6 textures, `bgcolor` used - * `"plain"`: Uses 0 textures, `bgcolor` used - * `clouds`: Boolean for whether clouds appear in front of `"skybox"` or - `"plain"` custom skyboxes (default: `true`) -* `get_sky(as_table)`: - * `as_table`: boolean that determines whether the deprecated version of this - function is being used. - * `true` returns a table containing sky parameters as defined in `set_sky(sky_parameters)`. - * Deprecated: `false` or `nil` returns base_color, type, table of textures, - clouds. -* `get_sky_color()`: - * Deprecated: Use `get_sky(as_table)` instead. - * returns a table with the `sky_color` parameters as in `set_sky`. -* `set_sun(sun_parameters)`: - * Passing no arguments resets the sun to its default values. - * `sun_parameters` is a table with the following optional fields: - * `visible`: Boolean for whether the sun is visible. - (default: `true`) - * `texture`: A regular texture for the sun. Setting to `""` - will re-enable the mesh sun. (default: "sun.png", if it exists) - The texture appears non-rotated at sunrise and rotated 180 degrees - (upside down) at sunset. - * `tonemap`: A 512x1 texture containing the tonemap for the sun - (default: `"sun_tonemap.png"`) - * `sunrise`: A regular texture for the sunrise texture. - (default: `"sunrisebg.png"`) - * `sunrise_visible`: Boolean for whether the sunrise texture is visible. - (default: `true`) - * `scale`: Float controlling the overall size of the sun. (default: `1`) - Note: For legacy reasons, the sun is bigger than the moon by a factor - of about `1.57` for equal `scale` values. -* `get_sun()`: returns a table with the current sun parameters as in - `set_sun`. -* `set_moon(moon_parameters)`: - * Passing no arguments resets the moon to its default values. - * `moon_parameters` is a table with the following optional fields: - * `visible`: Boolean for whether the moon is visible. - (default: `true`) - * `texture`: A regular texture for the moon. Setting to `""` - will re-enable the mesh moon. (default: `"moon.png"`, if it exists) - The texture appears non-rotated at sunrise / moonset and rotated 180 - degrees (upside down) at sunset / moonrise. - Note: Relative to the sun, the moon texture is hence rotated by 180°. - You can use the `^[transformR180` texture modifier to achieve the same orientation. - * `tonemap`: A 512x1 texture containing the tonemap for the moon - (default: `"moon_tonemap.png"`) - * `scale`: Float controlling the overall size of the moon (default: `1`) - Note: For legacy reasons, the sun is bigger than the moon by a factor - of about `1.57` for equal `scale` values. -* `get_moon()`: returns a table with the current moon parameters as in - `set_moon`. -* `set_stars(star_parameters)`: - * Passing no arguments resets stars to their default values. - * `star_parameters` is a table with the following optional fields: - * `visible`: Boolean for whether the stars are visible. - (default: `true`) - * `day_opacity`: Float for maximum opacity of stars at day. - No effect if `visible` is false. - (default: 0.0; maximum: 1.0; minimum: 0.0) - * `count`: Integer number to set the number of stars in - the skybox. Only applies to `"skybox"` and `"regular"` sky types. - (default: `1000`) - * `star_color`: ColorSpec, sets the colors of the stars, - alpha channel is used to set overall star brightness. - (default: `#ebebff69`) - * `scale`: Float controlling the overall size of the stars (default: `1`) -* `get_stars()`: returns a table with the current stars parameters as in - `set_stars`. -* `set_clouds(cloud_parameters)`: set cloud parameters - * Passing no arguments resets clouds to their default values. - * `cloud_parameters` is a table with the following optional fields: - * `density`: from `0` (no clouds) to `1` (full clouds) (default `0.4`) - * `color`: basic cloud color with alpha channel, ColorSpec - (default `#fff0f0e5`). - * `ambient`: cloud color lower bound, use for a "glow at night" effect. - ColorSpec (alpha ignored, default `#000000`) - * `height`: cloud height, i.e. y of cloud base (default per conf, - usually `120`) - * `thickness`: cloud thickness in nodes (default `16`). - if set to zero the clouds are rendered flat. - * `speed`: 2D cloud speed + direction in nodes per second - (default `{x=0, z=-2}`). - * `shadow`: shadow color, applied to the base of the cloud - (default `#cccccc`). -* `get_clouds()`: returns a table with the current cloud parameters as in - `set_clouds`. -* `override_day_night_ratio(ratio or nil)` - * `0`...`1`: Overrides day-night ratio, controlling sunlight to a specific - amount. - * Passing no arguments disables override, defaulting to sunlight based on day-night cycle - * See also `core.time_to_day_night_ratio`, -* `get_day_night_ratio()`: returns the ratio or nil if it isn't overridden -* `set_local_animation(idle, walk, dig, walk_while_dig, frame_speed)`: - set animation for player model in third person view. - * Every animation equals to a `{x=starting frame, y=ending frame}` table. - * `frame_speed` sets the animations frame speed. Default is 30. -* `get_local_animation()`: returns idle, walk, dig, walk_while_dig tables and - `frame_speed`. -* `set_eye_offset([firstperson, thirdperson_back, thirdperson_front])`: Sets camera offset vectors. - * `firstperson`: Offset in first person view. - Defaults to `vector.zero()` if unspecified. - * `thirdperson_back`: Offset in third person back view. - Clamped between `vector.new(-10, -10, -5)` and `vector.new(10, 15, 5)`. - Defaults to `vector.zero()` if unspecified. - * `thirdperson_front`: Offset in third person front view. - Same limits as for `thirdperson_back` apply. - Defaults to `thirdperson_back` if unspecified. -* `get_eye_offset()`: Returns camera offset vectors as set via `set_eye_offset`. -* `set_camera(params)`: Sets camera parameters. - * `mode`: Defines the camera mode used - - `any`: free choice between all modes (default) - - `first`: first-person camera - - `third`: third-person camera - - `third_front`: third-person camera, looking opposite of movement direction - * Supported by client since 5.12.0. -* `get_camera()`: Returns the camera parameters as a table as above. -* `send_mapblock(blockpos)`: - * Sends an already loaded mapblock to the player. - * Returns `false` if nothing was sent (note that this can also mean that - the client already has the block) - * Resource intensive - use sparsely -* `set_lighting(light_definition)`: sets lighting for the player - * Passing no arguments resets lighting to its default values. - * `light_definition` is a table with the following optional fields: - * `saturation` sets the saturation (vividness; default: `1.0`). - * It is applied according to the function `result = b*(1-s) + c*s`, where: - * `c` is the original color - * `b` is the greyscale version of the color with the same luma - * `s` is the saturation set here - * The resulting color always has the same luma (perceived brightness) as the original. - * This means that: - * values > 1 oversaturate - * values < 1 down to 0 desaturate, 0 being entirely greyscale - * values < 0 cause an effect similar to inversion, - but keeping original luma and being symmetrical in terms of saturation - (eg. -1 and 1 is the same saturation and luma, but different hues) - * This value has no effect on clients who have shaders or post-processing disabled. - * `shadows` is a table that controls ambient shadows - * This has no effect on clients who have the "Dynamic Shadows" effect disabled. - * `intensity` sets the intensity of the shadows from 0 (no shadows, default) to 1 (blackness) - * `tint` tints the shadows with the provided color, with RGB values ranging from 0 to 255. - (default `{r=0, g=0, b=0}`) - * `exposure` is a table that controls automatic exposure. - The basic exposure factor equation is `e = 2^exposure_correction / clamp(luminance, 2^luminance_min, 2^luminance_max)` - * This has no effect on clients who have the "Automatic Exposure" effect disabled. - * `luminance_min` set the lower luminance boundary to use in the calculation (default: `-3.0`) - * `luminance_max` set the upper luminance boundary to use in the calculation (default: `-3.0`) - * `exposure_correction` correct observed exposure by the given EV value (default: `0.0`) - * `speed_dark_bright` set the speed of adapting to bright light (default: `1000.0`) - * `speed_bright_dark` set the speed of adapting to dark scene (default: `1000.0`) - * `center_weight_power` set the power factor for center-weighted luminance measurement (default: `1.0`) - * `bloom` is a table that controls bloom. - * This has no effect on clients with protocol version < 46 or clients who - have the "Bloom" effect disabled. - * `intensity` defines much bloom is applied to the rendered image. - * Recommended range: from 0.0 to 1.0, default: 0.05 - * If set to 0, bloom is disabled. - * The default value is to be changed from 0.05 to 0 in the future. - If you wish to keep the current default value, you should set it - explicitly. - * `strength_factor` defines the magnitude of bloom overexposure. - * Recommended range: from 0.1 to 10.0, default: 1.0 - * `radius` is a logical value that controls how far the bloom effect - spreads from the bright objects. - * Recommended range: from 0.1 to 8.0, default: 1.0 - * The behavior of values outside the recommended range is unspecified. - * `volumetric_light`: is a table that controls volumetric light (a.k.a. "godrays") - * This has no effect on clients who have the "Volumetric Lighting" or "Bloom" effects disabled. - * `strength`: sets the strength of the volumetric light effect from 0 (off, default) to 1 (strongest). - * `0.2` is a reasonable standard value. - * Currently, bloom `intensity` and `strength_factor` affect volumetric - lighting `strength` and vice versa. This behavior is to be changed - in the future, do not rely on it. - -* `get_lighting()`: returns the current state of lighting for the player. - * Result is a table with the same fields as `light_definition` in `set_lighting`. -* `respawn()`: Respawns the player using the same mechanism as the death screen, - including calling `on_respawnplayer` callbacks. -* `get_flags()`: returns a table of player flags (the following boolean fields): - * `breathing`: Whether breathing (regaining air) is enabled, default `true`. - * `drowning`: Whether drowning (losing air) is enabled, default `true`. - * `node_damage`: Whether the player takes damage from nodes, default `true`. -* `set_flags(flags)`: sets flags - * takes a table in the same format as returned by `get_flags` - * absent fields are left unchanged - - -`PcgRandom` ------------ - -A 32-bit pseudorandom number generator. -Uses PCG32, an algorithm of the permuted congruential generator family, -offering very strong randomness. - -* constructor `PcgRandom(seed, [seq])` - * `seed`: 64-bit unsigned seed - * `seq`: 64-bit unsigned sequence, optional - -### Methods - -* `next()`: return next integer random number [`-2147483648`...`2147483647`] -* `next(min, max)`: return next integer random number [`min`...`max`] -* `rand_normal_dist(min, max, num_trials=6)`: return normally distributed - random number [`min`...`max`]. - * This is only a rough approximation of a normal distribution with: - * `mean = (max - min) / 2`, and - * `variance = (((max - min + 1) ^ 2) - 1) / (12 * num_trials)` - * Increasing `num_trials` improves accuracy of the approximation -* `get_state()`: return generator state encoded in string -* `set_state(state_string)`: restore generator state from encoded string - -`PlayerMetaRef` ---------------- - -Player metadata. -Uses the same method of storage as the deprecated player attribute API, so -data there will also be in player meta. -Can be obtained using `player:get_meta()`. - -### Methods - -* All methods in MetaDataRef - -`PseudoRandom` --------------- - -A 16-bit pseudorandom number generator. -Uses a well-known LCG algorithm introduced by K&R. - -**Note**: -`PseudoRandom` is slower and has worse random distribution than `PcgRandom`. -Use `PseudoRandom` only if you need output to match the well-known LCG algorithm introduced by K&R. -Otherwise, use `PcgRandom`. - -* constructor `PseudoRandom(seed)` - * `seed`: 32-bit signed number - -### Methods - -* `next()`: return next integer random number [`0`...`32767`] -* `next(min, max)`: return next integer random number [`min`...`max`] - * Either `max - min == 32767` or `max - min <= 6553` must be true - due to the simple implementation making a bad distribution otherwise. -* `get_state()`: return state of pseudorandom generator as number - * use returned number as seed in PseudoRandom constructor to restore - -`Raycast` ---------- - -A raycast on the map. It works with selection boxes. -Can be used as an iterator in a for loop as: - -```lua -local ray = Raycast(...) -for pointed_thing in ray do - ... -end -``` - -The map is loaded as the ray advances. If the map is modified after the -`Raycast` is created, the changes may or may not have an effect on the object. - -It can be created via `Raycast(pos1, pos2, objects, liquids, pointabilities)` -or `core.raycast(pos1, pos2, objects, liquids, pointabilities)` where: - -* `pos1`: start of the ray -* `pos2`: end of the ray -* `objects`: if false, only nodes will be returned. Default is `true`. -* `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be - returned. Default is `false`. -* `pointabilities`: Allows overriding the `pointable` property of - nodes and objects. Uses the same format as the `pointabilities` property - of item definitions. Default is `nil`. - -### Limitations - -Raycasts don't always work properly for attached objects as the server has no knowledge of models & bones. - -**Rotated selectionboxes paired with `automatic_rotate` are not reliable** either since the server -can't reliably know the total rotation of the objects on different clients (which may differ on a per-client basis). -The server calculates the total rotation incurred through `automatic_rotate` as a "best guess" -assuming the object was active & rotating on the client all the time since its creation. -This may be significantly out of sync with what clients see. -Additionally, network latency and delayed property sending may create a mismatch of client- & server rotations. - -In singleplayer mode, raycasts on objects with rotated selectionboxes & automatic rotate will usually only be slightly off; -toggling automatic rotation may however cause errors to add up. - -In multiplayer mode, the error may be arbitrarily large. - -### Methods - -* `next()`: returns a `pointed_thing` with exact pointing location - * Returns the next thing pointed by the ray or nil. - -`SecureRandom` --------------- - -Interface for the operating system's crypto-secure PRNG. - -It can be created via `SecureRandom()`. The constructor throws an error if a -secure random device cannot be found on the system. - -### Methods - -* `next_bytes([count])`: return next `count` (default 1, capped at 2048) many - random bytes, as a string. - -`Settings` ----------- - -An interface to read config files in the format of `minetest.conf`. - -`core.settings` is a `Settings` instance that can be used to access the -main config file (`minetest.conf`). Instances for other config files can be -created via `Settings(filename)`. - -Engine settings on the `core.settings` object have internal defaults that -will be returned if a setting is unset. -The engine does *not* (yet) read `settingtypes.txt` for this purpose. This -means that no defaults will be returned for mod settings. - -### Methods - -* `get(key)`: returns a value - * Returns `nil` if `key` is not found. -* `get_bool(key, [default])`: returns a boolean - * `default` is the value returned if `key` is not found. - * Returns `nil` if `key` is not found and `default` not specified. -* `get_np_group(key)`: returns a NoiseParams table - * Returns `nil` if `key` is not found. -* `get_flags(key)`: - * Returns `{flag = true/false, ...}` according to the set flags. - * Is currently limited to mapgen flags `mg_flags` and mapgen-specific - flags like `mgv5_spflags`. - * Returns `nil` if `key` is not found. -* `get_pos(key)`: - * Returns a `vector` - * Returns `nil` if no value is found or parsing failed. -* `set(key, value)` - * Setting names can't contain whitespace or any of `="{}#`. - * Setting values can't contain the sequence `\n"""`. - * Setting names starting with "secure." can't be set on the main settings - object (`core.settings`). -* `set_bool(key, value)` - * See documentation for `set()` above. -* `set_np_group(key, value)` - * `value` is a NoiseParams table. - * Also, see documentation for `set()` above. -* `set_pos(key, value)` - * `value` is a `vector`. - * Also, see documentation for `set()` above. -* `remove(key)`: returns a boolean (`true` for success) -* `get_names()`: returns `{key1,...}` -* `has(key)`: - * Returns a boolean indicating whether `key` exists. - * In contrast to the various getter functions, `has()` doesn't consider - any default values. - * This means that on the main settings object (`core.settings`), - `get(key)` might return a value even if `has(key)` returns `false`. -* `write()`: returns a boolean (`true` for success) - * Writes changes to file. -* `to_table()`: returns `{[key1]=value1,...}` - -### Format - -The settings have the format `key = value`. Example: - - foo = example text - bar = """ - Multiline - value - """ - - -`StorageRef` ------------- - -Mod metadata: per mod and world metadata, saved automatically. -Can be obtained via `core.get_mod_storage()` during load time. - -WARNING: This storage backend is incapable of saving raw binary data due -to restrictions of JSON. - -### Methods - -* All methods in MetaDataRef - -`ValueNoise` -------------- - -A value noise generator. -It can be created via `ValueNoise()` or `core.get_value_noise()`. -For `core.get_value_noise()`, the actual seed used is the noiseparams seed -plus the world seed, to create world-specific noise. - -**Important**: These require the mapgen environment to be initalized, do not use at load time. - -* `ValueNoise(noiseparams)` -* `ValueNoise(seed, octaves, persistence, spread)` (deprecated) -* `core.get_value_noise(noiseparams)` -* `core.get_value_noise(seeddiff, octaves, persistence, spread)` (deprecated) - -These were previously called `PerlinNoise()` and `core.get_perlin()`, but the -implemented noise was not Perlin noise. They were renamed in 5.12.0. The old -names still exist as aliases. - -### Methods - -* `get_2d(pos)`: returns 2D noise value at `pos={x=,y=}` -* `get_3d(pos)`: returns 3D noise value at `pos={x=,y=,z=}` - -`ValueNoiseMap` ----------------- - -A fast, bulk noise generator. - -It can be created via `ValueNoiseMap(noiseparams, size)` or -`core.get_value_noise_map(noiseparams, size)`. -For `core.get_value_noise_map()`, the actual seed used is the noiseparams seed -plus the world seed, to create world-specific noise. - -These were previously called `PerlinNoiseMap()` and `core.get_perlin_map()`, -but the implemented noise was not Perlin noise. They were renamed in 5.12.0. -The old names still exist as aliases. - -Format of `size` is `{x=dimx, y=dimy, z=dimz}`. The `z` component is omitted -for 2D noise, and it must be larger than 1 for 3D noise (otherwise -`nil` is returned). - -For each of the functions with an optional `buffer` parameter: If `buffer` is -not nil, this table will be used to store the result instead of creating a new -table. - -**Important**: These require the mapgen environment to be initalized, do not use at load time. - -### Methods - -* `get_2d_map(pos)`: returns a `` times `` 2D array of 2D noise - with values starting at `pos={x=,y=}` -* `get_3d_map(pos)`: returns a `` times `` times `` - 3D array of 3D noise with values starting at `pos={x=,y=,z=}`. -* `get_2d_map_flat(pos, buffer)`: returns a flat `` element - array of 2D noise with values starting at `pos={x=,y=}` -* `get_3d_map_flat(pos, buffer)`: Same as `get2dMap_flat`, but 3D noise -* `calc_2d_map(pos)`: Calculates the 2d noise map starting at `pos`. The result - is stored internally. -* `calc_3d_map(pos)`: Calculates the 3d noise map starting at `pos`. The result - is stored internally. -* `get_map_slice(slice_offset, slice_size, buffer)`: In the form of an array, - returns a slice of the most recently computed noise results. The result slice - begins at coordinates `slice_offset` and takes a chunk of `slice_size`. - E.g., to grab a 2-slice high horizontal 2d plane of noise starting at buffer - offset `y = 20`: - ```lua - noisevals = noise:get_map_slice({y=20}, {y=2}) - ``` - It is important to note that `slice_offset` offset coordinates begin at 1, - and are relative to the starting position of the most recently calculated - noise. - To grab a single vertical column of noise starting at map coordinates - `x = 1023, y=1000, z = 1000`: - ```lua - noise:calc_3d_map({x=1000, y=1000, z=1000}) - noisevals = noise:get_map_slice({x=24, z=1}, {x=1, z=1}) - ``` - - - - -Definition tables -================= - -Object properties ------------------ - -Used by `ObjectRef` methods. Part of an Entity definition. -These properties are not persistent, but are applied automatically to the -corresponding Lua entity using the given registration fields. -Player properties need to be saved manually. - -```lua -{ - hp_max = 10, - -- Defines the maximum and default HP of the object. - -- For Lua entities, the maximum is not enforced. - -- For players, this defaults to `core.PLAYER_MAX_HP_DEFAULT` (20). - -- For Lua entities, the default is 10. - - breath_max = 0, - -- For players only. Defines the maximum amount of "breath" for the player. - -- Defaults to `core.PLAYER_MAX_BREATH_DEFAULT` (10). - - zoom_fov = 0.0, - -- For players only. Zoom FOV in degrees. - -- Note that zoom loads and/or generates world beyond the server's - -- maximum send and generate distances, so acts like a telescope. - -- Smaller zoom_fov values increase the distance loaded/generated. - -- Defaults to 15 in creative mode, 0 in survival mode. - -- zoom_fov = 0 disables zooming for the player. - - eye_height = 1.625, - -- For players only. Camera height above feet position in nodes. - - physical = false, - -- Collide with `walkable` nodes. - - collide_with_objects = true, - -- Collide with other objects if physical = true - - collisionbox = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 }, -- default - selectionbox = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5, rotate = false }, - -- { xmin, ymin, zmin, xmax, ymax, zmax } in nodes from object position. - -- Collision boxes cannot rotate, setting `rotate = true` on it has no effect. - -- If not set, the selection box copies the collision box, and will also not rotate. - -- If `rotate = false`, the selection box will not rotate with the object itself, remaining fixed to the axes. - -- If `rotate = true`, it will match the object's rotation and any attachment rotations. - -- Raycasts use the selection box and object's rotation, but do *not* obey attachment rotations. - -- For server-side raycasts to work correctly, - -- the selection box should extend at most 5 units in each direction. - - - pointable = true, - -- Can be `true` if it is pointable, `false` if it can be pointed through, - -- or `"blocking"` if it is pointable but not selectable. - -- Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`. - -- Can be overridden by the `pointabilities` of the held item. - - visual = "", - -- "cube" is a node-sized cube. - -- "sprite" is a flat texture always facing the player. - -- "upright_sprite" is a vertical flat texture. - -- "mesh" uses the defined mesh model. - -- "wielditem" is used for dropped items. - -- (see builtin/game/item_entity.lua). - -- For this use 'wield_item = itemname'. - -- Setting 'textures = {itemname}' has the same effect, but is deprecated. - -- If the item has a 'wield_image' the object will be an extrusion of - -- that, otherwise: - -- If 'itemname' is a cubic node or nodebox the object will appear - -- identical to 'itemname'. - -- If 'itemname' is a plantlike node the object will be an extrusion - -- of its texture. - -- Otherwise for non-node items, the object will be an extrusion of - -- 'inventory_image'. - -- If 'itemname' contains a ColorString or palette index (e.g. from - -- `core.itemstring_with_palette()`), the entity will inherit the color. - -- Wielditems are scaled a bit. If you want a wielditem to appear - -- to be as large as a node, use `0.667` in `visual_size` - -- "item" is similar to "wielditem" but ignores the 'wield_image' parameter. - -- "node" looks exactly like a node in-world (supported since 5.12.0) - -- Note that visual effects like waving or liquid reflections will not work. - - visual_size = {x = 1, y = 1, z = 1}, - -- Multipliers for the visual size. If `z` is not specified, `x` will be used - -- to scale the entity along both horizontal axes. - - mesh = "model.obj", - -- File name of mesh when using "mesh" visual. - -- For legacy reasons, this uses a 10x scale for meshes: 10 units = 1 node. - - textures = {}, - -- Number of required textures depends on visual: - -- "cube" uses 6 textures just like a node, but all 6 must be defined. - -- "sprite" uses 1 texture. - -- "upright_sprite" uses 2 textures: {front, back}. - -- "mesh" requires one texture for each mesh buffer/material (in order) - -- Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above). - - colors = {}, - -- Currently unused. - - node = {name = "ignore", param1=0, param2=0}, - -- Node to show when using the "node" visual - - use_texture_alpha = false, - -- Use texture's alpha channel for transparency blending. - -- Note: currently causes visual issues when viewed through other - -- semi-transparent materials such as water. - -- Note: ignored for "item", "wielditem" and "node" visual. - - spritediv = {x = 1, y = 1}, - -- Used with spritesheet textures for animation and/or frame selection - -- according to position relative to player. - -- Defines the number of columns and rows in the spritesheet: - -- {columns, rows}. - - initial_sprite_basepos = {x = 0, y = 0}, - -- Used with spritesheet textures. - -- Defines the {column, row} position of the initially used frame in the - -- spritesheet. - - is_visible = true, - -- If false, object is invisible and can't be pointed. - - makes_footstep_sound = false, - -- If true, object is able to make footstep sounds of nodes - -- (see node sound definition for details). - - automatic_rotate = 0, - -- Set constant right-handed rotation in radians per second, positive or negative. - -- Object rotates along the local Y-axis, and works with set_rotation. - -- Set to 0 to disable constant rotation. - - stepheight = 0, - -- If positive number, object will climb upwards when it moves - -- horizontally against a `walkable` node, if the height difference - -- is within `stepheight`. - - automatic_face_movement_dir = 0.0, - -- Automatically set yaw to movement direction, offset in degrees. - -- 'false' to disable. - - automatic_face_movement_max_rotation_per_sec = -1, - -- Limit automatic rotation to this value in degrees per second. - -- No limit if value <= 0. - - backface_culling = true, - -- Set to false to disable backface_culling for model - -- Note: only used by "mesh" and "cube" visual - - glow = 0, - -- Add this much extra lighting when calculating texture color. - -- Value < 0 disables light's effect on texture color. - -- For faking self-lighting, UI style entities, or programmatic coloring - -- in mods. - - nametag = "", - -- The name to display on the head of the object. By default empty. - -- If the object is a player, a nil or empty nametag is replaced by the player's name. - -- For all other objects, a nil or empty string removes the nametag. - -- To hide a nametag, set its color alpha to zero. That will disable it entirely. - - nametag_color = , - -- Sets text color of nametag - - nametag_bgcolor = , - -- Sets background color of nametag - -- `false` will cause the background to be set automatically based on user settings. - -- Default: false - - infotext = "", - -- Same as infotext for nodes. Empty by default - - static_save = true, - -- If false, never save this object statically. It will simply be - -- deleted when the block gets unloaded. - -- The get_staticdata() callback is never called then. - -- Defaults to 'true'. - - damage_texture_modifier = "^[brighten", - -- Texture modifier to be applied for a short duration when object is hit - - shaded = true, - -- Setting this to 'false' disables diffuse lighting of entity - -- Note: ignored for "item", "wielditem" and "node" visual - - show_on_minimap = false, - -- Defaults to true for players, false for other entities. - -- If set to true the entity will show as a marker on the minimap. -} -``` - -Entity definition ------------------ - -Used by `core.register_entity`. -The entity definition table becomes a metatable of a newly created per-entity -luaentity table, meaning its fields (e.g. `initial_properties`) will be shared -between all instances of an entity. - -```lua -{ - initial_properties = { - visual = "mesh", - mesh = "boats_boat.obj", - ..., - }, - -- A table of object properties, see the `Object properties` section. - -- The properties in this table are applied to the object - -- once when it is spawned. - - -- Refer to the "Registered entities" section for explanations - on_activate = function(self, staticdata, dtime_s) end, - on_deactivate = function(self, removal) end, - on_step = function(self, dtime, moveresult) end, - on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage) end, - on_death = function(self, killer) end, - on_rightclick = function(self, clicker) end, - on_attach_child = function(self, child) end, - on_detach_child = function(self, child) end, - on_detach = function(self, parent) end, - get_staticdata = function(self) end, - - _custom_field = whatever, - -- You can define arbitrary member variables here (see Item definition - -- for more info) by using a '_' prefix -} -``` - - -ABM (ActiveBlockModifier) definition ------------------------------------- - -Used by `core.register_abm`. - -An active block modifier (ABM) is used to define a function that is continously -and randomly called for specific nodes (defined by `nodenames` and other conditions) -in active mapblocks. - -```lua -{ - label = "Lava cooling", - -- Descriptive label for profiling purposes (optional). - -- Definitions with identical labels will be listed as one. - - nodenames = {"default:lava_source"}, - -- Apply `action` function to these nodes. - -- `group:groupname` can also be used here. - - neighbors = {"default:water_source", "default:water_flowing"}, - -- Only apply `action` to nodes that have one of, or any - -- combination of, these neighbors. - -- If left out or empty, any neighbor will do. - -- `group:groupname` can also be used here. - - without_neighbors = {"default:lava_source", "default:lava_flowing"}, - -- Only apply `action` to nodes that have no one of these neighbors. - -- If left out or empty, it has no effect. - -- `group:groupname` can also be used here. - - interval = 10.0, - -- Operation interval in seconds - - chance = 50, - -- Probability of triggering `action` per-node per-interval is 1.0 / chance (integers only) - - min_y = -32768, - max_y = 32767, - -- min and max height levels where ABM will be processed (inclusive) - -- can be used to reduce CPU usage - - catch_up = true, - -- If true, catch-up behavior is enabled: The `chance` value is - -- temporarily reduced when returning to an area to simulate time lost - -- by the area being unattended. Note that the `chance` value can often - -- be reduced to 1. - - action = function(pos, node, active_object_count, active_object_count_wider), - -- Function triggered for each qualifying node. - -- `active_object_count` is number of active objects in the node's - -- mapblock. - -- `active_object_count_wider` is number of active objects in the node's - -- mapblock plus all 26 neighboring mapblocks. If any neighboring - -- mapblocks are unloaded an estimate is calculated for them based on - -- loaded mapblocks. -} -``` - -LBM (LoadingBlockModifier) definition -------------------------------------- - -Used by `core.register_lbm`. - -A loading block modifier (LBM) is used to define a function that is called for -specific nodes (defined by `nodenames`) when a mapblock which contains such nodes -gets **activated** (**not loaded!**). - -*Note*: LBMs operate on a "snapshot" of node positions taken once before they are triggered. -That means if an LBM callback adds a node, it won't be taken into account. -However the engine guarantees that at the point in time when the callback is called -that all given positions contain a matching node. - -For `run_at_every_load = false` to work, both mapblocks and LBMs have timestamps -associated with them: - -* Each mapblock has a "last active" timestamp. It is also updated when the - mapblock is generated. -* For each LBM, an introduction timestamp is stored in the world data, identified - by the LBM's `name` field. If an LBM disappears, the corresponding timestamp - is cleared. - -When a mapblock is activated, only LBMs whose introduction timestamp is newer -than the mapblock's timestamp are run. - -*Note*: For maps generated in 5.11.0 or older, many newly generated mapblocks -did not get a timestamp set. This means LBMs introduced between generation time -and time of first activation will never run. -Currently the only workaround is to use `run_at_every_load = true`. - -```lua -{ - label = "Upgrade legacy doors", - -- Descriptive label for profiling purposes (optional). - -- Definitions with identical labels will be listed as one. - - name = "modname:replace_legacy_door", - -- Identifier of the LBM, should follow the modname: convention - - nodenames = {"default:lava_source"}, - -- List of node names to trigger the LBM on. - -- Names of non-registered nodes and groups (as group:groupname) - -- will work as well. - - run_at_every_load = false, - -- If `false`: The LBM only runs on mapblocks the first time they are - -- activated after the LBM was introduced. - -- It never runs on mapblocks generated after the LBM's introduction. - -- See above for details. - -- - -- If `true`: The LBM runs every time a mapblock is activated. - - action = function(pos, node, dtime_s) end, - -- Function triggered for each qualifying node. - -- `dtime_s` is the in-game time (in seconds) elapsed since the mapblock - -- was last active (available since 5.7.0). - - bulk_action = function(pos_list, dtime_s) end, - -- Function triggered with a list of all applicable node positions at once. - -- This can be provided as an alternative to `action` (not both). - -- Available since `core.features.bulk_lbms` (5.10.0) - -- `dtime_s`: as above -} -``` - -Tile definition ---------------- - -* `"image.png"` -* `{name="image.png", animation={Tile Animation definition}}` -* `{name="image.png", backface_culling=bool, align_style="node"/"world"/"user", scale=int}` - * backface culling enabled by default for most nodes - * align style determines whether the texture will be rotated with the node - or kept aligned with its surroundings. "user" means that client - setting will be used, similar to `glasslike_framed_optional`. - Note: supported by solid nodes and nodeboxes only. - * scale is used to make texture span several (exactly `scale`) nodes, - instead of just one, in each direction. Works for world-aligned - textures only. - Note that as the effect is applied on per-mapblock basis, `16` should - be equally divisible by `scale` or you may get wrong results. -* `{name="image.png", color=ColorSpec}` - * the texture's color will be multiplied with this color. - * the tile's color overrides the owning node's color in all cases. -* deprecated, yet still supported field names: - * `image` (name) - -Tile animation definition -------------------------- - -```lua -{ - type = "vertical_frames", - - aspect_w = 16, - -- Width of a frame in pixels - - aspect_h = 16, - -- Height of a frame in pixels - - length = 3.0, - -- Full loop length -} - -{ - type = "sheet_2d", - - frames_w = 5, - -- Width in number of frames - - frames_h = 3, - -- Height in number of frames - - frame_length = 0.5, - -- Length of a single frame -} -``` - -Item definition ---------------- - -Used by `core.register_node`, `core.register_craftitem`, and -`core.register_tool`. - -```lua -{ - description = "", - -- Can contain new lines. "\n" has to be used as new line character. - -- See also: `get_description` in [`ItemStack`] - - short_description = "", - -- Must not contain new lines. - -- Defaults to nil. - -- Use an [`ItemStack`] to get the short description, e.g.: - -- ItemStack(itemname):get_short_description() - - groups = {}, - -- key = name, value = rating; rating = . - -- If rating not applicable, use 1. - -- e.g. {wool = 1, fluffy = 3} - -- {soil = 2, outerspace = 1, crumbly = 1} - -- {bendy = 2, snappy = 1}, - -- {hard = 1, metal = 1, spikes = 1} - - inventory_image = "", - -- Texture shown in the inventory GUI - -- Defaults to a 3D rendering of the node if left empty. - - inventory_overlay = "", - -- An overlay texture which is not affected by colorization - - wield_image = "", - -- Texture shown when item is held in hand - -- Defaults to a 3D rendering of the node if left empty. - - wield_overlay = "", - -- Like inventory_overlay but only used in the same situation as wield_image - - wield_scale = {x = 1, y = 1, z = 1}, - -- Scale for the item when held in hand - - palette = "", - -- An image file containing the palette of a node. - -- You can set the currently used color as the "palette_index" field of - -- the item stack metadata. - -- The palette is always stretched to fit indices between 0 and 255, to - -- ensure compatibility with "colorfacedir" (and similar) nodes. - - color = "#ffffffff", - -- Color the item is colorized with. The palette overrides this. - -- It is a colorspec. - - stack_max = 99, - -- Maximum amount of items that can be in a single stack. - -- The default can be changed by the setting `default_stack_max` - - range = 4.0, - -- Range of node and object pointing that is possible with this item held - -- Can be overridden with itemstack meta. - - liquids_pointable = false, - -- If true, item can point to all liquid nodes (`liquidtype ~= "none"`), - -- even those for which `pointable = false` - - pointabilities = { - nodes = { - ["default:stone"] = "blocking", - ["group:leaves"] = false, - }, - objects = { - ["modname:entityname"] = true, - ["group:ghosty"] = true, -- (an armor group) - }, - }, - -- Contains lists to override the `pointable` property of nodes and objects. - -- The index can be a node/entity name or a group with the prefix `"group:"`. - -- (For objects `armor_groups` are used and for players the entity name is irrelevant.) - -- If multiple fields fit, the following priority order is applied: - -- 1. value of matching node/entity name - -- 2. `true` for any group - -- 3. `false` for any group - -- 4. `"blocking"` for any group - -- 5. `liquids_pointable` if it is a liquid node - -- 6. `pointable` property of the node or object - - light_source = 0, - -- When used for nodes: Defines amount of light emitted by node. - -- Otherwise: Defines texture glow when viewed as a dropped item - -- To set the maximum (14), use the value 'core.LIGHT_MAX'. - -- A value outside the range 0 to core.LIGHT_MAX causes undefined - -- behavior. - - -- See "Tool Capabilities" section for an example including explanation - tool_capabilities = { - full_punch_interval = 1.0, - max_drop_level = 0, - groupcaps = { - -- For example: - choppy = {times = {2.50, 1.40, 1.00}, uses = 20, maxlevel = 2}, - }, - damage_groups = {groupname = damage}, - -- Damage values must be between -32768 and 32767 (2^15) - - punch_attack_uses = nil, - -- Amount of uses this tool has for attacking players and entities - -- by punching them (0 = infinite uses). - -- For compatibility, this is automatically set from the first - -- suitable groupcap using the formula "uses * 3^(maxlevel - 1)". - -- It is recommend to set this explicitly instead of relying on the - -- fallback behavior. - }, - - -- Set wear bar color of the tool by setting color stops and blend mode - -- See "Wear Bar Color" section for further explanation including an example - wear_color = { - -- interpolation mode: 'constant' or 'linear' - -- (nil defaults to 'constant') - blend = "linear", - color_stops = { - [0.0] = "#ff0000", - [0.5] = "#ffff00", - [1.0] = "#00ff00", - } - }, - - node_placement_prediction = nil, - -- If nil and item is node, prediction is made automatically. - -- If nil and item is not a node, no prediction is made. - -- If "" and item is anything, no prediction is made. - -- Otherwise should be name of node which the client immediately places - -- on ground when the player places the item. Server will always update - -- with actual result shortly. - - node_dig_prediction = "air", - -- if "", no prediction is made. - -- if "air", node is removed. - -- Otherwise should be name of node which the client immediately places - -- upon digging. Server will always update with actual result shortly. - - touch_interaction = OR { - pointed_nothing = , - pointed_node = , - pointed_object = , - }, - -- Only affects touchscreen clients. - -- Defines the meaning of short and long taps with the item in hand. - -- If specified as a table, the field to be used is selected according to - -- the current `pointed_thing`. - -- There are three possible TouchInteractionMode values: - -- * "long_dig_short_place" (long tap = dig, short tap = place) - -- * "short_dig_long_place" (short tap = dig, long tap = place) - -- * "user": - -- * For `pointed_object`: Equivalent to "short_dig_long_place" if the - -- client-side setting "touch_punch_gesture" is "short_tap" (the - -- default value) and the item is able to punch (i.e. has no on_use - -- callback defined). - -- Equivalent to "long_dig_short_place" otherwise. - -- * For `pointed_node` and `pointed_nothing`: - -- Equivalent to "long_dig_short_place". - -- * The behavior of "user" may change in the future. - -- The default value is "user". - - sound = { - -- Definition of item sounds to be played at various events. - -- All fields in this table are optional. - - breaks = , - -- When tool breaks due to wear. Ignored for non-tools - - eat = , - -- When item is eaten with `core.do_item_eat` - - punch_use = , - -- When item is used with the 'punch/mine' key pointing at a node or entity - - punch_use_air = , - -- When item is used with the 'punch/mine' key pointing at nothing (air) - }, - - on_place = function(itemstack, placer, pointed_thing), - -- When the 'place' key was pressed with the item in hand - -- and a node was pointed at. - -- Shall place item and return the leftover itemstack - -- or nil to not modify the inventory. - -- The placer may be any ObjectRef or nil. - -- default: core.item_place - - on_secondary_use = function(itemstack, user, pointed_thing), - -- Same as on_place but called when not pointing at a node. - -- Function must return either nil if inventory shall not be modified, - -- or an itemstack to replace the original itemstack. - -- The user may be any ObjectRef or nil. - -- default: nil - - on_drop = function(itemstack, dropper, pos), - -- Shall drop item and return the leftover itemstack. - -- The dropper may be any ObjectRef or nil. - -- default: core.item_drop - - on_pickup = function(itemstack, picker, pointed_thing, time_from_last_punch, ...), - -- Called when a dropped item is punched by a player. - -- Shall pick-up the item and return the leftover itemstack or nil to not - -- modify the dropped item. - -- Parameters: - -- * `itemstack`: The `ItemStack` to be picked up. - -- * `picker`: Any `ObjectRef` or `nil`. - -- * `pointed_thing` (optional): The dropped item (a `"__builtin:item"` - -- luaentity) as `type="object"` `pointed_thing`. - -- * `time_from_last_punch, ...` (optional): Other parameters from - -- `luaentity:on_punch`. - -- default: `core.item_pickup` - - on_use = function(itemstack, user, pointed_thing), - -- default: nil - -- When user pressed the 'punch/mine' key with the item in hand. - -- Function must return either nil if inventory shall not be modified, - -- or an itemstack to replace the original itemstack. - -- e.g. itemstack:take_item(); return itemstack - -- Otherwise, the function is free to do what it wants. - -- The user may be any ObjectRef or nil. - -- The default functions handle regular use cases. - - after_use = function(itemstack, user, node, digparams), - -- default: nil - -- If defined, should return an itemstack and will be called instead of - -- wearing out the item (if tool). If returns nil, does nothing. - -- If after_use doesn't exist, it is the same as: - -- function(itemstack, user, node, digparams) - -- itemstack:add_wear(digparams.wear) - -- return itemstack - -- end - -- The user may be any ObjectRef or nil. - - _custom_field = whatever, - -- Add your own custom fields. By convention, all custom field names - -- should start with `_` to avoid naming collisions with future engine - -- usage. -} -``` - -Node definition ---------------- - -Used by `core.register_node`. - -```lua -{ - -- - - drawtype = "normal", -- See "Node drawtypes" - - visual_scale = 1.0, - -- Supported for drawtypes "plantlike", "signlike", "torchlike", - -- "firelike", "mesh", "nodebox", "allfaces". - -- For plantlike and firelike, the image will start at the bottom of the - -- node. For torchlike, the image will start at the surface to which the - -- node "attaches". For the other drawtypes the image will be centered - -- on the node. - - tiles = {tile definition 1, def2, def3, def4, def5, def6}, - -- Textures of node; +Y, -Y, +X, -X, +Z, -Z - -- List can be shortened to needed length. - - overlay_tiles = {tile definition 1, def2, def3, def4, def5, def6}, - -- Same as `tiles`, but these textures are drawn on top of the base - -- tiles. You can use this to colorize only specific parts of your - -- texture. If the texture name is an empty string, that overlay is not - -- drawn. Since such tiles are drawn twice, it is not recommended to use - -- overlays on very common nodes. - - special_tiles = {tile definition 1, Tile definition 2}, - -- Special textures of node; used rarely. - -- List can be shortened to needed length. - - color = ColorSpec, - -- The node's original color will be multiplied with this color. - -- If the node has a palette, then this setting only has an effect in - -- the inventory and on the wield item. - - use_texture_alpha = ..., - -- Specifies how the texture's alpha channel will be used for rendering. - -- Possible values: - -- * "opaque": - -- Node is rendered opaque regardless of alpha channel. - -- * "clip": - -- A given pixel is either fully see-through or opaque - -- depending on the alpha channel being below/above 50% in value. - -- Use this for nodes with fully transparent and fully opaque areas. - -- * "blend": - -- The alpha channel specifies how transparent a given pixel - -- of the rendered node is. This comes at a performance cost. - -- Only use this when correct rendering - -- among semitransparent nodes is necessary. - -- The default is "opaque" for drawtypes normal, liquid and flowingliquid, - -- mesh and nodebox or "clip" otherwise. - -- If set to a boolean value (deprecated): true either sets it to blend - -- or clip, false sets it to clip or opaque mode depending on the drawtype. - - palette = "", - -- The node's `param2` is used to select a pixel from the image. - -- Pixels are arranged from left to right and from top to bottom. - -- The node's color will be multiplied with the selected pixel's color. - -- Tiles can override this behavior. - -- Only when `paramtype2` supports palettes. - - post_effect_color = "#00000000", - -- Screen tint if a player is inside this node, see `ColorSpec`. - -- Color is alpha-blended over the screen. - - post_effect_color_shaded = false, - -- Determines whether `post_effect_color` is affected by lighting. - - paramtype = "none", -- See "Nodes" - - paramtype2 = "none", -- See "Nodes" - - place_param2 = 0, - -- Value for param2 that is set when player places node - - wallmounted_rotate_vertical = false, - -- If true, place_param2 is nil, and this is a wallmounted node, - -- this node might use the special 90° rotation when placed - -- on the floor or ceiling, depending on the direction. - -- See the explanation about wallmounted for details. - -- Otherwise, the rotation is always the same on vertical placement. - - is_ground_content = true, - -- If false, the cave generator and dungeon generator will not carve - -- through this node. - -- Specifically, this stops mod-added nodes being removed by caves and - -- dungeons when those generate in a neighbor mapchunk and extend out - -- beyond the edge of that mapchunk. - - sunlight_propagates = false, - -- If true, sunlight will go infinitely through this node - - walkable = true, -- If true, objects collide with node - - pointable = true, - -- Can be `true` if it is pointable, `false` if it can be pointed through, - -- or `"blocking"` if it is pointable but not selectable. - -- Clients older than 5.9.0 interpret `pointable = "blocking"` as `pointable = true`. - -- Can be overridden by the `pointabilities` of the held item. - -- A client may be able to point non-pointable nodes, since it isn't checked server-side. - - diggable = true, -- If false, can never be dug - - climbable = false, -- If true, can be climbed on like a ladder - - move_resistance = 0, - -- Slows down movement of players through this node (max. 7). - -- If this is nil, it will be equal to liquid_viscosity. - -- Note: If liquid movement physics apply to the node - -- (see `liquid_move_physics`), the movement speed will also be - -- affected by the `movement_liquid_*` settings. - - buildable_to = false, -- If true, placed nodes can replace this node - - floodable = false, - -- If true, liquids flow into and replace this node. - -- Warning: making a liquid node 'floodable' will cause problems. - - liquidtype = "none", -- specifies liquid flowing physics - -- * "none": no liquid flowing physics - -- * "source": spawns flowing liquid nodes at all 4 sides and below; - -- recommended drawtype: "liquid". - -- * "flowing": spawned from source, spawns more flowing liquid nodes - -- around it until `liquid_range` is reached; - -- will drain out without a source; - -- recommended drawtype: "flowingliquid". - -- If it's "source" or "flowing", then the - -- `liquid_alternative_*` fields _must_ be specified - - liquid_alternative_flowing = "", - liquid_alternative_source = "", - -- These fields may contain node names that represent the - -- flowing version (`liquid_alternative_flowing`) and - -- source version (`liquid_alternative_source`) of a liquid. - -- - -- Specifically, these fields are required if `liquidtype ~= "none"` or - -- `drawtype == "flowingliquid"`. - -- - -- Liquids consist of up to two nodes: source and flowing. - -- - -- There are two ways to define a liquid: - -- 1) Source node and flowing node. This requires both fields to be - -- specified for both nodes. - -- 2) Standalone source node (cannot flow). `liquid_alternative_source` - -- must be specified and `liquid_range` must be set to 0. - -- - -- Example: - -- liquid_alternative_flowing = "example:water_flowing", - -- liquid_alternative_source = "example:water_source", - - liquid_viscosity = 0, - -- Controls speed at which the liquid spreads/flows (max. 7). - -- 0 is fastest, 7 is slowest. - -- By default, this also slows down movement of players inside the node - -- (can be overridden using `move_resistance`) - - liquid_renewable = true, - -- If true, a new liquid source can be created by placing two or more - -- sources nearby - - liquid_move_physics = nil, -- specifies movement physics if inside node - -- * false: No liquid movement physics apply. - -- * true: Enables liquid movement physics. Enables things like - -- ability to "swim" up/down, sinking slowly if not moving, - -- smoother speed change when falling into, etc. The `movement_liquid_*` - -- settings apply. - -- * nil: Will be treated as true if `liquidtype ~= "none"` - -- and as false otherwise. - - air_equivalent = nil, - -- unclear meaning, the engine sets this to true for 'air' and 'ignore' - -- deprecated. - - leveled = 0, - -- Only valid for "nodebox" drawtype with 'type = "leveled"'. - -- Allows defining the nodebox height without using param2. - -- The nodebox height is 'leveled' / 64 nodes. - -- The maximum value of 'leveled' is `leveled_max`. - - leveled_max = 127, - -- Maximum value for `leveled` (0-127), enforced in - -- `core.set_node_level` and `core.add_node_level`. - -- Values above 124 might causes collision detection issues. - - liquid_range = 8, - -- Maximum distance that flowing liquid nodes can spread around - -- source on flat land; - -- maximum = 8; set to 0 to disable liquid flow - - drowning = 0, - -- Player will take this amount of damage if no bubbles are left - - damage_per_second = 0, - -- If player is inside node, this damage is caused - - node_box = {type = "regular"}, -- See "Node boxes" - - connects_to = {}, - -- Used for nodebox nodes with the type == "connected". - -- Specifies to what neighboring nodes connections will be drawn. - -- e.g. `{"group:fence", "default:wood"}` or `"default:stone"` - - connect_sides = {}, - -- Tells connected nodebox nodes to connect only to these sides of this - -- node. possible: "top", "bottom", "front", "left", "back", "right" - - mesh = "", - -- File name of mesh when using "mesh" drawtype - -- The center of the node is the model origin. - -- For legacy reasons, this uses a different scale depending on the mesh: - -- 1. For glTF models: 10 units = 1 node (consistent with the scale for entities). - -- 2. For obj models: 1 unit = 1 node. - -- 3. For b3d and x models: 1 unit = 1 node if static, otherwise 10 units = 1 node. - -- Using static glTF or obj models is recommended. - -- You can use the `visual_scale` multiplier to achieve the expected scale. - - selection_box = { - -- see [Node boxes] for possibilities - }, - -- Custom selection box definition. Multiple boxes can be defined. - -- If "nodebox" drawtype is used and selection_box is nil, then node_box - -- definition is used for the selection box. - - collision_box = { - -- see [Node boxes] for possibilities - }, - -- Custom collision box definition. Multiple boxes can be defined. - -- If "nodebox" drawtype is used and collision_box is nil, then node_box - -- definition is used for the collision box. - - -- Support maps made in and before January 2012 - legacy_facedir_simple = false, - legacy_wallmounted = false, - - waving = 0, - -- Valid for drawtypes: - -- mesh, nodebox, plantlike, allfaces_optional, liquid, flowingliquid. - -- 1 - wave node like plants (node top moves side-to-side, bottom is fixed) - -- 2 - wave node like leaves (whole node moves side-to-side) - -- 3 - wave node like liquids (whole node moves up and down) - -- Not all models will properly wave. - -- plantlike drawtype can only wave like plants. - -- allfaces_optional drawtype can only wave like leaves. - -- liquid, flowingliquid drawtypes can only wave like liquids. - - sounds = { - -- Definition of node sounds to be played at various events. - -- All fields in this table are optional. - - footstep = , - -- If walkable, played when object walks on it. If node is - -- climbable or a liquid, played when object moves through it. - -- Sound is played at the base of the object's collision-box. - -- Gain is multiplied by `0.6`. - -- For local player, it's played position-less, with normal gain. - - dig = or "__group", - -- While digging node. - -- If `"__group"`, then the sound will be - -- `{name = "default_dig_", gain = 0.5}` , where `` is the - -- name of the item's digging group with the fastest digging time. - -- In case of a tie, one of the sounds will be played (but we - -- cannot predict which one) - -- Default value: `"__group"` - - dug = , - -- Node was dug - - place = , - -- Node was placed. Also played after falling - - place_failed = , - -- When node placement failed. - -- Note: This happens if the _built-in_ node placement failed. - -- This sound will still be played if the node is placed in the - -- `on_place` callback manually. - - fall = , - -- When node starts to fall or is detached - }, - - drop = "", - -- Name of dropped item when dug. - -- Default dropped item is the node itself. - - -- Using a table allows multiple items, drop chances and item filtering: - drop = { - max_items = 1, - -- Maximum number of item lists to drop. - -- The entries in 'items' are processed in order. For each: - -- Item filtering is applied, chance of drop is applied, if both are - -- successful the entire item list is dropped. - -- Entry processing continues until the number of dropped item lists - -- equals 'max_items'. - -- Therefore, entries should progress from low to high drop chance. - items = { - -- Examples: - { - -- 1 in 1000 chance of dropping a diamond. - -- Default rarity is '1'. - rarity = 1000, - items = {"default:diamond"}, - }, - { - -- Only drop if using an item whose name is identical to one - -- of these. - tools = {"default:shovel_mese", "default:shovel_diamond"}, - rarity = 5, - items = {"default:dirt"}, - -- Whether all items in the dropped item list inherit the - -- hardware coloring palette color from the dug node. - -- Default is 'false'. - inherit_color = true, - }, - { - -- Only drop if using an item whose name contains - -- "default:shovel_" (this item filtering by string matching - -- is deprecated, use tool_groups instead). - tools = {"~default:shovel_"}, - rarity = 2, - -- The item list dropped. - items = {"default:sand", "default:desert_sand"}, - }, - { - -- Only drop if using an item in the "magicwand" group, or - -- an item that is in both the "pickaxe" and the "lucky" - -- groups. - tool_groups = { - "magicwand", - {"pickaxe", "lucky"} - }, - items = {"default:coal_lump"}, - }, - }, - }, - - on_construct = function(pos), - -- Node constructor; called after adding node. - -- Can set up metadata and stuff like that. - -- Not called for bulk node placement (i.e. schematics and VoxelManip). - -- Note: Within an on_construct callback, core.set_node can cause an - -- infinite loop if it invokes the same callback. - -- Consider using core.swap_node instead. - -- default: nil - - on_destruct = function(pos), - -- Node destructor; called before removing node. - -- Not called for bulk node placement. - -- default: nil - - after_destruct = function(pos, oldnode), - -- Node destructor; called after removing node. - -- Not called for bulk node placement. - -- default: nil - - on_flood = function(pos, oldnode, newnode), - -- Called when a liquid (newnode) is about to flood oldnode, if it has - -- `floodable = true` in the nodedef. Not called for bulk node placement - -- (i.e. schematics and VoxelManip) or air nodes. If return true the - -- node is not flooded, but on_flood callback will most likely be called - -- over and over again every liquid update interval. - -- Default: nil - -- Warning: making a liquid node 'floodable' will cause problems. - - preserve_metadata = function(pos, oldnode, oldmeta, drops), - -- Called when `oldnode` is about be converted to an item, but before the - -- node is deleted from the world or the drops are added. This is - -- generally the result of either the node being dug or an attached node - -- becoming detached. - -- * `pos`: node position - -- * `oldnode`: node table of node before it was deleted - -- * `oldmeta`: metadata of node before it was deleted, as a metadata table - -- * `drops`: a table of `ItemStack`s, so any metadata to be preserved can - -- be added directly to one or more of the dropped items. See - -- "ItemStackMetaRef". - -- default: `nil` - - after_place_node = function(pos, placer, itemstack, pointed_thing), - -- Called after constructing node when node was placed using - -- core.item_place_node / core.place_node. - -- If return true no item is taken from itemstack. - -- `placer` may be any valid ObjectRef or nil. - -- default: nil - - after_dig_node = function(pos, oldnode, oldmetadata, digger), - -- Called after destructing the node when node was dug using - -- `core.node_dig` / `core.dig_node`. - -- * `pos`: node position - -- * `oldnode`: node table of node before it was dug - -- * `oldmetadata`: metadata of node before it was dug, - -- as a metadata table - -- * `digger`: ObjectRef of digger - -- default: nil - - can_dig = function(pos, [player]), - -- Returns true if node can be dug, or false if not. - -- default: nil - - on_punch = function(pos, node, puncher, pointed_thing), - -- default: core.node_punch - -- Called when puncher (an ObjectRef) punches the node at pos. - -- By default calls core.register_on_punchnode callbacks. - - on_rightclick = function(pos, node, clicker, itemstack, pointed_thing), - -- default: nil - -- Called when clicker (an ObjectRef) used the 'place/build' key - -- (not necessarily an actual rightclick) - -- while pointing at the node at pos with 'node' being the node table. - -- itemstack will hold clicker's wielded item. - -- Shall return the leftover itemstack. - -- Note: pointed_thing can be nil, if a mod calls this function. - -- This function does not get triggered by clients <=0.4.16 if the - -- "formspec" node metadata field is set. - - on_dig = function(pos, node, digger), - -- default: core.node_dig - -- By default checks privileges, wears out item (if tool) and removes node. - -- return true if the node was dug successfully, false otherwise. - -- Deprecated: returning nil is the same as returning true. - - on_timer = function(pos, elapsed), - -- default: nil - -- called by NodeTimers, see core.get_node_timer and NodeTimerRef. - -- elapsed is the total time passed since the timer was started. - -- return true to run the timer for another cycle with the same timeout - -- value. - - on_receive_fields = function(pos, formname, fields, sender), - -- fields = {name1 = value1, name2 = value2, ...} - -- formname should be the empty string; you **must not** use formname. - -- Called when an UI form (e.g. sign text input) returns data. - -- See core.register_on_player_receive_fields for more info. - -- default: nil - - allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player), - -- Called when a player wants to move items inside the inventory. - -- Return value: number of items allowed to move. - - allow_metadata_inventory_put = function(pos, listname, index, stack, player), - -- Called when a player wants to put something into the inventory. - -- Return value: number of items allowed to put. - -- Return value -1: Allow and don't modify item count in inventory. - - allow_metadata_inventory_take = function(pos, listname, index, stack, player), - -- Called when a player wants to take something out of the inventory. - -- Return value: number of items allowed to take. - -- Return value -1: Allow and don't modify item count in inventory. - - on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player), - on_metadata_inventory_put = function(pos, listname, index, stack, player), - on_metadata_inventory_take = function(pos, listname, index, stack, player), - -- Called after the actual action has happened, according to what was - -- allowed. - -- No return value. - - on_blast = function(pos, intensity), - -- intensity: 1.0 = mid range of regular TNT. - -- If defined, called when an explosion touches the node, instead of - -- removing the node. - - mod_origin = "modname", - -- stores which mod actually registered a node - -- If the source could not be determined it contains "??" - -- Useful for getting which mod truly registered something - -- example: if a node is registered as ":othermodname:nodename", - -- nodename will show "othermodname", but mod_origin will say "modname" -} -``` - -Wear Bar Color --------------- - -'Wear Bar' is a property of items that defines the coloring -of the bar that appears under damaged tools. -If it is absent, the default behavior of green-yellow-red is -used. - -### Wear bar colors definition - -#### Syntax - -```lua -{ - -- 'constant' or 'linear' - -- (nil defaults to 'constant') - blend = "linear", - color_stops = { - [0.0] = "#ff0000", - [0.5] = "slateblue", - [1.0] = {r=0, g=255, b=0, a=150}, - } -} -``` - -#### Blend mode `blend` - -* `linear`: blends smoothly between each defined color point. -* `constant`: each color starts at its defined point, and continues up to the next point - -#### Color stops `color_stops` - -Specified as `ColorSpec` color values assigned to `float` durability keys. - -"Durability" is defined as `1 - (wear / 65535)`. - -#### Shortcut usage - -Wear bar color can also be specified as a single `ColorSpec` instead of a table. - -Crafting recipes ----------------- - -Crafting converts one or more inputs to one output itemstack of arbitrary -count (except for fuels, which don't have an output). The conversion reduces -each input ItemStack by 1. - -Craft recipes are registered by `core.register_craft` and use a -table format. The accepted parameters are listed below. - -Recipe input items can either be specified by item name (item count = 1) -or by group (see "Groups in crafting recipes" for details). -Only the item name (and groups) matter for matching a recipe, i.e. meta and count -are ignored. - -If multiple recipes match the input of a craft grid, one of them is chosen by the -following priority rules: - -* Shaped recipes are preferred over shapeless recipes, which in turn are preferred - over tool repair. -* Otherwise, recipes without groups are preferred over recipes with groups. -* Otherwise, earlier registered recipes are preferred. - -The following sections describe the types and syntaxes of recipes. - -### Shaped - -This is the default recipe type (when no `type` is specified). - -A shaped recipe takes one or multiple items as input and has -a single item stack as output. The input items must be specified -in a 2-dimensional matrix (see parameters below) to specify the -exact arrangement (the "shape") in which the player must place them -in the crafting grid. - -For example, for a 3x3 recipe, the `recipes` table must have -3 rows and 3 columns. - -In order to craft the recipe, the players' crafting grid must -have equal or larger dimensions (both width and height). - -Empty slots outside of the recipe's extents are ignored, e.g. a 3x3 -recipe where only the bottom right 2x2 slots are filled is the same -as the corresponding 2x2 recipe without the empty slots. - -Parameters: - -* `type = "shaped"`: (optional) specifies recipe type as shaped -* `output`: Itemstring of output itemstack (item counts >= 1 are allowed) -* `recipe`: A 2-dimensional matrix of items, with a width *w* and height *h*. - * *w* and *h* are chosen by you, they don't have to be equal but must be at least 1 - * The matrix is specified as a table containing tables containing itemnames - * The inner tables are the rows. There must be *h* tables, specified from the top to the bottom row - * Values inside of the inner table are the columns. - Each inner table must contain a list of *w* items, specified from left to right - * Empty slots *must* be filled with the empty string -* `replacements`: (optional) Allows you to replace input items with some other items - when something is crafted - * Provided as a list of item pairs of the form `{ old_item, new_item }` where - `old_item` is the input item to replace (same syntax as for a regular input - slot; groups are allowed) and `new_item` is an itemstring for the item stack - it will become - * When the output is crafted, Luanti iterates through the list - of input items if the crafting grid. For each input item stack, it checks if - it matches with an `old_item` in the item pair list. - * If it matches, the item will be replaced. Also, this item pair - will *not* be applied again for the remaining items - * If it does not match, the item is consumed (reduced by 1) normally - * The `new_item` will appear in one of 3 places: - * Crafting grid, if the input stack size was exactly 1 - * Player inventory, if input stack size was larger - * Drops as item entity, if it fits neither in craft grid or inventory - -#### Examples - -A typical shaped recipe: - -```lua --- Stone pickaxe -{ - output = "example:stone_pickaxe", - -- A 3x3 recipe which needs 3 stone in the 1st row, - -- and 1 stick in the horizontal middle in each of the 2nd and 3nd row. - -- The 4 remaining slots have to be empty. - recipe = { - {"example:stone", "example:stone", "example:stone"}, -- row 1 - {"", "example:stick", "" }, -- row 2 - {"", "example:stick", "" }, -- row 3 - -- ^ column 1 ^ column 2 ^ column 3 - }, - -- There is no replacements table, so every input item - -- will be consumed. -} -``` - -Simple replacement example: - -```lua --- Wet sponge -{ - output = "example:wet_sponge", - -- 1x2 recipe with a water bucket above a dry sponge - recipe = { - {"example:water_bucket"}, - {"example:dry_sponge"}, - }, - -- When the wet sponge is crafted, the water bucket - -- in the input slot is replaced with an empty - -- bucket - replacements = { - {"example:water_bucket", "example:empty_bucket"}, - }, -} -``` - -Complex replacement example 1: - -```lua --- Very wet sponge -{ - output = "example:very_wet_sponge", - -- 3x3 recipe with a wet sponge in the center - -- and 4 water buckets around it - recipe = { - {"","example:water_bucket",""}, - {"example:water_bucket","example:wet_sponge","example:water_bucket"}, - {"","example:water_bucket",""}, - }, - -- When the wet sponge is crafted, all water buckets - -- in the input slot become empty - replacements = { - -- Without these repetitions, only the first - -- water bucket would be replaced. - {"example:water_bucket", "example:empty_bucket"}, - {"example:water_bucket", "example:empty_bucket"}, - {"example:water_bucket", "example:empty_bucket"}, - {"example:water_bucket", "example:empty_bucket"}, - }, -} -``` - -Complex replacement example 2: - -```lua --- Magic book: --- 3 magic orbs + 1 book crafts a magic book, --- and the orbs will be replaced with 3 different runes. -{ - output = "example:magic_book", - -- 3x2 recipe - recipe = { - -- 3 items in the group `magic_orb` on top of a book in the middle - {"group:magic_orb", "group:magic_orb", "group:magic_orb"}, - {"", "example:book", ""}, - }, - -- When the book is crafted, the 3 magic orbs will be turned into - -- 3 runes: ice rune, earth rune and fire rune (from left to right) - replacements = { - {"group:magic_orb", "example:ice_rune"}, - {"group:magic_orb", "example:earth_rune"}, - {"group:magic_orb", "example:fire_rune"}, - }, -} -``` - -### Shapeless - -Takes a list of input items (at least 1). The order or arrangement -of input items does not matter. - -In order to craft the recipe, the players' crafting grid must have matching or -larger *count* of slots. The grid dimensions do not matter. - -Parameters: - -* `type = "shapeless"`: Mandatory -* `output`: Same as for shaped recipe -* `recipe`: List of item names -* `replacements`: Same as for shaped recipe - -#### Example - -```lua -{ - -- Craft a mushroom stew from a bowl, a brown mushroom and a red mushroom - -- (no matter where in the input grid the items are placed) - type = "shapeless", - output = "example:mushroom_stew", - recipe = { - "example:bowl", - "example:mushroom_brown", - "example:mushroom_red", - }, -} -``` - -### Tool repair - -Syntax: - - { - type = "toolrepair", - additional_wear = -0.02, -- multiplier of 65536 - } - -Adds a shapeless recipe for *every* tool that doesn't have the `disable_repair=1` -group. If this recipe is used, repairing is possible with any crafting grid -with at least 2 slots. -The player can put 2 equal tools in the craft grid to get one "repaired" tool -back. -The wear of the output is determined by the wear of both tools, plus a -'repair bonus' given by `additional_wear`. To reduce the wear (i.e. 'repair'), -you want `additional_wear` to be negative. - -The formula used to calculate the resulting wear is: - - 65536 * (1 - ( (1 - tool_1_wear) + (1 - tool_2_wear) + additional_wear)) - -The result is rounded and can't be lower than 0. If the result is 65536 or higher, -no crafting is possible. - -### Cooking - -A cooking recipe has a single input item, a single output item stack -and a cooking time. It represents cooking/baking/smelting/etc. items in -an oven, furnace, or something similar; the exact meaning is up for games -to decide, if they choose to use cooking at all. - -The engine does not implement anything specific to cooking recipes, but -the recipes can be retrieved later using `core.get_craft_result` to -have a consistent interface across different games/mods. - -Parameters: - -* `type = "cooking"`: Mandatory -* `output`: Same as for shaped recipe -* `recipe`: An itemname of the single input item -* `cooktime`: (optional) Time it takes to cook this item, in seconds. - A floating-point number. (default: 3.0) -* `replacements`: Same meaning as for shaped recipes, but the mods - that utilize cooking recipes (e.g. for adding a furnace - node) need to implement replacements on their own - -Note: Games and mods are free to re-interpret the cooktime in special -cases, e.g. for a super furnace that cooks items twice as fast. - -#### Example - -Cooking sand to glass in 3 seconds: - -```lua -{ - type = "cooking", - output = "example:glass", - recipe = "example:sand", - cooktime = 3.0, -} -``` - -### Fuel - -A fuel recipe is an item associated with a "burning time" and an optional -item replacement. There is no output. This is usually used as fuel for -furnaces, ovens, stoves, etc. - -Like with cooking recipes, the engine does not do anything specific with -fuel recipes and it's up to games and mods to use them by retrieving -them via `core.get_craft_result`. - -Parameters: - -* `type = "fuel"`: Mandatory -* `recipe`: Itemname of the item to be used as fuel -* `burntime`: (optional) Burning time this item provides, in seconds. - A floating-point number. (default: 1.0) -* `replacements`: Same meaning as for shaped recipes, but the mods - that utilize fuels need to implement replacements - on their own - -Note: Games and mods are free to re-interpret the burntime in special -cases, e.g. for an efficient furnace in which fuels burn twice as -long. - -#### Examples - -Coal lump with a burntime of 20 seconds. Will be consumed when used. - -```lua -{ - type = "fuel", - recipe = "example:coal_lump", - burntime = 20.0, -} -``` - -Lava bucket with a burn time of 60 seconds. Will become an empty bucket -if used: - -```lua -{ - type = "fuel", - recipe = "example:lava_bucket", - burntime = 60.0, - replacements = {{"example:lava_bucket", "example:empty_bucket"}}, -} -``` - -Ore definition --------------- - -Used by `core.register_ore`. - -See [Ores] section above for essential information. - -```lua -{ - name = "", - -- If set, core.registered_ores[that_name] will return this definition. - - ore_type = "", - -- Supported: "scatter", "sheet", "puff", "blob", "vein", "stratum" - - ore = "", - -- Ore node to place - - ore_param2 = 0, - -- Param2 to set for ore (e.g. facedir rotation) - - wherein = "", - -- Node to place ore in. Multiple are possible by passing a list. - - clust_scarcity = 8 * 8 * 8, - -- Ore has a 1 out of clust_scarcity chance of spawning in a node. - -- If the desired average distance between ores is 'd', set this to - -- d * d * d. - - clust_num_ores = 8, - -- Number of ores in a cluster - - clust_size = 3, - -- Size of the bounding box of the cluster. - -- In this example, there is a 3 * 3 * 3 cluster where 8 out of the 27 - -- nodes are coal ore. - - y_min = -31000, - y_max = 31000, - -- Lower and upper limits for ore (inclusive) - - flags = "", - -- Attributes for the ore generation, see 'Ore attributes' section above - - noise_threshold = 0, - -- If noise is above this threshold, ore is placed. Not needed for a - -- uniform distribution. - - noise_params = { - offset = 0, - scale = 1, - spread = {x = 100, y = 100, z = 100}, - seed = 23, - octaves = 3, - persistence = 0.7 - }, - -- NoiseParams structure describing one of the noises used for - -- ore distribution. - -- Needed by "sheet", "puff", "blob" and "vein" ores. - -- Omit from "scatter" ore for a uniform ore distribution. - -- Omit from "stratum" ore for a simple horizontal strata from y_min to - -- y_max. - - biomes = {"desert", "rainforest"}, - -- List of biomes in which this ore occurs. - -- Occurs in all biomes if this is omitted, and ignored if the Mapgen - -- being used does not support biomes. - -- Can be a list of (or a single) biome names, IDs, or definitions. - - -- Type-specific parameters - - -- "sheet" - column_height_min = 1, - column_height_max = 16, - column_midpoint_factor = 0.5, - - -- "puff" - np_puff_top = { - offset = 4, - scale = 2, - spread = {x = 100, y = 100, z = 100}, - seed = 47, - octaves = 3, - persistence = 0.7 - }, - np_puff_bottom = { - offset = 4, - scale = 2, - spread = {x = 100, y = 100, z = 100}, - seed = 11, - octaves = 3, - persistence = 0.7 - }, - - -- "vein" - random_factor = 1.0, - - -- "stratum" - np_stratum_thickness = { - offset = 8, - scale = 4, - spread = {x = 100, y = 100, z = 100}, - seed = 17, - octaves = 3, - persistence = 0.7 - }, - stratum_thickness = 8, -- only used if no noise defined -} -``` - -Biome definition ----------------- - -Used by `core.register_biome`. - -The maximum number of biomes that can be used is 65535. However, using an -excessive number of biomes will slow down map generation. Depending on desired -performance and computing power the practical limit is much lower. - -```lua -{ - name = "tundra", - - node_dust = "default:snow", - -- Node dropped onto upper surface after all else is generated - - node_top = "default:dirt_with_snow", - depth_top = 1, - -- Node forming surface layer of biome and thickness of this layer - - node_filler = "default:permafrost", - depth_filler = 3, - -- Node forming lower layer of biome and thickness of this layer - - node_stone = "default:bluestone", - -- Node that replaces all stone nodes between roughly y_min and y_max. - - node_water_top = "default:ice", - depth_water_top = 10, - -- Node forming a surface layer in seawater with the defined thickness - - node_water = "", - -- Node that replaces all seawater nodes not in the surface layer - - node_river_water = "default:ice", - -- Node that replaces river water in mapgens that use - -- default:river_water - - node_riverbed = "default:gravel", - depth_riverbed = 2, - -- Node placed under river water and thickness of this layer - - node_cave_liquid = "default:lava_source", - node_cave_liquid = {"default:water_source", "default:lava_source"}, - -- Nodes placed inside 50% of the medium size caves. - -- Multiple nodes can be specified, each cave will use a randomly - -- chosen node from the list. - -- If this field is left out or 'nil', cave liquids fall back to - -- classic behavior of lava and water distributed using 3D noise. - -- For no cave liquid, specify "air". - - node_dungeon = "default:cobble", - -- Node used for primary dungeon structure. - -- If absent, dungeon nodes fall back to the 'mapgen_cobble' mapgen - -- alias, if that is also absent, dungeon nodes fall back to the biome - -- 'node_stone'. - -- If present, the following two nodes are also used. - - node_dungeon_alt = "default:mossycobble", - -- Node used for randomly-distributed alternative structure nodes. - -- If alternative structure nodes are not wanted leave this absent. - - node_dungeon_stair = "stairs:stair_cobble", - -- Node used for dungeon stairs. - -- If absent, stairs fall back to 'node_dungeon'. - - y_max = 31000, - y_min = 1, - -- Upper and lower limits for biome. - -- Alternatively you can use xyz limits as shown below. - - max_pos = {x = 31000, y = 128, z = 31000}, - min_pos = {x = -31000, y = 9, z = -31000}, - -- xyz limits for biome, an alternative to using 'y_min' and 'y_max'. - -- Biome is limited to a cuboid defined by these positions. - -- Any x, y or z field left undefined defaults to -31000 in 'min_pos' or - -- 31000 in 'max_pos'. - - vertical_blend = 8, - -- Vertical distance in nodes above 'y_max' over which the biome will - -- blend with the biome above. - -- Set to 0 for no vertical blend. Defaults to 0. - - heat_point = 0, - humidity_point = 50, - -- Characteristic temperature and humidity for the biome. - -- These values create 'biome points' on a voronoi diagram with heat and - -- humidity as axes. The resulting voronoi cells determine the - -- distribution of the biomes. - -- Heat and humidity have average values of 50, vary mostly between - -- 0 and 100 but can exceed these values. - - weight = 1.0, - -- Relative weight of the biome in the Voronoi diagram. - -- A value of 0 (or less) is ignored and equivalent to 1.0. -} -``` - -Decoration definition ---------------------- - -See [Decoration types](#decoration-types). Used by `core.register_decoration`. - -```lua -{ - deco_type = "simple", - -- Type. "simple", "schematic" or "lsystem" supported - - place_on = "default:dirt_with_grass", - -- Node (or list of nodes) that the decoration can be placed on - - sidelen = 8, - -- Size of the square (X / Z) divisions of the mapchunk being generated. - -- Determines the resolution of noise variation if used. - -- If the chunk size is not evenly divisible by sidelen, sidelen is made - -- equal to the chunk size. - - fill_ratio = 0.02, - -- The value determines 'decorations per surface node'. - -- Used only if noise_params is not specified. - -- If >= 10.0 complete coverage is enabled and decoration placement uses - -- a different and much faster method. - - noise_params = { - offset = 0, - scale = 0.45, - spread = {x = 100, y = 100, z = 100}, - seed = 354, - octaves = 3, - persistence = 0.7, - lacunarity = 2.0, - flags = "absvalue" - }, - -- NoiseParams structure describing the noise used for decoration - -- distribution. - -- A noise value is calculated for each square division and determines - -- 'decorations per surface node' within each division. - -- If the noise value >= 10.0 complete coverage is enabled and - -- decoration placement uses a different and much faster method. - - biomes = {"Oceanside", "Hills", "Plains"}, - -- List of biomes in which this decoration occurs. Occurs in all biomes - -- if this is omitted, and ignored if the Mapgen being used does not - -- support biomes. - -- Can be a list of (or a single) biome names, IDs, or definitions. - - y_min = -31000, - y_max = 31000, - -- Lower and upper limits for decoration (inclusive). - -- These parameters refer to the Y coordinate of the 'place_on' node. - - spawn_by = "default:water", - -- Node (or list of nodes) that the decoration only spawns next to. - -- Checks the 8 neighboring nodes on the same height, - -- and also the ones at the height plus the check_offset, excluding both center nodes. - - check_offset = -1, - -- Specifies the offset that spawn_by should also check - -- The default value of -1 is useful to e.g check for water next to the base node. - -- 0 disables additional checks, valid values: {-1, 0, 1} - - num_spawn_by = 1, - -- Number of spawn_by nodes that must be surrounding the decoration - -- position to occur. - -- If absent or -1, decorations occur next to any nodes. - - flags = "liquid_surface, force_placement, all_floors, all_ceilings", - -- Flags for all decoration types. - -- "liquid_surface": Find the highest liquid (not solid) surface under - -- open air. Search stops and fails on the first solid node. - -- Cannot be used with "all_floors" or "all_ceilings" below. - -- "force_placement": Nodes other than "air" and "ignore" are replaced - -- by the decoration. - -- "all_floors", "all_ceilings": Instead of placement on the highest - -- surface in a mapchunk the decoration is placed on all floor and/or - -- ceiling surfaces, for example in caves and dungeons. - -- Ceiling decorations act as an inversion of floor decorations so the - -- effect of 'place_offset_y' is inverted. - -- Y-slice probabilities do not function correctly for ceiling - -- schematic decorations as the behavior is unchanged. - -- If a single decoration registration has both flags the floor and - -- ceiling decorations will be aligned vertically. - - ----- Simple-type parameters - - decoration = "default:grass", - -- The node name used as the decoration. - -- If instead a list of strings, a randomly selected node from the list - -- is placed as the decoration. - - height = 1, - -- Decoration height in nodes. - -- If height_max is not 0, this is the lower limit of a randomly - -- selected height. - - height_max = 0, - -- Upper limit of the randomly selected height. - -- If absent, the parameter 'height' is used as a constant. - - param2 = 0, - -- Param2 value of decoration nodes. - -- If param2_max is not 0, this is the lower limit of a randomly - -- selected param2. - - param2_max = 0, - -- Upper limit of the randomly selected param2. - -- If absent, the parameter 'param2' is used as a constant. - - place_offset_y = 0, - -- Y offset of the decoration base node relative to the standard base - -- node position. - -- Can be positive or negative. Default is 0. - -- Effect is inverted for "all_ceilings" decorations. - -- Ignored by 'y_min', 'y_max' and 'spawn_by' checks, which always refer - -- to the 'place_on' node. - - ----- Schematic-type parameters - - schematic = "foobar.mts", - -- If schematic is a string, it is the filepath relative to the current - -- working directory of the specified Luanti schematic file. - -- Could also be the ID of a previously registered schematic. - - schematic = { - size = {x = 4, y = 6, z = 4}, - data = { - {name = "default:cobble", param1 = 255, param2 = 0}, - {name = "default:dirt_with_grass", param1 = 255, param2 = 0}, - {name = "air", param1 = 255, param2 = 0}, - ... - }, - yslice_prob = { - {ypos = 2, prob = 128}, - {ypos = 5, prob = 64}, - ... - }, - }, - -- Alternative schematic specification by supplying a table. The fields - -- size and data are mandatory whereas yslice_prob is optional. - -- See 'Schematic specifier' for details. - - replacements = {["oldname"] = "convert_to", ...}, - -- Map of node names to replace in the schematic after reading it. - - flags = "place_center_x, place_center_y, place_center_z", - -- Flags for schematic decorations. See 'Schematic attributes'. - - rotation = "90", - -- Rotation can be "0", "90", "180", "270", or "random" - - place_offset_y = 0, - -- If the flag 'place_center_y' is set this parameter is ignored. - -- Y offset of the schematic base node layer relative to the 'place_on' - -- node. - -- Can be positive or negative. Default is 0. - -- Effect is inverted for "all_ceilings" decorations. - -- Ignored by 'y_min', 'y_max' and 'spawn_by' checks, which always refer - -- to the 'place_on' node. - - ----- L-system-type parameters - - treedef = {}, - -- Same as for `core.spawn_tree`. - -- See section [L-system trees] for more details. -} -``` - -Chat command definition ------------------------ - -Used by `core.register_chatcommand`. - -Specifies the function to be called and the privileges required when a player -issues the command. A help message that is the concatenation of the params and -description fields is shown when the "/help" chatcommand is issued. - -```lua -{ - params = "", - -- Short parameter description. See the below note. - - description = "", - -- General description of the command's purpose. - - privs = {}, - -- Required privileges to run. See `core.check_player_privs()` for - -- the format and see [Privileges] for an overview of privileges. - - func = function(name, param), - -- Called when command is run. - -- * `name` is the name of the player who issued the command. - -- * `param` is a string with the full arguments to the command. - -- Returns a boolean for success and a string value. - -- The string is shown to the issuing player upon exit of `func` or, - -- if `func` returns `false` and no string, the help message is shown. -} -``` - -Note that in params, the conventional use of symbols is as follows: - -* `<>` signifies a placeholder to be replaced when the command is used. For - example, when a player name is needed: `` -* `[]` signifies param is optional and not required when the command is used. - For example, if you require param1 but param2 is optional: - ` []` -* `|` signifies exclusive or. The command requires one param from the options - provided. For example: ` | ` -* `()` signifies grouping. For example, when param1 and param2 are both - required, or only param3 is required: `( ) | ` - -Example: - -```lua -{ - params = " ", - - description = "Remove privilege from player", - - privs = {privs=true}, -- Require the "privs" privilege to run - - func = function(name, param), -} -``` - -Privilege definition --------------------- - -Used by `core.register_privilege`. - -```lua -{ - description = "", - -- Privilege description - - give_to_singleplayer = true, - -- Whether to grant the privilege to singleplayer. - - give_to_admin = true, - -- Whether to grant the privilege to the server admin. - -- Uses value of 'give_to_singleplayer' by default. - - on_grant = function(name, granter_name), - -- Called when given to player 'name' by 'granter_name'. - -- 'granter_name' will be nil if the priv was granted by a mod. - - on_revoke = function(name, revoker_name), - -- Called when taken from player 'name' by 'revoker_name'. - -- 'revoker_name' will be nil if the priv was revoked by a mod. - - -- Note that the above two callbacks will be called twice if a player is - -- responsible, once with the player name, and then with a nil player - -- name. - -- Return true in the above callbacks to stop register_on_priv_grant or - -- revoke being called. -} -``` - -Detached inventory callbacks ----------------------------- - -Used by `core.create_detached_inventory`. - -```lua -{ - allow_move = function(inv, from_list, from_index, to_list, to_index, count, player), - -- Called when a player wants to move items inside the inventory. - -- Return value: number of items allowed to move. - - allow_put = function(inv, listname, index, stack, player), - -- Called when a player wants to put something into the inventory. - -- Return value: number of items allowed to put. - -- Return value -1: Allow and don't modify item count in inventory. - - allow_take = function(inv, listname, index, stack, player), - -- Called when a player wants to take something out of the inventory. - -- Return value: number of items allowed to take. - -- Return value -1: Allow and don't modify item count in inventory. - - on_move = function(inv, from_list, from_index, to_list, to_index, count, player), - on_put = function(inv, listname, index, stack, player), - on_take = function(inv, listname, index, stack, player), - -- Called after the actual action has happened, according to what was - -- allowed. - -- No return value. -} -``` - -HUD Definition --------------- - -Since most values have multiple different functions, please see the -documentation in [HUD](#hud) section. - -Used by `ObjectRef:hud_add`. Returned by `ObjectRef:hud_get`. - -```lua -{ - type = "image", - -- Type of element, can be "compass", "hotbar" (46 ¹), "image", "image_waypoint", - -- "inventory", "minimap" (44 ¹), "statbar", "text" or "waypoint" - -- ¹: minimal protocol version for client-side support - -- If undefined "text" will be used. - - hud_elem_type = "image", - -- Deprecated, same as `type`. - -- In case both are specified `type` will be used. - - position = {x=0.5, y=0.5}, - -- Top left corner position of element - - name = "", - - scale = {x = 1, y = 1}, - - text = "", - - text2 = "", - - number = 0, - - item = 0, - - direction = 0, - -- Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top - - alignment = {x=0, y=0}, - - offset = {x=0, y=0}, - - world_pos = {x=0, y=0, z=0}, - - size = {x=0, y=0}, - - z_index = 0, - -- Z index: lower z-index HUDs are displayed behind higher z-index HUDs - - style = 0, -} -``` - -Particle definition -------------------- - -Used by `core.add_particle`. - -```lua -{ - pos = {x=0, y=0, z=0}, - velocity = {x=0, y=0, z=0}, - acceleration = {x=0, y=0, z=0}, - -- Spawn particle at pos with velocity and acceleration - - expirationtime = 1, - -- Disappears after expirationtime seconds - - size = 1, - -- Scales the visual size of the particle texture. - -- If `node` is set, size can be set to 0 to spawn a randomly-sized - -- particle (just like actual node dig particles). - - collisiondetection = false, - -- If true collides with `walkable` nodes and, depending on the - -- `object_collision` field, objects too. - - collision_removal = false, - -- If true particle is removed when it collides. - -- Requires collisiondetection = true to have any effect. - - object_collision = false, - -- If true particle collides with objects that are defined as - -- `physical = true,` and `collide_with_objects = true,`. - -- Requires collisiondetection = true to have any effect. - - vertical = false, - -- If true faces player using y axis only - - texture = "image.png", - -- The texture of the particle - -- v5.6.0 and later: also supports the table format described in the - -- following section, but due to a bug this did not take effect - -- (beyond the texture name). - -- v5.9.0 and later: fixes the bug. - -- Note: "texture.animation" is ignored here. Use "animation" below instead. - - playername = "singleplayer", - -- Optional, if specified spawns particle only on the player's client - - animation = {Tile Animation definition}, - -- Optional, specifies how to animate the particle texture - - glow = 0 - -- Optional, specify particle self-luminescence in darkness. - -- Values 0-14. - - node = {name = "ignore", param2 = 0}, - -- Optional, if specified the particle will have the same appearance as - -- node dig particles for the given node. - -- `texture` and `animation` will be ignored if this is set. - - node_tile = 0, - -- Optional, only valid in combination with `node` - -- If set to a valid number 1-6, specifies the tile from which the - -- particle texture is picked. - -- Otherwise, the default behavior is used. (currently: any random tile) - - drag = {x=0, y=0, z=0}, - -- v5.6.0 and later: Optional drag value, consult the following section - -- Note: Only a vector is supported here. Alternative forms like a single - -- number are not supported. - - jitter = {min = ..., max = ..., bias = 0}, - -- v5.6.0 and later: Optional jitter range, consult the following section - - bounce = {min = ..., max = ..., bias = 0}, - -- v5.6.0 and later: Optional bounce range, consult the following section -} -``` - - -`ParticleSpawner` definition ----------------------------- - -Used by `core.add_particlespawner`. - -Before v5.6.0, particlespawners used a different syntax and had a more limited set -of features. Definition fields that are the same in both legacy and modern versions -are shown in the next listing, and the fields that are used by legacy versions are -shown separated by a comment; the modern fields are too complex to compactly -describe in this manner and are documented after the listing. - -The older syntax can be used in combination with the newer syntax (e.g. having -`minpos`, `maxpos`, and `pos` all set) to support older servers. On newer servers, -the new syntax will override the older syntax; on older servers, the newer syntax -will be ignored. - -```lua -{ - ------------------- - -- Common fields -- - ------------------- - -- (same name and meaning in both new and legacy syntax) - - amount = 1, - -- Number of particles spawned over the time period `time`. - - time = 1, - -- Lifespan of spawner in seconds. - -- If time is 0 spawner has infinite lifespan and spawns the `amount` on - -- a per-second basis. - - collisiondetection = false, - -- If true collide with `walkable` nodes and, depending on the - -- `object_collision` field, objects too. - - collision_removal = false, - -- If true particles are removed when they collide. - -- Requires collisiondetection = true to have any effect. - - object_collision = false, - -- If true particles collide with objects that are defined as - -- `physical = true,` and `collide_with_objects = true,`. - -- Requires collisiondetection = true to have any effect. - - attached = ObjectRef, - -- If defined, particle positions, velocities and accelerations are - -- relative to this object's position and yaw - - vertical = false, - -- If true face player using y axis only - - texture = "image.png", - -- The texture of the particle - -- v5.6.0 and later: also supports the table format described in the - -- following section. - - playername = "singleplayer", - -- Optional, if specified spawns particles only on the player's client - - animation = {Tile Animation definition}, - -- Optional, specifies how to animate the particles' texture - -- v5.6.0 and later: set length to -1 to synchronize the length - -- of the animation with the expiration time of individual particles. - -- (-2 causes the animation to be played twice, and so on) - - glow = 0, - -- Optional, specify particle self-luminescence in darkness. - -- Values 0-14. - - node = {name = "ignore", param2 = 0}, - -- Optional, if specified the particles will have the same appearance as - -- node dig particles for the given node. - -- `texture` and `animation` will be ignored if this is set. - - node_tile = 0, - -- Optional, only valid in combination with `node` - -- If set to a valid number 1-6, specifies the tile from which the - -- particle texture is picked. - -- Otherwise, the default behavior is used. (currently: any random tile) - - ------------------- - -- Legacy fields -- - ------------------- - - minpos = {x=0, y=0, z=0}, - maxpos = {x=0, y=0, z=0}, - minvel = {x=0, y=0, z=0}, - maxvel = {x=0, y=0, z=0}, - minacc = {x=0, y=0, z=0}, - maxacc = {x=0, y=0, z=0}, - minexptime = 1, - maxexptime = 1, - minsize = 1, - maxsize = 1, - -- The particles' properties are random values between the min and max - -- values. - -- applies to: pos, velocity, acceleration, expirationtime, size - -- If `node` is set, min and maxsize can be set to 0 to spawn - -- randomly-sized particles (just like actual node dig particles). -} -``` - -### Modern definition fields - -After v5.6.0, spawner properties can be defined in several different ways depending -on the level of control you need. `pos` for instance can be set as a single vector, -in which case all particles will appear at that exact point throughout the lifetime -of the spawner. Alternately, it can be specified as a min-max pair, specifying a -cubic range the particles can appear randomly within. Finally, some properties can -be animated by suffixing their key with `_tween` (e.g. `pos_tween`) and supplying -a tween table. - -The following definitions are all equivalent, listed in order of precedence from -lowest (the legacy syntax) to highest (tween tables). If multiple forms of a -property definition are present, the highest-precedence form will be selected -and all lower-precedence fields will be ignored, allowing for graceful -degradation in older clients). - -```lua -{ - -- old syntax - maxpos = {x = 0, y = 0, z = 0}, - minpos = {x = 0, y = 0, z = 0}, - - -- absolute value - pos = 0, - -- all components of every particle's position vector will be set to this - -- value - - -- vec3 - pos = vector.new(0,0,0), - -- all particles will appear at this exact position throughout the lifetime - -- of the particlespawner - - -- vec3 range - pos = { - -- the particle will appear at a position that is picked at random from - -- within a cubic range - - min = vector.new(0,0,0), - -- `min` is the minimum value this property will be set to in particles - -- spawned by the generator - - max = vector.new(0,0,0), - -- `max` is the minimum value this property will be set to in particles - -- spawned by the generator - - bias = 0, - -- when `bias` is 0, all random values are exactly as likely as any - -- other. when it is positive, the higher it is, the more likely values - -- will appear towards the minimum end of the allowed spectrum. when - -- it is negative, the lower it is, the more likely values will appear - -- towards the maximum end of the allowed spectrum. the curve is - -- exponential and there is no particular maximum or minimum value - }, - - -- tween table - pos_tween = {...}, - -- a tween table should consist of a list of frames in the same form as the - -- untweened pos property above, which the engine will interpolate between, - -- and optionally a number of properties that control how the interpolation - -- takes place. currently **only two frames**, the first and the last, are - -- used, but extra frames are accepted for the sake of forward compatibility. - -- any of the above definition styles can be used here as well in any combination - -- supported by the property type - - pos_tween = { - style = "fwd", - -- linear animation from first to last frame (default) - style = "rev", - -- linear animation from last to first frame - style = "pulse", - -- linear animation from first to last then back to first again - style = "flicker", - -- like "pulse", but slightly randomized to add a bit of stutter - - reps = 1, - -- number of times the animation is played over the particle's lifespan - - start = 0.0, - -- point in the spawner's lifespan at which the animation begins. 0 is - -- the very beginning, 1 is the very end - - -- frames can be defined in a number of different ways, depending on the - -- underlying type of the property. for now, all but the first and last - -- frame are ignored - - -- frames - - -- floats - 0, 0, - - -- vec3s - vector.new(0,0,0), - vector.new(0,0,0), - - -- vec3 ranges - { min = vector.new(0,0,0), max = vector.new(0,0,0), bias = 0 }, - { min = vector.new(0,0,0), max = vector.new(0,0,0), bias = 0 }, - - -- mixed - 0, { min = vector.new(0,0,0), max = vector.new(0,0,0), bias = 0 }, - }, -} -``` - -All of the properties that can be defined in this way are listed in the next -section, along with the datatypes they accept. - -#### List of particlespawner properties - -All properties in this list of type "vec3 range", "float range" or "vec3" can -be animated with `*_tween` tables. For example, `jitter` can be tweened by -setting a `jitter_tween` table instead of (or in addition to) a `jitter` -table/value. This also applies to the `attract` table. - -In this section, a float range is a table defined as so: { min = A, max = B } -A and B are your supplemented values. For a vec3 range this means they are vectors. -Types used are defined in the previous section. - -* vec3 range `pos`: the position at which particles can appear - -* vec3 range `vel`: the initial velocity of the particle - -* vec3 range `acc`: the direction and speed with which the particle - accelerates - -* float range `size`: scales the visual size of the particle texture. - if `node` is set, this can be set to 0 to spawn randomly-sized particles - (just like actual node dig particles). - -* vec3 range `jitter`: offsets the velocity of each particle by a random - amount within the specified range each frame. used to create Brownian motion. - -* vec3 range `drag`: the amount by which absolute particle velocity along - each axis is decreased per second. a value of 1.0 means that the particle - will be slowed to a stop over the space of a second; a value of -1.0 means - that the particle speed will be doubled every second. to avoid interfering - with gravity provided by `acc`, a drag vector like `vector.new(1,0,1)` can - be used instead of a uniform value. - -* float range `bounce`: how bouncy the particles are when `collisiondetection` - is turned on. values less than or equal to `0` turn off particle bounce; - `1` makes the particles bounce without losing any velocity, and `2` makes - them double their velocity with every bounce. `bounce` is not bounded but - values much larger than `1.0` probably aren't very useful. - -* float range `exptime`: the number of seconds after which the particle - disappears. - -* table `attract`: sets the birth orientation of particles relative to various - shapes defined in world coordinate space. this is an alternative means of - setting the velocity which allows particles to emerge from or enter into - some entity or node on the map, rather than simply being assigned random - velocity values within a range. the velocity calculated by this method will - be **added** to that specified by `vel` if `vel` is also set, so in most - cases **`vel` should be set to 0**. `attract` has the fields: - - * string `kind`: selects the kind of shape towards which the particles will - be oriented. it must have one of the following values: - - * `"none"`: no attractor is set and the `attract` table is ignored - * `"point"`: the particles are attracted to a specific point in space. - use this also if you want a sphere-like effect, in combination with - the `radius` property. - * `"line"`: the particles are attracted to an (infinite) line passing - through the point `origin`, with direction specified by `direction`. use this for e.g. beacon - effects, energy beam effects, etc. - * `"plane"`: the particles are attracted to an (infinite) plane on whose - surface `origin` designates a point in world coordinate space. use this - for e.g. particles entering or emerging from a portal. - - * float range `strength`: the speed with which particles will move towards - the attractor shape. If negative, the particles will instead move away from that - point. - - * vec3 `origin`: the origin point of the attractor shape towards which particles will - initially be oriented. functions as an offset if `origin_attached` is also - set. - - * vec3 `direction`: sets the direction in which the attractor shape faces. for - lines, this sets the angle of the line; e.g. a vector of (0,1,0) will - create a vertical line that passes through `origin`. for planes, `direction` - is the surface normal of an infinite plane on whose surface `origin` is - a point. functions as an offset if `direction_attached` is also set. - - * ObjectRef `origin_attached`: allows the origin to be specified as an offset - from the position of an entity rather than a coordinate in world space. - - * ObjectRef `direction_attached`: allows the direction to be specified as an - offset from the position of an entity rather than a coordinate in world space. - - * bool `die_on_contact`: if true, the particles' lifetimes are adjusted so - that they will die as they cross the attractor threshold. this behavior - is the default but is undesirable for some kinds of animations; set it to - false to allow particles to live out their natural lives. - -* vec3 range `radius`: if set, particles will be arranged in a sphere around - `pos`. A constant can be used to create a spherical shell of particles, a - vector to create an ovoid shell, and a range to create a volume; e.g. - `{min = 0.5, max = 1, bias = 1}` will allow particles to appear between 0.5 - and 1 nodes away from `pos` but will cluster them towards the center of the - sphere. Usually if `radius` is used, `pos` should be a single point, but it - can still be a range if you really know what you're doing (e.g. to create a - "roundcube" emitter volume). - -### Textures - -In versions before v5.6.0, particle/particlespawner textures could only be -specified as a single texture string. After v5.6.0, textures can now be -specified as a table as well. This table contains options that allow simple -animations to be applied to the texture. - -```lua -texture = { - name = "mymod_particle_texture.png", - -- the texture specification string - - alpha = 1.0, - -- controls how visible the particle is; at 1.0 the particle is fully - -- visible, at 0, it is completely invisible. - - alpha_tween = {1, 0}, - -- can be used instead of `alpha` to animate the alpha value over the - -- particle's lifetime. these tween tables work identically to the tween - -- tables used in particlespawner properties, except that time references - -- are understood with respect to the particle's lifetime, not the - -- spawner's. {1,0} fades the particle out over its lifetime. - - scale = 1, - scale = {x = 1, y = 1}, - -- scales the texture onscreen - - scale_tween = { - {x = 1, y = 1}, - {x = 0, y = 1}, - }, - -- animates the scale over the particle's lifetime. works like the - -- alpha_tween table, but can accept two-dimensional vectors as well as - -- integer values. the example value would cause the particle to shrink - -- in one dimension over the course of its life until it disappears - - blend = "alpha", - -- (default) blends transparent pixels with those they are drawn atop - -- according to the alpha channel of the source texture. useful for - -- e.g. material objects like rocks, dirt, smoke, or node chunks - -- note: there will be rendering bugs when particles interact with - -- translucent nodes. particles are also not transparency-sorted - -- relative to each other. - blend = "clip", - -- pixels are either fully opaque or fully transparent, - -- depending on whether alpha is greater than or less than 50% - -- (just like `use_texture_alpha = "clip"` for nodes). - -- you should prefer this if you don't need semi-transparency, as it's faster. - blend = "add", - -- adds the value of pixels to those underneath them, modulo the sources - -- alpha channel. useful for e.g. bright light effects like sparks or fire - blend = "screen", - -- like "add" but less bright. useful for subtler light effects. note that - -- this is NOT formally equivalent to the "screen" effect used in image - -- editors and compositors, as it does not respect the alpha channel of - -- of the image being blended - blend = "sub", - -- the inverse of "add"; the value of the source pixel is subtracted from - -- the pixel underneath it. a white pixel will turn whatever is underneath - -- it black; a black pixel will be "transparent". useful for creating - -- darkening effects - - animation = {Tile Animation definition}, - -- overrides the particlespawner's global animation property for a single - -- specific texture -} -``` - -For particlespawners, it is also possible to set the `texpool` property instead -of a single texture definition. A `texpool` consists of a list of possible -particle textures. Every time a particle is spawned, the engine will pick a -texture at random from the `texpool` and assign it as that particle's texture. -You can also specify a `texture` in addition to a `texpool`; the `texture` -value will be ignored on newer clients but will be sent to older (pre-v5.6.0) -clients that do not implement texpools. - -```lua -texpool = { - "mymod_particle_texture.png"; - { name = "mymod_spark.png", alpha_tween = {1, 0} }, - { - name = "mymod_dust.png", - alpha = 0.3, - scale = 1.5, - animation = { - type = "vertical_frames", - aspect_w = 16, aspect_h = 16, - - length = 3, - -- the animation lasts for 3s and then repeats - length = -3, - -- repeat the animation three times over the particle's lifetime - -- (post-v5.6.0 clients only) - }, - }, -} -``` - -#### List of animatable texture properties - -While animated particlespawner values vary over the course of the particlespawner's -lifetime, animated texture properties vary over the lifespans of the individual -particles spawned with that texture. So a particle with the texture property - -```lua -alpha_tween = { - 0.0, 1.0, - style = "pulse", - reps = 4, -} -``` - -would be invisible at its spawning, pulse visible four times throughout its -lifespan, and then vanish again before expiring. - -* float `alpha` (0.0 - 1.0): controls the visibility of the texture -* vec2 `scale`: controls the size of the displayed billboard onscreen. Its units - are multiples of the parent particle's assigned size (see the `size` property above) - -`HTTPRequest` definition ------------------------- - -Used by `HTTPApiTable.fetch` and `HTTPApiTable.fetch_async`. - -```lua -{ - url = "https://example.org", - - timeout = 10, - -- Timeout for request to be completed in seconds. Default depends on engine settings. - - method = "GET", "HEAD", "POST", "PUT", "PATCH" or "DELETE" - -- The http method to use. Defaults to "GET". - - data = "Raw request data string" or {field1 = "data1", field2 = "data2"}, - -- Data for the POST, PUT, PATCH or DELETE request. - -- Accepts both a string and a table. If a table is specified, encodes - -- table as x-www-form-urlencoded key-value pairs. - - user_agent = "ExampleUserAgent", - -- Optional, if specified replaces the default Luanti user agent with - -- given string. - - extra_headers = { "Accept-Language: en-us", "Accept-Charset: utf-8" }, - -- Optional, if specified adds additional headers to the HTTP request. - -- You must make sure that the header strings follow HTTP specification - -- ("Key: Value"). - - multipart = boolean - -- Optional, if true performs a multipart HTTP request. - -- Default is false. - -- Not allowed for GET or HEAD method and `data` must be a table. - - post_data = "Raw POST request data string" OR {field1 = "data1", field2 = "data2"}, - -- Deprecated, use `data` instead. Forces `method = "POST"`. -} -``` - -`HTTPRequestResult` definition ------------------------------- - -Passed to `HTTPApiTable.fetch` callback. Returned by -`HTTPApiTable.fetch_async_get`. - -```lua -{ - completed = true, - -- If true, the request has finished (either succeeded, failed or timed - -- out) - - succeeded = true, - -- If true, the request was successful - - timeout = false, - -- If true, the request timed out - - code = 200, - -- HTTP status code - - data = "", - -- Response body -} -``` - -Authentication handler definition ---------------------------------- - -Used by `core.register_authentication_handler`. - -```lua -{ - get_auth = function(name), - -- Get authentication data for existing player `name` (`nil` if player - -- doesn't exist). - -- Returns following structure: - -- `{password=, privileges=, last_login=}` - - create_auth = function(name, password), - -- Create new auth data for player `name`. - -- Note that `password` is not plain-text but an arbitrary - -- representation decided by the engine. - - delete_auth = function(name), - -- Delete auth data of player `name`. - -- Returns boolean indicating success (false if player is nonexistent). - - set_password = function(name, password), - -- Set password of player `name` to `password`. - -- Auth data should be created if not present. - - set_privileges = function(name, privileges), - -- Set privileges of player `name`. - -- `privileges` is in table form: keys are privilege names, values are `true`; - -- auth data should be created if not present. - - reload = function(), - -- Reload authentication data from the storage location. - -- Returns boolean indicating success. - - record_login = function(name), - -- Called when player joins, used for keeping track of last_login - - iterate = function(), - -- Returns an iterator (use with `for` loops) for all player names - -- currently in the auth database -} -``` - -Bit Library ------------ - -Functions: bit.tobit, bit.tohex, bit.bnot, bit.band, bit.bor, bit.bxor, bit.lshift, bit.rshift, bit.arshift, bit.rol, bit.ror, bit.bswap - -See http://bitop.luajit.org/ for advanced information. - -Tracy Profiler --------------- - -Luanti can be built with support for the Tracy profiler, which can also be -useful for profiling mods and is exposed to Lua as the global `tracy`. - -See doc/developing/misc.md for details. - -Note: This is a development feature and not covered by compatibility promises. - -Error Handling --------------- - -When an error occurs that is not caught, Luanti calls the function -`core.error_handler` with the error object as its first argument. The second -argument is the stack level where the error occurred. The return value is the -error string that should be shown. By default this is a backtrace from -`debug.traceback`. If the error object is not a string, it is first converted -with `tostring` before being displayed. This means that you can use tables as -error objects so long as you give them `__tostring` metamethods. - -You can override `core.error_handler`. You should call the previous handler -with the correct stack level in your implementation.