diff options
-rw-r--r-- | doc/lua_api.txt | 94 | ||||
-rw-r--r-- | src/inventory.cpp | 11 | ||||
-rw-r--r-- | src/inventory.h | 1 | ||||
-rw-r--r-- | src/map.cpp | 12 | ||||
-rw-r--r-- | src/nodemetadata.h | 4 | ||||
-rw-r--r-- | src/scriptapi.cpp | 155 |
6 files changed, 191 insertions, 86 deletions
diff --git a/doc/lua_api.txt b/doc/lua_api.txt index f8615b130..70ba82dc7 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -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) diff --git a/src/inventory.cpp b/src/inventory.cpp index 3d6707f60..df75ebcd5 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -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); diff --git a/src/inventory.h b/src/inventory.h index 0f620e83c..411eabb09 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -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) diff --git a/src/map.cpp b/src/map.cpp index c981567ae..10dba3de9 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1010,6 +1010,12 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, } /* + 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; } } diff --git a/src/nodemetadata.h b/src/nodemetadata.h index e855eab9b..c40e873df 100644 --- a/src/nodemetadata.h +++ b/src/nodemetadata.h @@ -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() diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp index 213fb47f9..76807b14b 100644 --- a/src/scriptapi.cpp +++ b/src/scriptapi.cpp @@ -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} }; |