NodeMetaRef:{to,from}_table and lua_api.txt additions

This commit is contained in:
Perttu Ahola 2012-06-02 11:01:28 +03:00
parent 5f3c70061d
commit 3899f83da8
6 changed files with 191 additions and 86 deletions

@ -278,6 +278,8 @@ param2 is reserved for the engine when any of these are used:
^ The rotation of the node is stored in param2. Furnaces and chests are ^ 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(). 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 Representations of simple things
-------------------------------- --------------------------------
Position/vector: Position/vector:
@ -548,6 +550,91 @@ time_from_last_punch, tool_capabilities, direction)''.
* If ''direction'' is nil and ''puncher'' is not nil, ''direction'' will be * If ''direction'' is nil and ''puncher'' is not nil, ''direction'' will be
automatically filled in based on the location of ''puncher''. 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 Helper functions
----------------- -----------------
dump2(obj, name="_", dumped={}) dump2(obj, name="_", dumped={})
@ -766,7 +853,9 @@ Deprecated:
- add_rat(pos): Add C++ rat object (no-op) - add_rat(pos): Add C++ rat object (no-op)
- add_firefly(pos): Add C++ firefly 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: methods:
- set_string(name, value) - set_string(name, value)
- get_string(name) - get_string(name)
@ -775,6 +864,9 @@ methods:
- set_float(name, value) - set_float(name, value)
- get_float(name) - get_float(name)
- get_inventory() -> InvRef - 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 ObjectRef: Moving things in the game are generally these
(basically reference to a C++ ServerActiveObject) (basically reference to a C++ ServerActiveObject)

@ -915,6 +915,17 @@ InventoryList * Inventory::getList(const std::string &name)
return m_lists[i]; return m_lists[i];
} }
std::vector<const InventoryList*> Inventory::getLists()
{
std::vector<const InventoryList*> lists;
for(u32 i=0; i<m_lists.size(); i++)
{
InventoryList *list = m_lists[i];
lists.push_back(list);
}
return lists;
}
bool Inventory::deleteList(const std::string &name) bool Inventory::deleteList(const std::string &name)
{ {
s32 i = getListIndex(name); s32 i = getListIndex(name);

@ -262,6 +262,7 @@ public:
InventoryList * addList(const std::string &name, u32 size); InventoryList * addList(const std::string &name, u32 size);
InventoryList * getList(const std::string &name); InventoryList * getList(const std::string &name);
const InventoryList * getList(const std::string &name) const; const InventoryList * getList(const std::string &name) const;
std::vector<const InventoryList*> getLists();
bool deleteList(const std::string &name); bool deleteList(const std::string &name);
// A shorthand for adding items. Returns leftover item (possibly empty). // A shorthand for adding items. Returns leftover item (possibly empty).
ItemStack addItem(const std::string &listname, const ItemStack &newitem) ItemStack addItem(const std::string &listname, const ItemStack &newitem)

@ -1009,6 +1009,12 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr); n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
} }
/*
Remove node metadata
*/
removeNodeMetadata(p);
/* /*
Set the node on the map Set the node on the map
*/ */
@ -3451,15 +3457,15 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
} }
catch(InvalidFilenameException &e) catch(InvalidFilenameException &e)
{ {
return false; return NULL;
} }
catch(FileNotGoodException &e) catch(FileNotGoodException &e)
{ {
return false; return NULL;
} }
catch(std::exception &e) catch(std::exception &e)
{ {
return false; return NULL;
} }
} }

@ -64,6 +64,10 @@ public:
else else
m_stringvars[name] = var; m_stringvars[name] = var;
} }
std::map<std::string, std::string> getStrings() const
{
return m_stringvars;
}
// The inventory // The inventory
Inventory* getInventory() Inventory* getInventory()

