Startup
--------
Mods are loaded during server startup from the mod load paths by running
-the init.lua scripts.
+the init.lua scripts in a shared environment.
Mod load path
-------------
~/.minetest/mods/gameid/ <-- User-installed mods
~/.minetest/worlds/worldname/worldmods
+Mod load path for 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 eg. adventure worlds.
+
+This happens if the following directory exists:
+ $world/game/
+
+Mods should be then be placed in:
+ $world/game/mods/
+
+Modpack support
+----------------
+Mods can be put in a subdirectory, if the parent directory, which otherwise
+should be a mod, contains a file named modpack.txt. This file shall be
+empty, except for lines starting with #, which are comments.
+
Mod directory structure
------------------------
mods
-- Play connected to an object, looped
{
object = <an ObjectRef>,
- gain = 1.0, -- default
- max_hear_distance = 32, -- default
+ gain = 1.0, -- default
+ max_hear_distance = 32, -- default
loop = true, -- only sounds connected to objects can be looped
}
+SimpleSoundSpec:
+eg. ""
+eg. "default_place_node"
+eg. {}
+eg. {name="default_place_node"}
+eg. {name="default_place_node", gain=1.0}
+
+Registered definitions of stuff
+--------------------------------
+Anything added using certain minetest.register_* functions get added to
+the global minetest.registered_* tables.
+
+minetest.register_entity(name, prototype table)
+ -> minetest.registered_entities[name]
+
+minetest.register_node(name, node definition)
+ -> minetest.registered_items[name]
+ -> minetest.registered_nodes[name]
+
+minetest.register_tool(name, item definition)
+ -> minetest.registered_items[name]
+
+minetest.register_craftitem(name, item definition)
+ -> minetest.registered_items[name]
+
+Note that in some cases you will stumble upon things that are not contained
+in these tables (eg. when a mod has been removed). Always check for
+existence before trying to access the fields.
+
+Example: If you want to check the drawtype of a node, you could do:
+
+local function get_nodedef_field(nodename, fieldname)
+ if not minetest.registered_nodes[nodename] then
+ return nil
+ end
+ return minetest.registered_nodes[nodename][fieldname]
+end
+local drawtype = get_nodedef_field(nodename, "drawtype")
+
+Example: minetest.get_item_group(name, group) has been implemented as:
+
+function minetest.get_item_group(name, group)
+ if not minetest.registered_items[name] or not
+ minetest.registered_items[name].groups[group] then
+ return 0
+ end
+ return minetest.registered_items[name].groups[group]
+end
+
Nodes
------
Nodes are the bulk data of the world: cubes and other things that take the
The definition of a node is stored and can be accessed by name in
minetest.registered_nodes[node.name]
+See "Registered definitions of stuff".
-Please note that for unknown nodes (eg. a node of an uninstalled mod) the
-minetest.registered_nodes field for the node is nil.
-
-Nodes are passed by value in Lua. They are represented by a table:
+Nodes are passed by value between Lua and the engine.
+They are represented by a table:
{name="name", param1=num, param2=num}
param1 and param2 are 8 bit and 4 bit integers, respectively. The engine
^ The rotation of the node is stored in param2. Furnaces and chests are
rotated this way. Can be made by using minetest.dir_to_facedir().
+Nodes can also contain extra data. See "Node Metadata".
+
Representations of simple things
--------------------------------
Position/vector:
Currently the API does not provide any helper functions for addition,
subtraction and whatever; you can define those that you need yourself.
-stackstring/itemstring: A stack of items in serialized format.
+Items
+------
+Node (register_node):
+ A node from the world
+Tool (register_tool):
+ A tool/weapon that can dig and damage things according to tool_capabilities
+Craftitem (register_craftitem):
+ A miscellaneous item
+
+Items and item stacks can exist in three formats:
+
+Serialized; This is called stackstring or itemstring:
eg. 'default:dirt 5'
eg. 'default:pick_wood 21323'
eg. 'default:apple'
-item: A stack of items in Lua table format.
+Table format:
eg. {name="default:dirt", count=5, wear=0, metadata=""}
^ 5 dirt nodes
eg. {name="default:pick_wood", count=1, wear=21323, metadata=""}
eg. {name="default:apple", count=1, wear=0, metadata=""}
^ an apple.
-Any time an item must be passed to a function, it can be an
-ItemStack (see below), an itemstring or a table in the above format.
+ItemStack:
+C++ native format with many helper methods. Useful for converting between
+formats. See the Class reference section for details.
-SimpleSoundSpec:
-eg. ""
-eg. "default_place_node"
-eg. {}
-eg. {name="default_place_node"}
-eg. {name="default_place_node", gain=1.0}
-
-Items
-------
-Node (register_node):
- A node from the world
-Tool (register_tool):
- A tool/weapon that can dig and damage things according to tool_capabilities
-Craftitem (register_craftitem):
- A miscellaneous item
+When an item must be passed to a function, it can usually be in any of
+these formats.
Groups
-------
- 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
+ minetest.get_item_group(itemname, groupname)
+
Groups of items
----------------
Groups of items can define what kind of an item it is (eg. wool).
Groups in crafting recipes
---------------------------
-- Not implemented yet. (TODO)
-- Will probably look like this:
+An example:
{
output = 'food:meat_soup_raw',
recipe = {
{'group:water'},
{'group:bowl'},
},
- preserve = {'group:bowl'},
+ preserve = {'group:bowl'}, -- Not implemented yet (TODO)
}
Special groups
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
- speed of a tool if the tool can dig at a larger speed than this
+ speed of a tool if the tool can dig at a faster speed than this
suggests for the hand.
Examples of custom groups
Determines how many uses the tool has when it is used for digging a node,
of this group, of the maximum level. For lower leveled nodes, the use count
is multiplied by 3^leveldiff.
-- uses=10, leveldiff=0 -> actual_uses=10
-- uses=10, leveldiff=1 -> actual_uses=30
-- uses=10, leveldiff=2 -> actual_uses=90
+- uses=10, leveldiff=0 -> actual uses: 10
+- uses=10, leveldiff=1 -> actual uses: 30
+- uses=10, leveldiff=2 -> actual uses: 90
**Maximum level**
Tells what is the maximum level of a node of this group that the tool will
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 the tool to be able to dig nodes that have a rating of 2 or 3
+ result in the tool 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.
* For entities, damage equals the amount of nodes dug in the time spent
Damage calculation:
- Take the time spent after the last hit
- Limit time to full_punch_interval
-- Take the damage groups, assume a node has them
+- Take the damage groups and imagine a bunch of nodes that have them
- Damage in HP is the amount of nodes destroyed in this time.
Client predicts damage based on damage groups. Because of this, it is able to
TODO).
- Currently a smoke puff will appear when an entity dies.
-The group **immortal** will completely disable normal damage.
+The group **immortal** completely disables normal damage.
Entities can define a special armor group, which is **punch_operable**. This
-group will disable the regular damage mechanism for players punching it by hand
-or a non-tool item.
+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 ''entity:on_punch(puncher,
time_from_last_punch, tool_capabilities, direction)''. 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.
+ 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.
-To punch an entity/object in Lua, call ''object:punch(puncher, time_from_last_punch, tool_capabilities, direction)''.
+To punch an entity/object in Lua, call ''object:punch(puncher,
+time_from_last_punch, tool_capabilities, direction)''.
* Return value is tool wear.
* Parameters are equal to the above callback.
* If ''direction'' is nil and ''puncher'' is not nil, ''direction'' will be
automatically filled in based on the location of ''puncher''.
+Node Metadata
+-------------
+The instance of a node in the world normally only contains the three values
+mentioned in "Nodes". However, it is possible to insert extra data into a
+node. It is called "node metadata"; See "NodeMetaRef".
+
+Metadata contains two things:
+- A key-value store
+- An inventory
+
+Some of the values in the key-value store are handled specially:
+- formspec: Defines a right-click inventory menu. See "Formspec".
+- infotext: Text shown on the screen when the node is pointed at
+
+Example stuff:
+
+local meta = minetest.env:get_meta(pos)
+meta:set_string("formspec",
+ "invsize[8,9;]"..
+ "list[context;main;0,0;8,4;]"..
+ "list[current_player;main;0,5;8,4;]")
+meta:set_string("infotext", "Chest");
+local inv = meta:get_inventory()
+inv:set_size("main", 8*4)
+print(dump(meta:to_table()))
+meta:from_table({
+ inventory = {
+ 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] = ""}
+ },
+ fields = {
+ formspec = "invsize[8,9;]list[context;main;0,0;8,4;]list[current_player;main;0,5;8,4;]",
+ infotext = "Chest"
+ }
+})
+
+Formspec
+--------
+Formspec defines a menu. Currently not much else than inventories are
+supported. It is a string, with a somewhat strange format.
+
+Spaces and newlines can be inserted between the blocks, as is used in the
+examples.
+
+Examples:
+- Chest:
+ invsize[8,9;]
+ list[context;main;0,0;8,4;]
+ list[current_player;main;0,5;8,4;]
+- Furnace:
+ invsize[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
+ invsize[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;]
+
+Elements:
+
+invsize[<W>,<H>;]
+^ Define the size of the menu in inventory slots
+
+list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;]
+^ Show an inventory list
+
+image[<X>,<Y>;<W>,<H>;<texture name>]
+^ Show an image
+^ Position and size units are inventory slots
+
+field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]
+^ Textual field; will be sent to server when a button is clicked
+^ Position and size units are inventory slots
+^ Not implemented
+
+button[<X>,<Y>;<W>,<H>;<name>;<label>]
+^ Clickable button. When clicked, fields will be sent.
+^ Button will be visible as a field, with the value "active".
+^ Position and size units are inventory slots
+^ Not implemented
+
+Inventory location:
+- "context": Selected node metadata (deprecated: "current_name")
+- "current_player": Player to whom the menu is shown
+- "player:<name>": Any player
+- "nodemeta:<X>,<Y>,<Z>": Any node metadata
+
Helper functions
-----------------
dump2(obj, name="_", dumped={})
^ eg. string.trim("\n \t\tfoo bar\t ") == "foo bar"
minetest.pos_to_string({x=X,y=Y,z=Z}) -> "(X,Y,Z)"
^ Convert position to a printable string
+minetest.string_to_pos(string) -> position
minetest namespace reference
-----------------------------
minetest.is_singleplayer()
minetest.debug(line)
-^ Goes to dstream
+^ Always printed to stderr and logfile (print() is redirected here)
minetest.log(line)
minetest.log(loglevel, line)
^ loglevel one of "error", "action", "info", "verbose"
minetest.register_craftitem(name, item definition)
minetest.register_alias(name, convert_to)
minetest.register_craft(recipe)
+
+Global callback registration functions: (Call these only at load time)
minetest.register_globalstep(func(dtime))
+^ Called every server step, usually interval of 0.05s
minetest.register_on_placenode(func(pos, newnode, placer))
+^ Called when a node has been placed
+^ Deprecated: Use on_construct or after_place_node in node definition instead
minetest.register_on_dignode(func(pos, oldnode, digger))
+^ Called when a node has been dug. digger can be nil.
+^ Deprecated: Use on_destruct or after_dig_node in node definition instead
minetest.register_on_punchnode(func(pos, node, puncher))
+^ Called when a node is punched
minetest.register_on_generated(func(minp, maxp, blockseed))
+^ Called after generating a piece of world. Modifying nodes inside the area
+ is a bit faster than usually.
minetest.register_on_newplayer(func(ObjectRef))
+^ Called after a new player has been created
minetest.register_on_dieplayer(func(ObjectRef))
+^ Called when a player dies
minetest.register_on_respawnplayer(func(ObjectRef))
+^ Called when player is to be respawned
+^ Called _before_ repositioning of player occurs
^ return true in func to disable regular player placement
-^ currently called _before_ repositioning of player occurs
minetest.register_on_chat_message(func(name, message))
+
+Other registration functions:
minetest.register_chatcommand(cmd, chatcommand definition)
minetest.register_privilege(name, definition)
^ definition: "description text"
minetest.setting_set(name, value)
minetest.setting_get(name) -> string or nil
minetest.setting_getbool(name) -> boolean value or nil
+minetest.setting_get_pos(name) -> position or nil
minetest.add_to_creative_inventory(itemstring)
Authentication:
minetest.get_node_drops(nodename, toolname)
^ Returns list of item names.
^ Note: This will be removed or modified in a future version.
+minetest.get_craft_result(input) -> output, decremented_input
+^ input.method = 'normal' or 'cooking' or 'fuel'
+^ input.width = for example 3
+^ input.items = for example { stack 1, stack 2, stack 3, stack 4,
+ stack 5, stack 6, stack 7, stack 8, stack 9 }
+^ output.item = ItemStack, if unsuccessful: empty ItemStack
+^ output.time = number, if unsuccessful: 0
+^ decremented_input = like input
Defaults for the on_* item definition functions:
(These return the leftover itemstack)
minetest.get_connected_players() -> list of ObjectRefs
minetest.hash_node_position({x=,y=,z=}) -> 48-bit integer
^ Gives a unique hash number for a node position (16+16+16=48bit)
+minetest.get_item_group(name, group) -> rating
+^ Get rating of a group of an item. (0 = not in group)
+minetest.get_node_group(name, group) -> rating
+^ Deprecated: An alias for the former.
+minetest.serialize(table) -> string
+^ Convert a table containing tables, strings, numbers, booleans and nils
+ into string form readable by minetest.deserialize
+^ Example: serialize({foo='bar'}) -> 'return { ["foo"] = "bar" }'
+minetest.deserialize(string) -> table
+^ Convert a string returned by minetest.deserialize into a table
+^ String is loaded in an empty sandbox environment.
+^ Will load functions, but they cannot access the global environment.
+^ Example: deserialize('return { ["foo"] = "bar" }') -> {foo='bar'}
+^ Example: deserialize('print("foo")') -> nil (function call fails)
+ ^ error:[string "print("foo")"]:1: attempt to call global 'print' (a nil value)
Global objects:
-minetest.env - environment reference
+minetest.env - EnvRef of the server environment and world.
+^ Using this you can access nodes and entities
Global tables:
minetest.registered_items
methods:
- set_node(pos, node)
- add_node(pos, node): alias set_node(pos, node)
-- remove_node(pos): equivalent to set_node(pos, "air")
+ ^ Set node at position (node = {name="foo", param1=0, param2=0})
+- remove_node(pos)
+ ^ Equivalent to set_node(pos, "air")
- get_node(pos)
^ Returns {name="ignore", ...} for unloaded area
- get_node_or_nil(pos)
^ Returns nil for unloaded area
- get_node_light(pos, timeofday) -> 0...15 or nil
^ timeofday: nil = current time, 0 = night, 0.5 = day
+
+- place_node(pos, node)
+ ^ Place node with the same effects that a player would cause
+- dig_node(pos)
+ ^ Dig node with the same effects that a player would cause
+- punch_node(pos)
+ ^ Punch node with the same effects that a player would cause
+
- add_entity(pos, name): Spawn Lua-defined entity at position
^ Returns ObjectRef, or nil if failed
-- add_item(pos, itemstring): Spawn item
+- add_item(pos, item): Spawn item
^ Returns ObjectRef, or nil if failed
- get_meta(pos) -- Get a NodeMetaRef at that position
- get_player_by_name(name) -- Get an ObjectRef to a player
- add_rat(pos): Add C++ rat object (no-op)
- add_firefly(pos): Add C++ firefly object (no-op)
-NodeMetaRef (this stuff is subject to change in a future version)
+NodeMetaRef: Node metadata - reference extra data and functionality stored
+ in a node
+- Can be gotten via minetest.env:get_nodemeta(pos)
methods:
-- get_type()
-- allows_text_input()
-- set_text(text) -- eg. set the text of a sign
-- get_text()
-- get_owner()
-- set_owner(string)
-Generic node metadata specific:
-- set_infotext(infotext)
-- get_inventory() -> InvRef
-- set_inventory_draw_spec(string)
-- set_allow_text_input(bool)
-- set_allow_removal(bool)
-- set_enforce_owner(bool)
-- is_inventory_modified()
-- reset_inventory_modified()
-- is_text_modified()
-- reset_text_modified()
- set_string(name, value)
- get_string(name)
+- set_int(name, value)
+- get_int(name)
+- set_float(name, value)
+- get_float(name)
+- get_inventory() -> InvRef
+- to_table() -> nil or {fields = {...}, inventory = {list1 = {}, ...}}
+- from_table(nil or {})
+ ^ See "Node Metadata"
ObjectRef: Moving things in the game are generally these
(basically reference to a C++ ServerActiveObject)
- get_entity_name() (DEPRECATED: Will be removed in a future version)
- get_luaentity()
Player-only: (no-op for other objects)
-- get_player_name(): will return nil if is not a player
+- is_player(): true for players, false for others
+- get_player_name(): returns "" if is not a player
- get_look_dir(): get camera direction as a unit vector
- get_look_pitch(): pitch in radians
- get_look_yaw(): yaw in radians (wraps around pretty randomly as of now)
InvRef: 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
- get_stack(listname, i): get a copy of stack index i in list
choppy={times={[3]=0.90}, maxwear=0.05, maxlevel=0}
}
}
- on_drop = func(itemstack, dropper, pos),
+
on_place = func(itemstack, placer, pointed_thing),
+ ^ default: minetest.item_place
+ on_drop = func(itemstack, dropper, pos),
+ ^ default: minetest.item_drop
on_use = func(itemstack, user, pointed_thing),
+ ^ default: nil
^ Function must return either nil if no item shall be removed from
inventory, or an itemstack to replace the original itemstack.
eg. itemstack:take_item(); return itemstack
buildable_to = false,
drop = "",
-- alternatively drop = { max_items = ..., items = { ... } }
- metadata_name = "",
liquidtype = "none",
liquid_alternative_flowing = "",
liquid_alternative_source = "",
dig = <SimpleSoundSpec>, -- "__group" = group-based sound (default)
dug = <SimpleSoundSpec>,
},
+
+ on_construct = func(pos),
+ ^ Node constructor; always called after adding node
+ ^ Can set up metadata and stuff like that
+ ^ default: nil
+ on_destruct = func(pos),
+ ^ Node destructor; always called before removing node
+ ^ default: nil
+ after_destruct = func(pos, oldnode),
+ ^ Node destructor; always called after removing node
+ ^ default: nil
+
+ after_place_node = func(pos, placer),
+ ^ Called after constructing node when node was placed using
+ minetest.item_place_node / minetest.env:place_node
+ ^ default: nil
+ after_dig_node = func(pos, oldnode, oldmetadata, digger),
+ ^ oldmetadata is in table format
+ ^ Called after destructing node when node was dug using
+ minetest.node_dig / minetest.env:dig_node
+ ^ default: nil
+ can_dig = function(pos,player)
+ ^ returns true if node can be dug, or false if not
+ ^ default: nil
+
+ on_punch = func(pos, node, puncher),
+ ^ default: minetest.node_punch
+ ^ By default: does nothing
+ on_dig = func(pos, node, digger),
+ ^ default: minetest.node_dig
+ ^ By default: checks privileges, wears out tool and removes node
+
+ on_receive_fields = func(pos, formname, fields, sender),
+ ^ fields = {name1 = value1, name2 = value2, ...}
+ ^ Called when an UI form (eg. sign text input) returns data
+ ^ default: nil
+
+ on_metadata_inventory_move = func(pos, from_list, from_index,
+ to_list, to_index, count, player),
+ ^ Called when a player wants to move items inside the metadata
+ ^ Should move items, or some items, if permitted. If not, should do
+ nothing.
+ ^ The engine ensures the action is valid, i.e. the stack fits at the
+ given position
+ ^ default: minetest.node_metadata_inventory_move_allow_all
+
+ on_metadata_inventory_offer = func(pos, listname, index, stack, player),
+ ^ Called when a player wants to put something into the metadata
+ inventory
+ ^ Should check if the action is permitted (the engine ensures the
+ action is valid, i.e. the stack fits at the given position)
+ ^ If permitted, modify the metadata inventory and return the
+ "leftover" stack (normally nil).
+ ^ If not permitted, return itemstack.
+ ^ default: minetest.node_metadata_inventory_offer_allow_all
+
+ on_metadata_inventory_take = func(pos, listname, index, count, player),
+ ^ Called when a player wants to take something out of the metadata
+ inventory
+ ^ Should check if the action is permitted (the engine ensures the
+ action is valid, i.e. there's a stack of at least “count” items at
+ that position)
+ ^ If permitted, modify the metadata inventory and return the
+ stack of items
+ ^ If not permitted, return nil.
+ ^ default: minetest.node_metadata_inventory_take_allow_all
}
-Recipe: (register_craft)
+Recipe for register_craft: (shaped)
{
output = 'default:pick_stone',
recipe = {
{'default:cobble', 'default:cobble', 'default:cobble'},
{'', 'default:stick', ''},
- {'', 'default:stick', ''},
+ {'', 'default:stick', ''}, -- Also groups; eg. 'group:crumbly'
},
replacements = <optional list of item pairs,
replace one input item with another item on crafting>
}
-Recipe (shapeless):
+Recipe for register_craft (shapeless)
{
type = "shapeless",
output = 'mushrooms:mushroom_stew',
replace one input item with another item on crafting>
}
-Recipe (tool repair):
+Recipe for register_craft (tool repair)
{
type = "toolrepair",
additional_wear = -0.02,
}
-Recipe (cooking):
+Recipe for register_craft (cooking)
{
type = "cooking",
output = "default:glass",
cooktime = 3,
}
-Recipe (furnace fuel):
+Recipe for register_craft (furnace fuel)
{
type = "fuel",
recipe = "default:leaves",