NodeMetaRef:{to,from}_table and lua_api.txt additions
authorPerttu Ahola <celeron55@gmail.com>
Sat, 2 Jun 2012 08:01:28 +0000 (11:01 +0300)
committerPerttu Ahola <celeron55@gmail.com>
Sun, 3 Jun 2012 19:31:01 +0000 (22:31 +0300)
doc/lua_api.txt
src/inventory.cpp
src/inventory.h
src/map.cpp
src/nodemetadata.h
src/scriptapi.cpp

index f8615b1308f3413cb01a93c59c7524bb30c819af..70ba82dc797d81ec2b7957b81dd27486836b4e67 100644 (file)
@@ -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
     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:
@@ -548,6 +550,91 @@ time_from_last_punch, tool_capabilities, direction)''.
   * 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={})
@@ -766,7 +853,9 @@ Deprecated:
 - 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)
@@ -775,6 +864,9 @@ methods:
 - 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)
index 3d6707f60684b22a7209bc56456fc7bb00f7571b..df75ebcd53b006c5bd867b5ddb883343fe22c6a1 100644 (file)
@@ -915,6 +915,17 @@ InventoryList * Inventory::getList(const std::string &name)
        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)
 {
        s32 i = getListIndex(name);
index 0f620e83c0b724cd059c7c3686ca072474a8b8ee..411eabb0977c4939351d1e7ceb03331b3d1c67f5 100644 (file)
@@ -262,6 +262,7 @@ public:
        InventoryList * addList(const std::string &name, u32 size);
        InventoryList * getList(const std::string &name);
        const InventoryList * getList(const std::string &name) const;
+       std::vector<const InventoryList*> getLists();
        bool deleteList(const std::string &name);
        // A shorthand for adding items. Returns leftover item (possibly empty).
        ItemStack addItem(const std::string &listname, const ItemStack &newitem)
index c981567ae910571af3d13421d143dab160050fd6..10dba3de94cde1a1af0bcd409daafe412fb14836 100644 (file)
@@ -1009,6 +1009,12 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
        }
 
+       /*
+               Remove node metadata
+       */
+
+       removeNodeMetadata(p);
+
        /*
                Set the node on the map
        */
@@ -3451,15 +3457,15 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
                }
                catch(InvalidFilenameException &e)
                {
-                       return false;
+                       return NULL;
                }
                catch(FileNotGoodException &e)
                {
-                       return false;
+                       return NULL;
                }
                catch(std::exception &e)
                {
-                       return false;
+                       return NULL;
                }
        }
        
index e855eab9b4c3fa6a6d94beb0086548aabcfc90ec..c40e873dfa3b815157c2069a054fb95e5144445d 100644 (file)
@@ -64,6 +64,10 @@ public:
                else
                        m_stringvars[name] = var;
        }
+       std::map<std::string, std::string> getStrings() const
+       {
+               return m_stringvars;
+       }
 
        // The inventory
        Inventory* getInventory()
index 213fb47f9ae941a0a64d5223b721d60e3b5f5dfe..76807b14b378dd10cf4d201cf0ee68aab01155de 100644 (file)
@@ -1233,6 +1233,8 @@ static void inventory_get_list_to_lua(Inventory *inv, const char *name,
                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
 }
 
 /*
@@ -2087,98 +2089,91 @@ private:
                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:
@@ -2240,12 +2235,8 @@ const luaL_reg NodeMetaRef::methods[] = {
        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}
 };