@ -1233,6 +1233,8 @@ static void inventory_get_list_to_lua(Inventory *inv, const char *name,
if(lua_pcall(L, 2, 0, 0)) if(lua_pcall(L, 2, 0, 0))
script_error(L, "error: %s", lua_tostring(L, -1)); script_error(L, "error: %s", lua_tostring(L, -1));
} }
lua_remove(L, -2); // Remove table
lua_remove(L, -2); // Remove insert
} }
/* /*
@ -2088,97 +2090,90 @@ private:
return 1; return 1;
} }
// get_inventory_draw_spec(self) // to_table(self)
static int l_get_inventory_draw_spec(lua_State *L) static int l_to_table(lua_State *L)
{ {
NodeMetaRef *ref = checkobject(L, 1); NodeMetaRef *ref = checkobject(L, 1);
NodeMetadata *meta = getmeta(ref, false); NodeMetadata *meta = getmeta(ref, true);
if(meta == NULL){ if(meta == NULL){
lua_pushlstring(L, "", 0); lua_pushnil(L);
return 1; return 1;
} }
std::string str = meta->getString("formspec"); lua_newtable(L);
lua_pushlstring(L, str.c_str(), str.size()); // 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);
}
}
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; return 1;
} }
// set_inventory_draw_spec(self, text) // from_table(self, table)
static int l_set_inventory_draw_spec(lua_State *L) static int l_from_table(lua_State *L)
{ {
NodeMetaRef *ref = checkobject(L, 1); NodeMetaRef *ref = checkobject(L, 1);
size_t len = 0; int base = 2;
const char *s = lua_tolstring(L, 2, &len);
std::string str(s, len);
NodeMetadata *meta = getmeta(ref, !str.empty()); if(lua_isnil(L, base)){
if(meta == NULL || str == meta->getString("formspec")) // No metadata
return 0; ref->m_env->getMap().removeNodeMetadata(ref->m_p);
meta->setString("formspec",str); lua_pushboolean(L, true);
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; return 1;
} }
std::string str = meta->getString("formspec");
lua_pushlstring(L, str.c_str(), str.size());
return 1;
}
// set_form_spec(self, text) // Has metadata; clear old one first
static int l_set_form_spec(lua_State *L) ref->m_env->getMap().removeNodeMetadata(ref->m_p);
{ // Create new metadata
NodeMetaRef *ref = checkobject(L, 1); NodeMetadata *meta = getmeta(ref, true);
size_t len = 0; // Set fields
const char *s = lua_tolstring(L, 2, &len); lua_getfield(L, base, "fields");
std::string str(s, len); int fieldstable = lua_gettop(L);
lua_pushnil(L);
NodeMetadata *meta = getmeta(ref, !str.empty()); while(lua_next(L, fieldstable) != 0){
if(meta == NULL || str == meta->getString("formspec")) // key at index -2 and value at index -1
return 0; std::string name = lua_tostring(L, -2);
meta->setString("formspec",str); size_t cl;
reportMetadataChange(ref); const char *cs = lua_tolstring(L, -1, &cl);
return 0; std::string value(cs, cl);
} meta->setString(name, value);
lua_pop(L, 1); // removes value, keeps key for next iteration
// get_infotext(self) }
static int l_get_infotext(lua_State *L) // Set inventory
{ Inventory *inv = meta->getInventory();
NodeMetaRef *ref = checkobject(L, 1); lua_getfield(L, base, "inventory");
int inventorytable = lua_gettop(L);
NodeMetadata *meta = getmeta(ref, false); lua_pushnil(L);
if(meta == NULL){ while(lua_next(L, inventorytable) != 0){
lua_pushlstring(L, "", 0); // key at index -2 and value at index -1
return 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
} }
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);
reportMetadataChange(ref); reportMetadataChange(ref);
return 0; lua_pushboolean(L, true);
return 1;
} }
public: public:
@ -2240,12 +2235,8 @@ const luaL_reg NodeMetaRef::methods[] = {
method(NodeMetaRef, get_float), method(NodeMetaRef, get_float),
method(NodeMetaRef, set_float), method(NodeMetaRef, set_float),
method(NodeMetaRef, get_inventory), method(NodeMetaRef, get_inventory),
method(NodeMetaRef, get_inventory_draw_spec), method(NodeMetaRef, to_table),
method(NodeMetaRef, set_inventory_draw_spec), method(NodeMetaRef, from_table),
method(NodeMetaRef, get_form_spec),
method(NodeMetaRef, set_form_spec),
method(NodeMetaRef, get_infotext),
method(NodeMetaRef, set_infotext),
{0,0} {0,0}
}; };