^ 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:
* 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[current_name;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[current_name;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[current_name;main;0,0;8,4;]
+ list[current_player;main;0,5;8,4;]
+- Furnace:
+ invsize[8,9;]
+ list[current_name;fuel;2,3;1,1;]
+ list[current_name;src;2,1;1,1;]
+ list[current_name;dst;5,1;2,2;]
+ list[current_player;main;0,5;8,4;]
+
+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
+^ Not implemented
+
+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:
+- "current_name": Selected node metadata
+- "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={})
- 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:
- set_string(name, value)
- get_string(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)
if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1));
}
+ lua_remove(L, -2); // Remove table
+ lua_remove(L, -2); // Remove insert
}
/*
InvRef::createNodeMeta(L, ref->m_p);
return 1;
}
-
- // get_inventory_draw_spec(self)
- static int l_get_inventory_draw_spec(lua_State *L)
+
+ // to_table(self)
+ static int l_to_table(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
- NodeMetadata *meta = getmeta(ref, false);
+ NodeMetadata *meta = getmeta(ref, true);
if(meta == NULL){
- lua_pushlstring(L, "", 0);
+ lua_pushnil(L);
return 1;
}
- std::string str = meta->getString("formspec");
- lua_pushlstring(L, str.c_str(), str.size());
- return 1;
- }
-
- // set_inventory_draw_spec(self, text)
- static int l_set_inventory_draw_spec(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- size_t len = 0;
- const char *s = lua_tolstring(L, 2, &len);
- std::string str(s, len);
-
- NodeMetadata *meta = getmeta(ref, !str.empty());
- if(meta == NULL || str == meta->getString("formspec"))
- return 0;
- meta->setString("formspec",str);
- reportMetadataChange(ref);
- return 0;
- }
-
- // get_form_spec(self)
- static int l_get_form_spec(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
-
- NodeMetadata *meta = getmeta(ref, false);
- if(meta == NULL){
- lua_pushlstring(L, "", 0);
- return 1;
+ lua_newtable(L);
+ // fields
+ lua_newtable(L);
+ {
+ std::map<std::string, std::string> fields = meta->getStrings();
+ for(std::map<std::string, std::string>::const_iterator
+ i = fields.begin(); i != fields.end(); i++){
+ const std::string &name = i->first;
+ const std::string &value = i->second;
+ lua_pushlstring(L, name.c_str(), name.size());
+ lua_pushlstring(L, value.c_str(), value.size());
+ lua_settable(L, -3);
+ }
}
- std::string str = meta->getString("formspec");
- lua_pushlstring(L, str.c_str(), str.size());
+ lua_setfield(L, -2, "fields");
+ // inventory
+ lua_newtable(L);
+ Inventory *inv = meta->getInventory();
+ if(inv){
+ std::vector<const InventoryList*> lists = inv->getLists();
+ for(std::vector<const InventoryList*>::const_iterator
+ i = lists.begin(); i != lists.end(); i++){
+ inventory_get_list_to_lua(inv, (*i)->getName().c_str(), L);
+ lua_setfield(L, -2, (*i)->getName().c_str());
+ }
+ }
+ lua_setfield(L, -2, "inventory");
return 1;
}
- // set_form_spec(self, text)
- static int l_set_form_spec(lua_State *L)
+ // from_table(self, table)
+ static int l_from_table(lua_State *L)
{
NodeMetaRef *ref = checkobject(L, 1);
- size_t len = 0;
- const char *s = lua_tolstring(L, 2, &len);
- std::string str(s, len);
-
- NodeMetadata *meta = getmeta(ref, !str.empty());
- if(meta == NULL || str == meta->getString("formspec"))
- return 0;
- meta->setString("formspec",str);
- reportMetadataChange(ref);
- return 0;
- }
-
- // get_infotext(self)
- static int l_get_infotext(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
-
- NodeMetadata *meta = getmeta(ref, false);
- if(meta == NULL){
- lua_pushlstring(L, "", 0);
+ int base = 2;
+
+ if(lua_isnil(L, base)){
+ // No metadata
+ ref->m_env->getMap().removeNodeMetadata(ref->m_p);
+ lua_pushboolean(L, true);
return 1;
}
- std::string str = meta->getString("infotext");
- lua_pushlstring(L, str.c_str(), str.size());
- return 1;
- }
- // set_infotext(self, text)
- static int l_set_infotext(lua_State *L)
- {
- NodeMetaRef *ref = checkobject(L, 1);
- size_t len = 0;
- const char *s = lua_tolstring(L, 2, &len);
- std::string str(s, len);
-
- NodeMetadata *meta = getmeta(ref, !str.empty());
- if(meta == NULL || str == meta->getString("infotext"))
- return 0;
- meta->setString("infotext",str);
+ // Has metadata; clear old one first
+ ref->m_env->getMap().removeNodeMetadata(ref->m_p);
+ // Create new metadata
+ NodeMetadata *meta = getmeta(ref, true);
+ // Set fields
+ lua_getfield(L, base, "fields");
+ int fieldstable = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, fieldstable) != 0){
+ // key at index -2 and value at index -1
+ std::string name = lua_tostring(L, -2);
+ size_t cl;
+ const char *cs = lua_tolstring(L, -1, &cl);
+ std::string value(cs, cl);
+ meta->setString(name, value);
+ lua_pop(L, 1); // removes value, keeps key for next iteration
+ }
+ // Set inventory
+ Inventory *inv = meta->getInventory();
+ lua_getfield(L, base, "inventory");
+ int inventorytable = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, inventorytable) != 0){
+ // key at index -2 and value at index -1
+ std::string name = lua_tostring(L, -2);
+ inventory_set_list_from_lua(inv, name.c_str(), L, -1);
+ lua_pop(L, 1); // removes value, keeps key for next iteration
+ }
reportMetadataChange(ref);
- return 0;
+ lua_pushboolean(L, true);
+ return 1;
}
public:
method(NodeMetaRef, get_float),
method(NodeMetaRef, set_float),
method(NodeMetaRef, get_inventory),
- method(NodeMetaRef, get_inventory_draw_spec),
- method(NodeMetaRef, set_inventory_draw_spec),
- method(NodeMetaRef, get_form_spec),
- method(NodeMetaRef, set_form_spec),
- method(NodeMetaRef, get_infotext),
- method(NodeMetaRef, set_infotext),
+ method(NodeMetaRef, to_table),
+ method(NodeMetaRef, from_table),
{0,0}
};